summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore5
-rw-r--r--BUGS.txt6
-rw-r--r--CMakeLists.txt59
-rw-r--r--README.md99
-rw-r--r--README.txt85
-rw-r--r--changes.old6027
-rw-r--r--changes.txt198
-rw-r--r--doc/DEBUG.txt (renamed from DEBUG.txt)0
-rw-r--r--doc/RELEASE.txt8
-rw-r--r--doc/changes.txt208
-rw-r--r--doc/credits.txt (renamed from credits.txt)0
-rw-r--r--doc/images/screenshot.pngbin0 -> 20223 bytes
-rw-r--r--lib/.gitignore2
-rw-r--r--lib/CMakeLists.txt10
-rw-r--r--lib/apex/.cvsignore1
-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/edit/a_info.txt190
-rw-r--r--lib/edit/ab_info.txt19
-rw-r--r--lib/edit/al_info.txt2097
-rw-r--r--lib/edit/ba_info.txt50
-rw-r--r--lib/edit/d_info.txt6
-rw-r--r--lib/edit/e_info.txt22
-rw-r--r--lib/edit/f_info.txt5
-rw-r--r--lib/edit/k_info.txt193
-rw-r--r--lib/edit/misc.txt3
-rw-r--r--lib/edit/ow_info.txt146
-rw-r--r--lib/edit/p_info.txt50
-rw-r--r--lib/edit/r_info.txt4
-rw-r--r--lib/edit/ra_info.txt4
-rw-r--r--lib/edit/re_info.txt4
-rw-r--r--lib/edit/s_info.txt10
-rw-r--r--lib/edit/set_info.txt4
-rw-r--r--lib/edit/st_info.txt23
-rw-r--r--lib/edit/t_basic.txt80
-rw-r--r--lib/edit/t_bree.txt5
-rw-r--r--lib/edit/t_gondol.txt5
-rw-r--r--lib/edit/t_minas.txt5
-rw-r--r--lib/edit/tr_info.txt2
-rw-r--r--lib/edit/v_info.txt5
-rw-r--r--lib/edit/wf_info.txt4
-rw-r--r--lib/file/elvish.txt218
-rw-r--r--lib/help/ability.txt20
-rw-r--r--lib/help/advanced.hlp5
-rw-r--r--lib/help/automat.txt7
-rw-r--r--lib/help/birth.txt3
-rw-r--r--lib/help/c_alchem.txt135
-rw-r--r--lib/help/c_merch.txt29
-rw-r--r--lib/help/command.txt44
-rw-r--r--lib/help/debug.txt5
-rw-r--r--lib/help/def.aux3
-rw-r--r--lib/help/defines.txt23
-rw-r--r--lib/help/dungeon.txt2
-rw-r--r--lib/help/essences.txt219
-rw-r--r--lib/help/index.txt9
-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/macrofaq.txt16
-rw-r--r--lib/help/magic.txt5
-rw-r--r--lib/help/option.txt131
-rw-r--r--lib/help/skills.txt11
-rw-r--r--lib/help/spoiler.hlp1
-rw-r--r--lib/help/tome_faq.txt8
-rw-r--r--lib/mods/.cvsignore1
-rw-r--r--lib/mods/CMakeLists.txt1
-rw-r--r--lib/mods/mods_aux.lua185
-rw-r--r--lib/mods/modules.lua5
-rw-r--r--lib/mods/theme/CMakeLists.txt14
-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/edit/a_info.txt233
-rw-r--r--lib/mods/theme/edit/ab_info.txt10
-rw-r--r--lib/mods/theme/edit/al_info.txt12
-rw-r--r--lib/mods/theme/edit/ba_info.txt50
-rw-r--r--lib/mods/theme/edit/d_info.txt9
-rw-r--r--lib/mods/theme/edit/e_info.txt26
-rw-r--r--lib/mods/theme/edit/f_info.txt5
-rw-r--r--lib/mods/theme/edit/k_info.txt56
-rw-r--r--lib/mods/theme/edit/misc.txt3
-rw-r--r--lib/mods/theme/edit/ow_info.txt431
-rw-r--r--lib/mods/theme/edit/p_info.txt21
-rw-r--r--lib/mods/theme/edit/r_info.txt8
-rw-r--r--lib/mods/theme/edit/ra_info.txt4
-rw-r--r--lib/mods/theme/edit/re_info.txt4
-rw-r--r--lib/mods/theme/edit/s_info.txt4
-rw-r--r--lib/mods/theme/edit/set_info.txt4
-rw-r--r--lib/mods/theme/edit/st_info.txt20
-rw-r--r--lib/mods/theme/edit/t_basic.txt66
-rw-r--r--lib/mods/theme/edit/t_gondol.txt5
-rw-r--r--lib/mods/theme/edit/t_minas.txt2
-rw-r--r--lib/mods/theme/edit/tr_info.txt2
-rw-r--r--lib/mods/theme/edit/v_info.txt5
-rw-r--r--lib/mods/theme/edit/w_info.txt2
-rw-r--r--lib/mods/theme/edit/wf_info.txt10
-rw-r--r--lib/mods/theme/file/elvish.txt218
-rw-r--r--lib/mods/theme/help/ability.txt20
-rw-r--r--lib/mods/theme/help/advanced.hlp5
-rw-r--r--lib/mods/theme/help/automat.txt7
-rw-r--r--lib/mods/theme/help/c_alchem.txt135
-rw-r--r--lib/mods/theme/help/c_merch.txt29
-rw-r--r--lib/mods/theme/help/command.txt44
-rw-r--r--lib/mods/theme/help/debug.txt5
-rw-r--r--lib/mods/theme/help/def.aux3
-rw-r--r--lib/mods/theme/help/defines.txt23
-rw-r--r--lib/mods/theme/help/dungeon.txt2
-rw-r--r--lib/mods/theme/help/essences.txt219
-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/macrofaq.txt16
-rw-r--r--lib/mods/theme/help/magic.txt5
-rw-r--r--lib/mods/theme/help/option.txt131
-rw-r--r--lib/mods/theme/help/skills.txt11
-rw-r--r--lib/mods/theme/help/spoiler.hlp1
-rw-r--r--lib/mods/theme/help/tome_faq.txt8
-rw-r--r--lib/mods/theme/module.lua48
-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-mac.new110
-rw-r--r--lib/mods/theme/pref/font-xxx.prf3
-rw-r--r--lib/mods/theme/pref/font.prf20
-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.prf16
-rw-r--r--lib/mods/theme/pref/user.prf17
-rw-r--r--lib/mods/theme/pref/xtra-new.prf63
-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/user/all.prf63
-rw-r--r--lib/module.lua36
-rw-r--r--lib/patch/.cvsignore1
-rw-r--r--lib/pref/422color.prf909
-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-xxx.prf3
-rw-r--r--lib/pref/font.prf20
-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-iso.prf118
-rw-r--r--lib/pref/pref.prf16
-rw-r--r--lib/pref/trap-iso.prf429
-rw-r--r--lib/pref/user.prf17
-rw-r--r--lib/pref/xtra-new.prf1128
-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/xtra/graf/16x16.bmpbin1164238 -> 0 bytes
-rw-r--r--lib/xtra/graf/16x16.pngbin210021 -> 0 bytes
-rw-r--r--lib/xtra/graf/8x8.bmpbin203830 -> 0 bytes
-rw-r--r--lib/xtra/graf/8x8.pngbin44451 -> 0 bytes
-rw-r--r--lib/xtra/graf/mask.bmpbin1164342 -> 0 bytes
-rw-r--r--lib/xtra/graf/tome-128.pngbin45589 -> 0 bytes
-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/.gitignore3
-rw-r--r--src/CMakeLists.txt182
-rw-r--r--src/ability_type.hpp27
-rw-r--r--src/ability_type_fwd.hpp3
-rw-r--r--src/activation.hpp13
-rw-r--r--src/alloc_entry.hpp20
-rw-r--r--src/alloc_entry_fwd.hpp3
-rw-r--r--src/angband.h20
-rw-r--r--src/angband.rc21
-rw-r--r--src/artifact_type.hpp60
-rw-r--r--src/artifact_type_fwd.hpp3
-rw-r--r--src/between_exit.hpp18
-rw-r--r--src/birth.c3825
-rw-r--r--src/birth.cc3724
-rw-r--r--src/birth.h14
-rw-r--r--src/birth.hpp9
-rw-r--r--src/birther.hpp35
-rw-r--r--src/bldg.c2198
-rw-r--r--src/bldg.cc1469
-rw-r--r--src/bldg.hpp9
-rw-r--r--src/body.hpp12
-rw-r--r--src/carbon/Angband.icnsbin66668 -> 0 bytes
-rw-r--r--src/carbon/Carbon.r1568
-rw-r--r--src/carbon/Data.icnsbin36416 -> 0 bytes
-rw-r--r--src/carbon/Edit.icnsbin35735 -> 0 bytes
-rw-r--r--src/carbon/Image-DS_Storebin6148 -> 0 bytes
-rw-r--r--src/carbon/Info.plist39
-rw-r--r--src/carbon/Save.icnsbin43952 -> 0 bytes
-rwxr-xr-xsrc/carbon/getversion2
-rw-r--r--src/cave.c5055
-rw-r--r--src/cave.cc4693
-rw-r--r--src/cave.hpp55
-rw-r--r--src/cave_type.hpp65
-rw-r--r--src/cave_type_fwd.hpp3
-rw-r--r--src/cli_comm.hpp13
-rw-r--r--src/cli_comm_fwd.hpp3
-rw-r--r--src/cmd1.c5125
-rw-r--r--src/cmd1.cc4999
-rw-r--r--src/cmd1.hpp25
-rw-r--r--src/cmd2.c5107
-rw-r--r--src/cmd2.cc5014
-rw-r--r--src/cmd2.hpp33
-rw-r--r--src/cmd3.c2331
-rw-r--r--src/cmd3.cc2110
-rw-r--r--src/cmd3.hpp24
-rw-r--r--src/cmd4.c4658
-rw-r--r--src/cmd4.cc4415
-rw-r--r--src/cmd4.hpp28
-rw-r--r--src/cmd5.c2562
-rw-r--r--src/cmd5.cc2214
-rw-r--r--src/cmd5.hpp16
-rw-r--r--src/cmd6.c7731
-rw-r--r--src/cmd6.cc7928
-rw-r--r--src/cmd6.hpp18
-rw-r--r--src/cmd7.c7652
-rw-r--r--src/cmd7.cc4466
-rw-r--r--src/cmd7.hpp28
-rw-r--r--src/cmovie.c496
-rw-r--r--src/config.h185
-rw-r--r--src/corrupt.cc1003
-rw-r--r--src/corrupt.hpp47
-rw-r--r--src/defines.h1106
-rw-r--r--src/deity_type.hpp11
-rw-r--r--src/deity_type_fwd.hpp3
-rw-r--r--src/device_allocation.cc20
-rw-r--r--src/device_allocation.hpp17
-rw-r--r--src/device_allocation_fwd.hpp8
-rw-r--r--src/dice.cc98
-rw-r--r--src/dice.hpp13
-rw-r--r--src/dice_fwd.hpp12
-rw-r--r--src/dungeon.c5664
-rw-r--r--src/dungeon.cc5565
-rw-r--r--src/dungeon.h14
-rw-r--r--src/dungeon.hpp6
-rw-r--r--src/dungeon.pkg1607
-rw-r--r--src/dungeon_info_type.hpp72
-rw-r--r--src/dungeon_info_type_fwd.hpp3
-rw-r--r--src/effect_type.hpp17
-rw-r--r--src/ego_item_type.hpp68
-rw-r--r--src/ego_item_type_fwd.hpp3
-rw-r--r--src/externs.h1851
-rw-r--r--src/fate.hpp22
-rw-r--r--src/feature_type.hpp37
-rw-r--r--src/feature_type_fwd.hpp3
-rw-r--r--src/files.c6058
-rw-r--r--src/files.cc5788
-rw-r--r--src/files.h17
-rw-r--r--src/files.hpp27
-rw-r--r--src/flags_group.hpp20
-rw-r--r--src/gen_evol.c156
-rw-r--r--src/gen_evol.cc160
-rw-r--r--src/gen_evol.hpp6
-rw-r--r--src/gen_maze.c294
-rw-r--r--src/gen_maze.cc294
-rw-r--r--src/gen_maze.hpp5
-rw-r--r--src/generate.c8890
-rw-r--r--src/generate.cc8698
-rw-r--r--src/generate.hpp12
-rw-r--r--src/gf_name_type.hpp10
-rw-r--r--src/gods.c139
-rw-r--r--src/gods.cc212
-rw-r--r--src/gods.hpp13
-rw-r--r--src/h-basic.h10
-rw-r--r--src/h-config.h208
-rw-r--r--src/h-define.h19
-rw-r--r--src/h-system.h56
-rw-r--r--src/h-type.h23
-rw-r--r--src/help.c23
-rw-r--r--src/help.cc742
-rw-r--r--src/help.hpp11
-rw-r--r--src/help_info.hpp17
-rw-r--r--src/hiscore.cc85
-rw-r--r--src/hiscore.hpp83
-rw-r--r--src/hist_type.hpp16
-rw-r--r--src/hist_type_fwd.hpp3
-rw-r--r--src/hook_build_room1_in.hpp8
-rw-r--r--src/hook_calculate_hp_in.hpp7
-rw-r--r--src/hook_calculate_hp_out.hpp7
-rw-r--r--src/hook_chardump_in.hpp7
-rw-r--r--src/hook_chat_in.hpp7
-rw-r--r--src/hook_drop_in.hpp5
-rw-r--r--src/hook_eat_in.hpp7
-rw-r--r--src/hook_eat_out.hpp7
-rw-r--r--src/hook_enter_dungeon_in.hpp7
-rw-r--r--src/hook_get_in.hpp8
-rw-r--r--src/hook_give_in.hpp6
-rw-r--r--src/hook_identify_in.hpp9
-rw-r--r--src/hook_init_quest_in.hpp5
-rw-r--r--src/hook_mon_speak_in.hpp8
-rw-r--r--src/hook_monster_ai_in.hpp9
-rw-r--r--src/hook_monster_ai_out.hpp8
-rw-r--r--src/hook_monster_death_in.hpp7
-rw-r--r--src/hook_move_in.hpp6
-rw-r--r--src/hook_new_monster_end_in.hpp7
-rw-r--r--src/hook_new_monster_in.hpp7
-rw-r--r--src/hook_player_level_in.hpp5
-rw-r--r--src/hook_quest_fail_in.hpp7
-rw-r--r--src/hook_quest_finish_in.hpp7
-rw-r--r--src/hook_stair_in.hpp7
-rw-r--r--src/hook_stair_out.hpp7
-rw-r--r--src/hook_wield_in.hpp7
-rw-r--r--src/hook_wild_gen_in.hpp7
-rw-r--r--src/hooks.cc113
-rw-r--r--src/hooks.hpp10
-rw-r--r--src/identify_mode.hpp3
-rw-r--r--src/include/tome/enum_string_map.hpp55
-rw-r--r--src/include/tome/make_array.hpp13
-rw-r--r--src/include/tome/squelch/automatizer.hpp156
-rw-r--r--src/include/tome/squelch/automatizer_fwd.hpp10
-rw-r--r--src/include/tome/squelch/condition.hpp632
-rw-r--r--src/include/tome/squelch/condition_fwd.hpp15
-rw-r--r--src/include/tome/squelch/condition_metadata.hpp12
-rw-r--r--src/include/tome/squelch/condition_metadata_fwd.hpp14
-rw-r--r--src/include/tome/squelch/cursor.hpp50
-rw-r--r--src/include/tome/squelch/cursor_fwd.hpp10
-rw-r--r--src/include/tome/squelch/object_status.hpp28
-rw-r--r--src/include/tome/squelch/object_status_fwd.hpp12
-rw-r--r--src/include/tome/squelch/rule.hpp162
-rw-r--r--src/include/tome/squelch/rule_fwd.hpp16
-rw-r--r--src/include/tome/squelch/tree_printer.hpp49
-rw-r--r--src/include/tome/squelch/tree_printer_fwd.hpp10
-rw-r--r--src/init1.c11819
-rw-r--r--src/init1.cc10225
-rw-r--r--src/init1.hpp26
-rw-r--r--src/init2.c2918
-rw-r--r--src/init2.cc1494
-rw-r--r--src/init2.h14
-rw-r--r--src/init2.hpp9
-rw-r--r--src/inscription_info_type.hpp14
-rw-r--r--src/inventory.hpp35
-rw-r--r--src/iso/.cvsignore1
-rw-r--r--src/joke.cc40
-rw-r--r--src/joke.hpp5
-rw-r--r--src/lauxlib.h100
-rw-r--r--src/levels.c234
-rw-r--r--src/levels.cc237
-rw-r--r--src/levels.hpp13
-rw-r--r--src/loadsave.c3288
-rw-r--r--src/loadsave.cc2975
-rw-r--r--src/loadsave.h16
-rw-r--r--src/loadsave.hpp7
-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
-rw-r--r--src/lua_bind.cc277
-rw-r--r--src/lua_bind.hpp34
-rw-r--r--src/magic_power.hpp15
-rwxr-xr-xsrc/maid-x11.c855
-rw-r--r--src/main-crb.c6402
-rw-r--r--src/main-gcu.c217
-rw-r--r--src/main-gtk2.c3077
-rw-r--r--src/main-sdl.c219
-rw-r--r--src/main-sla.c455
-rw-r--r--src/main-win.c1080
-rw-r--r--src/main-x11.c832
-rw-r--r--src/main-xaw.c1888
-rw-r--r--src/main-xxx.c785
-rw-r--r--src/main.c389
-rw-r--r--src/martial_arts.hpp18
-rw-r--r--src/melee1.c3065
-rw-r--r--src/melee1.cc3048
-rw-r--r--src/melee1.hpp7
-rw-r--r--src/melee2.c7591
-rw-r--r--src/melee2.cc7475
-rw-r--r--src/melee2.hpp12
-rw-r--r--src/messages.cc368
-rw-r--r--src/messages.hpp9
-rw-r--r--src/meta_class_type.hpp10
-rw-r--r--src/meta_class_type_fwd.hpp3
-rw-r--r--src/mimic.cc728
-rw-r--r--src/mimic.hpp10
-rw-r--r--src/module_type.hpp64
-rw-r--r--src/modules.c274
-rw-r--r--src/modules.cc1279
-rw-r--r--src/modules.h15
-rw-r--r--src/modules.hpp11
-rw-r--r--src/monster.pkg2324
-rw-r--r--src/monster1.c1908
-rw-r--r--src/monster1.cc1887
-rw-r--r--src/monster1.hpp5
-rw-r--r--src/monster2.c4054
-rw-r--r--src/monster2.cc3985
-rw-r--r--src/monster2.hpp52
-rw-r--r--src/monster3.c706
-rw-r--r--src/monster3.cc722
-rw-r--r--src/monster3.hpp20
-rw-r--r--src/monster_blow.hpp19
-rw-r--r--src/monster_ego.hpp81
-rw-r--r--src/monster_ego_fwd.hpp3
-rw-r--r--src/monster_power.hpp14
-rw-r--r--src/monster_race.hpp116
-rw-r--r--src/monster_race_fwd.hpp3
-rw-r--r--src/monster_type.cc8
-rw-r--r--src/monster_type.hpp98
-rw-r--r--src/monster_type_fwd.hpp3
-rw-r--r--src/move_info_type.hpp15
-rw-r--r--src/music.hpp17
-rw-r--r--src/notes.c188
-rw-r--r--src/notes.cc185
-rw-r--r--src/notes.hpp6
-rw-r--r--src/obj_theme.hpp15
-rw-r--r--src/obj_theme_fwd.hpp3
-rw-r--r--src/object.pkg1169
-rw-r--r--src/object1.c6669
-rw-r--r--src/object1.cc6698
-rw-r--r--src/object1.hpp46
-rw-r--r--src/object2.c6617
-rw-r--r--src/object2.cc6465
-rw-r--r--src/object2.hpp69
-rw-r--r--src/object_filter.cc98
-rw-r--r--src/object_filter.hpp99
-rw-r--r--src/object_kind.hpp83
-rw-r--r--src/object_kind_fwd.hpp3
-rw-r--r--src/object_type.hpp104
-rw-r--r--src/object_type_fwd.hpp3
-rw-r--r--src/option_type.hpp40
-rw-r--r--src/options.cc89
-rw-r--r--src/options.hpp89
-rw-r--r--src/owner_type.hpp39
-rw-r--r--src/owner_type_fwd.hpp3
-rw-r--r--src/player.pkg3519
-rw-r--r--src/player_c.pkg1060
-rw-r--r--src/player_class.hpp105
-rw-r--r--src/player_class_fwd.hpp3
-rw-r--r--src/player_defs.hpp6
-rw-r--r--src/player_race.hpp83
-rw-r--r--src/player_race_fwd.hpp3
-rw-r--r--src/player_race_mod.hpp87
-rw-r--r--src/player_race_mod_fwd.hpp3
-rw-r--r--src/player_sex.hpp17
-rw-r--r--src/player_sex_fwd.hpp3
-rw-r--r--src/player_spec.hpp38
-rw-r--r--src/player_spec_fwd.hpp3
-rw-r--r--src/player_type.hpp423
-rw-r--r--src/player_type_fwd.hpp3
-rw-r--r--src/plots.c473
-rw-r--r--src/plots.h48
-rw-r--r--src/power_type.hpp19
-rw-r--r--src/powers.c1388
-rw-r--r--src/powers.cc1221
-rw-r--r--src/powers.hpp74
-rw-r--r--src/q_betwen.c188
-rw-r--r--src/q_betwen.cc212
-rw-r--r--src/q_betwen.hpp5
-rw-r--r--src/q_bounty.cc170
-rw-r--r--src/q_bounty.hpp8
-rw-r--r--src/q_dragons.c150
-rw-r--r--src/q_dragons.cc164
-rw-r--r--src/q_dragons.hpp5
-rw-r--r--src/q_eol.c195
-rw-r--r--src/q_eol.cc226
-rw-r--r--src/q_eol.hpp5
-rw-r--r--src/q_evil.c117
-rw-r--r--src/q_evil.cc132
-rw-r--r--src/q_evil.hpp5
-rw-r--r--src/q_fireprof.cc577
-rw-r--r--src/q_fireprof.hpp7
-rw-r--r--src/q_god.cc1212
-rw-r--r--src/q_god.hpp6
-rw-r--r--src/q_haunted.c147
-rw-r--r--src/q_haunted.cc163
-rw-r--r--src/q_haunted.hpp5
-rw-r--r--src/q_hobbit.c195
-rw-r--r--src/q_hobbit.cc230
-rw-r--r--src/q_hobbit.hpp5
-rw-r--r--src/q_invas.c201
-rw-r--r--src/q_invas.cc222
-rw-r--r--src/q_invas.hpp5
-rw-r--r--src/q_library.cc526
-rw-r--r--src/q_library.hpp8
-rw-r--r--src/q_main.c176
-rw-r--r--src/q_main.cc210
-rw-r--r--src/q_main.hpp7
-rw-r--r--src/q_narsil.c108
-rw-r--r--src/q_narsil.cc122
-rw-r--r--src/q_narsil.hpp5
-rw-r--r--src/q_nazgul.c116
-rw-r--r--src/q_nazgul.cc145
-rw-r--r--src/q_nazgul.hpp5
-rw-r--r--src/q_nirna.c109
-rw-r--r--src/q_nirna.cc125
-rw-r--r--src/q_nirna.hpp5
-rw-r--r--src/q_one.c354
-rw-r--r--src/q_one.cc378
-rw-r--r--src/q_one.hpp5
-rw-r--r--src/q_poison.c238
-rw-r--r--src/q_poison.cc263
-rw-r--r--src/q_poison.hpp5
-rw-r--r--src/q_rand.c465
-rw-r--r--src/q_rand.cc655
-rw-r--r--src/q_rand.hpp8
-rw-r--r--src/q_shroom.c293
-rw-r--r--src/q_shroom.cc311
-rw-r--r--src/q_shroom.hpp5
-rw-r--r--src/q_spider.c108
-rw-r--r--src/q_spider.cc127
-rw-r--r--src/q_spider.hpp5
-rw-r--r--src/q_thief.c172
-rw-r--r--src/q_thief.cc193
-rw-r--r--src/q_thief.hpp5
-rw-r--r--src/q_thrain.c230
-rw-r--r--src/q_thrain.cc261
-rw-r--r--src/q_thrain.hpp5
-rw-r--r--src/q_troll.c178
-rw-r--r--src/q_troll.cc194
-rw-r--r--src/q_troll.hpp5
-rw-r--r--src/q_ultrae.c11
-rw-r--r--src/q_ultrae.cc8
-rw-r--r--src/q_ultrae.hpp5
-rw-r--r--src/q_ultrag.c276
-rw-r--r--src/q_ultrag.cc292
-rw-r--r--src/q_ultrag.hpp5
-rw-r--r--src/q_wight.c156
-rw-r--r--src/q_wight.cc179
-rw-r--r--src/q_wight.hpp5
-rw-r--r--src/q_wolves.c130
-rw-r--r--src/q_wolves.cc146
-rw-r--r--src/q_wolves.hpp5
-rw-r--r--src/quark.cc96
-rw-r--r--src/quark.hpp12
-rw-r--r--src/quest.cc17
-rw-r--r--src/quest.hpp3
-rwxr-xr-xsrc/quest.pkg170
-rw-r--r--src/quest_type.hpp27
-rw-r--r--src/randart.c476
-rw-r--r--src/randart.cc481
-rw-r--r--src/randart.hpp9
-rw-r--r--src/randart_gen_type.hpp9
-rw-r--r--src/randart_gen_type_fwd.hpp3
-rw-r--r--src/randart_part_type.hpp43
-rw-r--r--src/randart_part_type_fwd.hpp3
-rw-r--r--src/random_artifact.hpp18
-rw-r--r--src/random_quest.hpp10
-rw-r--r--src/random_spell.hpp21
-rw-r--r--src/range.cc11
-rw-r--r--src/range.hpp15
-rw-r--r--src/range_fwd.hpp4
-rw-r--r--src/readdib.c342
-rw-r--r--src/readdib.h21
-rw-r--r--src/rule_type.hpp22
-rw-r--r--src/rune_spell.hpp15
-rw-r--r--src/rune_spell_fwd.hpp3
-rw-r--r--src/school_book.hpp15
-rw-r--r--src/school_book_fwd.hpp3
-rw-r--r--src/school_type.hpp21
-rw-r--r--src/school_type_fwd.hpp3
-rw-r--r--src/script.c535
-rw-r--r--src/script.cc30
-rw-r--r--src/script.h12
-rw-r--r--src/set_type.hpp28
-rw-r--r--src/set_type_fwd.hpp3
-rw-r--r--src/skill_type.hpp37
-rw-r--r--src/skill_type_fwd.hpp3
-rw-r--r--src/skills.c1661
-rw-r--r--src/skills.cc1829
-rw-r--r--src/skills.hpp27
-rw-r--r--src/skills_defs.hpp63
-rw-r--r--src/spell_type.cc433
-rw-r--r--src/spell_type.hpp86
-rw-r--r--src/spell_type_fwd.hpp16
-rw-r--r--src/spells.pkg2448
-rw-r--r--src/spells1.c9327
-rw-r--r--src/spells1.cc9275
-rw-r--r--src/spells1.hpp32
-rw-r--r--src/spells2.c8076
-rw-r--r--src/spells2.cc6837
-rw-r--r--src/spells2.hpp115
-rw-r--r--src/spells3.cc4606
-rw-r--r--src/spells3.hpp445
-rw-r--r--src/spells4.cc541
-rw-r--r--src/spells4.hpp42
-rw-r--r--src/spells5.cc2395
-rw-r--r--src/spells5.hpp9
-rw-r--r--src/spells6.cc402
-rw-r--r--src/spells6.hpp7
-rw-r--r--src/squelch/CMakeLists.txt9
-rw-r--r--src/squelch/automatizer.cc278
-rw-r--r--src/squelch/condition.cc1078
-rw-r--r--src/squelch/condition_metadata.cc496
-rw-r--r--src/squelch/cursor.cc96
-rw-r--r--src/squelch/object_status.cc153
-rw-r--r--src/squelch/rule.cc332
-rw-r--r--src/squelch/tree_printer.cc89
-rw-r--r--src/squeltch.c553
-rw-r--r--src/squeltch.cc593
-rw-r--r--src/squeltch.hpp13
-rw-r--r--src/stairs_direction.hpp3
-rw-r--r--src/stats.hpp11
-rw-r--r--src/status.c773
-rw-r--r--src/status.cc783
-rw-r--r--src/status.hpp3
-rw-r--r--src/store.c4458
-rw-r--r--src/store.cc3878
-rw-r--r--src/store.hpp12
-rw-r--r--src/store_action_type.hpp17
-rw-r--r--src/store_action_type_fwd.hpp3
-rw-r--r--src/store_info_type.hpp32
-rw-r--r--src/store_info_type_fwd.hpp3
-rw-r--r--src/store_type.hpp43
-rw-r--r--src/store_type_fwd.hpp3
-rw-r--r--src/tables.c4792
-rw-r--r--src/tables.cc4506
-rw-r--r--src/tables.h12
-rw-r--r--src/tables.hpp82
-rw-r--r--src/tactic_info_type.hpp17
-rw-r--r--src/terrain.hpp19
-rw-r--r--src/timer_type.hpp18
-rw-r--r--src/timer_type_fwd.hpp3
-rw-r--r--src/town_type.hpp21
-rw-r--r--src/town_type_fwd.hpp3
-rw-r--r--src/trap_type.hpp24
-rw-r--r--src/trap_type_fwd.hpp3
-rw-r--r--src/traps.c3169
-rw-r--r--src/traps.cc3174
-rw-r--r--src/traps.hpp13
-rw-r--r--src/tval_desc.hpp17
-rw-r--r--src/types.h2522
-rw-r--r--src/util.c4479
-rw-r--r--src/util.cc3685
-rw-r--r--src/util.h22
-rw-r--r--src/util.hpp74
-rw-r--r--src/util.pkg2683
-rw-r--r--src/variable.c1604
-rw-r--r--src/variable.cc1065
-rw-r--r--src/variable.h39
-rw-r--r--src/variable.hpp308
-rw-r--r--src/vault_type.hpp24
-rw-r--r--src/vault_type_fwd.hpp3
-rw-r--r--src/wild.c1275
-rw-r--r--src/wild.cc1301
-rw-r--r--src/wild.hpp6
-rw-r--r--src/wilderness_map.hpp15
-rw-r--r--src/wilderness_map_fwd.hpp3
-rw-r--r--src/wilderness_type_info.hpp25
-rw-r--r--src/wilderness_type_info_fwd.hpp3
-rw-r--r--src/wizard1.c2756
-rw-r--r--src/wizard1.cc2499
-rw-r--r--src/wizard1.hpp3
-rw-r--r--src/wizard2.c1950
-rw-r--r--src/wizard2.cc1868
-rw-r--r--src/wizard2.hpp8
-rw-r--r--src/xtra1.c4772
-rw-r--r--src/xtra1.cc4684
-rw-r--r--src/xtra1.hpp24
-rw-r--r--src/xtra2.c6158
-rw-r--r--src/xtra2.cc5626
-rw-r--r--src/xtra2.hpp96
-rw-r--r--src/z-form.c191
-rw-r--r--src/z-form.h21
-rw-r--r--src/z-rand.c355
-rw-r--r--src/z-rand.cc376
-rw-r--r--src/z-rand.h96
-rw-r--r--src/z-rand.hpp67
-rw-r--r--src/z-term.c1094
-rw-r--r--src/z-term.h128
-rw-r--r--src/z-util.c172
-rw-r--r--src/z-util.h60
-rw-r--r--src/z-virt.c187
-rw-r--r--src/z-virt.h168
-rw-r--r--src/z_pack.pkg398
-rw-r--r--tests/get_level_device.cc184
-rw-r--r--tests/harness.cc7
-rw-r--r--tests/lua_get_level.cc135
-rw-r--r--vendor/bandit/.travis.yml17
-rw-r--r--vendor/bandit/.vimrc0
-rw-r--r--vendor/bandit/CMakeLists.txt60
-rw-r--r--vendor/bandit/LICENSE.md21
-rw-r--r--vendor/bandit/README.md63
-rw-r--r--vendor/bandit/bandit/adapters/adapter.h12
-rw-r--r--vendor/bandit/bandit/adapters/adapters.h16
-rw-r--r--vendor/bandit/bandit/adapters/snowhouse.h22
-rw-r--r--vendor/bandit/bandit/assertion_exception.h41
-rw-r--r--vendor/bandit/bandit/assertion_frameworks/matchers/BeCloseTo.h55
-rw-r--r--vendor/bandit/bandit/assertion_frameworks/matchers/BeEmpty.h32
-rw-r--r--vendor/bandit/bandit/assertion_frameworks/matchers/BeFalsy.h39
-rw-r--r--vendor/bandit/bandit/assertion_frameworks/matchers/BeGTE.h45
-rw-r--r--vendor/bandit/bandit/assertion_frameworks/matchers/BeGreaterThan.h39
-rw-r--r--vendor/bandit/bandit/assertion_frameworks/matchers/BeLTE.h45
-rw-r--r--vendor/bandit/bandit/assertion_frameworks/matchers/BeLessThan.h39
-rw-r--r--vendor/bandit/bandit/assertion_frameworks/matchers/BeNull.h29
-rw-r--r--vendor/bandit/bandit/assertion_frameworks/matchers/BeTruthy.h35
-rw-r--r--vendor/bandit/bandit/assertion_frameworks/matchers/Contain.h58
-rw-r--r--vendor/bandit/bandit/assertion_frameworks/matchers/Equal.h90
-rw-r--r--vendor/bandit/bandit/assertion_frameworks/matchers/MatchProxy.h43
-rw-r--r--vendor/bandit/bandit/assertion_frameworks/matchers/Matcher.h74
-rw-r--r--vendor/bandit/bandit/assertion_frameworks/matchers/MatcherException.h16
-rw-r--r--vendor/bandit/bandit/assertion_frameworks/matchers/ThrowException.h60
-rw-r--r--vendor/bandit/bandit/assertion_frameworks/matchers/ValueProxy.h26
-rw-r--r--vendor/bandit/bandit/assertion_frameworks/matchers/matchers.h19
-rw-r--r--vendor/bandit/bandit/assertion_frameworks/matchers/must.h36
-rw-r--r--vendor/bandit/bandit/assertion_frameworks/snowhouse/CMakeLists.txt49
-rw-r--r--vendor/bandit/bandit/assertion_frameworks/snowhouse/LICENSE_1_0.txt23
-rw-r--r--vendor/bandit/bandit/assertion_frameworks/snowhouse/README.md419
-rwxr-xr-xvendor/bandit/bandit/assertion_frameworks/snowhouse/cross_compile.sh50
-rw-r--r--vendor/bandit/bandit/assertion_frameworks/snowhouse/example/basic_assertions.cpp228
-rw-r--r--vendor/bandit/bandit/assertion_frameworks/snowhouse/example/boolean_operators.cpp48
-rw-r--r--vendor/bandit/bandit/assertion_frameworks/snowhouse/example/container_spec.cpp85
-rw-r--r--vendor/bandit/bandit/assertion_frameworks/snowhouse/example/custom_matchers_test.cpp69
-rw-r--r--vendor/bandit/bandit/assertion_frameworks/snowhouse/example/exceptions_tests.cpp97
-rw-r--r--vendor/bandit/bandit/assertion_frameworks/snowhouse/example/expression_error_handling.cpp28
-rw-r--r--vendor/bandit/bandit/assertion_frameworks/snowhouse/example/main.cpp43
-rw-r--r--vendor/bandit/bandit/assertion_frameworks/snowhouse/example/map_tests.cpp38
-rw-r--r--vendor/bandit/bandit/assertion_frameworks/snowhouse/example/operator_tests.cpp137
-rw-r--r--vendor/bandit/bandit/assertion_frameworks/snowhouse/example/sequence_container_tests.cpp192
-rw-r--r--vendor/bandit/bandit/assertion_frameworks/snowhouse/example/string_line_tests.cpp179
-rw-r--r--vendor/bandit/bandit/assertion_frameworks/snowhouse/example/string_tests.cpp65
-rw-r--r--vendor/bandit/bandit/assertion_frameworks/snowhouse/example/stringize_tests.cpp111
-rw-r--r--vendor/bandit/bandit/assertion_frameworks/snowhouse/example/tests.h16
-rw-r--r--vendor/bandit/bandit/assertion_frameworks/snowhouse/snowhouse/assert.h126
-rw-r--r--vendor/bandit/bandit/assertion_frameworks/snowhouse/snowhouse/assertionexception.h58
-rw-r--r--vendor/bandit/bandit/assertion_frameworks/snowhouse/snowhouse/assertmacro.h22
-rw-r--r--vendor/bandit/bandit/assertion_frameworks/snowhouse/snowhouse/constraints/constraints.h23
-rw-r--r--vendor/bandit/bandit/assertion_frameworks/snowhouse/snowhouse/constraints/containsconstraint.h80
-rw-r--r--vendor/bandit/bandit/assertion_frameworks/snowhouse/snowhouse/constraints/endswithconstraint.h53
-rw-r--r--vendor/bandit/bandit/assertion_frameworks/snowhouse/snowhouse/constraints/equalsconstraint.h83
-rw-r--r--vendor/bandit/bandit/assertion_frameworks/snowhouse/snowhouse/constraints/equalscontainerconstraint.h80
-rw-r--r--vendor/bandit/bandit/assertion_frameworks/snowhouse/snowhouse/constraints/equalswithdeltaconstraint.h51
-rw-r--r--vendor/bandit/bandit/assertion_frameworks/snowhouse/snowhouse/constraints/expressions/andexpression.h46
-rw-r--r--vendor/bandit/bandit/assertion_frameworks/snowhouse/snowhouse/constraints/expressions/expression.h38
-rw-r--r--vendor/bandit/bandit/assertion_frameworks/snowhouse/snowhouse/constraints/expressions/expression_fwd.h15
-rw-r--r--vendor/bandit/bandit/assertion_frameworks/snowhouse/snowhouse/constraints/expressions/notexpression.h44
-rw-r--r--vendor/bandit/bandit/assertion_frameworks/snowhouse/snowhouse/constraints/expressions/orexpression.h46
-rw-r--r--vendor/bandit/bandit/assertion_frameworks/snowhouse/snowhouse/constraints/fulfillsconstraint.h51
-rw-r--r--vendor/bandit/bandit/assertion_frameworks/snowhouse/snowhouse/constraints/haslengthconstraint.h60
-rw-r--r--vendor/bandit/bandit/assertion_frameworks/snowhouse/snowhouse/constraints/isgreaterthanconstraint.h55
-rw-r--r--vendor/bandit/bandit/assertion_frameworks/snowhouse/snowhouse/constraints/isgreaterthanorequaltoconstraint.h55
-rw-r--r--vendor/bandit/bandit/assertion_frameworks/snowhouse/snowhouse/constraints/islessthanconstraint.h54
-rw-r--r--vendor/bandit/bandit/assertion_frameworks/snowhouse/snowhouse/constraints/islessthanorequaltoconstraint.h55
-rw-r--r--vendor/bandit/bandit/assertion_frameworks/snowhouse/snowhouse/constraints/startswithconstraint.h52
-rw-r--r--vendor/bandit/bandit/assertion_frameworks/snowhouse/snowhouse/exceptions.h120
-rw-r--r--vendor/bandit/bandit/assertion_frameworks/snowhouse/snowhouse/fluent/constraintadapter.h39
-rw-r--r--vendor/bandit/bandit/assertion_frameworks/snowhouse/snowhouse/fluent/constraintlist.h91
-rw-r--r--vendor/bandit/bandit/assertion_frameworks/snowhouse/snowhouse/fluent/expressionbuilder.h357
-rw-r--r--vendor/bandit/bandit/assertion_frameworks/snowhouse/snowhouse/fluent/fluent.h38
-rw-r--r--vendor/bandit/bandit/assertion_frameworks/snowhouse/snowhouse/fluent/operators/andoperator.h54
-rw-r--r--vendor/bandit/bandit/assertion_frameworks/snowhouse/snowhouse/fluent/operators/collections/alloperator.h35
-rw-r--r--vendor/bandit/bandit/assertion_frameworks/snowhouse/snowhouse/fluent/operators/collections/atleastoperator.h41
-rw-r--r--vendor/bandit/bandit/assertion_frameworks/snowhouse/snowhouse/fluent/operators/collections/atmostoperator.h39
-rw-r--r--vendor/bandit/bandit/assertion_frameworks/snowhouse/snowhouse/fluent/operators/collections/collectionconstraintevaluator.h113
-rw-r--r--vendor/bandit/bandit/assertion_frameworks/snowhouse/snowhouse/fluent/operators/collections/collectionoperator.h24
-rw-r--r--vendor/bandit/bandit/assertion_frameworks/snowhouse/snowhouse/fluent/operators/collections/exactlyoperator.h39
-rw-r--r--vendor/bandit/bandit/assertion_frameworks/snowhouse/snowhouse/fluent/operators/collections/noneoperator.h33
-rw-r--r--vendor/bandit/bandit/assertion_frameworks/snowhouse/snowhouse/fluent/operators/constraintoperator.h70
-rw-r--r--vendor/bandit/bandit/assertion_frameworks/snowhouse/snowhouse/fluent/operators/invalidexpressionexception.h28
-rw-r--r--vendor/bandit/bandit/assertion_frameworks/snowhouse/snowhouse/fluent/operators/notoperator.h53
-rw-r--r--vendor/bandit/bandit/assertion_frameworks/snowhouse/snowhouse/fluent/operators/oroperator.h55
-rw-r--r--vendor/bandit/bandit/assertion_frameworks/snowhouse/snowhouse/snowhouse.h33
-rw-r--r--vendor/bandit/bandit/assertion_frameworks/snowhouse/snowhouse/stringize.h104
-rw-r--r--vendor/bandit/bandit/assertion_frameworks/snowhouse/snowhouse/stringizers.h60
-rw-r--r--vendor/bandit/bandit/bandit.h42
-rw-r--r--vendor/bandit/bandit/context.h97
-rw-r--r--vendor/bandit/bandit/external/optionparser.h2825
-rw-r--r--vendor/bandit/bandit/failure_formatters/default_failure_formatter.h30
-rw-r--r--vendor/bandit/bandit/failure_formatters/failure_formatter.h13
-rw-r--r--vendor/bandit/bandit/failure_formatters/failure_formatters.h16
-rw-r--r--vendor/bandit/bandit/failure_formatters/visual_studio_failure_formatter.h36
-rw-r--r--vendor/bandit/bandit/grammar.h185
-rw-r--r--vendor/bandit/bandit/listener.h27
-rw-r--r--vendor/bandit/bandit/options.h111
-rw-r--r--vendor/bandit/bandit/registration/registrar.h25
-rw-r--r--vendor/bandit/bandit/registration/registration.h7
-rw-r--r--vendor/bandit/bandit/registration/spec_registry.h17
-rw-r--r--vendor/bandit/bandit/reporters/colorizer.h141
-rw-r--r--vendor/bandit/bandit/reporters/dots_reporter.h69
-rw-r--r--vendor/bandit/bandit/reporters/info_reporter.h194
-rw-r--r--vendor/bandit/bandit/reporters/progress_reporter.h116
-rw-r--r--vendor/bandit/bandit/reporters/reporters.h29
-rw-r--r--vendor/bandit/bandit/reporters/single_line_reporter.h86
-rw-r--r--vendor/bandit/bandit/reporters/spec_reporter.h126
-rw-r--r--vendor/bandit/bandit/reporters/test_run_summary.h90
-rw-r--r--vendor/bandit/bandit/reporters/xunit_reporter.h109
-rw-r--r--vendor/bandit/bandit/run_policies/always_run_policy.h16
-rw-r--r--vendor/bandit/bandit/run_policies/bandit_run_policy.h161
-rw-r--r--vendor/bandit/bandit/run_policies/never_run_policy.h14
-rw-r--r--vendor/bandit/bandit/run_policies/run_policies.h9
-rw-r--r--vendor/bandit/bandit/run_policies/run_policy.h44
-rw-r--r--vendor/bandit/bandit/runner.h103
-rw-r--r--vendor/bandit/bandit/skip_policies/always_include_policy.h16
-rw-r--r--vendor/bandit/bandit/skip_policies/always_skip_policy.h15
-rw-r--r--vendor/bandit/bandit/skip_policies/name_contains_skip_policy.h28
-rw-r--r--vendor/bandit/bandit/skip_policies/skip_policies.h9
-rw-r--r--vendor/bandit/bandit/skip_policies/skip_policy.h29
-rw-r--r--vendor/bandit/bandit/test_run_error.h12
-rw-r--r--vendor/bandit/cmake/cotire.cmake3185
-rwxr-xr-xvendor/bandit/cross_compile.sh43
-rw-r--r--vendor/bandit/specs/before_each_after_each.spec.cpp78
-rw-r--r--vendor/bandit/specs/context.spec.cpp44
-rw-r--r--vendor/bandit/specs/describe.spec.cpp117
-rw-r--r--vendor/bandit/specs/failure_formatters/default_formatter.spec.cpp21
-rw-r--r--vendor/bandit/specs/failure_formatters/visual_studio_failure_formatter.spec.cpp22
-rw-r--r--vendor/bandit/specs/fakes/fake_context.h69
-rw-r--r--vendor/bandit/specs/fakes/fake_reporter.h78
-rw-r--r--vendor/bandit/specs/fakes/fakes.h8
-rw-r--r--vendor/bandit/specs/fakes/logging_fake.h32
-rw-r--r--vendor/bandit/specs/fuzzbox.spec.cpp77
-rw-r--r--vendor/bandit/specs/it.spec.cpp355
-rw-r--r--vendor/bandit/specs/main.cpp6
-rw-r--r--vendor/bandit/specs/matchers/be_close_to.cpp112
-rw-r--r--vendor/bandit/specs/matchers/be_empty.cpp89
-rw-r--r--vendor/bandit/specs/matchers/be_falsy.cpp85
-rw-r--r--vendor/bandit/specs/matchers/be_greater_than.cpp105
-rw-r--r--vendor/bandit/specs/matchers/be_gte.cpp120
-rw-r--r--vendor/bandit/specs/matchers/be_less_than.cpp105
-rw-r--r--vendor/bandit/specs/matchers/be_lte.cpp119
-rw-r--r--vendor/bandit/specs/matchers/be_null.cpp43
-rw-r--r--vendor/bandit/specs/matchers/be_truthy.cpp85
-rw-r--r--vendor/bandit/specs/matchers/contain.cpp156
-rw-r--r--vendor/bandit/specs/matchers/equal.cpp214
-rw-r--r--vendor/bandit/specs/matchers/throw_exception.cpp104
-rw-r--r--vendor/bandit/specs/options.spec.cpp121
-rw-r--r--vendor/bandit/specs/reporters/colorizer.spec.cpp45
-rw-r--r--vendor/bandit/specs/reporters/dots_reporter.spec.cpp202
-rw-r--r--vendor/bandit/specs/reporters/single_line_reporter.spec.cpp201
-rw-r--r--vendor/bandit/specs/reporters/xunit_reporter.spec.cpp161
-rw-r--r--vendor/bandit/specs/run.spec.cpp77
-rw-r--r--vendor/bandit/specs/run_policies/bandit_run_policy.spec.cpp250
-rw-r--r--vendor/bandit/specs/specs.h10
-rw-r--r--vendor/bandit/specs/synopsis.spec.cpp54
-rw-r--r--vendor/bandit/specs/util/argv_helper.h62
-rw-r--r--vendor/bandit/specs/util/util.h6
1052 files changed, 210655 insertions, 340680 deletions
diff --git a/.gitignore b/.gitignore
index d7793155..a052f12e 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,4 +1,6 @@
+.idea
*.o
+lib*.a
*.~*
*.#*
CMakeFiles
@@ -6,3 +8,6 @@ CMakeCache.txt
cmake_install.cmake
install_manifest.txt
Makefile
+compile_commands.json
+/nbproject
+tome2.cbp
diff --git a/BUGS.txt b/BUGS.txt
deleted file mode 100644
index 9a88aaed..00000000
--- a/BUGS.txt
+++ /dev/null
@@ -1,6 +0,0 @@
-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
index 72cd53ec..853c01fe 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,20 +1,69 @@
# Project definition.
PROJECT (tome2)
-CMAKE_MINIMUM_REQUIRED (VERSION 2.6)
+CMAKE_MINIMUM_REQUIRED (VERSION 2.8)
# We want a readable feature summary.
INCLUDE(FeatureSummary)
-# Default flags.
+# pkg-config support
+INCLUDE(FindPkgConfig)
+
+#
+# Basic common compiler flags.
+#
+SET(COMMON_COMPILER_FLAGS "-pipe -Wall -Wno-unused-value -fsanitize=undefined -fsanitize=address")
+
+#
+# GCC/G++ 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 "${CMAKE_C_FLAGS} ${COMMON_COMPILER_FLAGS}")
+ SET(CMAKE_C_FLAGS_RELEASE "-O2")
+ SET(CMAKE_C_FLAGS_DEBUG "-O0 -g")
+ SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${COMMON_COMPILER_FLAGS} --std=c++11 -D_GLIBCXX_DEBUG -D_GLIBCXX_DEBUG_PEDANTIC")
+ SET(CMAKE_CXX_FLAGS_RELEASE "-O2")
+ SET(CMAKE_CXX_FLAGS_DEBUG "-O0 -g")
+ENDIF()
+
+#
+# Clang flags
+#
+IF("${CMAKE_C_COMPILER_ID}" STREQUAL "Clang")
+ SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${COMMON_COMPILER_FLAGS}")
SET(CMAKE_C_FLAGS_RELEASE "-O2")
SET(CMAKE_C_FLAGS_DEBUG "-O0 -g")
ENDIF()
+IF("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
+ SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${COMMON_COMPILER_FLAGS} --std=c++11 -D_GLIBCXX_DEBUG -D_GLIBCXX_DEBUG_PEDANTIC")
+ SET(CMAKE_CXX_FLAGS_RELEASE "-O2")
+ SET(CMAKE_CXX_FLAGS_DEBUG "-O0 -g")
+ENDIF()
+
+# Add standard math library
+SET(LIBS ${LIBS} m)
-# Add definitions.
-ADD_DEFINITIONS(-DUSE_PRECISE_CMOVIE)
+#
+# JSON support
+#
+PKG_CHECK_MODULES(JANSSON REQUIRED jansson)
+IF(JANSSON_FOUND)
+ ADD_DEFINITIONS(${JANSSON_CFLAGS})
+ INCLUDE_DIRECTORIES(${JANSSON_INCLUDE_DIRS})
+ LINK_DIRECTORIES(${JANSSON_LIBRARY_DIRS})
+ SET(LIBS ${LIBS} ${JANSSON_LIBRARIES})
+ENDIF()
+
+#
+# BOOST
+#
+FIND_PACKAGE(Boost 1.54.0 REQUIRED COMPONENTS system filesystem)
+
+IF(Boost_FOUND)
+ ADD_DEFINITIONS(-DBOOST_FILESYSTEM_NO_DEPRECATED)
+ INCLUDE_DIRECTORIES(${Boost_INCLUDE_DIRS})
+ SET(LIBS ${LIBS} ${Boost_LIBRARIES} ${Boost_SYSTEM_LIBRARY} ${Boost_FILESYSTEM_LIBRARY})
+ENDIF()
#
# X11 support (OPTIONAL)
diff --git a/README.md b/README.md
new file mode 100644
index 00000000..cdf11c24
--- /dev/null
+++ b/README.md
@@ -0,0 +1,99 @@
+ToME is a [rogue-like](https://en.wikipedia.org/wiki/Roguelike) game.
+
+![Screenshot](/doc/images/screenshot.png)
+
+## Getting Started
+
+### Prerequisites
+
+See below for specific distribution-specific hints, if needed.
+
+You will need to have the following libraries installed on your system
+somewhere where CMake can find them:
+
+- [jansson](http://www.digip.org/jansson/)
+- [Boost](https://www.boost.org/)
+
+Version requirements may vary somewhat, but usually you should be
+aiming for having at least a **recent** version of the above libraries.
+
+### Option 1: Running In-Place
+
+**This is currently the recommended option**, but it means that you
+don't 'install' ToME as such, you just run it from the build
+directory.
+
+To configure for your system, run
+
+ $ cmake .
+ $ make
+
+You should now be able to run
+
+ $ ./src/tome
+
+to start ToME.
+
+**Important:** The current working directory must be at the root of
+the source tree for the above command to run -- if it isn't, then
+you'll get mysterious errors about ToME not being able to find files
+(at best).
+
+
+### Option 2: Installing System-Wide
+
+To configure for your system, run
+
+ $ cmake -DSYSTEM_INSTALL:BOOL=true .
+ $ make
+ $ sudo make install
+
+You can now run ToME from anywhere and it will always use the files
+installed in the system-specific location.
+
+
+## Compiling on Ubuntu
+
+To compile on an Ubuntu install, you'll need at least the
+
+- `cmake`
+- `build-essential`
+- `libjansson-dev`
+- `libboost-all-dev`
+
+packages.
+
+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 executable. As a workaround, set the environment variable
+`LDFLAGS` 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
+
+The source **MUST** be unpacked in a directory without spaces in the
+name.
+
+To configure and compile on Windows using MinGW, use the commands
+
+ $ cmake -G "MinGW Makefiles"
+ $ mingw32-make
diff --git a/README.txt b/README.txt
deleted file mode 100644
index 1e0ad583..00000000
--- a/README.txt
+++ /dev/null
@@ -1,85 +0,0 @@
-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/changes.old b/changes.old
deleted file mode 100644
index dabf85a0..00000000
--- a/changes.old
+++ /dev/null
@@ -1,6027 +0,0 @@
-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
deleted file mode 100644
index d95e9b11..00000000
--- a/changes.txt
+++ /dev/null
@@ -1,198 +0,0 @@
-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/DEBUG.txt b/doc/DEBUG.txt
index f7146c28..f7146c28 100644
--- a/DEBUG.txt
+++ b/doc/DEBUG.txt
diff --git a/doc/RELEASE.txt b/doc/RELEASE.txt
new file mode 100644
index 00000000..ab082315
--- /dev/null
+++ b/doc/RELEASE.txt
@@ -0,0 +1,8 @@
+Release Checklist:
+==================
+
+* Bump version number.
+* Update changes.txt
+* Update IS_CVS in defines.h before tagging; undo post-tagging.
+* Check that system-wide installation succeeds.
+* Disable C/C++ compiler sanitization options
diff --git a/doc/changes.txt b/doc/changes.txt
new file mode 100644
index 00000000..7835ab9a
--- /dev/null
+++ b/doc/changes.txt
@@ -0,0 +1,208 @@
+T.O.M.E 2.4.x (ah)
+
+Game:
+
+- Removed Alchemist class from ToME module. They were
+ horribly broken and encouraged only scummy play. They
+ were also indirectly responsible for a lot of items
+ that were junk to every other character class.
+- Increased size of the home drastically.
+
+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/doc/credits.txt
index 96e8ef60..96e8ef60 100644
--- a/credits.txt
+++ b/doc/credits.txt
diff --git a/doc/images/screenshot.png b/doc/images/screenshot.png
new file mode 100644
index 00000000..457c68f5
--- /dev/null
+++ b/doc/images/screenshot.png
Binary files differ
diff --git a/lib/.gitignore b/lib/.gitignore
new file mode 100644
index 00000000..2de989fd
--- /dev/null
+++ b/lib/.gitignore
@@ -0,0 +1,2 @@
+*.raw
+
diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt
index 44d7d1ee..15591830 100644
--- a/lib/CMakeLists.txt
+++ b/lib/CMakeLists.txt
@@ -1,25 +1,19 @@
-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
)
+
+ADD_SUBDIRECTORY (mods)
diff --git a/lib/apex/.cvsignore b/lib/apex/.cvsignore
deleted file mode 100644
index dfa43964..00000000
--- a/lib/apex/.cvsignore
+++ /dev/null
@@ -1 +0,0 @@
-scores.raw
diff --git a/lib/core/auto.lua b/lib/core/auto.lua
deleted file mode 100644
index b758db52..00000000
--- a/lib/core/auto.lua
+++ /dev/null
@@ -1,859 +0,0 @@
--- 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
deleted file mode 100644
index 8e88888a..00000000
--- a/lib/core/building.lua
+++ /dev/null
@@ -1,15 +0,0 @@
-__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
deleted file mode 100644
index 97f8d4b6..00000000
--- a/lib/core/crpt_aux.lua
+++ /dev/null
@@ -1,182 +0,0 @@
--- 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
deleted file mode 100644
index d91d785b..00000000
--- a/lib/core/dungeon.lua
+++ /dev/null
@@ -1,55 +0,0 @@
--- 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
deleted file mode 100644
index 5f3af435..00000000
--- a/lib/core/gen_idx.lua
+++ /dev/null
@@ -1,261 +0,0 @@
--- 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
deleted file mode 100644
index 77e0aad5..00000000
--- a/lib/core/gods.lua
+++ /dev/null
@@ -1,40 +0,0 @@
--- 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
deleted file mode 100644
index a581fe63..00000000
--- a/lib/core/help.lua
+++ /dev/null
@@ -1,141 +0,0 @@
--- 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
deleted file mode 100644
index 11b812d5..00000000
--- a/lib/core/init.lua
+++ /dev/null
@@ -1,83 +0,0 @@
---
--- 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
deleted file mode 100644
index 9522ec91..00000000
--- a/lib/core/load.lua
+++ /dev/null
@@ -1,37 +0,0 @@
--- 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
deleted file mode 100644
index 7e151d91..00000000
--- a/lib/core/load2.lua
+++ /dev/null
@@ -1,56 +0,0 @@
--- 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
deleted file mode 100644
index cea1f4dc..00000000
--- a/lib/core/mimc_aux.lua
+++ /dev/null
@@ -1,96 +0,0 @@
--- 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
deleted file mode 100644
index ca2851a0..00000000
--- a/lib/core/monsters.lua
+++ /dev/null
@@ -1,16 +0,0 @@
--- 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
deleted file mode 100644
index 97320b82..00000000
--- a/lib/core/objects.lua
+++ /dev/null
@@ -1,45 +0,0 @@
--- 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
deleted file mode 100644
index 16878228..00000000
--- a/lib/core/player.lua
+++ /dev/null
@@ -1,135 +0,0 @@
--- 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
deleted file mode 100644
index dfe9db51..00000000
--- a/lib/core/quests.lua
+++ /dev/null
@@ -1,57 +0,0 @@
--- 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
deleted file mode 100644
index ec609b04..00000000
--- a/lib/core/s_aux.lua
+++ /dev/null
@@ -1,716 +0,0 @@
--- 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
deleted file mode 100644
index d4a63168..00000000
--- a/lib/core/stores.lua
+++ /dev/null
@@ -1,32 +0,0 @@
--- 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
deleted file mode 100644
index eea13014..00000000
--- a/lib/core/util.lua
+++ /dev/null
@@ -1,158 +0,0 @@
--- 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
deleted file mode 100644
index 14f0511f..00000000
--- a/lib/core/xml.lua
+++ /dev/null
@@ -1,375 +0,0 @@
--- 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
deleted file mode 100644
index 82490963..00000000
--- a/lib/data/.cvsignore
+++ /dev/null
@@ -1,2 +0,0 @@
-.cvsignore
-*.raw \ No newline at end of file
diff --git a/lib/edit/a_info.txt b/lib/edit/a_info.txt
index 427d5060..2e9c38b2 100644
--- a/lib/edit/a_info.txt
+++ b/lib/edit/a_info.txt
@@ -24,10 +24,6 @@
# -Leon Marrick
# Contributors: Jeff Butler, Neal Hackler, Ethan Sicotte, Pat Tracy, Divia
-# Version stamp (required)
-
-V:2.0.0
-
# The Phial of Galadriel
@@ -38,7 +34,7 @@ W:20:10:10:10000
P:0:1d1:0:0:0
F:ACTIVATE | SEARCH | LITE3 | LUCK
F:INSTA_ART | HIDE_TYPE
-a:HARDCORE=LIGHT
+a: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.
@@ -51,7 +47,7 @@ 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
+a:MAP_LIGHT
Z:detect curses
D:The shining Star of the West, a famed heirloom of Elendil's house.
@@ -65,7 +61,7 @@ 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
+a: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.
@@ -79,7 +75,7 @@ W:50:10:3:60000
F:CON | HIDE_TYPE |
F:ACTIVATE | RES_FIRE |
F:INSTA_ART
-a:HARDCORE=PROT_EVIL
+a:PROT_EVIL
D:A fiery circle of bronze, with mighty spells to ward off evil.
@@ -92,7 +88,7 @@ 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
+a:DISP_EVIL
D:The ancient heirloom of Ingwe, high lord of the Vanyar, against whom nothing
D:of evil could stand.
@@ -120,7 +116,7 @@ F:STR | CON | CHR | HIDE_TYPE |
F:IM_FIRE | ACTIVATE | SEARCH |
F:ESP_THUNDERLORD | SEE_INVIS | FLY |
F:INSTA_ART
-a:HARDCORE=DIM_DOOR
+a: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
@@ -136,7 +132,7 @@ 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
+a: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.
@@ -149,7 +145,7 @@ W:70:50:2:175000
F:STR | DEX | CON | HIDE_TYPE |
F:ACTIVATE | SPEED | ESP_EVIL |
F:INSTA_ART
-a:HARDCORE=TULKAS
+a:TULKAS
D:The treasure of Tulkas, most fleet and wrathful of the Valar.
@@ -164,7 +160,7 @@ 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
+a: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.
@@ -181,7 +177,7 @@ 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
+a: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.
@@ -199,7 +195,7 @@ 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
+a: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
@@ -221,7 +217,7 @@ 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
+a: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,
@@ -252,7 +248,7 @@ 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
+a:STONE_LORE
D:A great emerald that fills your mind with images of knowledge and dreadful
D:understanding as you stare into its depths.
@@ -267,7 +263,7 @@ 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
+a: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.
@@ -286,7 +282,7 @@ 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
+a: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.
@@ -314,7 +310,7 @@ 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
+a: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.
@@ -357,7 +353,7 @@ 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
+a: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.
@@ -372,7 +368,7 @@ 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
+a: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.
@@ -399,7 +395,7 @@ 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
+a: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.
@@ -509,7 +505,7 @@ 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
+a: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.
@@ -593,7 +589,7 @@ 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
+a:GORLIM
D:The legendary dragon helm of Turin Turambar, an object of dread to the
D:servants of Morgoth.
@@ -605,7 +601,7 @@ 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
+a:DETECT_ALL
D:A famous helm of forged iron granting extraordinary powers of mind and
D:awareness.
@@ -621,7 +617,7 @@ 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
+a:GORLIM
D:A headpiece, gaudy and barbaric, that betrayed a warrior when he most
D:needed succor.
@@ -635,7 +631,7 @@ 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
+a:CURE_700
D:The shining winged circlet brought by Elendil from dying Numenor, emblem of
D:Gondor through an age of the world.
@@ -651,7 +647,7 @@ 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
+a: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
@@ -665,7 +661,7 @@ 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
+a:COLLUIN
D:A cape worn by a hero from Valinor, a land utterly beyond the strife
D:of Elements.
@@ -678,7 +674,7 @@ 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
+a: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.
@@ -692,7 +688,7 @@ 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
+a:RECHARGE
D:A sable-hued cloak, with glowing elven-runes to restore magic showing calm
D:and clear as moonlight on still water.
@@ -717,7 +713,7 @@ W:5:20:10:11000
P:1:0d0:0:0:15
F:STEALTH | SPEED | RES_NEXUS |
F:RES_ACID | ACTIVATE
-a:HARDCORE=TELEPORT
+a: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.
@@ -731,7 +727,7 @@ 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
+a: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
@@ -780,7 +776,7 @@ 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
+a: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.
@@ -792,7 +788,7 @@ 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
+a:BO_FIRE_1
D:A fiery set of gauntlets that can even shoot fire from the user's
D:hands.
@@ -805,7 +801,7 @@ 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
+a:BO_COLD_1
D:A set of handgear so icy as to be able to fire frost bolts.
@@ -816,7 +812,7 @@ 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
+a:BO_ELEC_1
D:A set of handgear with sparks surrounding it, able to fire
D:bolts of electricity.
@@ -828,7 +824,7 @@ 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
+a:BO_ACID_1
D:A set of handgear so corrosive that it may fire bolts of acid.
@@ -853,7 +849,7 @@ 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
+a: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.
@@ -867,7 +863,7 @@ W:40:120:40:300000
P:3:1d1:0:0:20
F:SPEED | HIDE_TYPE |
F:RES_NEXUS | ACTIVATE
-a:HARDCORE=SPEED
+a: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.
@@ -882,7 +878,7 @@ 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
+a:CURE_POISON
D:A pair of high-laced shoes, strong against the powers of corruption and
D:withering, that grant the wearer extraordinary agility.
@@ -952,7 +948,7 @@ 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
+a:BO_FIRE_1
D:A fiery dagger finely balanced for deadly throws.
@@ -963,7 +959,7 @@ 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
+a:BO_COLD_1
D:A frosty dagger finely balanced for deadly throws.
@@ -974,7 +970,7 @@ 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
+a:BO_ELEC_1
D:A dagger covered in sparks and finely balanced for deadly throws.
@@ -985,7 +981,7 @@ 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
+a:BA_POIS_1
D:A large stiletto dagger that glistens with odourless poison, to which the
D:wearer seems oddly immune.
@@ -1000,7 +996,7 @@ 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
+a: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.
@@ -1182,7 +1178,7 @@ 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
+a: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.
@@ -1198,7 +1194,7 @@ 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
+a: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
@@ -1333,7 +1329,7 @@ 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
+a: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.
@@ -1394,7 +1390,7 @@ 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
+a: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.
@@ -1412,7 +1408,7 @@ 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
+a: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.
@@ -1472,7 +1468,7 @@ 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
+a: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.
@@ -1502,7 +1498,7 @@ 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
+a:CURE_MW
D:A superbly crafted double-bladed axe that slays the creatures of earth and
D:allows rapid recovery from their blows.
@@ -1564,7 +1560,7 @@ 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
+a: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.
@@ -1581,7 +1577,7 @@ 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
+a: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.
@@ -1596,7 +1592,7 @@ 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
+a: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...
@@ -1614,7 +1610,7 @@ F:RES_COLD | SEE_INVIS | ESP_ALL | AGGRAVATE | SHOW_MODS | INSTA_ART |
F:LEVELS | ACTIVATE | SPECIAL_GENE
F:MUST2H
f:MUST2H
-a:HARDCORE=GROND
+a: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.
@@ -1630,7 +1626,7 @@ F:SLAY_EVIL | BRAND_FIRE | RES_FIRE | RES_CONF | ACTIVATE |
F:SHOW_MODS | LITE1
F:COULD2H
f:COULD2H
-a:HARDCORE=CONFUSE
+a: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.
@@ -1671,7 +1667,7 @@ 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
+a:FIRESTAR
D:A famed battle-lord of old, with a ruddy head, coloured as embers are that
D:can yet rise up in wrath.
@@ -1685,7 +1681,7 @@ P:0:3d4:12:12:0
F:KILL_DRAGON | BRAND_ELEC | IM_ELEC | ACTIVATE | SHOW_MODS
F:COULD2H
f:COULD2H
-a:HARDCORE=SPEED
+a: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.
@@ -1730,7 +1726,7 @@ 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
+a: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.
@@ -1744,7 +1740,7 @@ 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
+a: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.
@@ -1780,7 +1776,7 @@ 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
+a: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.
@@ -1833,7 +1829,7 @@ W:50:25:110:50000
P:0:0d0:10:14:0
F:SPEED | HIDE_TYPE |
F:RES_FIRE | ACTIVATE | SHOW_MODS
-a:HARDCORE=CUBRAGOL
+a:CUBRAGOL
D:A crossbow that grants fiery speed to he who finds it, and from which
D:shoot bolts that blaze with flame unquenchable.
@@ -1852,7 +1848,7 @@ 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
+a:GANDALF
D:A simple, wooden wizard's staff. Unremarkable in all aspects...
D:except that it pulses with overwhelming power.
@@ -1992,7 +1988,7 @@ 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
+a:EREBOR
D:A pick that provides a magical light by which to see while tunnelling.
@@ -2003,7 +1999,7 @@ 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
+a: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.
@@ -2016,7 +2012,7 @@ 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
+a: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.
@@ -2029,7 +2025,7 @@ 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
+a: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.
@@ -2042,7 +2038,7 @@ 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
+a: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
@@ -2056,7 +2052,7 @@ 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
+a: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.
@@ -2085,7 +2081,7 @@ 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
+a: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.
@@ -2111,7 +2107,7 @@ 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
+a: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
@@ -2210,7 +2206,7 @@ P:0:2d7:20:14:0
F:DEX | SEARCH | SLAY_ORC | ACTIVATE | HIDE_TYPE | SHOW_MODS
F:COULD2H
f:COULD2H
-a:HARDCORE=ORCHAST
+a: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.
@@ -2223,7 +2219,7 @@ 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
+a:NIGHT
D:Found on an unmarked grave after a violent storm, this hatchet
D:has a sinister aura of darkness and decay.
@@ -2236,7 +2232,7 @@ 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
+a:NATUREBANE
D:Used by the orcs in their battle at Dagor Bragollach against the elves, this
D:axe has a bloodthirst for nature.
@@ -2261,7 +2257,7 @@ 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
+a: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.
@@ -2326,8 +2322,8 @@ N:165:'Lebohaum'
I:32:6:0
W:20:15:15:25000
P:20:0d0:0:0:80
-F:ACTIVATE
-a:SPELL=Artifact Lebauhaum
+F:ACTIVATE | EASY_USE
+a:LEBOHAUM
D:With the Helm 'Lebohaum' your head is safe!
@@ -2342,7 +2338,7 @@ 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
+a: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.
@@ -2354,7 +2350,7 @@ 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
+a: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.
@@ -2382,7 +2378,7 @@ 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
+a: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.
@@ -2396,7 +2392,7 @@ 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
+a: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
@@ -2413,7 +2409,7 @@ 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
+a: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.
@@ -2459,7 +2455,7 @@ 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
+a: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.
@@ -2477,7 +2473,7 @@ F:RES_FIRE | RES_ELEC | RES_NETHER | RES_DISEN | HOLD_LIFE |
F:ACTIVATE
F:COULD2H
f:COULD2H
-a:HARDCORE=FUNDIN
+a: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.
@@ -2492,7 +2488,7 @@ 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
+a: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
@@ -2512,7 +2508,7 @@ F:KILL_DRAGON | SLAY_ANIMAL | BRAND_POIS | BRAND_ELEC |
F:ACTIVATE
F:COULD2H
f:COULD2H
-a:HARDCORE=SKULLCLEAVER
+a:SKULLCLEAVER
D:This mighty bludgeon brings destruction to all around it, and is the
D:bane of dragons and magic.
@@ -2525,7 +2521,7 @@ 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
+a:EOL
D:The iron-shod gauntlets of the Dark Elven smith Eol, tingling with magics
D:that he could channel in battle.
@@ -2595,8 +2591,8 @@ 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
+F:ACTIVATE | EASY_USE | SHOW_MODS
+a:DURANDIL
D:Don't go adventuring without your Durandil sword!
@@ -2609,7 +2605,7 @@ 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
+a: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.
@@ -2633,7 +2629,7 @@ 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
+a: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
@@ -2702,7 +2698,7 @@ 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
+a: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.
@@ -2716,7 +2712,7 @@ 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
+a: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.
@@ -2731,7 +2727,7 @@ 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
+a: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
diff --git a/lib/edit/ab_info.txt b/lib/edit/ab_info.txt
index 7b9aa152..976c6d03 100644
--- a/lib/edit/ab_info.txt
+++ b/lib/edit/ab_info.txt
@@ -22,23 +22,17 @@
# 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
+D:Prereq: Combat@30, Dex@17
I:5
-k:30:Weaponmastery
+k:30:Combat
S:17:DEX
N:1:Tree walking
@@ -83,15 +77,6 @@ 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.
diff --git a/lib/edit/al_info.txt b/lib/edit/al_info.txt
deleted file mode 100644
index fbd4c9a0..00000000
--- a/lib/edit/al_info.txt
+++ /dev/null
@@ -1,2097 +0,0 @@
-# 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
index 8156fd2f..e5c49759 100644
--- a/lib/edit/ba_info.txt
+++ b/lib/edit/ba_info.txt
@@ -17,10 +17,6 @@
# 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:.
@@ -65,10 +61,6 @@ 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
@@ -97,14 +89,6 @@ 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
@@ -165,19 +149,6 @@ 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
@@ -190,10 +161,6 @@ 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
@@ -204,11 +171,6 @@ 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
@@ -257,18 +219,6 @@ 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
diff --git a/lib/edit/d_info.txt b/lib/edit/d_info.txt
index 59a1e6f2..24526ea2 100644
--- a/lib/edit/d_info.txt
+++ b/lib/edit/d_info.txt
@@ -29,10 +29,6 @@
# 3 = OR
# 4 = NOR
-# Version stamp (required)
-
-V:2.0.0
-
### Wilderness(purely cosmetic, never used) ###
N:0:Wilderness
@@ -303,7 +299,7 @@ M:ORC | R_CHAR_k | R_CHAR_o | R_CHAR_O
# There is Glaurung
N:20:Erebor
D:Ere:a tunnel leading into depths of the Lonely Mountain.
-W:60:72:35:0:20:140
+W:60:72:30:0:20:140
L:88:100:1:0:1:0
A:97:90:87:10:56:0:57:97
O:40:40:40:40
diff --git a/lib/edit/e_info.txt b/lib/edit/e_info.txt
index f01d8cf7..f3bc1d31 100644
--- a/lib/edit/e_info.txt
+++ b/lib/edit/e_info.txt
@@ -63,10 +63,6 @@
-# Version stamp (required)
-
-V:2.0.0
-
### Mage Staff ###
N:1:of Mana
@@ -231,7 +227,7 @@ C:0:0:0:3
Z:blink
R:100
F:ACTIVATE
-a:HARDCORE=JUMP
+a:JUMP
### Shields ###
@@ -321,7 +317,7 @@ C:0:0:0:2
W:0:1:8:500
R:100
F:DEX | SUST_DEX | ACTIVATE | ESP_ORC
-a:HARDCORE=NOLDOR
+a:NOLDOR
N:24:of Intelligence
X:A:33:13
@@ -859,7 +855,7 @@ W:0:1:44:9000
C:8:8:0:2
R:100
F:DEX | STR | VORPAL | ACTIVATE
-a:HARDCORE=SPIN
+a:SPIN
# The "Elemental" brands (4) (6)
@@ -1239,7 +1235,7 @@ T:24:0:255
X:A:24:22
W:0:1:100:7000
C:4:4:0:2
-a:HARDCORE=TELEPORT
+a:TELEPORT
R:100
F:SLAY_EVIL | KILL_DRAGON | TELEPORT | FREE_ACT | SEARCH | BRAND_ELEC
F:REGEN | SLOW_DIGEST | RES_NEXUS | ACTIVATE | FLY | ESP_DRAGON
@@ -1295,7 +1291,7 @@ W:0:1:5:5000
R:100
F:SLAY_UNDEAD | SEE_INVIS | HOLD_LIFE | DRAIN_HP
F:ACTIVATE
-a:HARDCORE=SPECTRAL
+a:SPECTRAL
N:103:of Morgul
T:125:0:255
@@ -1602,7 +1598,7 @@ R:50
F:PVAL_M1
R:25
F:PVAL_M1
-a:HARDCORE=BA_ACID_H
+a:BA_ACID_H
# Rods ego
N:131:Capacity of
@@ -2123,7 +2119,7 @@ T:14:7:7
X:B:25:20
W:0:1:2:2000
C:0:0:0:0
-a:HARDCORE=BA_COLD_3
+a:BA_COLD_3
R:100
F:IGNORE_ACID | IGNORE_ELEC | IGNORE_FIRE | IGNORE_COLD |
@@ -2132,7 +2128,7 @@ T:14:7:7
X:B:25:20
W:0:1:2:2000
C:0:0:0:0
-a:HARDCORE=BA_ELEC_3
+a:BA_ELEC_3
R:100
F:IGNORE_ACID | IGNORE_ELEC | IGNORE_FIRE | IGNORE_COLD |
@@ -2141,7 +2137,7 @@ T:14:7:7
X:B:25:20
W:0:1:2:2000
C:0:0:0:0
-a:HARDCORE=BA_FIRE_H
+a:BA_FIRE_H
R:100
F:IGNORE_ACID | IGNORE_ELEC | IGNORE_FIRE | IGNORE_COLD |
diff --git a/lib/edit/f_info.txt b/lib/edit/f_info.txt
index c0dc2e9a..5ab0cbdc 100644
--- a/lib/edit/f_info.txt
+++ b/lib/edit/f_info.txt
@@ -15,11 +15,6 @@
# Note that terrain feature zero contains the "darkness" picture.
-# Version stamp (required)
-
-V:2.0.0
-
-
# 0x00 --> nothing
N:0:nothing
diff --git a/lib/edit/k_info.txt b/lib/edit/k_info.txt
index aba86074..612bdc5c 100644
--- a/lib/edit/k_info.txt
+++ b/lib/edit/k_info.txt
@@ -20,11 +20,6 @@
# Note that object zero is used for the "stack" picture (unused).
-# Version stamp (required)
-
-V:2.0.0
-
-
##### Something special #####
N:0:something
@@ -1404,7 +1399,7 @@ G:=:d
I:45:4:0
W:5:0:2:250
A:5/1
-a:HARDCORE=DEST_TELE
+a:DEST_TELE
F:CURSED | TELEPORT | EASY_KNOW | ACTIVATE
f:TELEPORT
D:This ring will uncontrollably send you to different places at its whim.
@@ -1483,7 +1478,7 @@ I:45:18:0
W:50:0:2:3000
A:50/1
P:0:0d0:0:0:15
-a:HARDCORE=BA_FIRE_4
+a: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
@@ -1495,7 +1490,7 @@ I:45:17:0
W:50:0:2:3000
A:50/1
P:0:0d0:0:0:15
-a:HARDCORE=BA_ACID_4
+a: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
@@ -1506,7 +1501,7 @@ G:=:d
I:45:19:0
W:50:0:2:3000
A:50/1
-a:HARDCORE=BA_COLD_4
+a:BA_COLD_4
P:0:0d0:0:0:15
F:RES_COLD | IGNORE_COLD | ACTIVATE
f:RES_COLD
@@ -2775,9 +2770,9 @@ 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:NORM_ART | FULL_NAME | SPECIAL_GENE | EASY_USE
F:ACTIVATE | ACTIVATE_NO_WIELD
-a:SPELL=Artifact Eternal Flame
+a: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.
@@ -3518,7 +3513,7 @@ I:38:1:0
W:60:0:200:50000
A:60/8
P:30:2d4:-2:0:10
-a:HARDCORE=BR_ACID
+a:BR_ACID
F:RES_ACID | FLY |
f:RES_ACID |
F:ACTIVATE | IGNORE_ACID | IGNORE_ELEC | IGNORE_FIRE | IGNORE_COLD
@@ -3530,7 +3525,7 @@ I:38:2:0
W:50:0:200:40000
A:50/8
P:30:2d4:-2:0:10
-a:HARDCORE=BR_ELEC
+a:BR_ELEC
F:RES_ELEC | FLY |
f:RES_ELEC |
F:ACTIVATE | IGNORE_ACID | IGNORE_ELEC | IGNORE_FIRE | IGNORE_COLD
@@ -3541,7 +3536,7 @@ G:[:w
I:38:3:0
W:50:0:200:40000
A:50/8
-a:HARDCORE=BR_COLD
+a:BR_COLD
P:30:2d4:-2:0:10
F:RES_COLD | FLY |
f:RES_COLD |
@@ -3554,7 +3549,7 @@ I:38:4:0
W:60:0:200:50000
A:60/8
P:30:2d4:-2:0:10
-a:HARDCORE=BR_FIRE
+a:BR_FIRE
F:RES_FIRE | FLY |
f:RES_FIRE |
F:ACTIVATE | IGNORE_ACID | IGNORE_ELEC | IGNORE_FIRE | IGNORE_COLD
@@ -3566,7 +3561,7 @@ I:38:5:0
W:50:0:200:40000
A:50/8
P:30:2d4:-2:0:10
-a:HARDCORE=BR_POIS
+a:BR_POIS
F:RES_POIS | FLY |
f:RES_POIS |
F:ACTIVATE | IGNORE_ACID | IGNORE_ELEC | IGNORE_FIRE | IGNORE_COLD
@@ -3578,7 +3573,7 @@ I:38:6:0
W:90:0:200:150000
A:90/32
P:30:2d4:-2:0:10
-a:HARDCORE=BR_MANY
+a: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 |
@@ -3591,7 +3586,7 @@ I:38:10:0
W:70:0:200:70000
A:70/16
P:30:2d4:-2:0:10
-a:HARDCORE=BR_LIGHT
+a: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?
@@ -3602,7 +3597,7 @@ I:38:12:0
W:80:0:200:80000
A:80/16
P:30:2d4:-2:0:10
-a:HARDCORE=BR_SHARD
+a: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,
@@ -3614,7 +3609,7 @@ I:38:14:0
W:50:0:200:40000
A:50/8
P:30:2d4:-2:0:10
-a:HARDCORE=BR_CONF
+a: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.
@@ -3625,7 +3620,7 @@ I:38:16:0
W:60:0:200:50000
A:60/8
P:30:2d4:-2:0:10
-a:HARDCORE=BR_SOUND
+a: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
@@ -3637,7 +3632,7 @@ I:38:18:0
W:80:0:200:80000
A:80/16
P:30:2d4:-2:0:10
-a:HARDCORE=BR_CHAOS
+a:BR_CHAOS
F:ATTR_MULTI
F:RES_CHAOS | RES_DISEN | FLY |
f:RES_CHAOS |
@@ -3652,7 +3647,7 @@ I:38:20:0
W:95:0:200:100000
A:95/32
P:30:2d4:-2:0:10
-a:HARDCORE=BR_BALANCE
+a: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
@@ -3664,7 +3659,7 @@ I:38:30:0
W:100:0:250:350000
A:100/64
P:40:2d4:-3:0:15
-a:HARDCORE=BR_POWER
+a: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 |
@@ -4782,13 +4777,6 @@ 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
@@ -4821,24 +4809,10 @@ 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
+# FIXME: Could remove "of Nothing" (amulets, rings, rods)
+
N:572:Nothing
G:":d
I:40:16:0
@@ -4859,27 +4833,6 @@ 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~
@@ -4901,35 +4854,12 @@ I:45:56:0
W:50:0:2:3000
A:50/1
P:0:0d0:0:0:15
-a:HARDCORE=BA_ELEC_4
+a: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~
@@ -4950,14 +4880,6 @@ 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
@@ -4980,15 +4902,6 @@ 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
@@ -5154,15 +5067,6 @@ 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
@@ -5602,15 +5506,6 @@ 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
@@ -6047,54 +5942,12 @@ G:":G
I:40:17:0
W:25:0:3:10000
A:25/1
-a:HARDCORE=BA_POIS_4
+a: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.
diff --git a/lib/edit/misc.txt b/lib/edit/misc.txt
index 08e35c1f..b2471a06 100644
--- a/lib/edit/misc.txt
+++ b/lib/edit/misc.txt
@@ -33,9 +33,6 @@ 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
diff --git a/lib/edit/ow_info.txt b/lib/edit/ow_info.txt
index a1e3d0a3..d71dfa26 100644
--- a/lib/edit/ow_info.txt
+++ b/lib/edit/ow_info.txt
@@ -13,435 +13,429 @@
# 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
+I:20000:120
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
+I:20000:120
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
+I:100:120
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
+I:0:120
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
+I:0:120
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
+I:20000:130
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
+I:30000:120
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
+I:30000:120
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
+I:5000:140
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
+I:10000:130
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
+I:25000:140
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
+I:30000:140
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
+I:5000:140
C:120:100:80
N:13:Arndal Beast-Slayer(Half-Elf)
-I:10000:185:110:5:9
+I:10000:130
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
+I:25000:140
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
+I:30000:130
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
+I:20000:140
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
+I:0:140
C:120:100:80
N:18:Celebor(Half-Elf)
-I:100:170:108:4:10
+I:100:120
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
+I:25000:140
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
+I:5000:140
C:120:100:80
#L:Warrior |
N:21:Tanistil(Elf)
-I:5000:210:115:6:6
+I:5000:140
C:120:100:80
#L:Mage | Sorceror | Thaumaturgist
#H:Warrior |
N:22:Eldore(Human)
-I:5000:210:115:6:6
+I:5000:140
C:120:100:80
#L:Priest
#H:Necromancer
N:23:Vilios(Human)
-I:5000:210:115:6:6
+I:5000:140
C:120:100:80
#L:Paladin
#H:Necromancer
N:24:Angros(Elf)
-I:5000:210:115:6:6
+I:5000:140
C:120:100:80
#L:Ranger
N:25:Palano(Thunderlord)
-I:0:210:115:6:6
+I:0:140
C:120:100:80
L:Thunderlord
N:26:Ludwig the Humble(Dwarf)
-I:5000:175:109:6:15
+I:5000:130
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
+I:10000:130
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
+I:25000:130
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
+I:30000:130
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
+I:10000:130
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
+I:10000:130
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
+I:15000:140
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
+I:15000:140
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
+I:20000:140
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
+I:20000:140
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
+I:30000:140
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
+I:30000:130
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
+I:20000:180
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
+I:20000:180
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
+I:30000:180
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
+I:30000:180
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
+I:10000:130
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
+I:15000:110
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
+I:25000:110
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
+I:30000:110
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
+I:10000:130
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
+I:15000:110
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
+I:25000:110
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
+I:30000:110
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
+I:30000:110
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
+I:15000:110
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
+I:15000:110
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
+I:30000:110
C:120:100:80
#L:Warrior |
H:Orc | Troll | Half-Ogre | Beorning | Kobold |
N:54:Valceronwe(Elf)
-I:30000:140:105:6:12
+I:30000:110
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
+I:30000:110
C:120:100:80
#L:Priest | Paladin
H:Orc | Troll | Half-Ogre | Beorning | Kobold |
N:56:Celegail(Elf)
-I:30000:140:105:6:12
+I:30000:110
C:120:100:80
#L:Ranger
H:Orc | Troll | Half-Ogre | Beorning | Kobold |
N:57:Turgon(High-Elf)
-I:30000:120:105:6:16
+I:30000:110
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
+I:0:110
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
+I:0:110
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
+I:0:110
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
+I:0:110
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
+I:0:110
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
+I:0:110
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
+I:0:110
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
+I:0:110
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
+I:0:110
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
+I:0:110
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
+I:5000:140
C:120:100:80
-#L:Merchant
-#H:Rogue
N:69:Barliman Butterbur(Human)
-I:100:170:108:4:10
+I:100:120
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
index 1531f4fd..c02e765a 100644
--- a/lib/edit/p_info.txt
+++ b/lib/edit/p_info.txt
@@ -8,8 +8,6 @@
# 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
-
##############################################################################
##############################################################################
##############################################################################
@@ -342,35 +340,6 @@ 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.
@@ -1953,22 +1922,3 @@ 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/r_info.txt b/lib/edit/r_info.txt
index e7801d09..5c93f1f6 100644
--- a/lib/edit/r_info.txt
+++ b/lib/edit/r_info.txt
@@ -182,10 +182,6 @@
# Note that monster zero is used for the "player" picture.
-# Version stamp (required)
-
-V:2.2.0
-
##### The Player #####
N:0:Player
diff --git a/lib/edit/ra_info.txt b/lib/edit/ra_info.txt
index 57dcee95..30ff3f38 100644
--- a/lib/edit/ra_info.txt
+++ b/lib/edit/ra_info.txt
@@ -16,10 +16,6 @@
# 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
diff --git a/lib/edit/re_info.txt b/lib/edit/re_info.txt
index c0e36a92..c1fb01c8 100644
--- a/lib/edit/re_info.txt
+++ b/lib/edit/re_info.txt
@@ -6,8 +6,6 @@
# 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
@@ -28,8 +26,6 @@
# 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
diff --git a/lib/edit/s_info.txt b/lib/edit/s_info.txt
index 5e41fe97..d53fb7e0 100644
--- a/lib/edit/s_info.txt
+++ b/lib/edit/s_info.txt
@@ -22,10 +22,6 @@
# T:father:child
-# Version stamp (required)
-
-V:2.0.0
-
################################## MAGIC ##################################
N:56:Magic-Device
@@ -371,11 +367,6 @@ 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
@@ -526,7 +517,6 @@ T:Magic:Demonology
T:Magic:Necromancy
T:Magic:Runecraft
T:Magic:Thaumaturgy
-T:Magic:Alchemy
T:Geomancy:Fire
T:Geomancy:Water
diff --git a/lib/edit/set_info.txt b/lib/edit/set_info.txt
index b6141e01..f114b7ef 100644
--- a/lib/edit/set_info.txt
+++ b/lib/edit/set_info.txt
@@ -7,15 +7,11 @@
# 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
diff --git a/lib/edit/st_info.txt b/lib/edit/st_info.txt
index 3762d0c5..d0defd31 100644
--- a/lib/edit/st_info.txt
+++ b/lib/edit/st_info.txt
@@ -1,13 +1,5 @@
# 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.
@@ -22,10 +14,6 @@
# 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~
@@ -271,7 +259,7 @@ N:7:Home
A:0:0:54:55:3:0
O:0:0:0:0
G:8:y
-W:24
+W:240
N:8:Book Store
# & Book~ of Beginner Cantrips
@@ -348,9 +336,6 @@ 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
@@ -692,12 +677,6 @@ 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
diff --git a/lib/edit/t_basic.txt b/lib/edit/t_basic.txt
deleted file mode 100644
index 78103425..00000000
--- a/lib/edit/t_basic.txt
+++ /dev/null
@@ -1,80 +0,0 @@
-# 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
index c74fd58a..3ea29922 100644
--- a/lib/edit/t_bree.txt
+++ b/lib/edit/t_bree.txt
@@ -44,9 +44,6 @@ 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
@@ -93,7 +90,7 @@ D:# ---- ---- ,,CT--.B#.-SStSS-
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:# ---- -------- ,,CCTT----..----,sssss,-##7#####--------OO,.,,.,-##.----TTTT^^ ^ ^^ -, OOOOO #
D:# --------------- ,,,CCTTTT--..---,##3##-,--,,,---------...OOOOOOOOOOOTTTTTCC^^^ ^^ ^^ ,- OOO #
D:# -------- ,,,CCCC --..........,-,,---,--.......-------TTTTTOCCCCC,,^^^^^^^^^^^ -.- OOOOO #
D:# ---------- ,, ,,CCCTT----------.....-......-------TTTTTTTCCCCO,,,,, ^^^^^^^ -.- O #
diff --git a/lib/edit/t_gondol.txt b/lib/edit/t_gondol.txt
index 779c4fbb..51cf4b39 100644
--- a/lib/edit/t_gondol.txt
+++ b/lib/edit/t_gondol.txt
@@ -123,9 +123,6 @@ 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
@@ -178,7 +175,7 @@ D:######$$$$$$$$$$$$$$$$$### ...
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:####$$$$#############$$$$# #########.........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------,,,,,,,^^^^^###
diff --git a/lib/edit/t_minas.txt b/lib/edit/t_minas.txt
index 51c74da3..9f6ae669 100644
--- a/lib/edit/t_minas.txt
+++ b/lib/edit/t_minas.txt
@@ -64,9 +64,6 @@ 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
@@ -84,7 +81,7 @@ D:#^^----ssss-----###--------####------ ^^^^^^
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:#^ ---------------OO--###-###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 #
diff --git a/lib/edit/tr_info.txt b/lib/edit/tr_info.txt
index e86d9617..0643f1ab 100644
--- a/lib/edit/tr_info.txt
+++ b/lib/edit/tr_info.txt
@@ -35,8 +35,6 @@
# I:diff:prob: :minlevel: :color
# D:description
-V:2.0.0
-
#
# stat traps
#
diff --git a/lib/edit/v_info.txt b/lib/edit/v_info.txt
index fb4a4d20..964f2b54 100644
--- a/lib/edit/v_info.txt
+++ b/lib/edit/v_info.txt
@@ -16,11 +16,6 @@
# Quest vaults added - rr9
-# Version stamp (required)
-
-V:2.0.0
-
-
### Simple Vaults (type 7) -- maximum size 44x22 ###
diff --git a/lib/edit/wf_info.txt b/lib/edit/wf_info.txt
index 80ab14a6..1d4b25f9 100644
--- a/lib/edit/wf_info.txt
+++ b/lib/edit/wf_info.txt
@@ -28,10 +28,6 @@
# 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
diff --git a/lib/file/elvish.txt b/lib/file/elvish.txt
deleted file mode 100644
index a00b5a22..00000000
--- a/lib/file/elvish.txt
+++ /dev/null
@@ -1,218 +0,0 @@
-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/help/ability.txt b/lib/help/ability.txt
index 175d6745..17d89dbc 100644
--- a/lib/help/ability.txt
+++ b/lib/help/ability.txt
@@ -27,11 +27,15 @@ 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*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*10[Far reaching attack]
+*****ability.txt*11[Trapping]
*****ability.txt*12[Undead Form]
~~~~~02|Abilities|Spread blows
@@ -84,12 +88,6 @@ 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.
diff --git a/lib/help/advanced.hlp b/lib/help/advanced.hlp
index 3f6fe4bd..8595712b 100644
--- a/lib/help/advanced.hlp
+++ b/lib/help/advanced.hlp
@@ -7,9 +7,8 @@ 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
+ *****/ddebug.txt*0[(d) Debug commands]
+ *****/eversion.txt*0[(e) Version information] A history of ToME's roots
*****/zhelp.hlp*0[(z) Main Help menu]
diff --git a/lib/help/automat.txt b/lib/help/automat.txt
index bf6478f8..0ba56d19 100644
--- a/lib/help/automat.txt
+++ b/lib/help/automat.txt
@@ -25,10 +25,9 @@ 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.
+vampire, 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
diff --git a/lib/help/birth.txt b/lib/help/birth.txt
index 00b1a921..990b5eba 100644
--- a/lib/help/birth.txt
+++ b/lib/help/birth.txt
@@ -240,7 +240,7 @@ 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_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]
@@ -504,7 +504,6 @@ are listed in the following table.
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
diff --git a/lib/help/c_alchem.txt b/lib/help/c_alchem.txt
deleted file mode 100644
index 2f7cd58c..00000000
--- a/lib/help/c_alchem.txt
+++ /dev/null
@@ -1,135 +0,0 @@
-|||||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_merch.txt b/lib/help/c_merch.txt
deleted file mode 100644
index 31fb60dd..00000000
--- a/lib/help/c_merch.txt
+++ /dev/null
@@ -1,29 +0,0 @@
-#####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/command.txt b/lib/help/command.txt
index 6616c252..04a63fd8 100644
--- a/lib/help/command.txt
+++ b/lib/help/command.txt
@@ -137,7 +137,7 @@ that you can always, for example, use "\" + "." + "6", to specify "run east".
*****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*79[\ (special - bypass keymap)]
*****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]
@@ -198,13 +198,13 @@ that you can always, for example, use "\" + "." + "6", to specify "run east".
*****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*79[\ (special - bypass keymap)]
*****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.
@@ -498,12 +498,7 @@ for a quantity will convert any "letters" into the maximal legal value.
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
+ You must be using an object to receive any of its special
powers.
~~~~~7
[[[[[GDrop an item (d)]
@@ -518,8 +513,7 @@ for a quantity will convert any "letters" into the maximal legal value.
[[[[[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.
+ a quantity. You must always verify this command.
~~~~~42
[[[[[GWear/Wield equipment (w)]
To wear or wield an object in your inventory, use this command.
@@ -789,9 +783,9 @@ for a quantity will convert any "letters" into the maximal legal value.
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.
+ takes effect. 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
@@ -997,10 +991,8 @@ for a quantity will convert any "letters" into the maximal legal value.
~~~~~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.
+ note file. 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
@@ -1054,9 +1046,8 @@ for a quantity will convert any "letters" into the maximal legal value.
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 (:).
+ 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)]
@@ -1218,17 +1209,6 @@ for a quantity will convert any "letters" into the maximal legal value.
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
diff --git a/lib/help/debug.txt b/lib/help/debug.txt
index 4d5e75da..65e7ff91 100644
--- a/lib/help/debug.txt
+++ b/lib/help/debug.txt
@@ -29,7 +29,7 @@ will not be scored if you use debug commands.
*****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]
+ r (unused) *****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]
@@ -138,8 +138,7 @@ maximal legal value.
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.
+ Summons a Pack of Creatures of the same kind.
~~~~~17
[[[[[GIdentify (i)]
Like a Scroll of Identify.
diff --git a/lib/help/def.aux b/lib/help/def.aux
deleted file mode 100644
index 983e9683..00000000
--- a/lib/help/def.aux
+++ /dev/null
@@ -1,3 +0,0 @@
-file_ext="html"
-link_prefix=""
-link_suffix=""
diff --git a/lib/help/defines.txt b/lib/help/defines.txt
index ac997501..147e61a1 100644
--- a/lib/help/defines.txt
+++ b/lib/help/defines.txt
@@ -12,7 +12,6 @@ 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 ('~') */
@@ -66,7 +65,6 @@ TV_BOOK 111 /* spell books */
~~~~~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 */
@@ -604,27 +602,6 @@ TV_BOOK 111 /* spell books */
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
diff --git a/lib/help/dungeon.txt b/lib/help/dungeon.txt
index eca8046d..f719fabc 100644
--- a/lib/help/dungeon.txt
+++ b/lib/help/dungeon.txt
@@ -98,7 +98,7 @@ something you are more comfortable with.
~ Lites, Tools, Chests, etc ) A shield
~ Junk, Sticks, Skeletons, etc ` Trapping kit, climbing set
~ Stone, random artifact o Egg
- * An essence & (unused)
+ & (unused)
~~~~~05|Monsters
#####G Monsters
diff --git a/lib/help/essences.txt b/lib/help/essences.txt
deleted file mode 100644
index f329fa80..00000000
--- a/lib/help/essences.txt
+++ /dev/null
@@ -1,219 +0,0 @@
-|||||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/index.txt b/lib/help/index.txt
index d306b688..87293d27 100644
--- a/lib/help/index.txt
+++ b/lib/help/index.txt
@@ -27,7 +27,6 @@ Don't forget you can browse the help from the *****help.hlp*02[Main menu].
*****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]
@@ -38,9 +37,6 @@ Don't forget you can browse the help from the *****help.hlp*02[Main menu].
*****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]
@@ -88,7 +84,6 @@ Don't forget you can browse the help from the *****help.hlp*02[Main menu].
*****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]
@@ -192,7 +187,6 @@ Don't forget you can browse the help from the *****help.hlp*02[Main menu].
*****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
@@ -424,8 +418,6 @@ Don't forget you can browse the help from the *****help.hlp*02[Main menu].
*****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]
@@ -509,7 +501,6 @@ Don't forget you can browse the help from the *****help.hlp*02[Main menu].
*****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]
diff --git a/lib/help/lua.hlp b/lib/help/lua.hlp
deleted file mode 100644
index ba61676a..00000000
--- a/lib/help/lua.hlp
+++ /dev/null
@@ -1,34 +0,0 @@
-|||||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
deleted file mode 100644
index 000f4af5..00000000
--- a/lib/help/lua_gf.txt
+++ /dev/null
@@ -1,45 +0,0 @@
-|||||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
deleted file mode 100644
index ccb87067..00000000
--- a/lib/help/lua_intr.txt
+++ /dev/null
@@ -1,133 +0,0 @@
-|||||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
deleted file mode 100644
index 9bb363c0..00000000
--- a/lib/help/lua_mon.txt
+++ /dev/null
@@ -1,535 +0,0 @@
-|||||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
deleted file mode 100644
index 6ab64ddb..00000000
--- a/lib/help/lua_play.txt
+++ /dev/null
@@ -1,1225 +0,0 @@
-|||||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
deleted file mode 100644
index c221a664..00000000
--- a/lib/help/lua_pow.txt
+++ /dev/null
@@ -1,266 +0,0 @@
-|||||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
deleted file mode 100644
index 1d4b9c65..00000000
--- a/lib/help/lua_ques.txt
+++ /dev/null
@@ -1,299 +0,0 @@
-|||||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
deleted file mode 100644
index 87385e5d..00000000
--- a/lib/help/lua_skil.txt
+++ /dev/null
@@ -1,342 +0,0 @@
-|||||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
deleted file mode 100644
index aa4a532b..00000000
--- a/lib/help/lua_spel.txt
+++ /dev/null
@@ -1,2150 +0,0 @@
-|||||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
deleted file mode 100644
index 8886a2b4..00000000
--- a/lib/help/lua_util.txt
+++ /dev/null
@@ -1,898 +0,0 @@
-|||||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/macrofaq.txt b/lib/help/macrofaq.txt
index 03a00eaa..8194d7fe 100644
--- a/lib/help/macrofaq.txt
+++ b/lib/help/macrofaq.txt
@@ -975,10 +975,6 @@ 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----------------------------------------------------------------------
@@ -1070,15 +1066,7 @@ create a macro for a function key.
#####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".
+(Content removed because it was obsolete. Inscribe-on-pickup is now the default.)
#####G----------------------------------------------------------------------
#####G5.3 Can I use macros inside other macros?
@@ -1784,9 +1772,7 @@ options screen.
rogue_like_commands
use_old_target
always_pickup
-depth_in_feet
alert_hitpoint
-auto_haggle
auto_scum
#####G----------------------------------------------------------------------
diff --git a/lib/help/magic.txt b/lib/help/magic.txt
index 93486f0b..14fa6570 100644
--- a/lib/help/magic.txt
+++ b/lib/help/magic.txt
@@ -24,7 +24,7 @@ schools:
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]
+ *****m_thaum.txt*0[Thaumaturgy] *****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
@@ -32,8 +32,7 @@ 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].
+harness the powers of the elements using *****m_geoman.txt*0[Geomancy].
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,
diff --git a/lib/help/option.txt b/lib/help/option.txt
index 6fd3b413..7563f83b 100644
--- a/lib/help/option.txt
+++ b/lib/help/option.txt
@@ -56,20 +56,6 @@ can also be viewed from the option menu while playing, but not changed then.
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.
@@ -80,6 +66,10 @@ can also be viewed from the option menu while playing, but not changed then.
#####GYou can receive fates, good or bad [fate_option]
Allows the player to turn off ToME's *****fatespoi.txt*0[fates] for that character.
+#####GItems always sell for 0 gold [no_selling]
+ Disables selling items back to shops for money. The value of gold found in the
+ dungeon is increased to compensate.
+
~~~~~07|Options|Ingame
#####RIN GAME OPTIONS
#####R===============
@@ -98,9 +88,6 @@ off at will during the course of the game.
(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.
@@ -126,54 +113,6 @@ off at will during the course of the game.
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.
@@ -205,7 +144,7 @@ off at will during the course of the game.
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.
+ a monster is viewable.
#####GDisturb whenever map panel changes [disturb_panel]
This option causes you to be disturbed (stop running) when the screen
@@ -245,18 +184,6 @@ off at will during the course of the game.
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
@@ -308,18 +235,6 @@ off at will during the course of the game.
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
@@ -374,38 +289,10 @@ off at will during the course of the game.
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
@@ -432,9 +319,6 @@ off at will during the course of the game.
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
@@ -552,11 +436,6 @@ Features which are unique to ToME are collected in this menu.
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.
diff --git a/lib/help/skills.txt b/lib/help/skills.txt
index c4a02c06..fe68da6e 100644
--- a/lib/help/skills.txt
+++ b/lib/help/skills.txt
@@ -108,7 +108,7 @@ on what each skill does, try [[[[[ghttp://www.killerbunnies.org/angband/skill-22
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*27[Air] *****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]
@@ -311,7 +311,7 @@ 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.
+Necromancy, Runecraft, and Thaumaturgy.
~~~~~54|Skills|Magic-device
[[[[[BMagic-device]
This skill is a sub-skill of the Magic skill. It eases the use of magical
@@ -465,13 +465,6 @@ 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
diff --git a/lib/help/spoiler.hlp b/lib/help/spoiler.hlp
index bc229852..996c0d32 100644
--- a/lib/help/spoiler.hlp
+++ b/lib/help/spoiler.hlp
@@ -7,7 +7,6 @@ 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]
diff --git a/lib/help/tome_faq.txt b/lib/help/tome_faq.txt
index 7ad7a421..171b74d4 100644
--- a/lib/help/tome_faq.txt
+++ b/lib/help/tome_faq.txt
@@ -81,8 +81,7 @@ 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.
+drinking pints of fine ale/wine will give you emtpy bottles.
#####G------------------------------------------------------------------------------
#####GQ: I got killed by a Great Wyrm of Power at 50'!!! What happened?
@@ -102,13 +101,10 @@ 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?
+#####GQ: I keep coming across "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.
diff --git a/lib/mods/.cvsignore b/lib/mods/.cvsignore
deleted file mode 100644
index 61a33fff..00000000
--- a/lib/mods/.cvsignore
+++ /dev/null
@@ -1 +0,0 @@
-tomk
diff --git a/lib/mods/CMakeLists.txt b/lib/mods/CMakeLists.txt
new file mode 100644
index 00000000..5cce23ea
--- /dev/null
+++ b/lib/mods/CMakeLists.txt
@@ -0,0 +1 @@
+ADD_SUBDIRECTORY(theme)
diff --git a/lib/mods/mods_aux.lua b/lib/mods/mods_aux.lua
deleted file mode 100644
index 1562a566..00000000
--- a/lib/mods/mods_aux.lua
+++ /dev/null
@@ -1,185 +0,0 @@
--- 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
deleted file mode 100644
index 5deddef7..00000000
--- a/lib/mods/modules.lua
+++ /dev/null
@@ -1,5 +0,0 @@
--- Load ToME
-tome_dofile_anywhere(ANGBAND_DIR, "module.lua")
-
--- Look for more modules
-scan_extra_modules()
diff --git a/lib/mods/theme/CMakeLists.txt b/lib/mods/theme/CMakeLists.txt
new file mode 100644
index 00000000..f1160786
--- /dev/null
+++ b/lib/mods/theme/CMakeLists.txt
@@ -0,0 +1,14 @@
+INSTALL(DIRECTORY
+ apex
+ data
+ dngn
+ edit
+ file
+ help
+ note
+ pref
+ save
+ user
+ DESTINATION ${DEFAULT_PATH}/mods/theme
+ PATTERN "delete.me" EXCLUDE
+ )
diff --git a/lib/mods/theme/core/auto.lua b/lib/mods/theme/core/auto.lua
deleted file mode 100644
index b758db52..00000000
--- a/lib/mods/theme/core/auto.lua
+++ /dev/null
@@ -1,859 +0,0 @@
--- 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
deleted file mode 100644
index 8e88888a..00000000
--- a/lib/mods/theme/core/building.lua
+++ /dev/null
@@ -1,15 +0,0 @@
-__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
deleted file mode 100644
index 97f8d4b6..00000000
--- a/lib/mods/theme/core/crpt_aux.lua
+++ /dev/null
@@ -1,182 +0,0 @@
--- 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
deleted file mode 100644
index d91d785b..00000000
--- a/lib/mods/theme/core/dungeon.lua
+++ /dev/null
@@ -1,55 +0,0 @@
--- 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
deleted file mode 100644
index 5f3af435..00000000
--- a/lib/mods/theme/core/gen_idx.lua
+++ /dev/null
@@ -1,261 +0,0 @@
--- 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
deleted file mode 100644
index 77e0aad5..00000000
--- a/lib/mods/theme/core/gods.lua
+++ /dev/null
@@ -1,40 +0,0 @@
--- 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
deleted file mode 100644
index a581fe63..00000000
--- a/lib/mods/theme/core/help.lua
+++ /dev/null
@@ -1,141 +0,0 @@
--- 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
deleted file mode 100644
index 11b812d5..00000000
--- a/lib/mods/theme/core/init.lua
+++ /dev/null
@@ -1,83 +0,0 @@
---
--- 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
deleted file mode 100644
index 9522ec91..00000000
--- a/lib/mods/theme/core/load.lua
+++ /dev/null
@@ -1,37 +0,0 @@
--- 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
deleted file mode 100644
index 7e151d91..00000000
--- a/lib/mods/theme/core/load2.lua
+++ /dev/null
@@ -1,56 +0,0 @@
--- 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
deleted file mode 100644
index cea1f4dc..00000000
--- a/lib/mods/theme/core/mimc_aux.lua
+++ /dev/null
@@ -1,96 +0,0 @@
--- 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
deleted file mode 100644
index ca2851a0..00000000
--- a/lib/mods/theme/core/monsters.lua
+++ /dev/null
@@ -1,16 +0,0 @@
--- 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
deleted file mode 100644
index 97320b82..00000000
--- a/lib/mods/theme/core/objects.lua
+++ /dev/null
@@ -1,45 +0,0 @@
--- 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
deleted file mode 100644
index 16878228..00000000
--- a/lib/mods/theme/core/player.lua
+++ /dev/null
@@ -1,135 +0,0 @@
--- 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
deleted file mode 100644
index dfe9db51..00000000
--- a/lib/mods/theme/core/quests.lua
+++ /dev/null
@@ -1,57 +0,0 @@
--- 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
deleted file mode 100644
index ec609b04..00000000
--- a/lib/mods/theme/core/s_aux.lua
+++ /dev/null
@@ -1,716 +0,0 @@
--- 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
deleted file mode 100644
index d4a63168..00000000
--- a/lib/mods/theme/core/stores.lua
+++ /dev/null
@@ -1,32 +0,0 @@
--- 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
deleted file mode 100644
index eea13014..00000000
--- a/lib/mods/theme/core/util.lua
+++ /dev/null
@@ -1,158 +0,0 @@
--- 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
deleted file mode 100644
index 14f0511f..00000000
--- a/lib/mods/theme/core/xml.lua
+++ /dev/null
@@ -1,375 +0,0 @@
--- 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/edit/a_info.txt b/lib/mods/theme/edit/a_info.txt
index e2a312c5..c9f888cc 100644
--- a/lib/mods/theme/edit/a_info.txt
+++ b/lib/mods/theme/edit/a_info.txt
@@ -26,11 +26,6 @@
# 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
@@ -40,7 +35,7 @@ W:20:10:10:10000
P:0:1d1:0:0:0
F:ACTIVATE | SEARCH | LITE3 | LUCK
F:INSTA_ART | HIDE_TYPE
-a:HARDCORE=LIGHT
+a: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.
@@ -53,7 +48,7 @@ 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
+a: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
@@ -68,7 +63,7 @@ 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
+a: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.
@@ -94,7 +89,7 @@ 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
+a:DISP_EVIL
D:The ancient heirloom of Ingwe, high lord of the Vanyar, against whom nothing
D:of evil could stand.
@@ -108,7 +103,7 @@ 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
+a: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.
@@ -133,7 +128,7 @@ 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
+a: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.
@@ -146,7 +141,7 @@ 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
+a: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
@@ -164,7 +159,7 @@ 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
+a: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.
@@ -181,7 +176,7 @@ 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
+a: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.
@@ -199,7 +194,7 @@ 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
+a: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
@@ -221,7 +216,7 @@ 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
+a: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,
@@ -251,7 +246,7 @@ 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
+a: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
@@ -268,7 +263,7 @@ 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
+a: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.
@@ -285,7 +280,7 @@ 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
+a: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.
@@ -312,7 +307,7 @@ 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
+a: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
@@ -355,7 +350,7 @@ 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
+a: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.
@@ -370,7 +365,7 @@ 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
+a: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.
@@ -397,7 +392,7 @@ 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
+a: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.
@@ -412,7 +407,7 @@ 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
+a:SUNLIGHT
D:The shining helm that Gil-galad, legendary Elven-king, wore in battle.
# The Leather Jerkin of Tom Bombadil
@@ -504,7 +499,7 @@ 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
+a: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.
@@ -588,7 +583,7 @@ 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
+a:GORLIM
D:The legendary dragon helm of Turin Turambar, an object of dread to the
D:servants of Morgoth.
@@ -600,7 +595,7 @@ 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
+a:DETECT_ALL
D:A famous helm of forged iron granting extraordinary powers of mind and
D:awareness.
@@ -616,7 +611,7 @@ 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
+a:GORLIM
D:A headpiece, gaudy and barbaric, that betrayed a warrior when he most
D:needed succor.
@@ -630,7 +625,7 @@ 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
+a:CURE_700
D:The shining winged circlet brought by Elendil from dying Numenor, emblem of
D:Gondor through an age of the world.
@@ -646,7 +641,7 @@ 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
+a: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
@@ -661,7 +656,7 @@ 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
+a:COLLUIN
D:A cape worn by a hero from Valinor, a land utterly beyond the strife
D:of the elements.
@@ -673,7 +668,7 @@ 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
+a: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.
@@ -687,7 +682,7 @@ 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
+a:RECHARGE
D:A sable-hued cloak, with glowing elven-runes to restore magic showing calm
D:and clear as moonlight on still water.
@@ -712,7 +707,7 @@ W:5:20:10:11000
P:1:0d0:0:0:15
F:STEALTH | SPEED | RES_NEXUS |
F:RES_ACID | ACTIVATE
-a:HARDCORE=TELEPORT
+a: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.
@@ -726,7 +721,7 @@ 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
+a: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
@@ -775,7 +770,7 @@ 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
+a: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.
@@ -787,7 +782,7 @@ 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
+a: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.
@@ -800,7 +795,7 @@ 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
+a: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.
@@ -813,7 +808,7 @@ 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
+a: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.
@@ -826,7 +821,7 @@ 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
+a: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.
@@ -852,7 +847,7 @@ 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
+a: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.
@@ -866,7 +861,7 @@ W:40:120:40:300000
P:3:1d1:0:0:20
F:SPEED | HIDE_TYPE |
F:RES_NEXUS | ACTIVATE
-a:HARDCORE=SPEED
+a: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.
@@ -881,7 +876,7 @@ 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
+a:CURE_POISON
D:A pair of high-laced shoes, strong against the powers of corruption and
D:withering, that grant the wearer extraordinary agility.
@@ -949,7 +944,7 @@ 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
+a: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.
@@ -960,7 +955,7 @@ 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
+a: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.
@@ -971,7 +966,7 @@ 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
+a: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.
@@ -983,7 +978,7 @@ 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
+a:BA_POIS_1
D:A large stiletto dagger that glistens with odourless poison, to which the
D:wearer seems oddly immune.
@@ -998,7 +993,7 @@ 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
+a: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.
@@ -1160,7 +1155,7 @@ 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
+a: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
@@ -1176,7 +1171,7 @@ 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
+a: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.
@@ -1192,7 +1187,7 @@ 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
+a: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
@@ -1321,7 +1316,7 @@ 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
+a: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.
@@ -1381,7 +1376,7 @@ 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
+a: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
@@ -1401,7 +1396,7 @@ 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
+a:STONE_MUD
D:A magical spear, rumoured to have been forged by Orome himself
D:in the coldest reach of the cruel Redhorn.
@@ -1460,7 +1455,7 @@ 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
+a: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.
@@ -1490,7 +1485,7 @@ 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
+a:CURE_MW
D:A superbly crafted double-bladed axe that slays the creatures of earth and
D:allows rapid recovery from their blows.
@@ -1547,7 +1542,7 @@ 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
+a: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.
@@ -1563,7 +1558,7 @@ 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
+a: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.
@@ -1597,7 +1592,7 @@ F:RES_COLD | SEE_INVIS | ESP_ALL | AGGRAVATE | SHOW_MODS | INSTA_ART |
F:LEVELS | ACTIVATE | SPECIAL_GENE |
F:MUST2H
f:MUST2H
-a:HARDCORE=GROND
+a: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.
@@ -1612,7 +1607,7 @@ F:SLAY_EVIL | BRAND_FIRE | RES_FIRE | RES_CONF | ACTIVATE |
F:SHOW_MODS | LITE1 |
F:COULD2H
f:COULD2H
-a:HARDCORE=CONFUSE
+a: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.
@@ -1651,7 +1646,7 @@ 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
+a:FIRESTAR
D:A famed battle-lord of old, with a ruddy head, coloured as embers are that
D:can yet rise up in wrath.
@@ -1665,7 +1660,7 @@ P:0:3d4:12:12:0
F:KILL_DRAGON | BRAND_ELEC | IM_ELEC | ACTIVATE | SHOW_MODS |
F:COULD2H
f:COULD2H
-a:HARDCORE=SPEED
+a: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.
@@ -1709,7 +1704,7 @@ 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
+a: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.
@@ -1723,7 +1718,7 @@ 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
+a: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.
@@ -1757,7 +1752,7 @@ 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
+a: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.
@@ -1809,7 +1804,7 @@ W:50:25:110:50000
P:0:0d0:10:14:0
F:SPEED | HIDE_TYPE |
F:RES_FIRE | ACTIVATE | SHOW_MODS
-a:HARDCORE=CUBRAGOL
+a:CUBRAGOL
D:A crossbow that grants fiery speed to he who finds it, and from which
D:shoot bolts that blaze with flame unquenchable.
@@ -1826,7 +1821,7 @@ 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
+a:GANDALF
D:A simple, wooden wizard's staff. Unremarkable in all aspects...
D:except that it pulses with overwhelming power.
@@ -1926,7 +1921,7 @@ 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
+a: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
@@ -1941,7 +1936,7 @@ 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
+a: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
@@ -1996,7 +1991,7 @@ 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
+a:EREBOR
D:A pick that provides a magical light by which to see while tunnelling.
@@ -2007,7 +2002,7 @@ 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
+a: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.
@@ -2020,7 +2015,7 @@ I:14:60:2
W:14:10:15:80000
P:0:3d4:0:0:0
F:ACTIVATE | CHR | WIS | ESP_DRAGON
-a:HARDCORE=ROHAN
+a: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.
@@ -2033,7 +2028,7 @@ 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
+a: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.
@@ -2046,7 +2041,7 @@ 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
+a: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.
@@ -2060,7 +2055,7 @@ 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
+a: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.
@@ -2088,7 +2083,7 @@ 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
+a: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.
@@ -2114,7 +2109,7 @@ 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
+a: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
@@ -2205,7 +2200,7 @@ P:0:2d7:20:14:0
F:DEX | SEARCH | SLAY_ORC | ACTIVATE | HIDE_TYPE | SHOW_MODS |
F:COULD2H
f:COULD2H
-a:HARDCORE=ORCHAST
+a: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.
@@ -2218,7 +2213,7 @@ 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
+a:NIGHT
D:Found on an unmarked grave after a violent storm, this hatchet
D:has a sinister aura of darkness and decay.
@@ -2230,7 +2225,7 @@ 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
+a:NATUREBANE
D:Used by the orcs in their battle at Dagor Bragollach against the elves, this
D:axe has a bloodthirst for nature.
@@ -2254,7 +2249,7 @@ 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
+a: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.
@@ -2317,7 +2312,7 @@ 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
+a: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
@@ -2334,7 +2329,7 @@ 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
+a: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.
@@ -2345,7 +2340,7 @@ 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
+a: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.
@@ -2373,7 +2368,7 @@ 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
+a: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.
@@ -2387,7 +2382,7 @@ 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
+a: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
@@ -2404,7 +2399,7 @@ 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
+a: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.
@@ -2450,7 +2445,7 @@ 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
+a: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.
@@ -2467,7 +2462,7 @@ F:SLAY_EVIL | SLAY_UNDEAD | ACTIVATE |
F:RES_FIRE | RES_ELEC | RES_NETHER | RES_DISEN | HOLD_LIFE |
F:COULD2H
f:COULD2H
-a:HARDCORE=FUNDIN
+a: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.
@@ -2482,7 +2477,7 @@ 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
+a: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
@@ -2500,7 +2495,7 @@ F:RES_NEXUS | RES_BLIND | RES_SOUND |
F:KILL_DRAGON | SLAY_ANIMAL | BRAND_POIS | BRAND_ELEC |
F:COULD2H
f:COULD2H
-a:HARDCORE=SKULLCLEAVER
+a: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.
@@ -2512,7 +2507,7 @@ 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
+a:EOL
D:The iron-shod gauntlets of the Dark Elven smith Eol, tingling with magics
D:that he could channel in battle.
@@ -2581,7 +2576,7 @@ 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
+a: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
@@ -2597,7 +2592,7 @@ 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
+a: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
@@ -2615,7 +2610,7 @@ 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
+a: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
@@ -2634,7 +2629,7 @@ 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
+a: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
@@ -2651,7 +2646,7 @@ 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
+a: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
@@ -2694,7 +2689,7 @@ 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
+a: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.
@@ -2707,7 +2702,7 @@ 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
+a: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.
@@ -2723,7 +2718,7 @@ 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
+a: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
@@ -2737,7 +2732,7 @@ 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
+a: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.
@@ -2766,7 +2761,7 @@ 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
+a: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
@@ -2786,7 +2781,7 @@ 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
+a: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
@@ -2804,7 +2799,7 @@ 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
+a: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.
@@ -2817,7 +2812,7 @@ 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
+a: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
@@ -2832,7 +2827,7 @@ 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
+a: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
@@ -2859,7 +2854,7 @@ 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
+a: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
@@ -2922,7 +2917,7 @@ 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
+a: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.
@@ -2936,7 +2931,7 @@ 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
+a: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.
@@ -2950,7 +2945,7 @@ 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
+a: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
@@ -2990,7 +2985,7 @@ 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
+a: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.
@@ -3002,7 +2997,7 @@ 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
+a: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
@@ -3120,7 +3115,7 @@ 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
+a: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
@@ -3158,7 +3153,7 @@ 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
+a:BLADETURNER
D:A shining shield, once borne by the great mariner Earendil, "scored with
D:runes to keep all wounds and harm from him".
@@ -3218,7 +3213,7 @@ 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
+a: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,
@@ -3236,7 +3231,7 @@ 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
+a: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.
@@ -3253,7 +3248,7 @@ 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
+a: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)
@@ -3268,7 +3263,7 @@ 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
+a: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.
@@ -3333,7 +3328,7 @@ 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
+a: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
diff --git a/lib/mods/theme/edit/ab_info.txt b/lib/mods/theme/edit/ab_info.txt
index 4272776a..976c6d03 100644
--- a/lib/mods/theme/edit/ab_info.txt
+++ b/lib/mods/theme/edit/ab_info.txt
@@ -22,23 +22,17 @@
# 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
+D:Prereq: Combat@30, Dex@17
I:5
-k:30:Weaponmastery
+k:30:Combat
S:17:DEX
N:1:Tree walking
diff --git a/lib/mods/theme/edit/al_info.txt b/lib/mods/theme/edit/al_info.txt
deleted file mode 100644
index c5e7c55d..00000000
--- a/lib/mods/theme/edit/al_info.txt
+++ /dev/null
@@ -1,12 +0,0 @@
-# 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
index b76f79dd..b0270989 100644
--- a/lib/mods/theme/edit/ba_info.txt
+++ b/lib/mods/theme/edit/ba_info.txt
@@ -17,10 +17,6 @@
# 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:.
@@ -65,10 +61,6 @@ 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
@@ -97,14 +89,6 @@ 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
@@ -165,19 +149,6 @@ 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
@@ -190,10 +161,6 @@ 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
@@ -204,11 +171,6 @@ 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
@@ -257,18 +219,6 @@ 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
diff --git a/lib/mods/theme/edit/d_info.txt b/lib/mods/theme/edit/d_info.txt
index 91cf3d20..f5d836f6 100644
--- a/lib/mods/theme/edit/d_info.txt
+++ b/lib/mods/theme/edit/d_info.txt
@@ -29,10 +29,6 @@
# 3 = OR
# 4 = NOR
-# Version stamp (required)
-
-V:2.0.0
-
### Wilderness(purely cosmetic, never used) ###
N:0:Wilderness
@@ -83,7 +79,8 @@ 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
+#L:88:94:210:2:199:4
+L:88:78:89:18:199:4
A:96:80:97:19:57:1:57:97
A:100:0:0
O:20:20:20:20
@@ -308,7 +305,7 @@ M:ORC | R_CHAR_o | R_CHAR_O
# There is Glaurung
N:20:Erebor
D:Ere:a tunnel leading into depths of the Lonely Mountain.
-W:60:72:35:0:20:140
+W:60:72:30:0:20:140
L:88:100:1:0:1:0
A:97:90:87:10:56:0:57:97
O:40:40:40:40
diff --git a/lib/mods/theme/edit/e_info.txt b/lib/mods/theme/edit/e_info.txt
index 72b8348e..70d0e917 100644
--- a/lib/mods/theme/edit/e_info.txt
+++ b/lib/mods/theme/edit/e_info.txt
@@ -63,10 +63,6 @@
-# Version stamp (required)
-
-V:2.0.0
-
### Mage Staff ###
N:1:of Mana
@@ -233,7 +229,7 @@ C:0:0:0:3
Z:blink
R:100
F:ACTIVATE
-a:HARDCORE=JUMP
+a:JUMP
### Shields ###
@@ -323,7 +319,7 @@ C:0:0:0:2
W:0:1:8:500
R:100
F:DEX | SUST_DEX | ACTIVATE | ESP_ORC
-a:HARDCORE=NOLDOR
+a:NOLDOR
N:24:of Intelligence
X:A:33:13
@@ -869,7 +865,7 @@ W:0:1:44:9000
C:8:8:0:2
R:100
F:DEX | STR | VORPAL | ACTIVATE
-a:HARDCORE=SPIN
+a:SPIN
# The "Elemental" brands (4) (6)
@@ -1251,7 +1247,7 @@ T:24:0:99
X:A:24:22
W:10:6:90:45000
C:4:4:0:2
-a:HARDCORE=TELEPORT
+a:TELEPORT
R:100
F:SLAY_EVIL | KILL_DRAGON | TELEPORT | FREE_ACT | SEARCH | BRAND_ELEC
F:REGEN | SLOW_DIGEST | RES_MORGUL | ACTIVATE | ESP_DRAGON
@@ -1310,7 +1306,7 @@ W:0:1:5:5000
R:100
F:SLAY_UNDEAD | SEE_INVIS | HOLD_LIFE | DRAIN_HP
F:ACTIVATE
-a:HARDCORE=SPECTRAL
+a:SPECTRAL
N:103:of Morgul
T:125:0:99
@@ -1617,7 +1613,7 @@ R:50
F:PVAL_M1
R:25
F:PVAL_M1
-a:HARDCORE=BA_ACID_H
+a:BA_ACID_H
# Rods ego
N:131:Capacity of
@@ -2148,7 +2144,7 @@ T:14:7:7
X:B:25:20
W:0:1:2:2000
C:0:0:0:0
-a:HARDCORE=BA_COLD_3
+a:BA_COLD_3
R:100
F:IGNORE_ACID | IGNORE_ELEC | IGNORE_FIRE | IGNORE_COLD |
@@ -2157,7 +2153,7 @@ T:14:7:7
X:B:25:20
W:0:1:2:2000
C:0:0:0:0
-a:HARDCORE=BA_ELEC_3
+a:BA_ELEC_3
R:100
F:IGNORE_ACID | IGNORE_ELEC | IGNORE_FIRE | IGNORE_COLD |
@@ -2166,7 +2162,7 @@ T:14:7:7
X:B:25:20
W:0:1:2:2000
C:0:0:0:0
-a:HARDCORE=BA_FIRE_H
+a:BA_FIRE_H
R:100
F:IGNORE_ACID | IGNORE_ELEC | IGNORE_FIRE | IGNORE_COLD |
@@ -2434,7 +2430,7 @@ 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
+a:PROT_EVIL
r:F:CURSED | HEAVY_CURSE | AUTO_CURSE |
R:33
F:ESP_EVIL |
@@ -2453,7 +2449,7 @@ 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
+a:SPECTRAL
R:33
F:RES_NETHER |
R:5
diff --git a/lib/mods/theme/edit/f_info.txt b/lib/mods/theme/edit/f_info.txt
index dbfec51a..2b42aa47 100644
--- a/lib/mods/theme/edit/f_info.txt
+++ b/lib/mods/theme/edit/f_info.txt
@@ -15,11 +15,6 @@
# Note that terrain feature zero contains the "darkness" picture.
-# Version stamp (required)
-
-V:2.0.0
-
-
# 0x00 --> nothing
N:0:nothing
diff --git a/lib/mods/theme/edit/k_info.txt b/lib/mods/theme/edit/k_info.txt
index 07e4bbe2..c8a78082 100644
--- a/lib/mods/theme/edit/k_info.txt
+++ b/lib/mods/theme/edit/k_info.txt
@@ -27,10 +27,6 @@
# A: depth/rarity : depth/rarity : etc
# F: flag | flag | etc
-# Version stamp (required)
-
-V:2.0.0
-
##### Something special #####
@@ -1413,7 +1409,7 @@ G:=:d
I:45:4:0
W:5:0:2:250
A:5/1
-a:HARDCORE=DEST_TELE
+a:DEST_TELE
F:CURSED | TELEPORT | EASY_KNOW | ACTIVATE
f:TELEPORT
D:This ring will uncontrollably send you to different places at its whim.
@@ -1474,7 +1470,7 @@ I:45:18:0
W:50:0:2:3000
A:50/1
P:0:0d0:0:0:15
-a:HARDCORE=BA_FIRE_4
+a: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
@@ -1486,7 +1482,7 @@ I:45:17:0
W:50:0:2:3000
A:50/1
P:0:0d0:0:0:15
-a:HARDCORE=BA_ACID_4
+a: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
@@ -1497,7 +1493,7 @@ G:=:d
I:45:19:0
W:50:0:2:3000
A:50/1
-a:HARDCORE=BA_COLD_4
+a:BA_COLD_4
P:0:0d0:0:0:15
F:RES_COLD | ACTIVATE
f:RES_COLD | IGNORE_COLD
@@ -1538,7 +1534,7 @@ I:45:28:0
W:20:0:2:500
A:20/1
F:HIDE_TYPE | EASY_USE | ACTIVATE |
-a:HARDCORE=WHIRLWIND
+a: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.
@@ -1621,7 +1617,7 @@ I:40:2:0
W:25:0:3:10000
A:25/1
F:EASY_KNOW | ACTIVATE | BLESSED | ESP_EVIL
-a:HARDCORE=PROT_EVIL
+a:PROT_EVIL
D:This blessed amulet fends off evil beings and warns the wearer
D:of their presence.
@@ -2698,9 +2694,9 @@ 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:NORM_ART | FULL_NAME | SPECIAL_GENE | EASY_USE
F:ACTIVATE | ACTIVATE_NO_WIELD
-a:SPELL=Artifact Eternal Flame
+a: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.
@@ -3472,7 +3468,7 @@ I:38:1:0
W:60:0:200:50000
A:60/8
P:30:2d4:-2:0:10
-a:HARDCORE=BR_ACID
+a:BR_ACID
F:RES_ACID | FLY |
f:RES_ACID |
F:ACTIVATE | IGNORE_ACID | IGNORE_ELEC | IGNORE_FIRE | IGNORE_COLD
@@ -3485,7 +3481,7 @@ I:38:2:0
W:50:0:200:40000
A:50/8
P:30:2d4:-2:0:10
-a:HARDCORE=BR_ELEC
+a:BR_ELEC
F:RES_ELEC | FLY |
f:RES_ELEC |
F:ACTIVATE | IGNORE_ACID | IGNORE_ELEC | IGNORE_FIRE | IGNORE_COLD
@@ -3497,7 +3493,7 @@ G:[:w
I:38:3:0
W:50:0:200:40000
A:50/8
-a:HARDCORE=BR_COLD
+a:BR_COLD
P:30:2d4:-2:0:10
F:RES_COLD | FLY |
f:RES_COLD |
@@ -3511,7 +3507,7 @@ I:38:4:0
W:60:0:200:50000
A:60/8
P:30:2d4:-2:0:10
-a:HARDCORE=BR_FIRE
+a:BR_FIRE
F:RES_FIRE | FLY |
f:RES_FIRE |
F:ACTIVATE | IGNORE_ACID | IGNORE_ELEC | IGNORE_FIRE | IGNORE_COLD
@@ -3524,7 +3520,7 @@ I:38:5:0
W:50:0:200:40000
A:50/8
P:30:2d4:-2:0:10
-a:HARDCORE=BR_POIS
+a:BR_POIS
F:RES_POIS | FLY |
f:RES_POIS |
F:ACTIVATE | IGNORE_ACID | IGNORE_ELEC | IGNORE_FIRE | IGNORE_COLD
@@ -3537,7 +3533,7 @@ I:38:6:0
W:90:0:200:150000
A:90/32
P:30:2d4:-2:0:10
-a:HARDCORE=BR_MANY
+a: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 |
@@ -3551,7 +3547,7 @@ I:38:10:0
W:70:0:200:70000
A:70/16
P:30:2d4:-2:0:10
-a:HARDCORE=BR_LIGHT
+a: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.
@@ -3563,7 +3559,7 @@ I:38:12:0
W:80:0:200:80000
A:80/16
P:30:2d4:-2:0:10
-a:HARDCORE=BR_SHARD
+a: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.
@@ -3575,7 +3571,7 @@ I:38:14:0
W:50:0:200:40000
A:50/8
P:30:2d4:-2:0:10
-a:HARDCORE=BR_CONF
+a: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.
@@ -3587,7 +3583,7 @@ I:38:16:0
W:60:0:200:50000
A:60/8
P:30:2d4:-2:0:10
-a:HARDCORE=BR_SOUND
+a: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.
@@ -3599,7 +3595,7 @@ I:38:18:0
W:80:0:200:80000
A:80/16
P:30:2d4:-2:0:10
-a:HARDCORE=BR_CHAOS
+a:BR_CHAOS
F:ATTR_MULTI
F:RES_CHAOS | RES_DISEN | FLY |
f:RES_CHAOS |
@@ -3614,7 +3610,7 @@ I:38:20:0
W:95:0:200:100000
A:95/32
P:30:2d4:-2:0:10
-a:HARDCORE=BR_BALANCE
+a: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
@@ -3626,7 +3622,7 @@ I:38:30:0
W:100:0:250:350000
A:100/64
P:40:2d4:-3:0:15
-a:HARDCORE=BR_POWER
+a: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 |
@@ -3850,7 +3846,7 @@ W:50:0:2:100000
A:50/2
F:BLOWS | ACTIVATE | EASY_USE |
f:BLOWS | ACTIVATE
-a:HARDCORE=SPIN
+a:SPIN
D:This powerful ring of fighters greatly enhances your fighting speed, allowing you to attack
D:more often in a round of combat.
@@ -4785,7 +4781,7 @@ I:45:56:0
W:50:0:2:3000
A:50/1
P:0:0d0:0:0:15
-a:HARDCORE=BA_ELEC_4
+a:BA_ELEC_4
F:RES_ELEC | ACTIVATE
f:RES_ELEC | IGNORE_ELEC
D:This sparkling circlet grants you protection, makes electricity less
@@ -5992,7 +5988,7 @@ G:":G
I:40:17:0
W:25:0:3:10000
A:25/1
-a:HARDCORE=BA_POIS_4
+a: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
@@ -6465,7 +6461,7 @@ A:100/10
F:SUST_STR | SUST_DEX | SUST_CON | REGEN |
F:HOLD_LIFE | LIFE |
F:HIDE_TYPE | ACTIVATE |
-a:HARDCORE=CURE_HUNGER
+a: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.
@@ -6476,7 +6472,7 @@ 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
+a: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
diff --git a/lib/mods/theme/edit/misc.txt b/lib/mods/theme/edit/misc.txt
index 2d380202..98375869 100644
--- a/lib/mods/theme/edit/misc.txt
+++ b/lib/mods/theme/edit/misc.txt
@@ -33,9 +33,6 @@ 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
diff --git a/lib/mods/theme/edit/ow_info.txt b/lib/mods/theme/edit/ow_info.txt
index bf1283fb..75683581 100644
--- a/lib/mods/theme/edit/ow_info.txt
+++ b/lib/mods/theme/edit/ow_info.txt
@@ -13,13 +13,9 @@
# 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
+I:20000:120
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
@@ -27,25 +23,25 @@ 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
+I:25000:130
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
+I:20000:130
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
+I:30000:120
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
+I:10000:140
C:110:100:80
L:High-Elf | Dunadan | Elf
H:Dragon | Demon | Orc | Half-Ogre | Troll | Easterling
@@ -53,25 +49,25 @@ H:Dragon | Demon | Orc | Half-Ogre | Troll | Easterling
### The Armoury - 2 ###
N:5:Bifur(Dwarf)
-I:20000:190:109:3:4
+I:20000:130
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
+I:25000:130
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
+I:10000:140
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
+I:30000:120
C:110:100:80
L:High-Elf | Dunadan | Elf
H:Dragon | Demon | Orc | Dark-Elf | Half-Ogre | Petty-Dwarf | Troll | Easterling
@@ -79,25 +75,25 @@ 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
+I:30000:120
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
+I:20000:130
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
+I:25000:130
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
+I:10000:140
C:125:100:50
L:Dark-Elf | Elf
H:Dragon | Demon | Orc | Half-Ogre | Petty-Dwarf | Dwarf | Troll | Easterling
@@ -105,25 +101,25 @@ H:Dragon | Demon | Orc | Half-Ogre | Petty-Dwarf | Dwarf | Troll | Easterling
### The Temple - 4 ###
N:13:Bombur(Dwarf)
-I:20000:190:109:3:4
+I:20000:130
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
+I:30000:120
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
+I:10000:140
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
+I:25000:130
C:110:100:80
L:High-Elf | Dunadan | Hobbit | Elf
H:Dragon | Demon | Orc | Dark-Elf | Half-Ogre | Dwarf | Troll | Easterling
@@ -131,25 +127,25 @@ H:Dragon | Demon | Orc | Dark-Elf | Half-Ogre | Dwarf | Troll | Easterling
### The Alchemist - 5 ###
N:17:Borin(Dwarf)
-I:20000:190:109:3:4
+I:20000:130
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
+I:10000:140
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
+I:25000:130
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
+I:30000:120
C:125:100:70
L:Human | Half-Elf | High-Elf | Dunadan | Elf
H:Dragon | Demon | Beorning | Orc | Dark-Elf | Half-Ogre | Dwarf | Troll
@@ -157,25 +153,25 @@ 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
+I:30000:120
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
+I:10000:140
C:110:100:80
L:Hobbit
H:Dragon | Demon | Orc | Troll
N:23:Ciryon(Dunadan)
-I:25000:180:108:2:2
+I:25000:130
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
+I:20000:130
C:125:100:70
L:Human | Dark-Elf | Elf
H:Dragon | Demon | Beorning | Orc | High-Elf | Half-Ogre | Petty-Dwarf | Troll | Easterling
@@ -183,25 +179,25 @@ H:Dragon | Demon | Beorning | Orc | High-Elf | Half-Ogre | Petty-Dwarf | Troll |
### The Black Market - 7 ###
N:25:Dori(Dwarf)
-I:30000:210:120:8:8
+I:30000:150
C:110:100:90
L:Dwarf | Easterling
H:Dragon | Demon | Orc
N:26:Halfred Greenhand(Hobbit)
-I:30000:210:120:8:8
+I:30000:150
C:110:100:90
L:Hobbit
H:Dragon | Demon | Troll
N:27:Deorwine(Half-Elf)
-I:30000:210:120:8:8
+I:30000:150
C:110:100:90
L:Half-Elf | Easterling
H:Dragon | Demon | Dark-Elf
N:28:Artanis(Wood-Elf)
-I:30000:210:120:8:8
+I:30000:150
C:110:100:90
L:High-Elf | Elf | Easterling
H:Dragon | Demon | Orc | Troll
@@ -209,25 +205,25 @@ H:Dragon | Demon | Orc | Troll
### The Bookstore - 9 ###
N:29:Dwalin(Dwarf)
-I:20000:190:109:3:4
+I:20000:130
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
+I:10000:140
C:110:100:80
L:Human | Hobbit | Elf
H:Dragon | Demon | Beorning | Orc | Troll
N:31:Dorlas(Human)
-I:30000:170:107:1:1
+I:30000:120
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
+I:25000:130
C:110:100:80
L:Half-Elf | High-Elf | Elf
H:Dragon | Demon | Orc | Dark-Elf | Half-Ogre | Petty-Dwarf | Dwarf | Troll | Easterling
@@ -235,25 +231,25 @@ H:Dragon | Demon | Orc | Dark-Elf | Half-Ogre | Petty-Dwarf | Dwarf | Troll | Ea
### The Pet Shop - 0 ###
N:33:Fili(Dwarf)
-I:20000:190:109:3:4
+I:20000:130
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
+I:25000:130
C:110:100:80
L:Human | Hobbit | Elf
H:Dragon | Demon | Beorning | Orc | Troll
N:35:Elfwine(Dunadan)
-I:10000:200:110:4:8
+I:10000:140
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
+I:30000:120
C:150:100:50
L:Dark-Elf | Elf | Easterling
H:Dragon | Demon | Orc | High-Elf | Half-Ogre | Dwarf | Troll
@@ -262,98 +258,98 @@ H:Dragon | Demon | Orc | High-Elf | Half-Ogre | Dwarf | Troll
#Bree
N:37:Uldrik(Human)
-I:0:0:0:0:0
+I: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
+I: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
+I: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
+I:100:100
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
+I:100:100
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
+I:100:100
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
+I:100:100
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
+I:100:100
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
+I:100:100
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
+I:100:100
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
+I:100:100
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
+I:100:100
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
+I:100:100
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
+I:100:100
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
@@ -361,37 +357,37 @@ H:Dragon | Demon | Beorning | Orc | Dark-Elf | Half-Ogre | Petty-Dwarf | Dwarf |
### Caras Galadhon owners ###
N:51:Galadriel(High-Elf)
-I:15000:120:105:6:16
+I:15000:110
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
+I:15000:110
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
+I:30000:110
C:120:100:80
#L:Warrior |
H:Dragon | Demon | Orc | Troll | Half-Ogre | Beorning
N:54:Valceronwe(Elf)
-I:30000:140:105:6:12
+I:30000:110
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
+I:30000:110
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
+I:30000:110
C:120:100:80
#L:Ranger
H:Dragon | Demon | Orc | Troll | Half-Ogre | Beorning
@@ -399,71 +395,71 @@ H:Dragon | Demon | Orc | Troll | Half-Ogre | Beorning
### Gondolin owners ###
N:57:Turgon(High-Elf)
-I:30000:120:105:6:16
+I:30000:110
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
+I:0:110
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
+I:0:110
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
+I:0:110
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
+I:0:110
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
+I:0:110
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
+I:0:110
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
+I:0:110
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
+I:0:110
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
+I:0:110
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
+I:0:110
C:120:100:80
L:High-Elf | Half-Elf
#L:Paladin
@@ -473,70 +469,70 @@ H:Dragon | Demon | Orc | Troll | Half-Ogre | Beorning | Easterling
#Bree
N:68:Barliman Butterbur(Human)
-I:100:170:108:4:10
+I:100:120
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
+I:100:120
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
+I:100:120
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
+I:100:120
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
+I:100:120
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
+I:100:120
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
+I:100:120
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
+I:100:120
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
+I:100:120
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
+I:100:120
C:110:100:80
L:Human | High-Elf | RohanKnight | Dunadan | Elf
H:Dragon | Demon | Beorning | Orc | Half-Ogre | Troll | Easterling
@@ -544,25 +540,25 @@ H:Dragon | Demon | Beorning | Orc | Half-Ogre | Troll | Easterling
### The Soothsayers ###
N:78:Ori(Dwarf)
-I:20000:190:109:3:4
+I:20000:130
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
+I:25000:130
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
+I:10000:140
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
+I:30000:120
C:110:100:80
L:High-Elf | Dunadan | Elf
H:Dragon | Demon | Orc | Dark-Elf | Half-Ogre | Petty-Dwarf | Troll
@@ -570,25 +566,25 @@ H:Dragon | Demon | Orc | Dark-Elf | Half-Ogre | Petty-Dwarf | Troll
### The Eagles ###
N:82:Palano(Eagle)
-I:30000:170:110:1:1
+I:30000:130
C:125:100:50
L:Eagle
H:Dragon | Demon | RohanKnight
N:83:Eglad(Eagle)
-I:30000:170:110:1:1
+I:30000:130
C:125:100:50
L:Eagle
H:Dragon | Demon | Hobbit
N:84:Hiron(Eagle)
-I:30000:170:110:1:1
+I:30000:130
C:125:100:50
L:Eagle
H:Dragon | Demon | Dunadan
N:85:Grada(Eagle)
-I:30000:170:110:1:1
+I:30000:130
C:125:100:50
L:Eagle
H:Dragon | Demon | High-Elf
@@ -596,25 +592,25 @@ H:Dragon | Demon | High-Elf
### The Librarians ###
N:86:Frerin(Dwarf)
-I:25000:180:108:2:2
+I:25000:130
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
+I:20000:130
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
+I:30000:120
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
+I:10000:140
C:110:100:80
L:High-Elf | Dunadan | Elf
H:Dragon | Demon | Orc | Half-Ogre | Troll
@@ -622,25 +618,25 @@ H:Dragon | Demon | Orc | Half-Ogre | Troll
### The Casino Owners ###
N:90:Fror(Dwarf)
-I:20000:190:109:3:4
+I:20000:130
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
+I:25000:130
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
+I:10000:140
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
+I:30000:120
C:110:100:80
L:High-Elf | Dunadan | Elf
H:Dragon | Demon | Orc | Dark-Elf | Half-Ogre | Petty-Dwarf | Troll
@@ -648,25 +644,25 @@ H:Dragon | Demon | Orc | Dark-Elf | Half-Ogre | Petty-Dwarf | Troll
### The Beastmasters ###
N:94:Gloin(Dwarf)
-I:30000:170:107:1:1
+I:30000:120
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
+I:20000:130
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
+I:25000:130
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
+I:10000:140
C:150:100:50
L:Dark-Elf | Elf | Easterling
H:Dragon | Demon | Orc | Half-Ogre | Petty-Dwarf | Dwarf | Troll
@@ -676,25 +672,25 @@ H:Dragon | Demon | Orc | Half-Ogre | Petty-Dwarf | Dwarf | Troll
#Fighters Hall
N:98:Tarcil(Human)
-I:30000:170:107:1:1
+I:30000:120
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
+I:10000:140
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
+I:25000:130
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
+I:20000:130
C:125:100:70
L:Human | RohanKnight | Dunadan
H:Dragon | Demon | Beorning | Orc | Half-Ogre | Dwarf | Troll | Easterling
@@ -702,25 +698,25 @@ H:Dragon | Demon | Beorning | Orc | Half-Ogre | Dwarf | Troll | Easterling
#Tower of Magery
N:102:Arveleg(Human)
-I:25000:180:108:2:2
+I:25000:130
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
+I:30000:120
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
+I:20000:130
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
+I:10000:140
C:110:100:80
L:Human | RohanKnight | Dunadan
H:Dragon | Demon | Beorning | Orc | Half-Ogre | Dwarf | Troll | Easterling
@@ -728,25 +724,25 @@ H:Dragon | Demon | Beorning | Orc | Half-Ogre | Dwarf | Troll | Easterling
#Inner Temple
N:106:Eradan(Human)
-I:30000:170:107:1:1
+I:30000:120
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
+I:25000:130
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
+I:20000:130
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
+I:10000:140
C:110:100:80
L:Human | RohanKnight | Dunadan
H:Dragon | Demon | Beorning | Orc | Half-Ogre | Dwarf | Troll
@@ -754,25 +750,25 @@ H:Dragon | Demon | Beorning | Orc | Half-Ogre | Dwarf | Troll
#Paladins Guild
N:110:Herion(Human)
-I:30000:170:107:1:1
+I:30000:120
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
+I:10000:140
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
+I:25000:130
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
+I:20000:130
C:125:100:70
L:Human | RohanKnight | Dunadan
H:Dragon | Demon | Beorning | Orc | Half-Ogre | Dwarf | Troll | Easterling
@@ -780,25 +776,25 @@ H:Dragon | Demon | Beorning | Orc | Half-Ogre | Dwarf | Troll | Easterling
#Rangers Guild
N:114:Egalmoth(Human)
-I:25000:180:108:2:2
+I:25000:130
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
+I:30000:120
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
+I:20000:130
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
+I:10000:140
C:110:100:80
L:Human | RohanKnight | Dunadan
H:Dragon | Demon | Beorning | Orc | Half-Ogre | Dwarf | Troll
@@ -808,25 +804,25 @@ H:Dragon | Demon | Beorning | Orc | Half-Ogre | Dwarf | Troll
### The Axesmiths ###
N:118:Ris(Dwarf)
-I:30000:200:130:1:1
+I:30000:150
C:150:100:50
L:Dwarf
H:Dragon | Demon | Orc
N:119:Malach Aradan(Human)
-I:25000:300:150:2:2
+I:25000:200
C:125:100:60
L:Human | Easterling
H:Dragon | Demon | Troll
N:120:Indis(Half-Elf)
-I:20000:250:140:3:4
+I:20000:170
C:115:100:70
L:Half-Elf | Easterling
H:Dragon | Demon | Half-Ogre
N:121:Rogdug(Half-Orc)
-I:10000:150:120:4:8
+I:10000:130
C:125:100:80
L:Orc | Easterling
H:Dragon | Demon | Elf
@@ -834,25 +830,25 @@ H:Dragon | Demon | Elf
### The Haftedsmiths ###
N:122:Sogur(Dwarf)
-I:20000:250:140:3:4
+I:20000:170
C:125:100:80
L:Dwarf
H:Dragon | Demon | Orc
N:123:Manwendil(Human)
-I:25000:300:150:2:2
+I:25000:200
C:115:100:70
L:Human | Easterling
H:Dragon | Demon | Troll
N:124:Lenwe(Half-Elf)
-I:10000:150:120:4:8
+I:10000:130
C:150:100:50
L:Half-Elf | Easterling
H:Dragon | Demon | Half-Ogre
N:125:Ghaz(Half-Orc)
-I:30000:200:130:1:1
+I:30000:150
C:125:100:60
L:Orc | Easterling
H:Dragon | Demon | Elf
@@ -860,25 +856,25 @@ H:Dragon | Demon | Elf
### The Polearmsmiths ###
N:126:Tolin(Dwarf)
-I:10000:150:120:4:8
+I:10000:130
C:115:100:70
L:Dwarf
H:Dragon | Demon | Orc
N:127:Narmacil(Human)
-I:25000:300:150:2:2
+I:25000:200
C:125:100:80
L:Human | Easterling
H:Dragon | Demon | Troll
N:128:Lindir(Half-Elf)
-I:20000:250:140:3:4
+I:20000:170
C:150:100:50
L:Half-Elf | Easterling
H:Dragon | Demon | Half-Ogre
N:129:Stogash(Half-Orc)
-I:30000:200:130:1:1
+I:30000:150
C:125:100:60
L:Orc | Easterling
H:Dragon | Demon | Elf
@@ -886,25 +882,25 @@ H:Dragon | Demon | Elf
### The Swordsmiths ###
N:130:Tis(Dwarf)
-I:20000:250:140:3:4
+I:20000:170
C:125:100:80
L:Dwarf
H:Dragon | Demon | Orc
N:131:Nuneth(Human)
-I:10000:150:120:4:8
+I:10000:130
C:125:100:60
L:Human | Easterling
H:Dragon | Demon | Troll
N:132:Mahtan(Half-Elf)
-I:30000:200:130:1:1
+I:30000:150
C:115:100:70
L:Half-Elf | Easterling
H:Dragon | Demon | Half-Ogre
N:133:Rudak(Half-Orc)
-I:25000:300:150:2:2
+I:25000:200
C:150:100:50
L:Orc | Easterling
H:Dragon | Demon | Elf
@@ -912,25 +908,25 @@ H:Dragon | Demon | Elf
### The Rare Jewellers ###
N:134:Uin(Dwarf)
-I:25000:300:150:2:2
+I:25000:200
C:115:100:70
L:Dwarf
H:Dragon | Demon | Orc
N:135:Ornendil(Human)
-I:10000:150:120:4:8
+I:10000:130
C:125:100:60
L:Human | Easterling
H:Dragon | Demon | Troll
N:136:Malgalad(Half-Elf)
-I:30000:200:130:1:1
+I:30000:150
C:125:100:80
L:Half-Elf | Easterling
H:Dragon | Demon | Half-Ogre
N:137:Ghashuf(Half-Orc)
-I:20000:250:140:3:4
+I:20000:170
C:150:100:50
L:Orc | Easterling
H:Dragon | Demon | Elf
@@ -938,25 +934,25 @@ H:Dragon | Demon | Elf
### The Jewellers ###
N:138:Vali(Dwarf)
-I:25000:300:150:2:2
+I:25000:200
C:150:100:50
L:Dwarf
H:Dragon | Demon | Orc
N:139:Orodreth(Human)
-I:30000:200:130:1:1
+I:30000:150
C:115:100:70
L:Human | Easterling
H:Dragon | Demon | Troll
N:140:Theodred(Half-Elf)
-I:10000:150:120:4:8
+I:10000:130
C:125:100:80
L:Half-Elf | Easterling
H:Dragon | Demon | Half-Ogre
N:141:Rangush(Half-Orc)
-I:20000:250:140:3:4
+I:20000:170
C:125:100:60
L:Orc | Easterling
H:Dragon | Demon | Elf
@@ -964,25 +960,25 @@ H:Dragon | Demon | Elf
### The Footwear Shop owners ###
N:142:Nellas(Human)
-I:10000:150:120:4:8
+I:10000:130
C:115:100:70
L:Human | Easterling
H:Dragon | Demon | Troll
N:143:Tindomiel(Half-Elf)
-I:25000:300:150:2:2
+I:25000:200
C:125:100:80
L:Half-Elf | Easterling
H:Dragon | Demon | Half-Ogre
N:144:Ragnor(Half-Elf)
-I:20000:250:140:3:4
+I:20000:170
C:150:100:50
L:Half-Elf | Easterling
H:Dragon | Demon | Half-Ogre
N:145:Idrish(Half-Orc)
-I:30000:200:130:1:1
+I:30000:150
C:125:100:60
L:Orc | Easterling
H:Dragon | Demon | Elf
@@ -990,25 +986,25 @@ H:Dragon | Demon | Elf
### The Rare Footwear Shop owners ###
N:146:Nerwen(Human)
-I:20000:250:140:3:4
+I:20000:170
C:125:100:80
L:Human | Easterling
H:Dragon | Demon | Troll
N:147:Ulbar (Half-Elf)
-I:10000:150:120:4:8
+I:10000:130
C:125:100:60
L:Half-Elf | Easterling
H:Dragon | Demon | Half-Ogre
N:148:Pelendur(Half-Elf)
-I:30000:200:130:1:1
+I:30000:150
C:115:100:70
L:Half-Elf | Easterling
H:Dragon | Demon | Half-Ogre
N:149:Budgar(Half-Orc)
-I:25000:300:150:2:2
+I:25000:200
C:150:100:50
L:Orc | Easterling
H:Dragon | Demon | Elf
@@ -1016,25 +1012,25 @@ H:Dragon | Demon | Elf
### The Dungeon Librarians ###
N:150:Nom(Human)
-I:25000:300:150:2:2
+I:25000:200
C:115:100:70
L:Human | Easterling
H:Dragon | Demon | Troll
N:151:Urwen (Half-Elf)
-I:10000:150:120:4:8
+I:10000:130
C:125:100:60
L:Half-Elf | Easterling
H:Dragon | Demon | Half-Ogre
N:152:Rian(Half-Elf)
-I:30000:200:130:1:1
+I:30000:150
C:125:100:80
L:Half-Elf | Easterling
H:Dragon | Demon | Half-Ogre
N:153:Mosrog(Half-Orc)
-I:20000:250:140:3:4
+I:20000:170
C:150:100:50
L:Orc | Easterling
H:Dragon | Demon | Elf
@@ -1042,25 +1038,25 @@ H:Dragon | Demon | Elf
### The Expensive Black Marketeers ###
N:154:Olwe(Human)
-I:30000:300:150:8:8
+I:30000:200
C:125:100:90
L:Human | Easterling
H:Dragon | Demon | Troll
N:155:Valacar(Half-Elf)
-I:30000:300:150:8:8
+I:30000:200
C:125:100:90
L:Half-Elf | Easterling
H:Dragon | Demon | Half-Ogre
N:156:Silmarien(Half-Elf)
-I:30000:300:150:8:8
+I:30000:200
C:125:100:90
L:Half-Elf | Easterling
H:Dragon | Demon | Half-Ogre
N:157:Ghaz(Half-Orc)
-I:30000:300:150:8:8
+I:30000:200
C:125:100:90
L:Orc | Easterling
H:Dragon | Demon | Elf
@@ -1068,25 +1064,25 @@ H:Dragon | Demon | Elf
### The Common Shop Owners ###
N:158:Ioreth(Human)
-I:25000:300:150:2:2
+I:25000:200
C:150:100:50
L:Human | Easterling
H:Dragon | Demon | Troll
N:159:Vidugavia(Half-Elf)
-I:30000:200:130:1:1
+I:30000:150
C:115:100:70
L:Half-Elf | Easterling
H:Dragon | Demon | Half-Ogre
N:160:Soronto(Half-Elf)
-I:10000:150:120:4:8
+I:10000:130
C:125:100:80
L:Half-Elf | Easterling
H:Dragon | Demon | Half-Ogre
N:161:Nazg(Half-Orc)
-I:20000:250:140:3:4
+I:20000:170
C:125:100:60
L:Orc | Easterling
H:Dragon | Demon | Elf
@@ -1094,25 +1090,25 @@ H:Dragon | Demon | Elf
### The Dragon Hunters ###
N:162:Oropher(Human)
-I:10000:150:120:4:8
+I:10000:130
C:115:100:70
L:Human | Easterling
H:Dragon | Demon | Troll
N:163:Walda(Half-Elf)
-I:25000:300:150:2:2
+I:25000:200
C:125:100:80
L:Half-Elf | Easterling
H:Dragon | Demon | Half-Ogre
N:164:Mithrellas(Half-Elf)
-I:20000:250:140:3:4
+I:20000:170
C:150:100:50
L:Half-Elf | Easterling
H:Dragon | Demon | Half-Ogre
N:165:Urbag(Half-Orc)
-I:30000:200:130:1:1
+I:30000:150
C:125:100:60
L:Orc | Easterling
H:Dragon | Demon | Elf
@@ -1120,25 +1116,25 @@ H:Dragon | Demon | Elf
### The Speed Ring Market Owners ###
N:166:Orophin(Human)
-I:20000:250:140:3:4
+I:20000:170
C:125:100:80
L:Human | Easterling
H:Dragon | Demon | Troll
N:167:Wulf(Half-Orc)
-I:10000:150:120:4:8
+I:10000:130
C:125:100:60
L:Orc | Easterling
H:Dragon | Demon | Elf
N:168:Baguk(Half-Troll)
-I:30000:200:130:1:1
+I:30000:150
C:115:100:70
L:Troll | Easterling
H:Dragon | Demon | Human
N:169:Zikram(Half-Orc)
-I:25000:300:150:2:2
+I:25000:200
C:150:100:50
L:Orc | Easterling
H:Dragon | Demon | Elf
@@ -1146,25 +1142,25 @@ H:Dragon | Demon | Elf
### The Scribes ###
N:170:Rumil(Human)
-I:25000:300:150:2:2
+I:25000:200
C:115:100:70
L:Human | Easterling
H:Dragon | Demon | Troll
N:171:Saeros(Half-Elf)
-I:10000:150:120:4:8
+I:10000:130
C:125:100:60
L:Half-Elf | Easterling
H:Dragon | Demon | Half-Ogre
N:172:Zartosh(Half-Orc)
-I:30000:200:130:1:1
+I:30000:150
C:125:100:80
L:Orc | Easterling
H:Dragon | Demon | Elf
N:173:Shog(Half-Troll)
-I:20000:250:140:3:4
+I:20000:170
C:150:100:50
L:Troll | Easterling
H:Dragon | Demon | Human
@@ -1172,25 +1168,25 @@ H:Dragon | Demon | Human
### The Potion Peddlers ###
N:174:Zamin(Human)
-I:25000:300:150:2:2
+I:25000:200
C:150:100:50
L:Human | Easterling
H:Dragon | Demon | Troll
N:175:Algosh(Half-Orc)
-I:30000:200:130:1:1
+I:30000:150
C:115:100:70
L:Orc | Easterling
H:Dragon | Demon | Elf
N:176:Seghash(Half-Troll)
-I:10000:150:120:4:8
+I:10000:130
C:125:100:80
L:Troll | Easterling
H:Dragon | Demon | Human
N:177:Kabbug(Half-Orc)
-I:20000:250:140:3:4
+I:20000:170
C:125:100:60
L:Orc | Easterling
H:Dragon | Demon | Elf
@@ -1198,25 +1194,25 @@ H:Dragon | Demon | Elf
### The Master Archers ###
N:178:Palin(Dwarf)
-I:30000:170:107:1:1
+I:30000:120
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
+I:20000:130
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
+I:25000:130
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
+I:10000:140
C:150:100:50
L:Dark-Elf | Elf | Easterling
H:Dragon | Demon | Orc | Half-Ogre | Petty-Dwarf | Dwarf | Troll
@@ -1226,25 +1222,25 @@ H:Dragon | Demon | Orc | Half-Ogre | Petty-Dwarf | Dwarf | Troll
### The Miners / Builders ###
N:182:Gror(Dwarf)
-I:20000:190:109:3:4
+I:20000:130
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
+I:30000:120
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
+I:10000:140
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
+I:25000:130
C:110:100:80
L:High-Elf | Dunadan | Hobbit | Elf
H:Dragon | Demon | Orc | Dark-Elf | Half-Ogre | Dwarf | Troll | Easterling
@@ -1252,25 +1248,25 @@ H:Dragon | Demon | Orc | Dark-Elf | Half-Ogre | Dwarf | Troll | Easterling
### The Hunters ###
N:186:Kili(Dwarf)
-I:20000:190:109:3:4
+I:20000:130
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
+I:10000:140
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
+I:25000:130
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
+I:30000:120
C:125:100:70
L:Human | Half-Elf | High-Elf | Dunadan | Elf
H:Dragon | Demon | Beorning | Orc | Dark-Elf | Half-Ogre | Dwarf | Troll | Easterling
@@ -1278,25 +1274,25 @@ H:Dragon | Demon | Beorning | Orc | Dark-Elf | Half-Ogre | Dwarf | Troll | East
### The Runecrafters ###
N:190:Nori(Dwarf)
-I:30000:170:107:1:1
+I:30000:120
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
+I:10000:140
C:110:100:80
L:Hobbit | Easterling
H:Dragon | Demon | Orc | Troll
N:192:Hador Lorindol(Dunadan)
-I:25000:180:108:2:2
+I:25000:130
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
+I:20000:130
C:125:100:70
L:Human | Dark-Elf | Elf
H:Dragon | Demon | Beorning | Orc | High-Elf | Half-Ogre | Petty-Dwarf | Troll
@@ -1304,25 +1300,25 @@ H:Dragon | Demon | Beorning | Orc | High-Elf | Half-Ogre | Petty-Dwarf | Troll
### The Musicians ###
N:194:Oin(Dwarf)
-I:20000:190:109:3:4
+I:20000:130
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
+I:10000:140
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
+I:30000:120
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
+I:25000:130
C:110:100:80
L:Half-Elf | High-Elf | Elf
H:Dragon | Demon | Orc | Dark-Elf | Half-Ogre | Petty-Dwarf | Dwarf | Troll | Easterling
@@ -1330,25 +1326,25 @@ H:Dragon | Demon | Orc | Dark-Elf | Half-Ogre | Petty-Dwarf | Dwarf | Troll | E
### The Precious Metalsmiths ###
N:198:Gabil(Dwarf)
-I:10000:150:120:4:8
+I:10000:130
C:115:100:70
L:Dwarf
H:Dragon | Demon | Orc
N:199:Isil(Human)
-I:25000:300:150:2:2
+I:25000:200
C:125:100:80
L:Human | Easterling
H:Dragon | Demon | Troll
N:200:Grima(Half-Orc)
-I:20000:250:140:3:4
+I:20000:170
C:150:100:50
L:Orc | Easterling
H:Dragon | Demon | Elf
N:201:Kosh(Half-Troll)
-I:30000:200:130:1:1
+I:30000:150
C:125:100:60
L:Troll | Easterling
H:Dragon | Demon | Human
@@ -1356,25 +1352,25 @@ H:Dragon | Demon | Human
### The Mapmakers ###
N:202:Pas(Dwarf)
-I:20000:190:109:3:4
+I:20000:130
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
+I:30000:120
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
+I:10000:140
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
+I:25000:130
C:110:100:80
L:High-Elf | Dunadan | Hobbit | Elf
H:Dragon | Demon | Orc | Dark-Elf | Half-Ogre | Dwarf | Troll
@@ -1382,25 +1378,25 @@ H:Dragon | Demon | Orc | Dark-Elf | Half-Ogre | Dwarf | Troll
### The Farmers ###
N:206:Rili(Dwarf)
-I:20000:190:109:3:4
+I:20000:130
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
+I:10000:140
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
+I:25000:130
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
+I:30000:120
C:125:100:70
L:Human | Half-Elf | High-Elf | Dunadan | Elf
H:Dragon | Demon | Beorning | Orc | Dark-Elf | Half-Ogre | Dwarf | Troll
@@ -1408,12 +1404,7 @@ 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
+I:20000:130
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
index 49832c32..89d335ab 100644
--- a/lib/mods/theme/edit/p_info.txt
+++ b/lib/mods/theme/edit/p_info.txt
@@ -8,8 +8,6 @@
# 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
-
##############################################################################
##############################################################################
##############################################################################
@@ -2834,22 +2832,3 @@ 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/r_info.txt b/lib/mods/theme/edit/r_info.txt
index bcc46bd5..18bf6643 100644
--- a/lib/mods/theme/edit/r_info.txt
+++ b/lib/mods/theme/edit/r_info.txt
@@ -183,10 +183,6 @@
# Note that monster zero is used for the "player" picture.
-# Version stamp (required)
-
-V:2.2.0
-
##### The Player #####
N:0:Player
@@ -13696,7 +13692,7 @@ 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
+O:0:0:0:0
B:HIT:HURT:12d10
B:HIT:HURT:12d10
B:CHARGE:HURT:10d10
@@ -13704,7 +13700,7 @@ 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:SMART | OPEN_DOOR | BASH_DOOR |
F:EVIL | IM_FIRE | IM_COLD | IM_POIS |
F:MORTAL | HAS_LITE
S:1_IN_4 |
diff --git a/lib/mods/theme/edit/ra_info.txt b/lib/mods/theme/edit/ra_info.txt
index 705db243..2220a4f0 100644
--- a/lib/mods/theme/edit/ra_info.txt
+++ b/lib/mods/theme/edit/ra_info.txt
@@ -16,10 +16,6 @@
# 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
diff --git a/lib/mods/theme/edit/re_info.txt b/lib/mods/theme/edit/re_info.txt
index c0e36a92..c1fb01c8 100644
--- a/lib/mods/theme/edit/re_info.txt
+++ b/lib/mods/theme/edit/re_info.txt
@@ -6,8 +6,6 @@
# 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
@@ -28,8 +26,6 @@
# 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
diff --git a/lib/mods/theme/edit/s_info.txt b/lib/mods/theme/edit/s_info.txt
index 40c0d41e..46c5cd9b 100644
--- a/lib/mods/theme/edit/s_info.txt
+++ b/lib/mods/theme/edit/s_info.txt
@@ -22,10 +22,6 @@
# T:father:child
-# Version stamp (required)
-
-V:2.0.0
-
################################## MAGIC ##################################
N:56:Magic-Device
diff --git a/lib/mods/theme/edit/set_info.txt b/lib/mods/theme/edit/set_info.txt
index 4b745e4b..d36ce59c 100644
--- a/lib/mods/theme/edit/set_info.txt
+++ b/lib/mods/theme/edit/set_info.txt
@@ -7,15 +7,11 @@
# 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
diff --git a/lib/mods/theme/edit/st_info.txt b/lib/mods/theme/edit/st_info.txt
index 29ca49fc..585dc657 100644
--- a/lib/mods/theme/edit/st_info.txt
+++ b/lib/mods/theme/edit/st_info.txt
@@ -1,13 +1,5 @@
# 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.
@@ -22,10 +14,6 @@
# 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~
@@ -266,7 +254,7 @@ N:7:Home
A:0:0:54:55:3:62
O:0:0:0:0
G:8:y
-W:24
+W:240
N:8:Book Store
# & Book~ of Beginner Cantrips
@@ -793,12 +781,6 @@ 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
diff --git a/lib/mods/theme/edit/t_basic.txt b/lib/mods/theme/edit/t_basic.txt
deleted file mode 100644
index 8153f6fe..00000000
--- a/lib/mods/theme/edit/t_basic.txt
+++ /dev/null
@@ -1,66 +0,0 @@
-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_gondol.txt b/lib/mods/theme/edit/t_gondol.txt
index 6b0a32cd..66807868 100644
--- a/lib/mods/theme/edit/t_gondol.txt
+++ b/lib/mods/theme/edit/t_gondol.txt
@@ -123,9 +123,6 @@ 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
@@ -178,7 +175,7 @@ D:######$$$$$$$$$$$$$$$$$### ...
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:####$$$$#############$$$$# #########.........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------,,,,,,,^^^^^###
diff --git a/lib/mods/theme/edit/t_minas.txt b/lib/mods/theme/edit/t_minas.txt
index b96481d8..cea53634 100644
--- a/lib/mods/theme/edit/t_minas.txt
+++ b/lib/mods/theme/edit/t_minas.txt
@@ -15,7 +15,7 @@ F:w:8:3:0:0:0:0:0:24
# Quest 16 finished, reward is a between gate
?:[EQU $QUEST16 5]
-F:Z:176:3:0:0:0:0:0:0
+F:Z:176:3:0:0:0:0:0:2
?:1
diff --git a/lib/mods/theme/edit/tr_info.txt b/lib/mods/theme/edit/tr_info.txt
index d181487a..7f9e4df9 100644
--- a/lib/mods/theme/edit/tr_info.txt
+++ b/lib/mods/theme/edit/tr_info.txt
@@ -35,8 +35,6 @@
# I:diff:prob: :minlevel: :color
# D:description
-V:2.0.0
-
#
# stat traps
#
diff --git a/lib/mods/theme/edit/v_info.txt b/lib/mods/theme/edit/v_info.txt
index fb4a4d20..964f2b54 100644
--- a/lib/mods/theme/edit/v_info.txt
+++ b/lib/mods/theme/edit/v_info.txt
@@ -16,11 +16,6 @@
# Quest vaults added - rr9
-# Version stamp (required)
-
-V:2.0.0
-
-
### Simple Vaults (type 7) -- maximum size 44x22 ###
diff --git a/lib/mods/theme/edit/w_info.txt b/lib/mods/theme/edit/w_info.txt
index 18cf7a0f..6ca43cfd 100644
--- a/lib/mods/theme/edit/w_info.txt
+++ b/lib/mods/theme/edit/w_info.txt
@@ -14,7 +14,7 @@ W:D:XWWWWAAAAAW%AAAA========WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW
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
+W:D:XT.2MMM=======.BB.=............HHHHHHHH..&&&&&......GGGGGGGGGGGGG.................tEEEEEtEEEEttEEEEEX
?:[EQU $TOWN_DESTROY2 1]
W:M:0:1
W:D:XT.PMMM=======.BB.=............HHHHHHHH..&&&&&......GGGGGGGGGGGGG.................tEEEEEtEEEEttEEEEEX
diff --git a/lib/mods/theme/edit/wf_info.txt b/lib/mods/theme/edit/wf_info.txt
index acdba872..764462b7 100644
--- a/lib/mods/theme/edit/wf_info.txt
+++ b/lib/mods/theme/edit/wf_info.txt
@@ -55,10 +55,6 @@
# 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
@@ -301,12 +297,6 @@ 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
diff --git a/lib/mods/theme/file/elvish.txt b/lib/mods/theme/file/elvish.txt
deleted file mode 100644
index a00b5a22..00000000
--- a/lib/mods/theme/file/elvish.txt
+++ /dev/null
@@ -1,218 +0,0 @@
-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/help/ability.txt b/lib/mods/theme/help/ability.txt
index 175d6745..17d89dbc 100644
--- a/lib/mods/theme/help/ability.txt
+++ b/lib/mods/theme/help/ability.txt
@@ -27,11 +27,15 @@ 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*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*10[Far reaching attack]
+*****ability.txt*11[Trapping]
*****ability.txt*12[Undead Form]
~~~~~02|Abilities|Spread blows
@@ -84,12 +88,6 @@ 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.
diff --git a/lib/mods/theme/help/advanced.hlp b/lib/mods/theme/help/advanced.hlp
index 3f6fe4bd..8595712b 100644
--- a/lib/mods/theme/help/advanced.hlp
+++ b/lib/mods/theme/help/advanced.hlp
@@ -7,9 +7,8 @@ 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
+ *****/ddebug.txt*0[(d) Debug commands]
+ *****/eversion.txt*0[(e) Version information] A history of ToME's roots
*****/zhelp.hlp*0[(z) Main Help menu]
diff --git a/lib/mods/theme/help/automat.txt b/lib/mods/theme/help/automat.txt
index bf6478f8..0ba56d19 100644
--- a/lib/mods/theme/help/automat.txt
+++ b/lib/mods/theme/help/automat.txt
@@ -25,10 +25,9 @@ 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.
+vampire, 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
diff --git a/lib/mods/theme/help/c_alchem.txt b/lib/mods/theme/help/c_alchem.txt
deleted file mode 100644
index 2f7cd58c..00000000
--- a/lib/mods/theme/help/c_alchem.txt
+++ /dev/null
@@ -1,135 +0,0 @@
-|||||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_merch.txt b/lib/mods/theme/help/c_merch.txt
deleted file mode 100644
index 31fb60dd..00000000
--- a/lib/mods/theme/help/c_merch.txt
+++ /dev/null
@@ -1,29 +0,0 @@
-#####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/command.txt b/lib/mods/theme/help/command.txt
index 6616c252..04a63fd8 100644
--- a/lib/mods/theme/help/command.txt
+++ b/lib/mods/theme/help/command.txt
@@ -137,7 +137,7 @@ that you can always, for example, use "\" + "." + "6", to specify "run east".
*****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*79[\ (special - bypass keymap)]
*****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]
@@ -198,13 +198,13 @@ that you can always, for example, use "\" + "." + "6", to specify "run east".
*****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*79[\ (special - bypass keymap)]
*****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.
@@ -498,12 +498,7 @@ for a quantity will convert any "letters" into the maximal legal value.
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
+ You must be using an object to receive any of its special
powers.
~~~~~7
[[[[[GDrop an item (d)]
@@ -518,8 +513,7 @@ for a quantity will convert any "letters" into the maximal legal value.
[[[[[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.
+ a quantity. You must always verify this command.
~~~~~42
[[[[[GWear/Wield equipment (w)]
To wear or wield an object in your inventory, use this command.
@@ -789,9 +783,9 @@ for a quantity will convert any "letters" into the maximal legal value.
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.
+ takes effect. 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
@@ -997,10 +991,8 @@ for a quantity will convert any "letters" into the maximal legal value.
~~~~~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.
+ note file. 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
@@ -1054,9 +1046,8 @@ for a quantity will convert any "letters" into the maximal legal value.
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 (:).
+ 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)]
@@ -1218,17 +1209,6 @@ for a quantity will convert any "letters" into the maximal legal value.
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
diff --git a/lib/mods/theme/help/debug.txt b/lib/mods/theme/help/debug.txt
index 56d57098..1fa0efd5 100644
--- a/lib/mods/theme/help/debug.txt
+++ b/lib/mods/theme/help/debug.txt
@@ -29,7 +29,7 @@ will not be scored if you use debug commands.
*****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]
+ r (unused) *****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]
@@ -138,8 +138,7 @@ maximal legal value.
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.
+ Summons a Pack of Creatures of the same kind.
~~~~~17
[[[[[GIdentify (i)]
Like a Scroll of Identify.
diff --git a/lib/mods/theme/help/def.aux b/lib/mods/theme/help/def.aux
deleted file mode 100644
index 983e9683..00000000
--- a/lib/mods/theme/help/def.aux
+++ /dev/null
@@ -1,3 +0,0 @@
-file_ext="html"
-link_prefix=""
-link_suffix=""
diff --git a/lib/mods/theme/help/defines.txt b/lib/mods/theme/help/defines.txt
index ac997501..147e61a1 100644
--- a/lib/mods/theme/help/defines.txt
+++ b/lib/mods/theme/help/defines.txt
@@ -12,7 +12,6 @@ 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 ('~') */
@@ -66,7 +65,6 @@ TV_BOOK 111 /* spell books */
~~~~~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 */
@@ -604,27 +602,6 @@ TV_BOOK 111 /* spell books */
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
diff --git a/lib/mods/theme/help/dungeon.txt b/lib/mods/theme/help/dungeon.txt
index 21c9651e..20426e2a 100644
--- a/lib/mods/theme/help/dungeon.txt
+++ b/lib/mods/theme/help/dungeon.txt
@@ -98,7 +98,7 @@ something you are more comfortable with.
~ Lites, Tools, Chests, etc ) A shield
~ Junk, Sticks, Skeletons, etc ` Trapping kit, climbing set
~ Stone, random artifact o Egg
- * An essence & (unused)
+ & (unused)
~~~~~05|Monsters
#####G Monsters
diff --git a/lib/mods/theme/help/essences.txt b/lib/mods/theme/help/essences.txt
deleted file mode 100644
index f329fa80..00000000
--- a/lib/mods/theme/help/essences.txt
+++ /dev/null
@@ -1,219 +0,0 @@
-|||||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/lua.hlp b/lib/mods/theme/help/lua.hlp
deleted file mode 100644
index ba61676a..00000000
--- a/lib/mods/theme/help/lua.hlp
+++ /dev/null
@@ -1,34 +0,0 @@
-|||||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
deleted file mode 100644
index 000f4af5..00000000
--- a/lib/mods/theme/help/lua_gf.txt
+++ /dev/null
@@ -1,45 +0,0 @@
-|||||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
deleted file mode 100644
index ccb87067..00000000
--- a/lib/mods/theme/help/lua_intr.txt
+++ /dev/null
@@ -1,133 +0,0 @@
-|||||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
deleted file mode 100644
index 9bb363c0..00000000
--- a/lib/mods/theme/help/lua_mon.txt
+++ /dev/null
@@ -1,535 +0,0 @@
-|||||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
deleted file mode 100644
index 6ab64ddb..00000000
--- a/lib/mods/theme/help/lua_play.txt
+++ /dev/null
@@ -1,1225 +0,0 @@
-|||||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
deleted file mode 100644
index c221a664..00000000
--- a/lib/mods/theme/help/lua_pow.txt
+++ /dev/null
@@ -1,266 +0,0 @@
-|||||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
deleted file mode 100644
index 1d4b9c65..00000000
--- a/lib/mods/theme/help/lua_ques.txt
+++ /dev/null
@@ -1,299 +0,0 @@
-|||||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
deleted file mode 100644
index 87385e5d..00000000
--- a/lib/mods/theme/help/lua_skil.txt
+++ /dev/null
@@ -1,342 +0,0 @@
-|||||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
deleted file mode 100644
index aa4a532b..00000000
--- a/lib/mods/theme/help/lua_spel.txt
+++ /dev/null
@@ -1,2150 +0,0 @@
-|||||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
deleted file mode 100644
index 8886a2b4..00000000
--- a/lib/mods/theme/help/lua_util.txt
+++ /dev/null
@@ -1,898 +0,0 @@
-|||||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/macrofaq.txt b/lib/mods/theme/help/macrofaq.txt
index 97fad944..035f674b 100644
--- a/lib/mods/theme/help/macrofaq.txt
+++ b/lib/mods/theme/help/macrofaq.txt
@@ -975,10 +975,6 @@ 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----------------------------------------------------------------------
@@ -1070,15 +1066,7 @@ create a macro for a function key.
#####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".
+(Content removed because it was obsolete. Inscribe-on-pickup is now the default.)
#####G----------------------------------------------------------------------
#####G5.3 Can I use macros inside other macros?
@@ -1788,9 +1776,7 @@ options screen.
rogue_like_commands
use_old_target
always_pickup
-depth_in_feet
alert_hitpoint
-auto_haggle
auto_scum
#####G----------------------------------------------------------------------
diff --git a/lib/mods/theme/help/magic.txt b/lib/mods/theme/help/magic.txt
index 93486f0b..14fa6570 100644
--- a/lib/mods/theme/help/magic.txt
+++ b/lib/mods/theme/help/magic.txt
@@ -24,7 +24,7 @@ schools:
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]
+ *****m_thaum.txt*0[Thaumaturgy] *****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
@@ -32,8 +32,7 @@ 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].
+harness the powers of the elements using *****m_geoman.txt*0[Geomancy].
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,
diff --git a/lib/mods/theme/help/option.txt b/lib/mods/theme/help/option.txt
index 34a2fe6b..00ee15a4 100644
--- a/lib/mods/theme/help/option.txt
+++ b/lib/mods/theme/help/option.txt
@@ -56,20 +56,6 @@ can also be viewed from the option menu while playing, but not changed then.
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.
@@ -80,6 +66,10 @@ can also be viewed from the option menu while playing, but not changed then.
#####GYou can receive fates, good or bad [fate_option]
Allows the player to turn off ToME's *****fatespoi.txt*0[fates] for that character.
+#####GItems always sell for 0 gold [no_selling]
+ Disables selling items back to shops for money. The value of gold found in the
+ dungeon is increased to compensate.
+
~~~~~07|Options|Ingame
#####RIN GAME OPTIONS
#####R===============
@@ -98,9 +88,6 @@ off at will during the course of the game.
(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.
@@ -126,54 +113,6 @@ off at will during the course of the game.
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.
@@ -205,7 +144,7 @@ off at will during the course of the game.
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.
+ a monster is viewable.
#####GDisturb whenever map panel changes [disturb_panel]
This option causes you to be disturbed (stop running) when the screen
@@ -245,18 +184,6 @@ off at will during the course of the game.
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
@@ -308,18 +235,6 @@ off at will during the course of the game.
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
@@ -374,38 +289,10 @@ off at will during the course of the game.
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
@@ -432,9 +319,6 @@ off at will during the course of the game.
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
@@ -551,11 +435,6 @@ Features which are unique to ToME are collected in this menu.
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.
diff --git a/lib/mods/theme/help/skills.txt b/lib/mods/theme/help/skills.txt
index c4a02c06..fe68da6e 100644
--- a/lib/mods/theme/help/skills.txt
+++ b/lib/mods/theme/help/skills.txt
@@ -108,7 +108,7 @@ on what each skill does, try [[[[[ghttp://www.killerbunnies.org/angband/skill-22
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*27[Air] *****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]
@@ -311,7 +311,7 @@ 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.
+Necromancy, Runecraft, and Thaumaturgy.
~~~~~54|Skills|Magic-device
[[[[[BMagic-device]
This skill is a sub-skill of the Magic skill. It eases the use of magical
@@ -465,13 +465,6 @@ 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
diff --git a/lib/mods/theme/help/spoiler.hlp b/lib/mods/theme/help/spoiler.hlp
index bc229852..996c0d32 100644
--- a/lib/mods/theme/help/spoiler.hlp
+++ b/lib/mods/theme/help/spoiler.hlp
@@ -7,7 +7,6 @@ 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]
diff --git a/lib/mods/theme/help/tome_faq.txt b/lib/mods/theme/help/tome_faq.txt
index 756ce639..55f6375b 100644
--- a/lib/mods/theme/help/tome_faq.txt
+++ b/lib/mods/theme/help/tome_faq.txt
@@ -81,8 +81,7 @@ 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.
+drinking pints of fine ale/wine will give you emtpy bottles.
#####G------------------------------------------------------------------------------
#####GQ: I got killed by a Great Wyrm of Power at 50'!!! What happened?
@@ -102,13 +101,10 @@ 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?
+#####GQ: I keep coming across "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.
diff --git a/lib/mods/theme/module.lua b/lib/mods/theme/module.lua
deleted file mode 100644
index cc0b6f08..00000000
--- a/lib/mods/theme/module.lua
+++ /dev/null
@@ -1,48 +0,0 @@
-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/pref/font-ami.prf b/lib/mods/theme/pref/font-ami.prf
deleted file mode 100644
index 1c06dbb3..00000000
--- a/lib/mods/theme/pref/font-ami.prf
+++ /dev/null
@@ -1,28 +0,0 @@
-# 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
deleted file mode 100644
index 9cf1866f..00000000
--- a/lib/mods/theme/pref/font-dos.prf
+++ /dev/null
@@ -1,8 +0,0 @@
-# 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-mac.new b/lib/mods/theme/pref/font-mac.new
deleted file mode 100644
index 8b7f937c..00000000
--- a/lib/mods/theme/pref/font-mac.new
+++ /dev/null
@@ -1,110 +0,0 @@
-# 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-xxx.prf b/lib/mods/theme/pref/font-xxx.prf
index 298a8643..3e5d24ee 100644
--- a/lib/mods/theme/pref/font-xxx.prf
+++ b/lib/mods/theme/pref/font-xxx.prf
@@ -429,9 +429,6 @@ E:114:0x0D
# DAEMON BOOK
E:115:0x03
-# POWER BATERIES
-E:4:0x0D
-
# MAGE STAFFS
E:6:0x0E
diff --git a/lib/mods/theme/pref/font.prf b/lib/mods/theme/pref/font.prf
index 505964bd..38614683 100644
--- a/lib/mods/theme/pref/font.prf
+++ b/lib/mods/theme/pref/font.prf
@@ -28,33 +28,13 @@
?:[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
deleted file mode 100644
index d9b1b356..00000000
--- a/lib/mods/theme/pref/graf-ami.prf
+++ /dev/null
@@ -1,64 +0,0 @@
-# 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
deleted file mode 100644
index 41f38c76..00000000
--- a/lib/mods/theme/pref/graf-dos.prf
+++ /dev/null
@@ -1,15 +0,0 @@
-# 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
deleted file mode 100644
index eee54a13..00000000
--- a/lib/mods/theme/pref/graf-ibm.prf
+++ /dev/null
@@ -1,6237 +0,0 @@
-# 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
deleted file mode 100644
index eaf26901..00000000
--- a/lib/mods/theme/pref/graf-iso.prf
+++ /dev/null
@@ -1,5963 +0,0 @@
-# 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
deleted file mode 100644
index 7bb84141..00000000
--- a/lib/mods/theme/pref/graf-mac.prf
+++ /dev/null
@@ -1,15 +0,0 @@
-# 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
deleted file mode 100644
index 2fb1b215..00000000
--- a/lib/mods/theme/pref/graf-new.prf
+++ /dev/null
@@ -1,6934 +0,0 @@
-# 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
deleted file mode 100644
index 818f876a..00000000
--- a/lib/mods/theme/pref/graf-sdl.prf
+++ /dev/null
@@ -1,37 +0,0 @@
-# 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
deleted file mode 100644
index f59edb35..00000000
--- a/lib/mods/theme/pref/graf-win.prf
+++ /dev/null
@@ -1,16 +0,0 @@
-# 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
deleted file mode 100644
index 818f876a..00000000
--- a/lib/mods/theme/pref/graf-x11.prf
+++ /dev/null
@@ -1,37 +0,0 @@
-# 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
deleted file mode 100644
index 8be9d6da..00000000
--- a/lib/mods/theme/pref/graf-xxx.prf
+++ /dev/null
@@ -1,3267 +0,0 @@
-# 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
deleted file mode 100644
index a82ce364..00000000
--- a/lib/mods/theme/pref/graf.prf
+++ /dev/null
@@ -1,51 +0,0 @@
-# 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
deleted file mode 100644
index ae95fe26..00000000
--- a/lib/mods/theme/pref/pref-acn.prf
+++ /dev/null
@@ -1,24 +0,0 @@
-# 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
deleted file mode 100644
index 08a1c310..00000000
--- a/lib/mods/theme/pref/pref-ami.prf
+++ /dev/null
@@ -1,7 +0,0 @@
-# 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
deleted file mode 100644
index 555c0dbc..00000000
--- a/lib/mods/theme/pref/pref-emx.prf
+++ /dev/null
@@ -1,19 +0,0 @@
-# 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.prf b/lib/mods/theme/pref/pref.prf
index a6bfdbe1..310e5b8a 100644
--- a/lib/mods/theme/pref/pref.prf
+++ b/lib/mods/theme/pref/pref.prf
@@ -285,27 +285,13 @@ L:j:jam:Jam a door
?:[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]]
+?:[EQU $SYS win]
%: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/user.prf b/lib/mods/theme/pref/user.prf
index 9e10b2ac..04715ebc 100644
--- a/lib/mods/theme/pref/user.prf
+++ b/lib/mods/theme/pref/user.prf
@@ -24,27 +24,10 @@
?:[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-new.prf b/lib/mods/theme/pref/xtra-new.prf
deleted file mode 100644
index 214796cf..00000000
--- a/lib/mods/theme/pref/xtra-new.prf
+++ /dev/null
@@ -1,63 +0,0 @@
-# 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/scpt/bounty.lua b/lib/mods/theme/scpt/bounty.lua
deleted file mode 100644
index 94c15598..00000000
--- a/lib/mods/theme/scpt/bounty.lua
+++ /dev/null
@@ -1,90 +0,0 @@
--- 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
deleted file mode 100644
index f402add3..00000000
--- a/lib/mods/theme/scpt/corrupt.lua
+++ /dev/null
@@ -1,1089 +0,0 @@
--- 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
deleted file mode 100644
index 7d90af8d..00000000
--- a/lib/mods/theme/scpt/drunk.lua
+++ /dev/null
@@ -1,21 +0,0 @@
--- 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
deleted file mode 100644
index 8691b821..00000000
--- a/lib/mods/theme/scpt/fireprof.lua
+++ /dev/null
@@ -1,415 +0,0 @@
--- 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
deleted file mode 100644
index 7567178c..00000000
--- a/lib/mods/theme/scpt/god.lua
+++ /dev/null
@@ -1,812 +0,0 @@
--- 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
deleted file mode 100644
index 014a4423..00000000
--- a/lib/mods/theme/scpt/gods.lua
+++ /dev/null
@@ -1,26 +0,0 @@
-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
deleted file mode 100644
index 8153d453..00000000
--- a/lib/mods/theme/scpt/gods_new.lua
+++ /dev/null
@@ -1,454 +0,0 @@
--- 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
deleted file mode 100644
index c85d8f53..00000000
--- a/lib/mods/theme/scpt/gondolin.lua
+++ /dev/null
@@ -1,63 +0,0 @@
--- 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
deleted file mode 100644
index 4e244df6..00000000
--- a/lib/mods/theme/scpt/help.lua
+++ /dev/null
@@ -1,445 +0,0 @@
--- 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
deleted file mode 100644
index 958d8f7d..00000000
--- a/lib/mods/theme/scpt/init.lua
+++ /dev/null
@@ -1,56 +0,0 @@
---
--- 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
deleted file mode 100644
index 3cdce225..00000000
--- a/lib/mods/theme/scpt/intro.lua
+++ /dev/null
@@ -1,43 +0,0 @@
-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
deleted file mode 100644
index 2d87b651..00000000
--- a/lib/mods/theme/scpt/joke.lua
+++ /dev/null
@@ -1,31 +0,0 @@
--- 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
deleted file mode 100644
index a16d37ef..00000000
--- a/lib/mods/theme/scpt/library.lua
+++ /dev/null
@@ -1,439 +0,0 @@
--- 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
deleted file mode 100644
index f38f70f7..00000000
--- a/lib/mods/theme/scpt/mimic.lua
+++ /dev/null
@@ -1,419 +0,0 @@
--- 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
deleted file mode 100644
index acb45f3c..00000000
--- a/lib/mods/theme/scpt/misc.lua
+++ /dev/null
@@ -1,213 +0,0 @@
--- 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
deleted file mode 100644
index 07105c64..00000000
--- a/lib/mods/theme/scpt/mkeys.lua
+++ /dev/null
@@ -1,95 +0,0 @@
--- 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
deleted file mode 100644
index ad3a5628..00000000
--- a/lib/mods/theme/scpt/monsters.lua
+++ /dev/null
@@ -1,182 +0,0 @@
--- 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
deleted file mode 100644
index fd11ed9d..00000000
--- a/lib/mods/theme/scpt/player.lua
+++ /dev/null
@@ -1,196 +0,0 @@
-------------------------------------------------------------------------------
------------------------ 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
deleted file mode 100644
index ff4c62c5..00000000
--- a/lib/mods/theme/scpt/powers.lua
+++ /dev/null
@@ -1,61 +0,0 @@
--- 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
deleted file mode 100644
index afd1f584..00000000
--- a/lib/mods/theme/scpt/s_air.lua
+++ /dev/null
@@ -1,193 +0,0 @@
--- 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
deleted file mode 100644
index d3ca4733..00000000
--- a/lib/mods/theme/scpt/s_aule.lua
+++ /dev/null
@@ -1,222 +0,0 @@
--- 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
deleted file mode 100644
index 1105a850..00000000
--- a/lib/mods/theme/scpt/s_convey.lua
+++ /dev/null
@@ -1,226 +0,0 @@
--- 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
deleted file mode 100644
index ada97310..00000000
--- a/lib/mods/theme/scpt/s_demon.lua
+++ /dev/null
@@ -1,337 +0,0 @@
--- 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
deleted file mode 100644
index 60b0275f..00000000
--- a/lib/mods/theme/scpt/s_divin.lua
+++ /dev/null
@@ -1,230 +0,0 @@
--- 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
deleted file mode 100644
index 23aa001c..00000000
--- a/lib/mods/theme/scpt/s_earth.lua
+++ /dev/null
@@ -1,184 +0,0 @@
--- 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
deleted file mode 100644
index c0cb0aaf..00000000
--- a/lib/mods/theme/scpt/s_eru.lua
+++ /dev/null
@@ -1,130 +0,0 @@
--- 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
deleted file mode 100644
index dbbf7604..00000000
--- a/lib/mods/theme/scpt/s_fire.lua
+++ /dev/null
@@ -1,227 +0,0 @@
--- 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
deleted file mode 100644
index b9730318..00000000
--- a/lib/mods/theme/scpt/s_geom.lua
+++ /dev/null
@@ -1,656 +0,0 @@
--- 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
deleted file mode 100644
index 736b06b0..00000000
--- a/lib/mods/theme/scpt/s_mana.lua
+++ /dev/null
@@ -1,132 +0,0 @@
--- 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
deleted file mode 100644
index cc7e346a..00000000
--- a/lib/mods/theme/scpt/s_mandos.lua
+++ /dev/null
@@ -1,186 +0,0 @@
--- 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
deleted file mode 100644
index 6f0f9661..00000000
--- a/lib/mods/theme/scpt/s_manwe.lua
+++ /dev/null
@@ -1,144 +0,0 @@
--- 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
deleted file mode 100644
index b2c693dd..00000000
--- a/lib/mods/theme/scpt/s_melkor.lua
+++ /dev/null
@@ -1,154 +0,0 @@
--- 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
deleted file mode 100644
index eab691d8..00000000
--- a/lib/mods/theme/scpt/s_meta.lua
+++ /dev/null
@@ -1,287 +0,0 @@
--- 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
deleted file mode 100644
index d1b25e9e..00000000
--- a/lib/mods/theme/scpt/s_mind.lua
+++ /dev/null
@@ -1,132 +0,0 @@
--- 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
deleted file mode 100644
index 9da6393a..00000000
--- a/lib/mods/theme/scpt/s_music.lua
+++ /dev/null
@@ -1,443 +0,0 @@
--- 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
deleted file mode 100644
index 3d44c569..00000000
--- a/lib/mods/theme/scpt/s_nature.lua
+++ /dev/null
@@ -1,184 +0,0 @@
--- 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
deleted file mode 100644
index 9bbd641a..00000000
--- a/lib/mods/theme/scpt/s_stick.lua
+++ /dev/null
@@ -1,494 +0,0 @@
--- 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
deleted file mode 100644
index d3d2fbb5..00000000
--- a/lib/mods/theme/scpt/s_tempo.lua
+++ /dev/null
@@ -1,162 +0,0 @@
--- 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
deleted file mode 100644
index 4afa8082..00000000
--- a/lib/mods/theme/scpt/s_tulkas.lua
+++ /dev/null
@@ -1,81 +0,0 @@
--- 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
deleted file mode 100644
index c4266239..00000000
--- a/lib/mods/theme/scpt/s_udun.lua
+++ /dev/null
@@ -1,180 +0,0 @@
--- 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
deleted file mode 100644
index a2c24b29..00000000
--- a/lib/mods/theme/scpt/s_ulmo.lua
+++ /dev/null
@@ -1,147 +0,0 @@
--- 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
deleted file mode 100644
index f4f46a83..00000000
--- a/lib/mods/theme/scpt/s_varda.lua
+++ /dev/null
@@ -1,140 +0,0 @@
--- 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
deleted file mode 100644
index 739b066b..00000000
--- a/lib/mods/theme/scpt/s_water.lua
+++ /dev/null
@@ -1,154 +0,0 @@
--- 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
deleted file mode 100644
index 2f594e85..00000000
--- a/lib/mods/theme/scpt/s_yavann.lua
+++ /dev/null
@@ -1,157 +0,0 @@
--- 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
deleted file mode 100644
index 838240a3..00000000
--- a/lib/mods/theme/scpt/spells.lua
+++ /dev/null
@@ -1,627 +0,0 @@
---
--- 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
deleted file mode 100644
index 4902c4d0..00000000
--- a/lib/mods/theme/scpt/stores.lua
+++ /dev/null
@@ -1,161 +0,0 @@
--- 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/user/all.prf b/lib/mods/theme/user/all.prf
index 4e9dead3..67671aa4 100644
--- a/lib/mods/theme/user/all.prf
+++ b/lib/mods/theme/user/all.prf
@@ -8,9 +8,6 @@ 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
@@ -26,36 +23,6 @@ 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
@@ -104,12 +71,6 @@ 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
@@ -134,12 +95,6 @@ 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
@@ -164,21 +119,9 @@ 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
@@ -188,9 +131,6 @@ 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
@@ -242,9 +182,6 @@ 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
diff --git a/lib/module.lua b/lib/module.lua
deleted file mode 100644
index e3214205..00000000
--- a/lib/module.lua
+++ /dev/null
@@ -1,36 +0,0 @@
-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/patch/.cvsignore b/lib/patch/.cvsignore
deleted file mode 100644
index d287cd3e..00000000
--- a/lib/patch/.cvsignore
+++ /dev/null
@@ -1 +0,0 @@
-debug
diff --git a/lib/pref/422color.prf b/lib/pref/422color.prf
deleted file mode 100644
index 309c36b0..00000000
--- a/lib/pref/422color.prf
+++ /dev/null
@@ -1,909 +0,0 @@
-# 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/font-ami.prf b/lib/pref/font-ami.prf
deleted file mode 100644
index 1c06dbb3..00000000
--- a/lib/pref/font-ami.prf
+++ /dev/null
@@ -1,28 +0,0 @@
-# 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
deleted file mode 100644
index 9cf1866f..00000000
--- a/lib/pref/font-dos.prf
+++ /dev/null
@@ -1,8 +0,0 @@
-# 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
deleted file mode 100644
index 0d6dd8e1..00000000
--- a/lib/pref/font-mac.new
+++ /dev/null
@@ -1,108 +0,0 @@
-# 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-xxx.prf b/lib/pref/font-xxx.prf
index 298a8643..3e5d24ee 100644
--- a/lib/pref/font-xxx.prf
+++ b/lib/pref/font-xxx.prf
@@ -429,9 +429,6 @@ E:114:0x0D
# DAEMON BOOK
E:115:0x03
-# POWER BATERIES
-E:4:0x0D
-
# MAGE STAFFS
E:6:0x0E
diff --git a/lib/pref/font.prf b/lib/pref/font.prf
index 505964bd..38614683 100644
--- a/lib/pref/font.prf
+++ b/lib/pref/font.prf
@@ -28,33 +28,13 @@
?:[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
deleted file mode 100644
index d9b1b356..00000000
--- a/lib/pref/graf-ami.prf
+++ /dev/null
@@ -1,64 +0,0 @@
-# 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
deleted file mode 100644
index 41f38c76..00000000
--- a/lib/pref/graf-dos.prf
+++ /dev/null
@@ -1,15 +0,0 @@
-# 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
deleted file mode 100644
index 05bc8621..00000000
--- a/lib/pref/graf-iso.prf
+++ /dev/null
@@ -1,6878 +0,0 @@
-%: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
deleted file mode 100644
index 7bb84141..00000000
--- a/lib/pref/graf-mac.prf
+++ /dev/null
@@ -1,15 +0,0 @@
-# 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
deleted file mode 100644
index ca806ca7..00000000
--- a/lib/pref/graf-new.prf
+++ /dev/null
@@ -1,6847 +0,0 @@
-# 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
deleted file mode 100644
index 818f876a..00000000
--- a/lib/pref/graf-sdl.prf
+++ /dev/null
@@ -1,37 +0,0 @@
-# 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
deleted file mode 100644
index f59edb35..00000000
--- a/lib/pref/graf-win.prf
+++ /dev/null
@@ -1,16 +0,0 @@
-# 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
deleted file mode 100644
index 818f876a..00000000
--- a/lib/pref/graf-x11.prf
+++ /dev/null
@@ -1,37 +0,0 @@
-# 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
deleted file mode 100644
index bea696d9..00000000
--- a/lib/pref/graf-xxx.prf
+++ /dev/null
@@ -1,6348 +0,0 @@
-# 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
deleted file mode 100644
index a82ce364..00000000
--- a/lib/pref/graf.prf
+++ /dev/null
@@ -1,51 +0,0 @@
-# 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
deleted file mode 100644
index ae95fe26..00000000
--- a/lib/pref/pref-acn.prf
+++ /dev/null
@@ -1,24 +0,0 @@
-# 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
deleted file mode 100644
index 08a1c310..00000000
--- a/lib/pref/pref-ami.prf
+++ /dev/null
@@ -1,7 +0,0 @@
-# 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
deleted file mode 100644
index 555c0dbc..00000000
--- a/lib/pref/pref-emx.prf
+++ /dev/null
@@ -1,19 +0,0 @@
-# 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-iso.prf b/lib/pref/pref-iso.prf
deleted file mode 100644
index a6bad2e3..00000000
--- a/lib/pref/pref-iso.prf
+++ /dev/null
@@ -1,118 +0,0 @@
-# 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.prf b/lib/pref/pref.prf
index a6bfdbe1..310e5b8a 100644
--- a/lib/pref/pref.prf
+++ b/lib/pref/pref.prf
@@ -285,27 +285,13 @@ L:j:jam:Jam a door
?:[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]]
+?:[EQU $SYS win]
%: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
deleted file mode 100644
index a2b77aec..00000000
--- a/lib/pref/trap-iso.prf
+++ /dev/null
@@ -1,429 +0,0 @@
-# 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/user.prf b/lib/pref/user.prf
index 9e10b2ac..04715ebc 100644
--- a/lib/pref/user.prf
+++ b/lib/pref/user.prf
@@ -24,27 +24,10 @@
?:[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-new.prf b/lib/pref/xtra-new.prf
deleted file mode 100644
index de82b976..00000000
--- a/lib/pref/xtra-new.prf
+++ /dev/null
@@ -1,1128 +0,0 @@
-# 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/scpt/.cvsignore b/lib/scpt/.cvsignore
deleted file mode 100644
index 908e5b42..00000000
--- a/lib/scpt/.cvsignore
+++ /dev/null
@@ -1 +0,0 @@
-debug.lua
diff --git a/lib/scpt/bounty.lua b/lib/scpt/bounty.lua
deleted file mode 100644
index 94c15598..00000000
--- a/lib/scpt/bounty.lua
+++ /dev/null
@@ -1,90 +0,0 @@
--- 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
deleted file mode 100644
index 550f8bc0..00000000
--- a/lib/scpt/corrupt.lua
+++ /dev/null
@@ -1,433 +0,0 @@
--- 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
deleted file mode 100644
index 7d90af8d..00000000
--- a/lib/scpt/drunk.lua
+++ /dev/null
@@ -1,21 +0,0 @@
--- 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
deleted file mode 100644
index 0a3aad28..00000000
--- a/lib/scpt/fireprof.lua
+++ /dev/null
@@ -1,415 +0,0 @@
--- 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
deleted file mode 100644
index 3f32888b..00000000
--- a/lib/scpt/god.lua
+++ /dev/null
@@ -1,640 +0,0 @@
--- 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
deleted file mode 100644
index 014a4423..00000000
--- a/lib/scpt/gods.lua
+++ /dev/null
@@ -1,26 +0,0 @@
-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
deleted file mode 100644
index 5350fec8..00000000
--- a/lib/scpt/help.lua
+++ /dev/null
@@ -1,411 +0,0 @@
--- 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
deleted file mode 100644
index a6f3f8ab..00000000
--- a/lib/scpt/init.lua
+++ /dev/null
@@ -1,46 +0,0 @@
---
--- 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
deleted file mode 100644
index ef6041a5..00000000
--- a/lib/scpt/intro.lua
+++ /dev/null
@@ -1,39 +0,0 @@
-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
deleted file mode 100644
index 2d87b651..00000000
--- a/lib/scpt/joke.lua
+++ /dev/null
@@ -1,31 +0,0 @@
--- 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
deleted file mode 100644
index 1433e47f..00000000
--- a/lib/scpt/library.lua
+++ /dev/null
@@ -1,436 +0,0 @@
--- 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
deleted file mode 100644
index 6529f35c..00000000
--- a/lib/scpt/mimic.lua
+++ /dev/null
@@ -1,419 +0,0 @@
--- 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
deleted file mode 100644
index 07105c64..00000000
--- a/lib/scpt/mkeys.lua
+++ /dev/null
@@ -1,95 +0,0 @@
--- 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
deleted file mode 100644
index 2a617608..00000000
--- a/lib/scpt/player.lua
+++ /dev/null
@@ -1,76 +0,0 @@
-------------------------------------------------------------------------------
------------------------ 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
deleted file mode 100644
index ff4c62c5..00000000
--- a/lib/scpt/powers.lua
+++ /dev/null
@@ -1,61 +0,0 @@
--- 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
deleted file mode 100644
index afd1f584..00000000
--- a/lib/scpt/s_air.lua
+++ /dev/null
@@ -1,193 +0,0 @@
--- 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
deleted file mode 100644
index e7856c43..00000000
--- a/lib/scpt/s_convey.lua
+++ /dev/null
@@ -1,227 +0,0 @@
--- 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
deleted file mode 100644
index ada97310..00000000
--- a/lib/scpt/s_demon.lua
+++ /dev/null
@@ -1,337 +0,0 @@
--- 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
deleted file mode 100644
index 60b0275f..00000000
--- a/lib/scpt/s_divin.lua
+++ /dev/null
@@ -1,230 +0,0 @@
--- 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
deleted file mode 100644
index 23aa001c..00000000
--- a/lib/scpt/s_earth.lua
+++ /dev/null
@@ -1,184 +0,0 @@
--- 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
deleted file mode 100644
index c0cb0aaf..00000000
--- a/lib/scpt/s_eru.lua
+++ /dev/null
@@ -1,130 +0,0 @@
--- 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
deleted file mode 100644
index dbbf7604..00000000
--- a/lib/scpt/s_fire.lua
+++ /dev/null
@@ -1,227 +0,0 @@
--- 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
deleted file mode 100644
index b9730318..00000000
--- a/lib/scpt/s_geom.lua
+++ /dev/null
@@ -1,656 +0,0 @@
--- 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
deleted file mode 100644
index 736b06b0..00000000
--- a/lib/scpt/s_mana.lua
+++ /dev/null
@@ -1,132 +0,0 @@
--- 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
deleted file mode 100644
index 6f0f9661..00000000
--- a/lib/scpt/s_manwe.lua
+++ /dev/null
@@ -1,144 +0,0 @@
--- 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
deleted file mode 100644
index b2c693dd..00000000
--- a/lib/scpt/s_melkor.lua
+++ /dev/null
@@ -1,154 +0,0 @@
--- 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
deleted file mode 100644
index eab691d8..00000000
--- a/lib/scpt/s_meta.lua
+++ /dev/null
@@ -1,287 +0,0 @@
--- 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
deleted file mode 100644
index d1b25e9e..00000000
--- a/lib/scpt/s_mind.lua
+++ /dev/null
@@ -1,132 +0,0 @@
--- 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
deleted file mode 100644
index 9da6393a..00000000
--- a/lib/scpt/s_music.lua
+++ /dev/null
@@ -1,443 +0,0 @@
--- 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
deleted file mode 100644
index e71a89bf..00000000
--- a/lib/scpt/s_nature.lua
+++ /dev/null
@@ -1,152 +0,0 @@
--- 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
deleted file mode 100644
index 36647414..00000000
--- a/lib/scpt/s_stick.lua
+++ /dev/null
@@ -1,444 +0,0 @@
--- 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
deleted file mode 100644
index d3d2fbb5..00000000
--- a/lib/scpt/s_tempo.lua
+++ /dev/null
@@ -1,162 +0,0 @@
--- 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
deleted file mode 100644
index 4afa8082..00000000
--- a/lib/scpt/s_tulkas.lua
+++ /dev/null
@@ -1,81 +0,0 @@
--- 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
deleted file mode 100644
index c4266239..00000000
--- a/lib/scpt/s_udun.lua
+++ /dev/null
@@ -1,180 +0,0 @@
--- 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
deleted file mode 100644
index 739b066b..00000000
--- a/lib/scpt/s_water.lua
+++ /dev/null
@@ -1,154 +0,0 @@
--- 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
deleted file mode 100644
index 2f594e85..00000000
--- a/lib/scpt/s_yavann.lua
+++ /dev/null
@@ -1,157 +0,0 @@
--- 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
deleted file mode 100644
index 2f90c10b..00000000
--- a/lib/scpt/spells.lua
+++ /dev/null
@@ -1,475 +0,0 @@
---
--- 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
deleted file mode 100644
index 03d29e6e..00000000
--- a/lib/scpt/stores.lua
+++ /dev/null
@@ -1,132 +0,0 @@
--- 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/xtra/graf/16x16.bmp b/lib/xtra/graf/16x16.bmp
deleted file mode 100644
index 2e6b0ebf..00000000
--- a/lib/xtra/graf/16x16.bmp
+++ /dev/null
Binary files differ
diff --git a/lib/xtra/graf/16x16.png b/lib/xtra/graf/16x16.png
deleted file mode 100644
index 9fc1681a..00000000
--- a/lib/xtra/graf/16x16.png
+++ /dev/null
Binary files differ
diff --git a/lib/xtra/graf/8x8.bmp b/lib/xtra/graf/8x8.bmp
deleted file mode 100644
index 02d2d1a9..00000000
--- a/lib/xtra/graf/8x8.bmp
+++ /dev/null
Binary files differ
diff --git a/lib/xtra/graf/8x8.png b/lib/xtra/graf/8x8.png
deleted file mode 100644
index d56e9d6a..00000000
--- a/lib/xtra/graf/8x8.png
+++ /dev/null
Binary files differ
diff --git a/lib/xtra/graf/mask.bmp b/lib/xtra/graf/mask.bmp
deleted file mode 100644
index fced8b05..00000000
--- a/lib/xtra/graf/mask.bmp
+++ /dev/null
Binary files differ
diff --git a/lib/xtra/graf/tome-128.png b/lib/xtra/graf/tome-128.png
deleted file mode 100644
index 31b79c31..00000000
--- a/lib/xtra/graf/tome-128.png
+++ /dev/null
Binary files differ
diff --git a/lib/xtra/sound/Sound.cfg b/lib/xtra/sound/Sound.cfg
deleted file mode 100644
index eb3a7f39..00000000
--- a/lib/xtra/sound/Sound.cfg
+++ /dev/null
@@ -1,79 +0,0 @@
-# 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
deleted file mode 100644
index 49bb86a1..00000000
--- a/lib/xtra/sound/readme.txt
+++ /dev/null
@@ -1,33 +0,0 @@
-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
deleted file mode 100644
index d99b4ed2..00000000
--- a/src/.cvsignore
+++ /dev/null
@@ -1,8 +0,0 @@
-.sconsign
-.gdb_history
-makefile
-tome
-tolua
-w_*.c
-TOME.EXE
-TOLUA.EXE
diff --git a/src/.gitignore b/src/.gitignore
new file mode 100644
index 00000000..098f3b10
--- /dev/null
+++ b/src/.gitignore
@@ -0,0 +1,3 @@
+/harness
+/tome
+*.plist
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 932fef4b..f4b2d2db 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -1,29 +1,137 @@
-# Lua support code.
-ADD_SUBDIRECTORY(lua)
+INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR})
+INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/include)
+INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/../vendor/bandit)
+
+# Add subdirectories
+ADD_SUBDIRECTORY (squelch)
+
+# Sources (common)
+SET(SRCS_COMMON
+ birth.cc
+ bldg.cc
+ cave.cc
+ cmd1.cc
+ cmd2.cc
+ cmd3.cc
+ cmd4.cc
+ cmd5.cc
+ cmd6.cc
+ cmd7.cc
+ corrupt.cc
+ device_allocation.cc
+ dice.cc
+ dungeon.cc
+ files.cc
+ gen_evol.cc
+ gen_maze.cc
+ generate.cc
+ gods.cc
+ help.cc
+ hiscore.cc
+ hooks.cc
+ init1.cc
+ init2.cc
+ joke.cc
+ levels.cc
+ loadsave.cc
+ lua_bind.cc
+ melee1.cc
+ melee2.cc
+ messages.cc
+ mimic.cc
+ modules.cc
+ monster_type.cc
+ monster1.cc
+ monster2.cc
+ monster3.cc
+ notes.cc
+ object1.cc
+ object2.cc
+ object_filter.cc
+ options.cc
+ powers.cc
+ q_betwen.cc
+ q_bounty.cc
+ q_dragons.cc
+ q_eol.cc
+ q_evil.cc
+ q_fireprof.cc
+ q_god.cc
+ q_god.cc
+ q_haunted.cc
+ q_hobbit.cc
+ q_invas.cc
+ q_library.cc
+ q_main.cc
+ q_narsil.cc
+ q_nazgul.cc
+ q_nirna.cc
+ q_one.cc
+ q_poison.cc
+ q_rand.cc
+ q_shroom.cc
+ q_spider.cc
+ q_thief.cc
+ q_thrain.cc
+ q_troll.cc
+ q_ultrae.cc
+ q_ultrag.cc
+ q_wight.cc
+ q_wolves.cc
+ quark.cc
+ quest.cc
+ randart.cc
+ range.cc
+ script.cc
+ skills.cc
+ spell_type.cc
+ spells1.cc
+ spells2.cc
+ spells3.cc
+ spells4.cc
+ spells5.cc
+ spells6.cc
+ squeltch.cc
+ status.cc
+ store.cc
+ tables.cc
+ traps.cc
+ util.cc
+ variable.cc
+ wild.cc
+ wizard1.cc
+ wizard2.cc
+ xtra1.cc
+ xtra2.cc
+ z-form.c
+ z-rand.cc
+ z-term.c
+ z-util.c
+)
-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
+# Sources (PROGRAM)
+SET(SRCS_PROGRAM
+ main-gcu.c
+ main-gtk2.c
+ main-sdl.c
+ main-x11.c
+ main.c
+)
+
+# Sources (TEST)
+SET(SRCS_TESTS
+ ../tests/get_level_device.cc
+ ../tests/harness.cc
+ ../tests/lua_get_level.cc
+)
+
+ADD_LIBRARY(game
+ ${SRCS_COMMON}
)
# Need a few additional source files for Windows.
if(WIN32)
- SET(SRCS ${SRCS} main-win.c readdib.c)
+ SET(SRCS ${SRCS} main-win.c)
# Resource files require a little workaround.
if(MINGW)
# Workaround for resource compilation for mingw on CMake.
@@ -38,33 +146,13 @@ if(WIN32)
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})
+ADD_EXECUTABLE(tome ${EXECUTABLE_OPTIONS} ${SRCS_PROGRAM})
+TARGET_LINK_LIBRARIES(tome game squelch ${LIBS})
+
+# test harness executable
+ADD_EXECUTABLE(harness ${EXECUTABLE_OPTIONS} ${SRCS_TESTS})
+TARGET_LINK_LIBRARIES(harness game squelch ${LIBS})
# Installation
INSTALL(TARGETS tome
diff --git a/src/ability_type.hpp b/src/ability_type.hpp
new file mode 100644
index 00000000..ea8a921d
--- /dev/null
+++ b/src/ability_type.hpp
@@ -0,0 +1,27 @@
+#pragma once
+
+#include "h-basic.h"
+
+/**
+ * Abilities.
+ */
+struct ability_type
+{
+ const char *name; /* Name */
+ char *desc; /* Description */
+
+ const char *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/ability_type_fwd.hpp b/src/ability_type_fwd.hpp
new file mode 100644
index 00000000..bade8638
--- /dev/null
+++ b/src/ability_type_fwd.hpp
@@ -0,0 +1,3 @@
+#pragma once
+
+struct ability_type;
diff --git a/src/activation.hpp b/src/activation.hpp
new file mode 100644
index 00000000..adb9d8bc
--- /dev/null
+++ b/src/activation.hpp
@@ -0,0 +1,13 @@
+#pragma once
+
+#include "h-basic.h"
+
+/**
+ * Activation descriptor.
+ */
+struct activation
+{
+ char desc[80]; /* Desc of the activation */
+ u32b cost; /* costs value */
+ s16b spell; /* Spell. */
+};
diff --git a/src/alloc_entry.hpp b/src/alloc_entry.hpp
new file mode 100644
index 00000000..41ec3b66
--- /dev/null
+++ b/src/alloc_entry.hpp
@@ -0,0 +1,20 @@
+#pragma once
+
+#include "h-basic.h"
+
+/**
+ * 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
+ */
+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 */
+};
diff --git a/src/alloc_entry_fwd.hpp b/src/alloc_entry_fwd.hpp
new file mode 100644
index 00000000..167af118
--- /dev/null
+++ b/src/alloc_entry_fwd.hpp
@@ -0,0 +1,3 @@
+#pragma once
+
+struct alloc_entry;
diff --git a/src/angband.h b/src/angband.h
index cac38122..5fbc94e5 100644
--- a/src/angband.h
+++ b/src/angband.h
@@ -1,9 +1,4 @@
-/* File: angband.h */
-
-/* Main "Angband" header file */
-
-#ifndef INCLUDED_ANGBAND_H
-#define INCLUDED_ANGBAND_H
+#pragma once
/*
* Copyright (c) 1989 James E. Wilson
@@ -13,7 +8,6 @@
* included in all such copies.
*/
-
/*
* C++ guard.
*/
@@ -32,9 +26,7 @@ extern "C" {
* 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"
@@ -45,12 +37,9 @@ extern "C" {
/*
- * Now, include the define's, the type's, and the extern's
+ * Now, include the defines and the types
*/
#include "defines.h"
-#include "types.h"
-#include "externs.h"
-#include "plots.h"
/***** Some copyright messages follow below *****/
@@ -103,8 +92,3 @@ extern "C" {
#ifdef __cplusplus
} /* extern "C" */
#endif
-
-#endif
-
-
-
diff --git a/src/angband.rc b/src/angband.rc
index 00e16516..37856f4a 100644
--- a/src/angband.rc
+++ b/src/angband.rc
@@ -1,10 +1,5 @@
/* 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"
@@ -12,7 +7,6 @@ ANGBAND MENU
MENUITEM "&Save", 110
MENUITEM SEPARATOR
MENUITEM "S&how score", 120
- /*MENUITEM "A&bort", 120*/
MENUITEM "E&xit", 121
}
@@ -107,25 +101,10 @@ ANGBAND MENU
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/artifact_type.hpp b/src/artifact_type.hpp
new file mode 100644
index 00000000..7a4340aa
--- /dev/null
+++ b/src/artifact_type.hpp
@@ -0,0 +1,60 @@
+#pragma once
+
+#include "h-basic.h"
+
+/**
+ * Artifact descriptor.
+ *
+ * Note that the save-file only writes "cur_num" to the savefile.
+ *
+ * Note that "max_num" is always "1" (if that artifact "exists")
+ */
+struct artifact_type
+{
+ char const *name; /* Artifact name */
+ char *text; /* Artifact description */
+
+ 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 ?*/
+};
diff --git a/src/artifact_type_fwd.hpp b/src/artifact_type_fwd.hpp
new file mode 100644
index 00000000..f3862d5a
--- /dev/null
+++ b/src/artifact_type_fwd.hpp
@@ -0,0 +1,3 @@
+#pragma once
+
+struct artifact_type;
diff --git a/src/between_exit.hpp b/src/between_exit.hpp
new file mode 100644
index 00000000..7ea686d7
--- /dev/null
+++ b/src/between_exit.hpp
@@ -0,0 +1,18 @@
+#pragma once
+
+#include "h-basic.h"
+
+/**
+ * Surface-level void gates descriptor.
+ */
+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;
+};
diff --git a/src/birth.c b/src/birth.c
deleted file mode 100644
index f073b2f6..00000000
--- a/src/birth.c
+++ /dev/null
@@ -1,3825 +0,0 @@
-/* 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/birth.cc b/src/birth.cc
new file mode 100644
index 00000000..f3897496
--- /dev/null
+++ b/src/birth.cc
@@ -0,0 +1,3724 @@
+/*
+ * 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 "birth.hpp"
+#include "birth.h"
+
+#include "ability_type.hpp"
+#include "artifact_type.hpp"
+#include "corrupt.hpp"
+#include "cmd4.hpp"
+#include "cmd5.hpp"
+#include "dungeon_info_type.hpp"
+#include "files.h"
+#include "files.hpp"
+#include "gods.hpp"
+#include "help.hpp"
+#include "hist_type.hpp"
+#include "hooks.hpp"
+#include "init2.hpp"
+#include "mimic.hpp"
+#include "messages.hpp"
+#include "meta_class_type.hpp"
+#include "modules.hpp"
+#include "monster2.hpp"
+#include "monster_race.hpp"
+#include "notes.hpp"
+#include "object1.hpp"
+#include "object2.hpp"
+#include "object_kind.hpp"
+#include "options.hpp"
+#include "player_class.hpp"
+#include "player_race.hpp"
+#include "player_race_mod.hpp"
+#include "player_type.hpp"
+#include "q_rand.hpp"
+#include "skill_type.hpp"
+#include "skills.hpp"
+#include "spells2.hpp"
+#include "spells3.hpp"
+#include "spells5.hpp"
+#include "stats.hpp"
+#include "store.hpp"
+#include "tables.hpp"
+#include "town_type.hpp"
+#include "trap_type.hpp"
+#include "util.hpp"
+#include "util.h"
+#include "variable.h"
+#include "variable.hpp"
+#include "wilderness_map.hpp"
+#include "xtra1.hpp"
+#include "xtra2.hpp"
+#include "z-rand.hpp"
+
+#include <string>
+
+/*
+ * 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 const 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 const 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 const 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)
+{
+ const 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 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 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 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 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
+ {
+ value += 10;
+ }
+ }
+ }
+
+ /* 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];
+
+ /* 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);
+
+ /* 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;
+
+
+ /* 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 quest */
+ p_ptr->inside_quest = 0;
+
+ /* 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;
+}
+
+
+/*
+ * 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);
+
+ /* 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.
+ */
+static 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;
+
+
+ /* Wipe special levels */
+ wipe_saved();
+
+ /* Hack -- zero the struct */
+ static_assert(std::is_pod<player_type>::value, "Cannot memset non-POD type");
+ memset(p_ptr, 0, sizeof(player_type));
+
+ /* Level 1 is the first level */
+ p_ptr->lev = 1;
+
+ /* Not dead yet */
+ p_ptr->lives = 0;
+
+ /* 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; i++)
+ {
+ quest[i].status = QUEST_STATUS_UNTAKEN;
+ for (auto &quest_data : quest[i].data)
+ {
+ quest_data = 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 "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;
+
+ /* 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 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;
+
+ /* Wipe the power list */
+ for (i = 0; i < POWER_MAX; i++)
+ {
+ p_ptr->powers_mod[i] = 0;
+ }
+
+ /* No companions killed */
+ p_ptr->companion_killed = 0;
+
+ /* Inertia control */
+ p_ptr->inertia_controlled_spell = -1;
+
+ /* Automatic stat-gain */
+ p_ptr->last_rewarded_level = 1;
+}
+
+
+/* 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);
+}
+
+
+/*
+ * Give the player an object.
+ */
+static void player_outfit_object(int qty, int tval, int sval)
+{
+ object_type forge;
+ object_type *q_ptr = &forge;
+ object_prep(q_ptr, lookup_kind(tval, sval));
+ q_ptr->number = qty;
+ object_aware(q_ptr);
+ object_known(q_ptr);
+ (void)inven_carry(q_ptr, FALSE);
+}
+
+
+/*
+ * Give player a spell book.
+ */
+static void player_outfit_spellbook(cptr spell_name)
+{
+ object_type forge;
+ object_type *q_ptr = &forge;
+ object_prep(q_ptr, lookup_kind(TV_BOOK, 255));
+ q_ptr->pval = find_spell(spell_name);
+ q_ptr->ident |= IDENT_MENTAL | IDENT_KNOWN;
+ 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;
+ cptr class_name = spp_ptr->title;
+ cptr subrace_name = rmp_ptr->title;
+
+ /*
+ * Get an adventurer guide describing a bit of the
+ * wilderness.
+ */
+ {
+ /* Hack -- Give the player an adventurer guide */
+ player_outfit_object(1, TV_PARCHMENT, 20);
+ }
+
+ /*
+ * Provide spell books
+ */
+ if (game_module_idx == MODULE_TOME)
+ {
+ if (streq(class_name, "Ranger"))
+ {
+ player_outfit_spellbook("Phase Door");
+ }
+ }
+ if (streq(class_name, "Geomancer"))
+ {
+ player_outfit_spellbook("Geyser");
+ }
+ if (streq(class_name, "Priest(Eru)"))
+ {
+ player_outfit_spellbook("See the Music");
+ }
+ if (streq(class_name, "Priest(Manwe)"))
+ {
+ player_outfit_spellbook("Manwe's Blessing");
+ }
+ if (streq(class_name, "Druid"))
+ {
+ player_outfit_spellbook("Charm Animal");
+ }
+ if (streq(class_name, "Dark-Priest"))
+ {
+ player_outfit_spellbook("Curse");
+ }
+ if (streq(class_name, "Paladin"))
+ {
+ player_outfit_spellbook("Divine Aim");
+ }
+ if (game_module_idx == MODULE_THEME)
+ {
+ /* Priests */
+ if (streq(class_name, "Stonewright"))
+ {
+ player_outfit_spellbook("Firebrand");
+ }
+ if (streq(class_name, "Priest(Varda)"))
+ {
+ player_outfit_spellbook("Light of Valinor");
+ }
+ if (streq(class_name, "Priest(Ulmo)"))
+ {
+ player_outfit_spellbook("Song of Belegaer");
+ }
+ if (streq(class_name, "Priest(Mandos)"))
+ {
+ player_outfit_spellbook("Tears of Luthien");
+ }
+
+ /* Dragons */
+ if (streq(subrace_name, "Red"))
+ {
+ player_outfit_spellbook("Globe of Light");
+ }
+ if (streq(subrace_name, "Black"))
+ {
+ player_outfit_spellbook("Geyser");
+ }
+ if (streq(subrace_name, "Green"))
+ {
+ player_outfit_spellbook("Noxious Cloud");
+ }
+ if (streq(subrace_name, "Blue"))
+ {
+ player_outfit_spellbook("Stone Skin");
+ }
+ if (streq(subrace_name, "White"))
+ {
+ player_outfit_spellbook("Sense Monsters");
+ }
+ if (streq(subrace_name, "Ethereal"))
+ {
+ player_outfit_spellbook("Recharge");
+ }
+
+ /* Demons */
+ if (streq(subrace_name, "(Aewrog)"))
+ {
+ player_outfit_spellbook("Charm");
+ }
+ if (streq(subrace_name, "(Narrog)"))
+ {
+ player_outfit_spellbook("Phase Door");
+ }
+
+ /* Peace-mages */
+ if (streq(class_name, "Peace-mage"))
+ {
+ player_outfit_spellbook("Phase Door");
+ }
+
+ /* Wainriders */
+ if (streq(class_name, "Wainrider"))
+ {
+ player_outfit_spellbook("Curse");
+ }
+ }
+
+ if (streq(class_name, "Mimic"))
+ {
+ object_type forge;
+ object_type *q_ptr = &forge;
+
+ object_prep(q_ptr, lookup_kind(TV_CLOAK, SV_MIMIC_CLOAK));
+ q_ptr->pval2 = resolve_mimic_name("Mouse");
+ q_ptr->ident |= IDENT_MENTAL | IDENT_KNOWN;
+ inven_carry(q_ptr, FALSE);
+ }
+
+ if (game_module_idx == MODULE_THEME)
+ {
+ /* Give everyone a scroll of WoR. */
+ player_outfit_object(1, TV_SCROLL, SV_SCROLL_WORD_OF_RECALL);
+
+ /* Identify everything in pack. */
+ identify_pack_fully();
+ }
+
+ if (streq(rmp_ptr->title, "Vampire"))
+ {
+ player_gain_corruption(CORRUPT_VAMPIRE_TEETH);
+ player_gain_corruption(CORRUPT_VAMPIRE_STRENGTH);
+ player_gain_corruption(CORRUPT_VAMPIRE_VAMPIRE);
+ }
+
+ process_hooks_new(HOOK_BIRTH_OBJECTS, NULL, NULL);
+ meta_inertia_control_hook_birth_objects();
+
+ {
+ /* Hack -- Give the player some food */
+ int qty = (byte)rand_range(3, 7);
+ player_outfit_object(qty, TV_FOOD, SV_FOOD_RATION);
+ }
+
+ {
+ 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]);
+}
+
+
+int dump_classes(s16b *classes, int sel, u32b *restrictions)
+{
+ int n = 0;
+
+ char buf[80];
+
+ /* 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];
+
+ if (sel == n)
+ {
+ p1 = '[';
+ p2 = ']';
+ }
+
+ /* Display */
+ strnfmt(buf, 80, "%c%c%c %s%s", p1,
+ (n <= 25) ? I2A(n) : I2D(n - 26), p2, cp_ptr->title, mod);
+
+ /* Print some more info */
+ if (sel == n)
+ {
+ std::string desc;
+
+ desc += cp_ptr->desc;
+ if (cp_ptr->flags1 & PR1_EXPERIMENTAL)
+ {
+ desc += "\nEXPERIMENTAL";
+ }
+
+ print_desc(desc.c_str());
+
+ 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++;
+ }
+
+ return (n);
+}
+
+int dump_specs(int sel)
+{
+ int n = 0;
+
+ char buf[80];
+
+ /* 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];
+
+ if (sel == n)
+ {
+ p1 = '[';
+ p2 = ']';
+ }
+
+ /* Display */
+ strnfmt(buf, 80, "%c%c%c %s", p1, I2A(n), p2, spp_ptr->title);
+
+ /* Print some more info */
+ if (sel == n)
+ {
+ std::string desc;
+
+ desc += spp_ptr->desc;
+ if (spp_ptr->flags1 & PR1_EXPERIMENTAL)
+ {
+ desc += "\nEXPERIMENTAL";
+ }
+
+ print_desc(desc.c_str());
+
+ 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));
+ }
+ }
+
+ return (n);
+}
+
+int dump_races(int sel)
+{
+ int n = 0;
+
+ char buf[80];
+
+ /* 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];
+
+ if (sel == n)
+ {
+ p1 = '[';
+ p2 = ']';
+ }
+
+ /* Display */
+ strnfmt(buf, 80, "%c%c%c %s", p1, I2A(n), p2, rp_ptr->title);
+
+ /* Print some more info */
+ if (sel == n)
+ {
+ std::string desc;
+
+ desc += rp_ptr->desc;
+ if (rp_ptr->flags1 & PR1_EXPERIMENTAL)
+ {
+ desc += "\nEXPERIMENTAL";
+ }
+
+ print_desc(desc.c_str());
+
+ 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));
+ }
+ }
+
+ return (n);
+}
+
+
+int dump_rmods(int sel, int *racem, int max)
+{
+ int n = 0;
+
+ char buf[80];
+
+ /* 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];
+
+ if (sel == n)
+ {
+ p1 = '[';
+ p2 = ']';
+ }
+
+ /* Display */
+ if (racem[n])
+ strnfmt(buf, 80, "%c%c%c %s", p1, I2A(n), p2, rmp_ptr->title);
+ else
+ strnfmt(buf, 80, "%c%c%c Classical", p1, I2A(n), p2);
+
+ /* Print some more info */
+ if (sel == n)
+ {
+ std::string desc;
+
+ desc += rmp_ptr->desc;
+ if (rmp_ptr->flags1 & PR1_EXPERIMENTAL)
+ {
+ desc += "\nEXPERIMENTAL";
+ }
+
+ print_desc(desc.c_str());
+
+ 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));
+ }
+ }
+
+ 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;
+
+ int racem[100], max_racem = 0;
+
+ u32b restrictions[2];
+
+ char c;
+
+ char p2 = ')';
+
+ char buf[200];
+ char inp[200];
+
+ s16b *class_types;
+
+ /*** 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];
+
+ /* Display */
+ strnfmt(buf, 200, "%c%c %s", I2A(n), p2, sp_ptr->title);
+ 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];
+
+ /* Display */
+ c_put_str(TERM_L_BLUE, sp_ptr->title, 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.");
+
+ /* 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 == '?')
+ {
+ help_race(race_info[sel].title);
+ }
+ 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];
+
+ /* Display */
+ c_put_str(TERM_L_BLUE, rp_ptr->title, 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 == '?')
+ {
+ help_subrace(race_mod_info[racem[sel]].title);
+ }
+
+ 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 == '?')
+ {
+ help_class(class_info[class_types[sel]].title);
+ }
+ 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 == '?')
+ {
+ help_class(class_info[p_ptr->pclass].spec[sel].title);
+ }
+ 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];
+
+ /* Display */
+ c_put_str(TERM_L_BLUE, spp_ptr->title, 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 (race_flags1_p(PR1_NO_GOD))
+ {
+ p_ptr->pgod = GOD_NONE;
+ }
+ else
+ {
+ int choice[MAX_GODS];
+ int max = 0;
+
+ /* Get the list of possible gods */
+ for (n = 0; n < MAX_GODS; n++)
+ {
+ if (god_enabled(&deity_info[n]) &&
+ ((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')
+ {
+ 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 == '?')
+ {
+ help_god(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();
+ }
+
+ /* Set god */
+ p_ptr->pgod = k;
+ p_ptr->grace = 0;
+ }
+
+ /* A god that like us ? more grace ! */
+ if (race_flags1_p(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->preserve = preserve;
+ p_ptr->special = special_lvls;
+ p_ptr->astral = (race_flags2_p(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 */
+ dungeon_type = DUNGEON_BASE;
+ p_ptr->recall_dungeon = dungeon_type;
+ max_dlv[dungeon_type] = d_info[dungeon_type].mindepth;
+
+ if (p_ptr->astral)
+ {
+ /* Somewhere in the misty mountains */
+ dungeon_type = DUNGEON_ASTRAL;
+ p_ptr->wilderness_x = DUNGEON_ASTRAL_WILD_X;
+ p_ptr->wilderness_y = DUNGEON_ASTRAL_WILD_Y;
+ }
+
+ /* Clean up */
+ clear_from(10);
+
+ /*** User enters number of quests ***/
+ /* Heino Vander Sanden and Jimmy De Laet */
+
+ if (!ironman_rooms)
+ {
+ 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 random quests */
+ initialize_random_quests(v);
+ max_quests = v;
+
+ p_ptr->inside_quest = 0;
+
+ /* Init the plots */
+ {
+ 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();
+
+ /* 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++)
+ {
+ /* Reset stats */
+ p_ptr->stat_cur[i] = p_ptr->stat_max[i] = stats[i];
+
+ /* 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];
+
+
+ /* 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;
+ }
+ }
+
+ /* 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, 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();
+
+ /* Check for a keypress */
+ if (inkey_scan()) 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();
+
+ /* 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 */
+ add_note_type(NOTE_BIRTH);
+
+ /* Note player birth in the message recall */
+ message_add(" ", TERM_L_BLUE);
+ message_add(" ", TERM_L_BLUE);
+ message_add("====================", TERM_L_BLUE);
+ message_add(" ", TERM_L_BLUE);
+ message_add(" ", 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(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;
+ }
+ }
+}
+
+
+
+
+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);
+
+ /* 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);
+
+ /* 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);
+
+ /* 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,
+ (!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;
+
+ can_use = module_savefile_loadable(savefile_module[k]);
+ 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/birth.h b/src/birth.h
new file mode 100644
index 00000000..41620bfa
--- /dev/null
+++ b/src/birth.h
@@ -0,0 +1,14 @@
+#pragma once
+
+#include "h-basic.h"
+
+// C linkage required for these functions since main-* code uses them.
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern bool_ no_begin_screen;
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
diff --git a/src/birth.hpp b/src/birth.hpp
new file mode 100644
index 00000000..fb036ecc
--- /dev/null
+++ b/src/birth.hpp
@@ -0,0 +1,9 @@
+#pragma once
+
+#include "h-basic.h"
+
+extern void print_desc_aux(cptr txt, int y, int x);
+extern void save_savefile_names(void);
+extern bool_ begin_screen(void);
+extern void get_height_weight(void);
+extern void player_birth(void);
diff --git a/src/birther.hpp b/src/birther.hpp
new file mode 100644
index 00000000..f517fb9d
--- /dev/null
+++ b/src/birther.hpp
@@ -0,0 +1,35 @@
+#pragma once
+
+#include "h-basic.h"
+
+/**
+ * Player information during the birth process.
+ */
+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;
+
+ char history[4][60];
+
+ bool_ quick_ok;
+};
diff --git a/src/bldg.c b/src/bldg.c
deleted file mode 100644
index 48e94e9f..00000000
--- a/src/bldg.c
+++ /dev/null
@@ -1,2198 +0,0 @@
-/* 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/bldg.cc b/src/bldg.cc
new file mode 100644
index 00000000..7095e8c3
--- /dev/null
+++ b/src/bldg.cc
@@ -0,0 +1,1469 @@
+/* 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 "cave_type.hpp"
+#include "cmd3.hpp"
+#include "files.hpp"
+#include "hooks.hpp"
+#include "hook_quest_finish_in.hpp"
+#include "hook_quest_fail_in.hpp"
+#include "hook_init_quest_in.hpp"
+#include "mimic.hpp"
+#include "object1.hpp"
+#include "object2.hpp"
+#include "owner_type.hpp"
+#include "player_type.hpp"
+#include "q_library.hpp"
+#include "q_fireprof.hpp"
+#include "q_bounty.hpp"
+#include "spells2.hpp"
+#include "stats.hpp"
+#include "store.hpp"
+#include "store_action_type.hpp"
+#include "store_info_type.hpp"
+#include "store_type.hpp"
+#include "tables.hpp"
+#include "util.hpp"
+#include "util.h"
+#include "variable.hpp"
+#include "xtra1.hpp"
+#include "xtra2.hpp"
+#include "z-rand.hpp"
+
+/* remember building location */
+static int building_loc = 0;
+
+
+/*
+ * A helper function for is_state
+ */
+static 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];
+
+
+ for (i = 0; i < 6; i++)
+ {
+ store_action_type *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, buff);
+ c_put_str(action_color, tmp_str, 21 + (i / 2), 2 + 17 + (30 * (i % 2)));
+ }
+ }
+}
+
+
+/*
+ * 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_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 = ((race_flags1_p(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;
+
+ 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;
+
+ struct hook_quest_finish_in in = { plots[plot] };
+ process_hooks_new(HOOK_QUEST_FINISH, &in, NULL);
+
+ 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;
+
+ hook_quest_fail_in in = { plots[plot] };
+ process_hooks_new(HOOK_QUEST_FAIL, &in, NULL);
+
+ return (FALSE);
+ }
+ /* No quest yet */
+ else if (q_ptr->status == QUEST_STATUS_UNTAKEN)
+ {
+ struct hook_init_quest_in in = { plots[plot] };
+ if (process_hooks_new(HOOK_INIT_QUEST, &in, NULL))
+ {
+ return (FALSE);
+ }
+
+ q_ptr->status = QUEST_STATUS_TAKEN;
+
+ /* Assign a new quest */
+ get_questinfo(plots[plot]);
+
+ /* Add the hooks */
+ 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, const char *attr, 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 const *o_ptr)
+{
+ return (wield_slot(o_ptr) == INVEN_WIELD);
+}
+
+/*
+ * compare_weapons -KMW-
+ */
+static bool_ compare_weapons(void)
+{
+ int item, i;
+
+ object_type *o1_ptr, *o2_ptr, *orig_ptr;
+
+ clear_bldg(6, 18);
+
+ o1_ptr = NULL;
+ o2_ptr = NULL;
+
+ /* Store copy of original wielded weapon in pack slot */
+ object_type *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 */
+ if (!get_item(&item,
+ "What is your first melee weapon? ",
+ "You have nothing to compare.",
+ (USE_EQUIP | USE_INVEN),
+ item_tester_hook_melee_weapon))
+ {
+ object_wipe(orig_ptr);
+ return (FALSE);
+ }
+
+ /* Get the item (in the pack) */
+ if (item >= 0)
+ o1_ptr = &p_ptr->inventory[item];
+
+ /* Get second weapon */
+ int item2;
+ if (!get_item(&item2,
+ "What is your second melee weapon? ",
+ "You have nothing to compare.",
+ (USE_EQUIP | USE_INVEN),
+ item_tester_hook_melee_weapon))
+ {
+ 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());
+}
+
+
+
+/*
+ * 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;
+ }
+
+ /* 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:
+ {
+ 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:
+ {
+ show_highclass(building_loc);
+ break;
+ }
+
+ case BACT_IN_BETWEEN:
+ case BACT_CRAPS:
+ 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_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_DROP_ITEM:
+ {
+ quest_bounty_drop_item();
+ break;
+ }
+
+ case BACT_GET_ITEM:
+ {
+ quest_bounty_get_item();
+ break;
+ }
+
+ case BACT_LIBRARY_QUEST:
+ {
+ quest_library_building(&paid, &recreate);
+ break;
+ }
+
+ case BACT_FIREPROOF_QUEST:
+ {
+ quest_fireproof_building(&paid, &recreate);
+ break;
+ }
+
+ case BACT_EREBOR_KEY:
+ {
+ 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.");
+ break;
+ }
+
+ default:
+ printf("Unknown building action %d\n", static_cast<int>(bact));
+ 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;
+ }
+}
diff --git a/src/bldg.hpp b/src/bldg.hpp
new file mode 100644
index 00000000..0daebbee
--- /dev/null
+++ b/src/bldg.hpp
@@ -0,0 +1,9 @@
+#pragma once
+
+#include "h-basic.h"
+#include "store_type_fwd.hpp"
+
+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 enter_quest(void);
diff --git a/src/body.hpp b/src/body.hpp
new file mode 100644
index 00000000..dd0be282
--- /dev/null
+++ b/src/body.hpp
@@ -0,0 +1,12 @@
+#pragma once
+
+/*
+ * 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
diff --git a/src/carbon/Angband.icns b/src/carbon/Angband.icns
deleted file mode 100644
index 3d775739..00000000
--- a/src/carbon/Angband.icns
+++ /dev/null
Binary files differ
diff --git a/src/carbon/Carbon.r b/src/carbon/Carbon.r
deleted file mode 100644
index e3194dd2..00000000
--- a/src/carbon/Carbon.r
+++ /dev/null
@@ -1,1568 +0,0 @@
-/*
- * 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
deleted file mode 100644
index dbaec173..00000000
--- a/src/carbon/Data.icns
+++ /dev/null
Binary files differ
diff --git a/src/carbon/Edit.icns b/src/carbon/Edit.icns
deleted file mode 100644
index 5e55c272..00000000
--- a/src/carbon/Edit.icns
+++ /dev/null
Binary files differ
diff --git a/src/carbon/Image-DS_Store b/src/carbon/Image-DS_Store
deleted file mode 100644
index efd42e72..00000000
--- a/src/carbon/Image-DS_Store
+++ /dev/null
Binary files differ
diff --git a/src/carbon/Info.plist b/src/carbon/Info.plist
deleted file mode 100644
index fff3fb15..00000000
--- a/src/carbon/Info.plist
+++ /dev/null
@@ -1,39 +0,0 @@
-<?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
deleted file mode 100644
index 362f80f6..00000000
--- a/src/carbon/Save.icns
+++ /dev/null
Binary files differ
diff --git a/src/carbon/getversion b/src/carbon/getversion
deleted file mode 100755
index 786fd14b..00000000
--- a/src/carbon/getversion
+++ /dev/null
@@ -1,2 +0,0 @@
-#! /bin/sh
-grep CFBundleVersion carbon/Info.plist | perl -pe "s,.*<string>([^<]*)<.*,\\1,"
diff --git a/src/cave.c b/src/cave.c
deleted file mode 100644
index d23fc44c..00000000
--- a/src/cave.c
+++ /dev/null
@@ -1,5055 +0,0 @@
-/* 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/cave.cc b/src/cave.cc
new file mode 100644
index 00000000..5ff31019
--- /dev/null
+++ b/src/cave.cc
@@ -0,0 +1,4693 @@
+#include "cave.hpp"
+
+#include "cave_type.hpp"
+#include "feature_type.hpp"
+#include "hook_enter_dungeon_in.hpp"
+#include "monster2.hpp"
+#include "monster_race.hpp"
+#include "monster_type.hpp"
+#include "object1.hpp"
+#include "object_kind.hpp"
+#include "options.hpp"
+#include "player_type.hpp"
+#include "q_rand.hpp"
+#include "spells1.hpp"
+#include "store_info_type.hpp"
+#include "tables.hpp"
+#include "trap_type.hpp"
+#include "util.hpp"
+#include "util.h"
+#include "variable.h"
+#include "variable.hpp"
+#include "z-rand.hpp"
+
+#include <cassert>
+#include <vector>
+#include <iterator>
+#include <algorithm>
+
+/*
+ * 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 const *c_ptr = &cave[y][x];
+
+ /* Forbid perma-grids */
+ if (cave_perma_grid(c_ptr)) return (FALSE);
+
+ /* Check objects */
+ for (auto const o_idx: c_ptr->o_idxs)
+ {
+ /* Acquire object */
+ object_type *o_ptr = &o_list[o_idx];
+
+ /* Forbid artifact grids */
+ if ((o_ptr->art_name) || artifact_p(o_ptr)) return (FALSE);
+ }
+
+ /* Accept */
+ return (TRUE);
+}
+
+
+
+/*
+ * Generate visual for hallucinatory monster
+ */
+static void image_monster(byte *ap, char *cp)
+{
+ // Cached state which keeps a list of all the "live" monster race entries.
+ static std::vector<size_t> *instance = nullptr;
+
+ // First-time initialization
+ if (!instance)
+ {
+ // Create the list of "live" indexes
+ instance = new std::vector<size_t>();
+ // Start at 1 to avoid 'player'
+ for (size_t i = 1; i < max_r_idx; i++)
+ {
+ if (r_info[i].name)
+ {
+ instance->push_back(i);
+ }
+ }
+ }
+
+ // Sanity check
+ assert(instance != nullptr);
+
+ // Select a race at random
+ int n = rand_int(instance->size());
+ *cp = r_info[(*instance)[n]].x_char;
+ *ap = r_info[(*instance)[n]].x_attr;
+}
+
+
+/*
+ * Generate visual for hallucinatory object
+ */
+static void image_object(byte *ap, char *cp)
+{
+ // Cached state which keeps a list of the "live" object_kind entries.
+ static std::vector<size_t> *instance = nullptr;
+
+ // First-time initialization
+ if (!instance)
+ {
+ // Create the list of "live" indexes
+ instance = new std::vector<size_t>();
+ // Filter all the "live" entries
+ for (size_t i = 0; i < max_k_idx; i++)
+ {
+ if (k_info[i].name)
+ {
+ instance->push_back(i);
+ }
+ }
+ }
+
+ // Sanity check
+ assert(instance != nullptr);
+
+ // Select an object kind at random
+ int n = rand_int(instance->size());
+ *cp = k_info[(*instance)[n]].x_char;
+ *ap = k_info[(*instance)[n]].x_attr;
+}
+
+
+/*
+ * 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);
+ }
+}
+
+
+
+static 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(std::shared_ptr<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
+};
+
+
+static void map_info(int y, int x, byte *ap, char *cp)
+{
+ byte a;
+
+ byte c;
+
+ /**** Preparation ****/
+
+ /* Access the grid */
+ cave_type *c_ptr = &cave[y][x];
+
+
+ /* Cache some frequently used values */
+
+ /* Grid info */
+ auto info = c_ptr->info;
+
+ /* Feature code */
+ auto feat = c_ptr->feat;
+
+ /* Apply "mimic" field */
+ if (c_ptr->mimic)
+ {
+ feat = c_ptr->mimic;
+ }
+ else
+ {
+ feat = f_info[feat].mimic;
+ }
+
+ /* Access floor */
+ feature_type *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)
+ {
+ /* 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 && ((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 */
+ auto 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].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)
+ {
+ /* 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)))
+ {
+ /* 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];
+ }
+
+ 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 info */
+ *ap = a;
+ *cp = c;
+
+
+ /**** Layer 2 -- Objects ****/
+
+ if (feat != FEAT_MON_TRAP)
+ {
+ for (auto const o_idx: c_ptr->o_idxs)
+ {
+ /* Acquire object */
+ object_type *o_ptr = &o_list[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 && (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];
+ auto const r_ptr = m_ptr->race();
+
+ if (r_ptr->flags9 & RF9_MIMIC)
+ {
+ /* Acquire object being mimicked */
+ object_type *o_ptr = &o_list[m_ptr->mimic_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 && (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)
+ {
+ /* 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;
+ }
+
+ /* 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];
+
+ /* Get the "player" attr */
+ if (!avoid_other && (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;
+
+ /* Show player health char instead? */
+ 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;
+ }
+ }
+
+ /* Save the info */
+ *ap = a;
+ *cp = c;
+
+ }
+}
+
+
+/*
+ * Special version of map_info, for use by HTML converter
+ * to obtain pure-ASCII image of dungeon map
+ */
+void map_info_default(int y, int x, byte *ap, char *cp)
+{
+ byte a;
+
+ byte c;
+
+ /**** Preparation ****/
+
+ /* Access the grid */
+ cave_type *c_ptr = &cave[y][x];
+
+
+ /* Cache some frequently used values */
+
+ /* Grid info */
+ auto info = c_ptr->info;
+
+ /* Feature code */
+ auto feat = c_ptr->feat;
+
+ /* Apply "mimic" field */
+ if (c_ptr->mimic)
+ {
+ feat = c_ptr->mimic;
+ }
+ else
+ {
+ feat = f_info[feat].mimic;
+ }
+
+ /* Access floor */
+ feature_type *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 */
+ auto 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 (auto const this_o_idx: c_ptr->o_idxs)
+ {
+ /* Acquire object */
+ object_type *o_ptr = &o_list[this_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];
+ auto const r_ptr = m_ptr->race();
+
+ if (r_ptr->flags9 & RF9_MIMIC)
+ {
+ /* Acquire object being mimicked */
+ object_type *o_ptr = &o_list[m_ptr->mimic_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);
+ }
+ }
+ else
+ {
+ /* Visible monster */
+ if (m_ptr->ml)
+ {
+ /* 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;
+
+ }
+}
+
+
+/*
+ * Calculate panel colum of a location in the map
+ */
+static int panel_col_of(int col)
+{
+ col -= panel_col_min;
+ 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);
+}
+
+
+
+
+
+/*
+ * 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;
+
+ /* Require "seen" flag */
+ if (!(info & (CAVE_SEEN))) return;
+
+
+ /* Hack -- memorize objects */
+ for (auto const this_o_idx: c_ptr->o_idxs)
+ {
+ /* Acquire object */
+ object_type *o_ptr = &o_list[this_o_idx];
+
+ /* Memorize objects */
+ o_ptr->marked = TRUE;
+ }
+
+ if (c_ptr->m_idx)
+ {
+ monster_type *m_ptr = &m_list[c_ptr->m_idx];
+ auto r_ptr = m_ptr->race();
+
+ if (r_ptr->flags9 & RF9_MIMIC)
+ {
+ object_type *o_ptr = &o_list[m_ptr->mimic_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;
+ char c;
+
+ /* Redraw if on screen */
+ if (panel_contains(y, x))
+ {
+ /* Examine the grid */
+ map_info(y, x, &a, &c);
+
+ /* Hack -- Queue it */
+ Term_queue_char(panel_col_of(x), y - panel_row_prt, a, c);
+ }
+}
+
+
+
+
+/*
+ * 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;
+ char c;
+
+ /* Determine what is there */
+ map_info(y, x, &a, &c);
+
+ /* Efficiency -- Redraw that grid of the map */
+ Term_queue_char(panel_col_of(x), y - panel_row_prt, a, c);
+ }
+ }
+
+ /* 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;
+
+ 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);
+
+ /*
+ * 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;
+
+
+ /* Set up initial maps */
+ std::vector<std::vector<byte>> ma;
+ std::vector<std::vector<char>> mc;
+ std::vector<std::vector<byte>> mp;
+ for (i = 0; i < hgt + 2; i++)
+ {
+ // Nothing there.
+ ma.push_back(std::vector<byte>(wid + 2, TERM_WHITE));
+ mc.push_back(std::vector<char>(wid + 2, ' '));
+
+ // No priority.
+ mp.push_back(std::vector<byte>(wid + 2, 0));
+ }
+ assert(static_cast<int>(ma.size()) == hgt + 2);
+ assert(static_cast<int>(mc.size()) == hgt + 2);
+ assert(static_cast<int>(mp.size()) == hgt + 2);
+
+ /* 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);
+
+ /* 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);
+ }
+ }
+
+ /* Player location in dungeon */
+ *cy = p_ptr->py * yfactor / yrat + ROW_MAP;
+ *cx = p_ptr->px * xfactor / xrat + COL_MAP;
+
+ /* 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];
+};
+
+
+
+/*
+ * 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;
+
+ int num_grids = 0;
+
+ int queue_head = 0;
+ int queue_tail = 0;
+ vinfo_type *queue[VINFO_MAX_GRIDS*2];
+
+
+ /* Make hack */
+ vinfo_hack hack;
+ memset(&hack, 0, sizeof(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 */
+ std::sort(std::begin(hack.slopes), std::end(hack.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!");
+ }
+
+
+ /* 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;
+
+ /* Check for "simple" illumination */
+ if (cave[yy][xx].info & (CAVE_GLOW))
+ {
+ /* Mark as 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;
+ }
+ }
+
+ /* 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];
+
+ /* 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 */
+ auto r_ptr = m_ptr->race();
+
+ /* 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 -- 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];
+ auto const r_ptr = m_ptr->race();
+
+ if (r_ptr->flags9 & RF9_MIMIC)
+ {
+ object_type *o_ptr = &o_list[m_ptr->mimic_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_FRAME);
+}
+
+
+
+/*
+ * 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.
+ *
+ * All disturbance cancels repeated commands, resting, and running.
+ */
+void disturb(int stop_search)
+{
+ /* Cancel auto-commands */
+ /* command_new = 0; */
+
+ /* Cancel repeated commands */
+ if (command_rep)
+ {
+ /* Cancel */
+ command_rep = 0;
+
+ /* Redraw the state (later) */
+ p_ptr->redraw |= (PR_FRAME);
+ }
+
+ /* Cancel Resting */
+ if (resting)
+ {
+ /* Cancel */
+ resting = 0;
+
+ /* Redraw the state (later) */
+ p_ptr->redraw |= (PR_FRAME);
+ }
+
+ /* 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_FRAME);
+ }
+
+ /* Flush the input if requested */
+ if (flush_disturb) flush();
+}
+
+
+
+/*
+ * Return the index of the random quest on this level
+ * (or zero)
+ */
+static 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;
+}
+
+
+
+/*
+ * 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);
+}
+
+
+/*
+ * 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;
+}
+
+/**
+ * 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-
+ */
+bool cave_floor_bold(int y, int x)
+{
+ return cave_floor_grid(&cave[y][x]);
+}
+
+/**
+ * Grid based version of "cave_floor_bold()"
+ */
+bool cave_floor_grid(cave_type const *c)
+{
+ return (f_info[c->feat].flags1 & FF1_FLOOR) && (c->feat != FEAT_MON_TRAP);
+}
+
+
+
+/**
+ * Determine if a "legal" grid is floor without the REMEMBER flag set
+ * Sometimes called "boring" grid
+ */
+bool cave_plain_floor_bold(int y, int x)
+{
+ return cave_plain_floor_grid(&cave[y][x]);
+}
+
+/**
+ * Grid based version of "cave_plain_floor_bold()"
+ */
+bool cave_plain_floor_grid(cave_type const *c)
+{
+ return
+ (f_info[c->feat].flags1 & FF1_FLOOR) &&
+ !(f_info[c->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-
+ */
+bool cave_sight_bold(int y, int x)
+{
+ return cave_sight_grid(&cave[y][x]);
+}
+
+bool cave_sight_grid(cave_type const *c)
+{
+ return !(f_info[c->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
+ */
+bool cave_clean_bold(int y, int x)
+{
+ return
+ (f_info[cave[y][x].feat].flags1 & FF1_FLOOR) &&
+ (cave[y][x].feat != FEAT_MON_TRAP) &&
+ (cave[y][x].o_idxs.empty()) &&
+ !(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
+ */
+bool cave_empty_bold(int y, int x)
+{
+ return
+ 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
+ */
+bool cave_naked_bold(int y, int x)
+{
+ return
+ (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_idxs.empty()) &&
+ (cave[y][x].m_idx == 0);
+}
+
+bool cave_naked_bold2(int y, int x)
+{
+ return
+ (f_info[cave[y][x].feat].flags1 & FF1_FLOOR) &&
+ (cave[y][x].feat != FEAT_MON_TRAP) &&
+ (cave[y][x].o_idxs.empty()) &&
+ (cave[y][x].m_idx == 0);
+}
+
+
+/**
+ * Determine if a "legal" grid is "permanent"
+ */
+bool cave_perma_bold(int y, int x)
+{
+ return cave_perma_grid(&cave[y][x]);
+}
+
+bool cave_perma_grid(cave_type const *c)
+{
+ return 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
+ */
+bool player_has_los_bold(int y, int x)
+{
+ return (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
+ */
+bool player_can_see_bold(int y, int x)
+{
+ return (cave[y][x].info & (CAVE_SEEN)) != 0;
+}
diff --git a/src/cave.hpp b/src/cave.hpp
new file mode 100644
index 00000000..64f67dba
--- /dev/null
+++ b/src/cave.hpp
@@ -0,0 +1,55 @@
+#pragma once
+
+#include "h-basic.h"
+#include "cave_type_fwd.hpp"
+#include "object_type_fwd.hpp"
+
+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_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 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);
+extern int is_quest(int level);
+extern int new_effect(int type, int dam, int time, int cy, int cx, int rad, s32b flags);
+extern bool cave_floor_bold(int y, int x);
+extern bool cave_floor_grid(cave_type const *c);
+extern bool cave_plain_floor_bold(int y, int x);
+extern bool cave_plain_floor_grid(cave_type const *c);
+extern bool cave_sight_bold(int y, int x);
+extern bool cave_sight_grid(cave_type const *c);
+extern bool cave_clean_bold(int y, int x);
+extern bool cave_empty_bold(int y, int x);
+extern bool cave_naked_bold(int y, int x);
+extern bool cave_naked_bold2(int y, int x);
+extern bool cave_perma_bold(int y, int x);
+extern bool cave_perma_grid(cave_type const *c);
+extern bool player_has_los_bold(int y, int x);
+extern bool player_can_see_bold(int y, int x);
diff --git a/src/cave_type.hpp b/src/cave_type.hpp
new file mode 100644
index 00000000..958ace1d
--- /dev/null
+++ b/src/cave_type.hpp
@@ -0,0 +1,65 @@
+#pragma once
+
+#include "h-basic.h"
+
+#include <cassert>
+#include <vector>
+
+/**
+ * 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 to create the
+ * singly linked list of objects. If "o_idx" is zero then there
+ * are no objects in the grid.
+ */
+struct cave_type
+{
+ u16b info = 0; /* Hack -- cave flags */
+
+ byte feat = 0; /* Hack -- feature type */
+
+ std::vector<s16b> o_idxs { }; /* Indexes of objects in this grid */
+
+ s16b m_idx = 0; /* Monster in this grid */
+
+ s16b t_idx = 0; /* trap index (in t_list) or zero */
+
+ s16b special = 0; /* Special cave info */
+ s16b special2 = 0; /* Special cave info */
+
+ s16b inscription = 0; /* Inscription of the grid */
+
+ byte mana = 0; /* Magical energy of the grid */
+
+ byte mimic = 0; /* Feature to mimic */
+
+ byte cost = 0; /* Hack -- cost of flowing */
+ byte when = 0; /* Hack -- when cost was computed */
+
+ s16b effect = 0; /* The lasting effects */
+
+ /**
+ * @brief wipe the object's state
+ */
+ void wipe() {
+ /* Reset to defaults */
+ *this = cave_type();
+ }
+
+};
diff --git a/src/cave_type_fwd.hpp b/src/cave_type_fwd.hpp
new file mode 100644
index 00000000..f2569ea6
--- /dev/null
+++ b/src/cave_type_fwd.hpp
@@ -0,0 +1,3 @@
+#pragma once
+
+struct cave_type;
diff --git a/src/cli_comm.hpp b/src/cli_comm.hpp
new file mode 100644
index 00000000..6ae53edc
--- /dev/null
+++ b/src/cli_comm.hpp
@@ -0,0 +1,13 @@
+#pragma once
+
+#include "h-basic.h"
+
+/**
+ * A structure for CLI commands.
+ */
+struct cli_comm
+{
+ cptr comm; /* Extended name of the command. */
+ cptr descrip; /* Description of the command. */
+ s16b key; /* Key to convert command to. */
+};
diff --git a/src/cli_comm_fwd.hpp b/src/cli_comm_fwd.hpp
new file mode 100644
index 00000000..6d9b76a3
--- /dev/null
+++ b/src/cli_comm_fwd.hpp
@@ -0,0 +1,3 @@
+#pragma once
+
+struct cli_comm;
diff --git a/src/cmd1.c b/src/cmd1.c
deleted file mode 100644
index 49c0d38f..00000000
--- a/src/cmd1.c
+++ /dev/null
@@ -1,5125 +0,0 @@
-/* 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/cmd1.cc b/src/cmd1.cc
new file mode 100644
index 00000000..f4066915
--- /dev/null
+++ b/src/cmd1.cc
@@ -0,0 +1,4999 @@
+/*
+ * 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 "cmd1.hpp"
+
+#include "cave.hpp"
+#include "cave_type.hpp"
+#include "cmd4.hpp"
+#include "cmd5.hpp"
+#include "dungeon_info_type.hpp"
+#include "feature_type.hpp"
+#include "files.hpp"
+#include "gods.hpp"
+#include "hooks.hpp"
+#include "hook_move_in.hpp"
+#include "lua_bind.hpp"
+#include "melee1.hpp"
+#include "melee2.hpp"
+#include "mimic.hpp"
+#include "monster2.hpp"
+#include "monster3.hpp"
+#include "monster_race.hpp"
+#include "monster_type.hpp"
+#include "object1.hpp"
+#include "object2.hpp"
+#include "options.hpp"
+#include "player_type.hpp"
+#include "quark.hpp"
+#include "skills.hpp"
+#include "spells1.hpp"
+#include "spells2.hpp"
+#include "spells3.hpp"
+#include "tables.hpp"
+#include "traps.hpp"
+#include "trap_type.hpp"
+#include "util.hpp"
+#include "util.h"
+#include "variable.h"
+#include "variable.hpp"
+#include "wild.hpp"
+#include "xtra1.hpp"
+#include "xtra2.hpp"
+#include "z-rand.hpp"
+
+#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;
+
+ auto const r_ptr = m_ptr->race();
+
+ 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)
+{
+ /* Start with base search ability */
+ int 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 (int y = (p_ptr->py - 1); y <= (p_ptr->py + 1); y++)
+ {
+ for (int x = (p_ptr->px - 1); x <= (p_ptr->px + 1); x++)
+ {
+ /* Sometimes, notice things */
+ if (rand_int(100) < chance)
+ {
+ /* Access the grid */
+ cave_type *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);
+ }
+
+ /* 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);
+ }
+
+ /* Scan all objects in the grid */
+ for (auto const o_idx: c_ptr->o_idxs)
+ {
+ object_type * o_ptr = &o_list[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);
+ }
+ }
+ }
+ }
+ }
+}
+
+
+
+
+/*
+ * 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);
+
+ /* 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_info[c_ptr->t_idx].name);
+ }
+ }
+}
+
+
+void touch_zap_player(monster_type *m_ptr)
+{
+ auto r_ptr = m_ptr->race();
+
+ if (r_ptr->flags2 & (RF2_AURA_FIRE))
+ {
+ if (!(p_ptr->immune_fire))
+ {
+ char aura_dam[80];
+
+ int 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];
+
+ int 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;
+
+ 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);
+
+ /* 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)
+ {
+ strnfmt(temp, sizeof(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)
+ {
+ auto tr_ptr = t_ptr->race();
+ /* 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);
+
+ /* 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];
+
+ auto tr_ptr = t_ptr->race();
+
+ 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;
+
+ auto r_ptr = &r_info[p_ptr->body_monster];
+
+ /* 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" */
+ power = get_attack_power(effect);
+
+ /* Monster hits */
+ if (!effect || check_hit2(power, rlev, ac))
+ {
+ /* Always disturbing */
+ disturb(1);
+
+ /* 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)
+ {
+ strnfmt(temp, sizeof(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);
+
+ /* 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)
+{
+ auto const r_ptr = m_ptr->race();
+
+ /* Extract monster name (or "it") */
+ char m_name[80];
+ 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 *blow_table = ma_blows;
+ int resist_stun = 0;
+ int max = MAX_MA;
+ bool_ desc = FALSE;
+ 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);
+ }
+ martial_arts *ma_ptr = &blow_table[0];
+ martial_arts *old_ptr = &blow_table[0];
+
+ /* Extract monster name (or "it") */
+ auto const r_ptr = m_ptr->race();
+ 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);
+
+ /* Extract name */
+ char m_name[80];
+ monster_desc(m_name, m_ptr, 0);
+
+ /* Describe attack */
+ 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;
+ }
+
+ bool_ done_crit;
+ *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
+ */
+static void do_nazgul(int *k, int *num, int num_blow, int weap, std::shared_ptr<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];
+
+ 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);
+
+ 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") */
+ char m_name[80];
+ 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);
+
+ /* 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 */
+ object_type *o_ptr = &p_ptr->inventory[INVEN_WIELD + weap];
+
+ /* Get race info */
+ auto r_ptr = m_ptr->race();
+
+ /* 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);
+ }
+
+ if (praying_to(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*/
+ if (praying_to(GOD_MELKOR))
+ {
+ int lv = get_level(MELKOR_CURSE, 100, 1);
+
+ 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))
+ {
+ do_melkor_curse(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 = m_ptr->race();
+
+ 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);
+ }
+}
+
+
+
+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 || (race_flags1_p(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) && praying_to(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);
+}
+
+/*
+ * 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().
+ */
+
+static 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);
+
+ /* 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);
+}
+
+/*
+ * 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];
+
+ 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 */
+ {
+ hook_move_in in = { y, x };
+ if (process_hooks_new(HOOK_MOVE, &in, NULL)) {
+ return; /* Prevent movement */
+ }
+ }
+
+ if (p_ptr->dripping_tread > 0)
+ {
+ geomancy_random_floor(y, x, FALSE);
+ p_ptr->dripping_tread -= 1;
+ if (p_ptr->dripping_tread == 0)
+ {
+ msg_print("You stop dripping raw elemental energies.");
+ }
+ }
+
+
+ /* Get the monster */
+ m_ptr = &m_list[c_ptr->m_idx];
+ auto const mr_ptr = m_ptr->race();
+
+ 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) &&
+ ((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;
+ }
+
+ /* 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);
+
+ 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_info[feat].block);
+ c_ptr->info |= (CAVE_MARK);
+ lite_spot(y, x);
+ }
+ }
+
+ /* Notice things */
+ else
+ {
+ /* Rubble */
+ if (c_ptr->feat == FEAT_RUBBLE)
+ {
+ 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...
+ */
+ }
+ /* Closed doors */
+ else if ((c_ptr->feat >= FEAT_DOOR_HEAD) && (c_ptr->feat <= FEAT_DOOR_TAIL))
+ {
+ if (easy_open_door(y, x)) return;
+ }
+
+ /* 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("There is %s.", f_info[feat].block);
+
+ if (!(p_ptr->confused || p_ptr->stun || p_ptr->image))
+ energy_use = 0;
+ }
+ }
+
+ /* Sound */
+ sound(SOUND_HITWALL);
+ }
+
+ /*
+ * 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);
+
+ /* 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;
+
+ /* 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_FRAME);
+ }
+ 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_FRAME);
+ }
+
+ /* 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 != DEFAULT_FEAT_TEXT)
+ {
+ /* Mega-hack for dungeon branches */
+ if ((feat == FEAT_MORE) && c_ptr->special)
+ {
+ msg_format("There is %s", d_info[c_ptr->special].text);
+ }
+ else
+ {
+ msg_print(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);
+
+ /* Hack -- Enter store */
+ command_new = '_';
+ }
+
+ else if (cave[y][x].feat >= FEAT_ALTAR_HEAD &&
+ cave[y][x].feat <= FEAT_ALTAR_TAIL)
+ {
+ cptr 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);
+
+ 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);
+
+ 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;
+
+ /* 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++)
+ {
+ /* 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 */
+ cave_type *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 (auto const o_idx: c_ptr->o_idxs)
+ {
+ /* Acquire object */
+ object_type * o_ptr = &o_list[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 */
+ cave_type *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 */
+ cave_type *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);
+
+ /* 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);
+
+ /* 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);
+}
+
+
+/*
+ * 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;
+
+ 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;
+
+ /* Build a prompt (accept all spells) */
+ if (num <= 26)
+ {
+ /* Build a prompt (accept all spells) */
+ strnfmt(out_val, 78,
+ "(Command %c-%c, ESC=exit) Select a command: ", I2A(0),
+ I2A(num - 1));
+ }
+ else
+ {
+ strnfmt(out_val, 78,
+ "(Command %c-%c, ESC=exit) Select a command: ", I2A(0),
+ '0' + num - 27);
+ }
+
+ /* Save the screen */
+ character_icky = TRUE;
+ Term_save();
+
+ /* Show the list */
+ {
+ byte y = 1, x = 0;
+ int ctr = 0;
+ char dummy[80];
+
+ strcpy(dummy, "");
+
+ 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);
+ }
+ }
+
+ /* Get a command from the user */
+ while (!flag && get_com(out_val, &choice))
+ {
+ 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 */
+ 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
+ */
+void do_cmd_integrate_body()
+{
+ if (!p_ptr->disembodied)
+ {
+ msg_print("You are already in a body.");
+ return;
+ }
+
+ /* Get an item */
+ int item;
+ if (!get_item(&item,
+ "Incarnate in which body? ",
+ "You have no corpse to incarnate in.",
+ (USE_FLOOR),
+ object_filter::TVal(TV_CORPSE)))
+ {
+ return;
+ }
+
+ object_type *o_ptr = &o_list[0 - item];
+
+ if (o_ptr->sval != SV_CORPSE_CORPSE)
+ {
+ msg_print("You must select a corpse.");
+ return;
+ }
+
+ 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();
+}
+
+/*
+ * 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:
+ {
+ int ii = x, ij = y;
+
+ cave_set_feat(ij, ii, FEAT_DARK_PIT);
+ msg_print("A chasm appears in the floor!");
+
+ cave_type *c_ptr = &cave[ij][ii];
+
+ if (c_ptr->m_idx)
+ {
+ monster_type *m_ptr = &m_list[c_ptr->m_idx];
+ auto const r_ptr = m_ptr->race();
+
+ 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(c_ptr->m_idx);
+ }
+ }
+ }
+
+ if (!c_ptr->o_idxs.empty())
+ {
+ /* Copy list of objects since we're going to be manipulating the list */
+ auto const object_idxs(c_ptr->o_idxs);
+
+ /* Scan all objects in the grid */
+ for (auto const this_o_idx: object_idxs)
+ {
+ bool_ plural = FALSE;
+
+ char o_name[80];
+
+ /* Acquire object */
+ object_type * o_ptr = &o_list[this_o_idx];
+
+ if (o_ptr->number > 1) plural = TRUE;
+
+ /* 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/cmd1.hpp b/src/cmd1.hpp
new file mode 100644
index 00000000..3ae44ed2
--- /dev/null
+++ b/src/cmd1.hpp
@@ -0,0 +1,25 @@
+#pragma once
+
+#include "h-basic.h"
+#include "monster_type_fwd.hpp"
+#include "object_type_fwd.hpp"
+
+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 do_cmd_pet(void);
+extern void do_cmd_integrate_body();
+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);
diff --git a/src/cmd2.c b/src/cmd2.c
deleted file mode 100644
index 2d05c125..00000000
--- a/src/cmd2.c
+++ /dev/null
@@ -1,5107 +0,0 @@
-/* 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/cmd2.cc b/src/cmd2.cc
new file mode 100644
index 00000000..cfdeab44
--- /dev/null
+++ b/src/cmd2.cc
@@ -0,0 +1,5014 @@
+/*
+ * 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 "cmd2.hpp"
+
+#include "bldg.hpp"
+#include "cave.hpp"
+#include "cave_type.hpp"
+#include "cmd1.hpp"
+#include "dungeon_info_type.hpp"
+#include "feature_type.hpp"
+#include "files.hpp"
+#include "gods.hpp"
+#include "hook_chat_in.hpp"
+#include "hook_enter_dungeon_in.hpp"
+#include "hook_give_in.hpp"
+#include "hook_stair_in.hpp"
+#include "hook_stair_out.hpp"
+#include "hooks.hpp"
+#include "levels.hpp"
+#include "monster2.hpp"
+#include "monster3.hpp"
+#include "monster_race.hpp"
+#include "monster_type.hpp"
+#include "object1.hpp"
+#include "object2.hpp"
+#include "object_kind.hpp"
+#include "options.hpp"
+#include "player_type.hpp"
+#include "skills.hpp"
+#include "spells1.hpp"
+#include "spells2.hpp"
+#include "spells3.hpp"
+#include "stats.hpp"
+#include "tables.hpp"
+#include "trap_type.hpp"
+#include "traps.hpp"
+#include "util.hpp"
+#include "util.h"
+#include "variable.h"
+#include "variable.hpp"
+#include "wilderness_map.hpp"
+#include "wilderness_type_info.hpp"
+#include "xtra1.hpp"
+#include "xtra2.hpp"
+#include "z-rand.hpp"
+
+#include <chrono>
+#include <thread>
+
+using std::this_thread::sleep_for;
+using std::chrono::milliseconds;
+
+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);
+}
+
+/*
+ * Stair hooks
+ */
+static bool_ stair_hooks(stairs_direction direction)
+{
+ hook_stair_in in = { direction };
+ hook_stair_out out = { TRUE }; /* Allow by default */
+ process_hooks_new(HOOK_STAIR, &in, &out);
+ return (!out.allow);
+}
+
+
+/*
+ * 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 (stair_hooks(STAIRS_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 (stair_hooks(STAIRS_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 ? ;) */
+ {
+ struct hook_enter_dungeon_in in = { c_ptr->special };
+ if (process_hooks_new(HOOK_ENTER_DUNGEON, &in, NULL))
+ {
+ 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_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_FRAME);
+
+ /* Cancel the arg */
+ command_arg = 0;
+ }
+
+ /* Take a turn */
+ energy_use = 100;
+
+ /* Search */
+ search();
+}
+
+
+/*
+ * Hack -- toggle search mode
+ */
+void do_cmd_toggle_search(void)
+{
+ p_ptr->update |= (PU_BONUS);
+ p_ptr->redraw |= (PR_FRAME);
+ p_ptr->searching = !p_ptr->searching;
+}
+
+
+
+/*
+ * Determine if a grid contains a chest
+ */
+static s16b chest_check(int y, int x)
+{
+ cave_type *c_ptr = &cave[y][x];
+
+ /* Scan all objects in the grid */
+ for (auto const this_o_idx: c_ptr->o_idxs)
+ {
+ object_type * o_ptr;
+
+ /* Acquire object */
+ o_ptr = &o_list[this_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_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;
+ }
+
+ /* Pick a direction if there's an obvious target */
+ {
+ 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_FRAME);
+
+ /* 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);
+ }
+ }
+
+ /* Cancel repeat unless we may continue */
+ if (!more) disturb(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;
+
+
+ /* Pick a direction if there's an obvious choice */
+ {
+ 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_FRAME);
+
+ /* 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);
+}
+
+
+/*
+ * 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_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
+ */
+static 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_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_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_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_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_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_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_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_FRAME);
+
+ /* 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);
+}
+
+
+/*
+ * 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
+ */
+static 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_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;
+
+
+ /* Pick a direction if there's an obvious choice */
+ {
+ 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_FRAME);
+
+ /* 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);
+}
+
+
+/*
+ * 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(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_FRAME);
+
+ /* 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);
+}
+
+
+
+/*
+ * 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_FRAME);
+
+ /* 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);
+}
+
+
+/*
+ * 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_FRAME);
+
+ /* 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);
+}
+
+
+/*
+ * Try to ``walk'' using phase door.
+ */
+static 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_FRAME);
+
+ /* 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);
+}
+
+
+/*
+ * 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_FRAME);
+
+ /* 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);
+
+ /* 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_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_FRAME);
+
+ /* 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];
+
+ 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))
+ {
+ /* Get an item */
+ if (!get_item(&item,
+ "Your quiver is empty. Fire which item? ",
+ "You have nothing to fire.",
+ (USE_INVEN | USE_FLOOR),
+ object_filter::TVal(p_ptr->tval_ammo)))
+ {
+ 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();
+ sleep_for(milliseconds(msec));
+ lite_spot(y, x);
+ Term_fresh();
+ }
+
+ /* The player cannot see the missile */
+ else
+ {
+ /* Pause anyway, for consistancy */
+ sleep_for(milliseconds(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];
+ auto const r_ptr = m_ptr->race();
+
+ /* 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;
+
+ 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;
+
+ 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;
+
+ /* Get an item */
+ int item;
+ if (!get_item(&item,
+ "Throw which item? ",
+ "You have nothing to throw.",
+ (USE_INVEN | USE_FLOOR)))
+ {
+ return;
+ }
+
+ /* Access the item */
+ object_type *o_ptr = get_object(item);
+
+ u32b f1, f2, f3, f4, f5, esp;
+ 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();
+ sleep_for(milliseconds(msec));
+ lite_spot(y, x);
+ Term_fresh();
+ }
+
+ /* The player cannot see the missile */
+ else
+ {
+ /* Pause anyway, for consistancy */
+ sleep_for(milliseconds(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];
+ auto r_ptr = m_ptr->race();
+
+ /* 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();
+ sleep_for(milliseconds(msec));
+ lite_spot(y, x);
+ Term_fresh();
+ }
+
+ /* The player cannot see the missile */
+ else
+ {
+ /* Pause anyway, for consistancy */
+ sleep_for(milliseconds(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];
+ auto const r_ptr = m_ptr->race();
+
+ /* 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();
+ sleep_for(milliseconds(msec));
+ lite_spot(y, x);
+ Term_fresh();
+ }
+
+ /* The player cannot see the missile */
+ else
+ {
+ /* Pause anyway, for consistancy */
+ sleep_for(milliseconds(msec));
+ }
+ }
+}
+
+
+static bool_ tport_vertically(bool_ how)
+{
+ /* quest? */
+ if (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_FRAME);
+ }
+
+ if (lose_hp)
+ {
+ p_ptr->chp -= lose_hp;
+ p_ptr->redraw |= (PR_FRAME);
+ }
+
+ energy_use = 100;
+ }
+}
+
+/* Can we sacrifice it ? */
+static bool item_tester_hook_sacrificable(object_type const *o_ptr)
+{
+ if (p_ptr->pgod == 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) && udun_in_book(o_ptr->sval, o_ptr->pval) <= 0)
+ {
+ return TRUE;
+ }
+ }
+
+ /* Assume not */
+ return (FALSE);
+}
+
+/*
+ * Is item eligible for sacrifice to Aule?
+ */
+static bool item_tester_hook_sacrifice_aule(object_type const *o_ptr)
+{
+ /* perhaps restrict this only to metal armour and weapons */
+ return (o_ptr->found == OBJ_FOUND_SELFMADE);
+}
+
+/*
+ * Handle sacrifices to Aule
+ */
+static void do_cmd_sacrifice_aule()
+{
+ int item;
+
+ if (!get_item(&item,
+ "Sacrifice which item? ",
+ "You have nothing to sacrifice.",
+ USE_INVEN,
+ item_tester_hook_sacrifice_aule))
+ {
+ return;
+ }
+
+ /* Increase piety by the value of the item / 10. */
+ {
+ object_type *o_ptr = get_object(item);
+ s32b delta = object_value(o_ptr) / 10;
+
+ inc_piety(GOD_ALL, delta);
+ }
+
+ /* Destroy the object */
+ inc_stack_size(item, -1);
+}
+
+/*
+ * 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();
+ return;
+ }
+ else
+ {
+ int agod = on_what - FEAT_ALTAR_HEAD + 1;
+
+ /* Not worshipping a god ? ahhhh! */
+ if (p_ptr->pgod == 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)
+ {
+ if (p_ptr->pgod == 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
+ {
+ /* Get an item */
+ int item;
+ if (!get_item(&item,
+ "Sacrifice which item? ",
+ "You have nothing to sacrifice.",
+ (USE_INVEN),
+ item_tester_hook_sacrificable))
+ {
+ return;
+ }
+
+ object_type *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 = levels_in_book(o_ptr->sval, o_ptr->pval);
+
+ inc_piety(GOD_MELKOR, 2 * x);
+ }
+
+ /* Remove the item */
+ inc_stack_size(item, -1);
+ }
+ }
+
+ if (p_ptr->pgod == GOD_AULE)
+ {
+ do_cmd_sacrifice_aule();
+ }
+
+ }
+ }
+}
+
+
+/*
+ * scan_monst --
+ *
+ * Return a list of o_list[] indexes of items of the given monster
+ */
+std::vector<s16b> scan_monst(int m_idx)
+{
+ constexpr std::size_t max_size = 23;
+
+ /* Create output vector. */
+ std::vector<s16b> objects;
+ objects.reserve(std::min(max_size, m_list[m_idx].hold_o_idxs.size()));
+
+ /* Scan all objects in the grid */
+ for (auto const this_o_idx: m_list[m_idx].hold_o_idxs)
+ {
+ objects.push_back(this_o_idx);
+ if (objects.size() == max_size) break;
+ }
+
+ /* Result */
+ return objects;
+}
+
+
+/*
+ * Display a list of the items that the given monster carries.
+ * Returns the list of objects.
+ */
+std::vector<s16b> show_monster_inven(int m_idx)
+{
+ byte out_color[23];
+ char out_desc[23][80];
+
+ /* Default length */
+ int len = 79 - 50;
+
+ /* Maximum space allowed for descriptions */
+ int lim = 79 - 3;
+
+ /* Require space for weight */
+ lim -= 9;
+
+ /* Scan for objects on the monster */
+ std::vector<s16b> objects = scan_monst(m_idx);
+ assert(objects.size() <= 23);
+
+ /* Calculate width of object names */
+ for (std::size_t i = 0; i < objects.size(); i++)
+ {
+ object_type *o_ptr = &o_list[objects.at(i)];
+
+ /* Describe the object */
+ char o_name[80];
+ object_desc(o_name, o_ptr, TRUE, 3);
+
+ /* Hack -- enforce max length */
+ o_name[lim] = '\0';
+
+ /* Acquire p_ptr->inventory color */
+ out_color[i] = tval_to_attr[o_ptr->tval & 0x7F];
+
+ /* Save the object description */
+ strcpy(out_desc[i], o_name);
+
+ /* Find the predicted "line length" */
+ int l = strlen(out_desc[i]) + 5;
+
+ /* Account for the weight */
+ l += 9;
+
+ /* Maintain the maximum length */
+ if (l > len) len = l;
+ }
+
+ /* Find the column to start in */
+ int col = (len > 76) ? 0 : (79 - len);
+
+ /* Output each entry */
+ std::size_t i = 0;
+ for (i = 0; i < objects.size(); i++)
+ {
+ /* Get the item */
+ object_type *o_ptr = &o_list[objects.at(i)];
+
+ /* Clear the line */
+ prt("", i + 1, col ? col - 2 : col);
+
+ /* Prepare an index --(-- */
+ char tmp_val[80];
+ strnfmt(tmp_val, 80, "%c)", index_to_label(i));
+
+ /* Clear the line with the (possibly indented) index */
+ put_str(tmp_val, i + 1, col);
+
+ /* Display the entry itself */
+ c_put_str(out_color[i], out_desc[i], i + 1, col + 3);
+
+ /* Display the weight if needed */
+ {
+ int wgt = o_ptr->weight * o_ptr->number;
+ strnfmt(tmp_val, 80, "%3d.%1d lb", wgt / 10, wgt % 10);
+ put_str(tmp_val, i + 1, 71);
+ }
+ }
+
+ /* Make a "shadow" below the list (only if needed) */
+ if (i && (i < 23))
+ {
+ prt("", i + 1, col ? col - 2 : col);
+ }
+
+ return objects;
+}
+
+
+/*
+ * Steal an object from a monster
+ */
+void do_cmd_steal()
+{
+ int dir = 0, item = -1, k = -1;
+
+ bool_ done = FALSE;
+
+ /* Only works on adjacent monsters */
+ if (!get_rep_dir(&dir)) return;
+ int y = p_ptr->py + ddy[dir];
+ int x = p_ptr->px + ddx[dir];
+
+ cave_type const *c_ptr = &cave[y][x];
+
+ if (!(c_ptr->m_idx))
+ {
+ msg_print("There is no monster there!");
+ return;
+ }
+
+ monster_type *m_ptr = &m_list[c_ptr->m_idx];
+
+ /* There were no non-gold items */
+ if (m_ptr->hold_o_idxs.empty())
+ {
+ 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();
+
+ std::vector<s16b> objects = show_monster_inven(c_ptr->m_idx);
+
+ /* 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 + objects.size());
+
+ /* 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) || (static_cast<std::size_t>(k) >= objects.size()))
+ {
+ bell();
+
+ break;
+ }
+
+ /* Verify the item */
+ if (ver && !verify("Try", -objects[k]))
+ {
+ done = TRUE;
+
+ break;
+ }
+
+ /* Accept that choice */
+ item = objects[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;
+ }
+
+ /* Remove from the monster's list of objects */
+ m_ptr->hold_o_idxs.erase(m_ptr->hold_o_idxs.begin() + k);
+
+ /* Rogues gain some xp */
+ if (race_flags1_p(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);
+ }
+
+ /* Create the object we're going to copy into */
+ object_type forge;
+ object_type *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_FRAME);
+
+ /* Window stuff */
+ p_ptr->window |= (PW_PLAYER);
+ }
+ else
+ {
+ object_copy(o_ptr, &o_list[item]);
+
+ inven_carry(o_ptr, FALSE);
+ }
+
+ /* Delete source item */
+ o_list[item].k_idx = 0;
+ }
+
+ screen_load();
+
+ /* Take a turn */
+ energy_use = 100;
+}
+
+
+/*
+ * Give an item to a monster
+ */
+void do_cmd_give()
+{
+ /* Get a "repeated" direction */
+ int dir;
+ if (!get_rep_dir(&dir)) return;
+
+ /* Get requested location */
+ int y = p_ptr->py + ddy[dir];
+ int x = p_ptr->px + ddx[dir];
+
+ /* Get requested grid */
+ cave_type *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 */
+ int item;
+ if (!get_item(&item,
+ "What item do you want to offer? ",
+ "You have nothing to offer.",
+ USE_INVEN))
+ {
+ return;
+ }
+
+ /* Process hooks if there are any */
+ hook_give_in in = { c_ptr->m_idx, item };
+ if (!process_hooks_new(HOOK_GIVE, &in, NULL))
+ {
+ 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 */
+ struct hook_chat_in in = { c_ptr->m_idx };
+ if (!process_hooks_new(HOOK_CHAT, &in, NULL))
+ {
+ msg_print("The monster does not want to chat.");
+ }
+
+ /* No energy spent */
+}
diff --git a/src/cmd2.hpp b/src/cmd2.hpp
new file mode 100644
index 00000000..142238ab
--- /dev/null
+++ b/src/cmd2.hpp
@@ -0,0 +1,33 @@
+#pragma once
+
+#include "h-basic.h"
+#include "object_type_fwd.hpp"
+#include <vector>
+
+extern std::vector<s16b> show_monster_inven(int m_idx);
+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 void do_cmd_tunnel(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_immovable_special(void);
+extern void fetch(int dir, int wgt, bool_ require_los);
+extern void do_cmd_sacrifice(void);
+extern void do_cmd_steal(void);
diff --git a/src/cmd3.c b/src/cmd3.c
deleted file mode 100644
index 02dbc1c4..00000000
--- a/src/cmd3.c
+++ /dev/null
@@ -1,2331 +0,0 @@
-/* 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/cmd3.cc b/src/cmd3.cc
new file mode 100644
index 00000000..59e61719
--- /dev/null
+++ b/src/cmd3.cc
@@ -0,0 +1,2110 @@
+/*
+ * 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 "cmd3.hpp"
+
+#include "artifact_type.hpp"
+#include "cave.hpp"
+#include "cave_type.hpp"
+#include "cli_comm.hpp"
+#include "files.hpp"
+#include "gods.hpp"
+#include "hook_drop_in.hpp"
+#include "hook_wield_in.hpp"
+#include "hooks.hpp"
+#include "monster1.hpp"
+#include "monster_race.hpp"
+#include "object1.hpp"
+#include "object2.hpp"
+#include "object_kind.hpp"
+#include "object_type.hpp"
+#include "options.hpp"
+#include "player_type.hpp"
+#include "quark.hpp"
+#include "squeltch.hpp"
+#include "store.hpp"
+#include "store_type.hpp"
+#include "tables.hpp"
+#include "town_type.hpp"
+#include "util.hpp"
+#include "util.h"
+#include "variable.h"
+#include "variable.hpp"
+#include "xtra1.hpp"
+#include "xtra2.hpp"
+#include "z-rand.hpp"
+
+#include <cassert>
+#include <algorithm>
+#include <memory>
+#include <utility>
+
+/*
+ * 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();
+
+ /* Show the inventory */
+ show_inven_full();
+
+ /* Show prompt */
+ {
+ 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();
+
+ /* Display the equipment */
+ show_equip_full();
+
+ /* Show 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 const *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 *i_ptr;
+
+ cptr act;
+
+ char o_name[80];
+
+ u32b f1, f2, f3, f4, f5, esp;
+
+
+ /* Get an item */
+ if (!get_item(&item,
+ "Wear/Wield which item? ",
+ "You have nothing you can wear or wield.",
+ (USE_INVEN | USE_FLOOR),
+ item_tester_hook_wear))
+ {
+ return;
+ }
+
+ /* Get the item */
+ object_type *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 */
+ {
+ struct hook_wield_in in = { o_ptr };
+ if (process_hooks_new(HOOK_WIELD, &in, NULL))
+ {
+ 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;
+ }
+ }
+
+ /* 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_FRAME);
+
+ p_ptr->window |= (PW_INVEN | PW_EQUIP | PW_PLAYER);
+}
+
+
+
+/*
+ * Take off an item
+ */
+void do_cmd_takeoff(void)
+{
+ /* Get an item */
+ int item;
+ if (!get_item(&item,
+ "Take off which item? ",
+ "You are not wearing anything to take off.",
+ (USE_EQUIP)))
+ {
+ return;
+ }
+
+ /* Get the item */
+ object_type *o_ptr = get_object(item);
+
+ /* 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_FRAME);
+}
+
+
+/*
+ * Drop an item
+ */
+void do_cmd_drop(void)
+{
+ /* Get an item */
+ int item;
+ if (!get_item(&item,
+ "Drop which item? ",
+ "You have nothing to drop.",
+ (USE_EQUIP | USE_INVEN)))
+ {
+ return;
+ }
+
+ /* Get the item */
+ object_type *o_ptr = get_object(item);
+ u32b f1, f2, f3, f4, f5, esp;
+ object_flags(o_ptr, &f1, &f2, &f3, &f4, &f5, &esp);
+
+ /* Can we drop */
+ struct hook_drop_in in = { item };
+ if (process_hooks_new(HOOK_DROP, &in, NULL)) 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 */
+ int amt = 1;
+ 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 old_number;
+
+ bool_ force = FALSE;
+
+ char o_name[80];
+
+ char out_val[160];
+
+ /* Hack -- force destruction */
+ if (command_arg > 0) force = TRUE;
+
+
+ /* Get an item */
+ int item;
+ if (!get_item(&item,
+ "Destroy which item? ",
+ "You have nothing to destroy.",
+ (USE_INVEN | USE_FLOOR | USE_AUTO)))
+ {
+ return;
+ }
+
+ /* Get the item */
+ object_type *o_ptr = get_object(item);
+
+ /* See how many items */
+ int amt = 1;
+ 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)
+ {
+ /* 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;
+
+ u32b f1, f2, f3, f4, f5, esp;
+ 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);
+ }
+
+ /*
+ * 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)
+{
+ /* Get an item */
+ int item;
+ if (!get_item(&item,
+ "Examine which item? ",
+ "You have nothing to examine.",
+ (USE_EQUIP | USE_INVEN | USE_FLOOR)))
+ {
+ return;
+ }
+
+ /* Get the item */
+ object_type *o_ptr = get_object(item);
+
+ /* Description */
+ char o_name[80];
+ 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)
+{
+ /* Get an item */
+ int item;
+ if (!get_item(&item,
+ "Un-inscribe which item? ",
+ "You have nothing to un-inscribe.",
+ (USE_EQUIP | USE_INVEN | USE_FLOOR)))
+ {
+ return;
+ }
+
+ /* Get the item */
+ object_type *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)
+{
+ /* Get an item */
+ int item;
+ if (!get_item(&item,
+ "Inscribe which item? ",
+ "You have nothing to inscribe.",
+ (USE_EQUIP | USE_INVEN | USE_FLOOR)))
+ {
+ return;
+ }
+
+ /* Get the item */
+ object_type *o_ptr = get_object(item);
+
+ /* Describe the activity */
+ char o_name[80];
+ object_desc(o_name, o_ptr, TRUE, 3);
+
+ /* Message */
+ msg_format("Inscribing %s.", o_name);
+ msg_print(NULL);
+
+ /* Start with nothing */
+ char out_val[80];
+ 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, sizeof(out_val)))
+ {
+ /* 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 object_filter_t const &item_tester_refill_lantern()
+{
+ using namespace object_filter;
+ static auto instance = Or(
+ TVal(TV_FLASK),
+ And(
+ TVal(TV_LITE),
+ SVal(SV_LITE_LANTERN)));
+ return instance;
+}
+
+
+/*
+ * Refill the players lamp (from the pack or floor)
+ */
+static void do_cmd_refill_lamp(void)
+{
+ /* Get an item */
+ int item;
+ if (!get_item(&item,
+ "Refill with which flask? ",
+ "You have no flasks of oil.",
+ (USE_INVEN | USE_FLOOR),
+ item_tester_refill_lantern()))
+ {
+ return;
+ }
+
+ /* Get the item */
+ object_type *o_ptr = get_object(item);
+
+ /* Take a partial turn */
+ energy_use = 50;
+
+ /* Access the lantern */
+ object_type *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 object_filter_t const &item_tester_refill_torch()
+{
+ using namespace object_filter;
+ static auto instance =
+ And(
+ TVal(TV_LITE),
+ SVal(SV_LITE_TORCH));
+ return instance;
+}
+
+
+/*
+ * Refuel the players torch (from the pack or floor)
+ */
+static void do_cmd_refill_torch(void)
+{
+ /* Get an item */
+ int item;
+ if (!get_item(&item,
+ "Refuel with which torch? ",
+ "You have no extra torches.",
+ (USE_INVEN | USE_FLOOR),
+ item_tester_refill_torch()))
+ {
+ return;
+ }
+
+ /* Get the item */
+ object_type *o_ptr = get_object(item);
+
+ /* Take a partial turn */
+ energy_use = 50;
+
+ /* Access the primary torch */
+ object_type *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
+};
+
+
+/**
+ * Sort by monster experience.
+ */
+static bool compare_monster_experience(int w1, int w2)
+{
+ /* Extract experience */
+ s32b z1 = r_info[w1].mexp;
+ s32b z2 = r_info[w2].mexp;
+
+ /* Compare experience */
+ if (z1 < z2) return true;
+ if (z1 > z2) return false;
+
+ /* Punt to index */
+ return w1 < w2;
+}
+
+/**
+ * Sort by monster level.
+ */
+static bool compare_monster_level(int w1, int w2)
+{
+ /* Extract levels */
+ byte z1 = r_info[w1].level;
+ byte z2 = r_info[w2].level;
+
+ /* Compare levels */
+ if (z1 < z2) return true;
+ if (z1 > z2) return false;
+
+ /* Punt to monster experience. */
+ return compare_monster_experience(w1, w2);
+}
+
+/**
+ * Sort by total number of kills
+ */
+static bool compare_total_kills(int w1, int w2)
+{
+ /* Extract total kills */
+ s16b z1 = r_info[w1].r_tkills;
+ s16b z2 = r_info[w2].r_tkills;
+
+ /* Compare total kills */
+ if (z1 < z2) return true;
+ if (z1 > z2) return false;
+
+ /* Punt to monster level. */
+ return compare_monster_level(w1, w2);
+}
+
+/*
+ * Sort by player kills
+ */
+static bool compare_player_kills(int w1, int w2)
+{
+ /* Extract player kills */
+ s16b z1 = r_info[w1].r_pkills;
+ s16b z2 = r_info[w2].r_pkills;
+
+ /* Compare player kills */
+ if (z1 < z2) return true;
+ if (z1 > z2) return false;
+
+ /* Punt to total number of kills. */
+ return compare_total_kills(w1, w2);
+}
+
+
+/*
+ * 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_ptr->name);
+
+ /* Append the "standard" attr/char info */
+ Term_addstr( -1, TERM_WHITE, " ('");
+ Term_addch(a1, c1);
+ Term_addstr( -1, TERM_WHITE, "')");
+
+ /* Append the "optional" attr/char info */
+ Term_addstr( -1, TERM_WHITE, "/('");
+ Term_addch(a2, c2);
+ 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, 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;
+
+ bool (*sort_by)(int,int) = nullptr;
+
+ /* 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);
+
+ /* Collect matching monsters */
+ std::vector<u16b> who;
+ for (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_ptr->name);
+ strlower(mon_name);
+
+ if (!strstr(mon_name, temp)) continue;
+ }
+
+ /* Collect "appropriate" monsters */
+ if (all || (r_ptr->d_char == sym)) {
+ who.push_back(i);
+ }
+ }
+
+ /* Nothing to recall */
+ if (who.empty())
+ {
+ 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')
+ {
+ sort_by = compare_player_kills;
+ query = 'y';
+ }
+
+ /* Sort by level */
+ if (query == 'p')
+ {
+ sort_by = compare_monster_level;
+ query = 'y';
+ }
+
+ /* Catch "escape" */
+ if (query != 'y')
+ {
+ return;
+ }
+
+
+ /* Sort if needed */
+ if (sort_by)
+ {
+ /* Sort the array */
+ std::sort(std::begin(who), std::end(who), sort_by);
+ }
+
+
+ /* Start at the end */
+ i = who.size() - 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 == '-')
+ {
+ i++;
+ assert(i >= 0);
+ if (static_cast<size_t>(i) == who.size())
+ {
+ i = 0;
+ }
+ }
+
+ /* Move to "next" monster */
+ else
+ {
+ if (i-- == 0)
+ {
+ i = who.size() - 1;
+ }
+ }
+ }
+
+ /* Re-display the identity */
+ prt(buf, 0, 0);
+}
+
+
+/*
+ * research_mon
+ * -KMW-
+ */
+bool_ research_mon()
+{
+ int i, 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;
+
+ monster_race *r2_ptr;
+
+ /* Hack -- Remember "cheat_know" flag */
+ oldcheat = cheat_know;
+
+
+ /* Get a character, or abort */
+ if (!get_com("Enter character of monster: ", &sym)) return (TRUE);
+
+ /* 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 */
+ std::vector<u16b> who;
+ for (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.push_back(i);
+ }
+ }
+
+ /* Nothing to recall */
+ if (who.empty())
+ {
+ /* Restore the "cheat_know" flag */
+ cheat_know = oldcheat;
+
+ return (TRUE);
+ }
+
+
+ query = 'y';
+
+ /* Sort by level */
+ std::sort(std::begin(who), std::end(who), compare_monster_level);
+
+
+ /* Start at the end */
+ i = who.size() - 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 == '-')
+ {
+ i++;
+ assert(i >= 0);
+ if (static_cast<size_t>(i) == who.size())
+ {
+ i = 0;
+ }
+ }
+
+ /* Move to "next" monster */
+ else
+ {
+ if (i-- == 0)
+ {
+ i = who.size() - 1;
+ }
+ }
+ }
+
+
+ /* Re-display the identity */
+ /* prt(buf, 5, 5);*/
+
+ /* 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;
+}
+
+
+/*
+ * 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 = strdup(temp);
+ }
+ else
+ {
+ cli_ptr->comm = strdup(trigger);
+ }
+
+ /* First try copying everything across. */
+ cli_ptr->key = num;
+ cli_ptr->descrip = nullptr;
+ if (descr) {
+ cli_ptr->descrip = strdup(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.
+ */
+static 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 */
+ res = askfor_aux_with_completion(buf, len);
+
+ /* 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);
+ 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);
+ Term_fresh();
+ return;
+ }
+ }
+
+ /* Now restore the screen to dump it */
+ Term_load_from(save);
+
+ 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/cmd3.hpp b/src/cmd3.hpp
new file mode 100644
index 00000000..48677b77
--- /dev/null
+++ b/src/cmd3.hpp
@@ -0,0 +1,24 @@
+#pragma once
+
+#include "h-basic.h"
+
+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);
diff --git a/src/cmd4.c b/src/cmd4.c
deleted file mode 100644
index c4440428..00000000
--- a/src/cmd4.c
+++ /dev/null
@@ -1,4658 +0,0 @@
-/* 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/cmd4.cc b/src/cmd4.cc
new file mode 100644
index 00000000..4b6c040c
--- /dev/null
+++ b/src/cmd4.cc
@@ -0,0 +1,4415 @@
+/*
+ * 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 "cmd4.hpp"
+
+#include "artifact_type.hpp"
+#include "cave_type.hpp"
+#include "corrupt.hpp"
+#include "dungeon_info_type.hpp"
+#include "feature_type.hpp"
+#include "files.hpp"
+#include "hooks.hpp"
+#include "init1.hpp"
+#include "levels.hpp"
+#include "messages.hpp"
+#include "monster2.hpp"
+#include "monster_race.hpp"
+#include "monster_type.hpp"
+#include "notes.hpp"
+#include "object1.hpp"
+#include "object2.hpp"
+#include "object_kind.hpp"
+#include "player_type.hpp"
+#include "skills.hpp"
+#include "squeltch.hpp"
+#include "tables.hpp"
+#include "town_type.hpp"
+#include "trap_type.hpp"
+#include "util.hpp"
+#include "util.h"
+#include "variable.h"
+#include "variable.hpp"
+#include "xtra1.hpp"
+#include "z-rand.hpp"
+
+#include <cassert>
+#include <memory>
+#include <string>
+#include <vector>
+#include <algorithm>
+
+/*
+ * 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_FRAME | 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_FRAME | 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;
+}
+
+// File-local
+namespace {
+
+ /**
+ * Interaction mode for options
+ */
+ enum class interaction_mode_t {
+ READ_ONLY = 0,
+ READ_WRITE = 1
+ };
+
+}
+
+/**
+ * Interact with given vector of options.
+ */
+static void interact_with_options(std::vector<option_type *> const &options, char const *info, interaction_mode_t interaction_mode)
+{
+ size_t n = options.size();
+
+ /* Clear screen */
+ Term_clear();
+
+ /* Interact with the player */
+ size_t k = 0; /* Currently selected option index */
+ while (TRUE)
+ {
+ /* Prompt XXX XXX XXX */
+ char buf[80];
+ strnfmt(buf, 80, "%s (RET to advance, y/n to set, ESC to accept) ", info);
+ prt(buf, 0, 0);
+
+ /* Display the options */
+ for (size_t 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)",
+ options[i]->o_desc,
+ (*options[i]->o_var ? "yes" : "no "),
+ options[i]->o_text);
+ c_prt(a, buf, i + 2, 0);
+ }
+
+ /* Hilite current option */
+ move_cursor(k + 2, 50);
+
+ /* Get a key */
+ int ch = inkey();
+
+ /*
+ * Hack -- Try to translate the key into a direction
+ * to allow the use of roguelike keys for navigation
+ */
+ {
+ int 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':
+ {
+ /* Adding n pre-modulo ensures that we don't
+ wrap around to the wrong (post-modulo) index. */
+ 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 (interaction_mode == interaction_mode_t::READ_ONLY)
+ {
+ break;
+ }
+ *(options[k]->o_var) = TRUE;
+ k = (k + 1) % n;
+ break;
+ }
+
+ case 'n':
+ case 'N':
+ case '4':
+ {
+ if (interaction_mode == interaction_mode_t::READ_ONLY)
+ {
+ break;
+ }
+
+ *(options[k]->o_var) = FALSE;
+ k = (k + 1) % n;
+ break;
+ }
+
+ default:
+ {
+ bell();
+
+ break;
+ }
+ }
+ }
+
+
+}
+
+
+
+/*
+ * Cheating options
+ */
+static option_type cheat_info[6] =
+{
+ { &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)
+{
+ // Calculate number of cheat options
+ size_t n = std::distance(std::begin(cheat_info), std::end(cheat_info));
+
+ // Build the vector of options we're going to interact with
+ std::vector<option_type *> options;
+ options.reserve(n);
+ for (auto &option : cheat_info)
+ {
+ options.push_back(&option);
+ }
+
+ // Interact
+ interact_with_options(options, info, interaction_mode_t::READ_WRITE);
+
+ // If user toggled any of the options to TRUE, then we add those cheats
+ // to the player's "noscore" flags. Note that it doesn't matter what the
+ // previous value was -- we don't "unset" noscore flags anyway.
+ for (auto &option: options)
+ {
+ if (*option->o_var)
+ {
+ noscore |= (option->o_page * 256 + option->o_bit);
+ }
+ }
+}
+
+
+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;
+ }
+ }
+ }
+}
+
+/*
+ * Interact with some options
+ */
+void do_cmd_options_aux(int page, cptr info, bool_ read_only)
+{
+ // Scrape together all the options from the relevant page.
+ std::vector<option_type *> options;
+ options.reserve(64); // Seems a reasonable number; anything more would be unusable anyway
+ for (size_t i = 0; option_info[i].o_desc; i++)
+ {
+ if (option_info[i].o_page == page)
+ {
+ options.push_back(&option_info[i]);
+ }
+ }
+
+ // Interact with the options
+ interaction_mode_t interaction_mode = read_only
+ ? interaction_mode_t::READ_ONLY
+ : interaction_mode_t::READ_WRITE;
+ interact_with_options(options, info, interaction_mode);
+}
+
+
+/*
+ * 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);
+
+ /* 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();
+}
+
+
+
+/*
+ * 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);
+
+ /* 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;
+
+ /* Attempt to read a key */
+ i = inkey_scan();
+ }
+
+ /* 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);
+
+ /* 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();
+
+
+ /* 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);
+
+ /* Make new keymap */
+ free(keymap_act[mode][(byte)(buf[0])]);
+ keymap_act[mode][(byte)(buf[0])] = strdup(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);
+
+ /* Make new keymap */
+ free(keymap_act[mode][(byte)(buf[0])]);
+ 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];
+
+
+ /* 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_ptr->name);
+
+ /* Dump the monster attr/char info */
+ fprintf(fff, "R:%d:0x%02X:0x%02X\n\n", i,
+ static_cast<unsigned int>(r_ptr->x_attr),
+ static_cast<unsigned int>(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_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_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_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);
+
+ /* 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);
+
+ /* 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 = (ca + 1);
+ if (i == 'A') r_ptr->x_attr = (ca - 1);
+ if (i == 'c') r_ptr->x_char = (cc + 1);
+ if (i == 'C') r_ptr->x_char = (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 = k_ptr->d_attr;
+ char dc = k_ptr->d_char;
+ byte ca = k_ptr->x_attr;
+ char cc = k_ptr->x_char;
+
+ /* Label the object */
+ Term_putstr(5, 17, -1, TERM_WHITE,
+ format("Object = %d, Name = %-40.40s",
+ k, 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);
+
+ /* 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);
+
+ /* 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 = (ca + 1);
+ if (i == 'A') k_info[k].x_attr = (ca - 1);
+ if (i == 'c') k_info[k].x_char = (cc + 1);
+ if (i == 'C') k_info[k].x_char = (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 = f_ptr->d_attr;
+ char dc = f_ptr->d_char;
+ byte ca = f_ptr->x_attr;
+ char cc = f_ptr->x_char;
+
+ /* Label the object */
+ Term_putstr(5, 17, -1, TERM_WHITE,
+ format("Terrain = %d, Name = %-40.40s",
+ f, 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);
+
+ /* 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);
+
+ /* 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 = (ca + 1);
+ if (i == 'A') f_info[f].x_attr = (ca - 1);
+ if (i == 'c') f_info[f].x_char = (cc + 1);
+ if (i == 'C') f_info[f].x_char = (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];
+
+
+ /* 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 = (a + 1);
+ if (i == 'N') a = (a - 1);
+ if (i == 'k') angband_color_table[a][0] = (angband_color_table[a][0] + 1);
+ if (i == 'K') angband_color_table[a][0] = (angband_color_table[a][0] - 1);
+ if (i == 'r') angband_color_table[a][1] = (angband_color_table[a][1] + 1);
+ if (i == 'R') angband_color_table[a][1] = (angband_color_table[a][1] - 1);
+ if (i == 'g') angband_color_table[a][2] = (angband_color_table[a][2] + 1);
+ if (i == 'G') angband_color_table[a][2] = (angband_color_table[a][2] - 1);
+ if (i == 'b') angband_color_table[a][3] = (angband_color_table[a][3] + 1);
+ if (i == 'B') angband_color_table[a][3] = (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;
+
+ /* Add note to file */
+ add_note(buf, ' ');
+}
+
+
+/*
+ * Mention the current version
+ */
+void do_cmd_version(void)
+{
+ /* Silly message */
+ msg_format("You are playing %s made by %s (%s).",
+ get_version_string(),
+ modules[game_module_idx].meta.author.name,
+ modules[game_module_idx].meta.author.email);
+}
+
+
+
+/*
+ * 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_new(HOOK_FEELING, NULL, NULL))
+ {
+ 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;
+}
+
+
+
+/*
+ * Hack -- save a screen dump to a file
+ */
+void do_cmd_save_screen(void)
+{
+ 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");
+
+ /* 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];
+
+ /* Temporary file */
+ if (path_temp(file_name, 1024)) return;
+
+ /* Open a new file */
+ fff = my_fopen(file_name, "w");
+
+ /* Scan the artifacts */
+ std::unique_ptr<bool_[]> okay(new bool_[max_a_idx]);
+ 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;
+ }
+
+ std::unique_ptr<bool_[]> okayk(new bool_[max_k_idx]);
+ 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];
+
+ /* Scan all objects in the grid */
+ for (auto const this_o_idx: c_ptr->o_idxs)
+ {
+ /* Acquire object */
+ object_type const * o_ptr = &o_list[this_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++)
+ {
+ /* Scan all objects the monster carries */
+ for (auto const this_o_idx: m_list[i].hold_o_idxs)
+ {
+ object_type * o_ptr;
+
+ /* Acquire object */
+ o_ptr = &o_list[this_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);
+}
+
+
+/*
+ * 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_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);
+}
+
+
+static int monster_get_race_level(int r_idx) {
+ /* Hack -- Morgoth is always last */
+ if (r_idx == 862) {
+ return 20000;
+ }
+ /* Otherwise, we'll use the real level. */
+ return r_info[r_idx].level;
+}
+
+static bool compare_monster_level(int r_idx1, int r_idx2) {
+ return monster_get_race_level(r_idx1) < monster_get_race_level(r_idx2);
+}
+
+/*
+ * Display known uniques
+ *
+ * Note that the player ghosts are ignored. XXX XXX XXX
+ */
+static void do_cmd_knowledge_uniques(void)
+{
+ int k;
+
+ 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");
+
+ // Extract the unique race indexes.
+ std::vector<int> unique_r_idxs;
+ 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))
+ {
+ unique_r_idxs.push_back(k);
+ }
+ }
+
+ // Sort races by level.
+ std::sort(std::begin(unique_r_idxs),
+ std::end(unique_r_idxs),
+ compare_monster_level);
+
+ /* Scan the monster races */
+ for (int r_idx : unique_r_idxs)
+ {
+ monster_race *r_ptr = &r_info[r_idx];
+
+ /* 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)
+ {
+ fprintf(fff, "[[[[[%c%c] [[[[[R%-68s is dead]\n",
+ conv_color[r_ptr->d_attr],
+ r_ptr->d_char,
+ r_ptr->name);
+ }
+ else
+ {
+ fprintf(fff, "[[[[[%c%c] [[[[[w%-68s is alive]\n",
+ conv_color[r_ptr->d_attr],
+ r_ptr->d_char,
+ r_ptr->name);
+ }
+ }
+ }
+ }
+
+ /* 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);
+}
+
+
+static 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)
+ {
+ auto const r_ptr = m_ptr->race();
+
+ t_friends++;
+ t_levels += m_ptr->level;
+
+ char pet_name[80];
+ 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 " FMTs32b " enemies.\n\n", 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_ptr->name);
+ Total++;
+ }
+ }
+ else
+ {
+ s16b This = r_ptr->r_pkills;
+
+ if (This > 0)
+ {
+ if (This < 2)
+ {
+ if (strstr(r_ptr->name, "coins"))
+ {
+ fprintf(fff, " 1 pile of %s\n", r_ptr->name);
+ }
+ else
+ {
+ fprintf(fff, " 1 %s\n", r_ptr->name);
+ }
+ }
+ else
+ {
+ char to_plural[80];
+ strcpy(to_plural, r_ptr->name);
+ plural_aux(to_plural);
+ fprintf(fff, " %d %s\n", This, to_plural);
+ }
+
+ Total += This;
+ }
+ }
+ }
+
+ fprintf(fff, "----------------------------------------------\n");
+ fprintf(fff, " Total: " FMTs32b " creature%s killed.\n", 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_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_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
+ */
+static 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, FALSE);
+ }
+
+ /* 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[MAX_Q_IDX] = { };
+
+ 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");
+
+ 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 descriptions */
+ if (quest[i].gen_desc != NULL)
+ {
+ if (!quest[i].gen_desc(fff))
+ {
+ continue;
+ }
+ }
+
+ /* 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");
+ }
+ }
+ }
+
+ /* 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;
+
+
+ /* 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);
+ 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':
+ {
+ do_cmd_knowledge_notes();
+
+ 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)
+{
+ /* 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 hour = bst(HOUR, turn);
+
+ int min = bst(MINUTE, turn);
+
+ int full = hour * 100 + min;
+
+ 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.");
+
+ /* Display day */
+ u32b days = bst(DAY, turn) + 1;
+ msg_format("This is the %s day of your adventure.",
+ get_day(days));
+
+ /* 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
+ */
+
+std::string *macro_recorder_current = nullptr;
+
+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.");
+ assert (macro_recorder_current == nullptr);
+ macro_recorder_current = new std::string();
+}
+
+void macro_recorder_add(char c)
+{
+ // Gets called unconditionally for all input, so ignore unless
+ // we're actual recording.
+ if (macro_recorder_current) {
+ macro_recorder_current->push_back(c);
+ }
+}
+
+void macro_recorder_stop()
+{
+ assert(macro_recorder_current != nullptr);
+
+ // Remove the last key, because it is the key to stop recording
+ macro_recorder_current->pop_back();
+
+ // Copy out current macro text.
+ std::string macro(*macro_recorder_current);
+
+ // Stop recording.
+ delete macro_recorder_current;
+ macro_recorder_current = nullptr;
+
+ /* Add it */
+ if (get_check("Are you satisfied and want to create the macro? "))
+ {
+ char buf[1024];
+
+ prt("Trigger: ", 0, 0);
+
+ /* Get a macro trigger */
+ do_cmd_macro_aux(buf, FALSE);
+
+ /* Link the macro */
+ macro_add(buf, macro.c_str());
+
+ /* Prompt */
+ std::unique_ptr<char[]> str(new char[(macro.length() + 1) * 3]);
+ str[0] = '\0';
+ ascii_to_text(str.get(), macro.c_str());
+ msg_format("Added a macro '%s'. If you want it to stay permanently, press @ now and dump macros to a file.", str.get());
+ }
+}
+
+void do_cmd_macro_recorder()
+{
+ if (macro_recorder_current == NULL)
+ macro_recorder_start();
+ else
+ macro_recorder_stop();
+}
diff --git a/src/cmd4.hpp b/src/cmd4.hpp
new file mode 100644
index 00000000..4470c94f
--- /dev/null
+++ b/src/cmd4.hpp
@@ -0,0 +1,28 @@
+#pragma once
+
+#include "h-basic.h"
+
+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 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);
diff --git a/src/cmd5.c b/src/cmd5.c
deleted file mode 100644
index b415b166..00000000
--- a/src/cmd5.c
+++ /dev/null
@@ -1,2562 +0,0 @@
-/* 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/cmd5.cc b/src/cmd5.cc
new file mode 100644
index 00000000..a1dd5cbf
--- /dev/null
+++ b/src/cmd5.cc
@@ -0,0 +1,2214 @@
+/*
+ * 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 "cmd5.hpp"
+
+#include "birth.hpp"
+#include "cave.hpp"
+#include "cave_type.hpp"
+#include "corrupt.hpp"
+#include "lua_bind.hpp"
+#include "monster2.hpp"
+#include "monster_race.hpp"
+#include "object1.hpp"
+#include "object2.hpp"
+#include "object_type.hpp"
+#include "player_class.hpp"
+#include "player_race.hpp"
+#include "player_race_mod.hpp"
+#include "player_type.hpp"
+#include "school_book.hpp"
+#include "skills.hpp"
+#include "spell_type.hpp"
+#include "spells1.hpp"
+#include "spells2.hpp"
+#include "spells4.hpp"
+#include "spells5.hpp"
+#include "stats.hpp"
+#include "tables.hpp"
+#include "util.hpp"
+#include "util.h"
+#include "variable.h"
+#include "variable.hpp"
+#include "quark.hpp"
+#include "wizard2.hpp"
+#include "xtra1.hpp"
+#include "xtra2.hpp"
+#include "z-rand.hpp"
+
+#include <boost/noncopyable.hpp>
+#include <boost/optional.hpp>
+#include <cassert>
+
+/* Maximum number of tries for teleporting */
+#define MAX_TRIES 300
+
+static object_filter_t const &is_school_book()
+{
+ using namespace object_filter;
+ static auto instance = Or(
+ TVal(TV_BOOK),
+ TVal(TV_DAEMON_BOOK),
+ TVal(TV_INSTRUMENT));
+ return instance;
+}
+
+/* Does it contains a schooled spell ? */
+static object_filter_t const &hook_school_spellable()
+{
+ using namespace object_filter;
+ static auto has_pval2 =
+ [=](object_type const *o_ptr) -> bool {
+ return (o_ptr->pval2 != -1);
+ };
+ static auto instance = Or(
+ is_school_book(),
+ And(
+ HasFlag5(TR5_SPELL_CONTAIN),
+ has_pval2));
+ return instance;
+}
+
+/* Is it a browsable for spells? */
+static object_filter_t const &item_tester_hook_browsable()
+{
+ using namespace object_filter;
+ static auto instance = Or(
+ hook_school_spellable(),
+ TVal(TV_BOOK));
+ return instance;
+}
+
+/*
+ * 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);
+}
+
+
+static int print_book(s16b sval, s32b spell_idx, object_type *obj)
+{
+ int y = 2;
+ int i;
+
+ random_book_setup(sval, spell_idx);
+
+ school_book *school_book = school_books_at(sval);
+
+ /* Parse all spells */
+ i = 0;
+ for (auto spell_idx : school_book->spell_idxs)
+ {
+ byte color = TERM_L_DARK;
+ bool_ is_ok;
+ char label[8];
+
+ is_ok = is_ok_spell(spell_idx, obj->pval);
+ if (is_ok)
+ {
+ color = (get_mana(spell_idx) > get_power(spell_idx)) ? TERM_ORANGE : TERM_L_GREEN;
+ }
+
+ sprintf(label, "%c) ", 'a' + i);
+
+ y = print_spell(label, color, y, spell_idx);
+ i++;
+ }
+
+ prt(format(" %-20s%-16s Level Cost Fail Info", "Name", "School"), 1, 0);
+ return y;
+}
+
+
+
+static void browse_school_spell(int book, int spell_idx, object_type *o_ptr)
+{
+ int i;
+ int num = 0;
+ int ask;
+ char choice;
+ char out_val[160];
+
+ /* Show choices */
+ window_stuff();
+
+ num = school_book_length(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 */
+ print_book(book, spell_idx, o_ptr);
+
+ /* Get a spell from the user */
+ while (get_com(out_val, &choice))
+ {
+ /* Display a list of spells */
+ print_book(book, spell_idx, o_ptr);
+
+ /* 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 */
+ auto where = print_book(book, spell_idx, o_ptr);
+ print_spell_desc(spell_x(book, spell_idx, i), where);
+ }
+
+
+ /* Restore the screen */
+ Term_load();
+ character_icky = FALSE;
+
+ /* Show choices */
+ window_stuff();
+}
+
+
+/*
+ * 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)
+{
+ /* Get an item */
+ int item;
+ if (!get_item(&item,
+ "Browse which book? ",
+ "You have no books that you can read.",
+ (USE_INVEN | USE_EQUIP | USE_FLOOR),
+ item_tester_hook_browsable()))
+ {
+ return;
+ }
+
+ /* Get the item */
+ object_type *o_ptr = get_object(item);
+
+ do_cmd_browse_aux(o_ptr);
+}
+
+static void do_poly_wounds()
+{
+ /* 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();
+ }
+
+ /*
+ * 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(*race_info[new_race].title)) ? "n" : ""),
+ race_info[new_race].title);
+ }
+ 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_FRAME);
+
+ 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;
+ gain_random_corruption();
+ }
+
+ 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--;
+ }
+}
+
+/*
+ * Fetch an item (teleport it right underneath the caster)
+ */
+void fetch(int dir, int wgt, bool_ require_los)
+{
+ /* Check to see if an object is already there */
+ if (!cave[p_ptr->py][p_ptr->px].o_idxs.empty())
+ {
+ msg_print("You can't fetch when you're already standing on something.");
+ return;
+ }
+
+ /* Use a target */
+ cave_type *c_ptr = nullptr;
+ if ((dir == 5) && target_okay())
+ {
+ int tx = target_col;
+ int 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_idxs.empty())
+ {
+ 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 */
+ int ty = p_ptr->py; /* Where to drop the item */
+ int 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_idxs.empty()) break;
+ }
+ }
+
+ assert(c_ptr != nullptr);
+ assert(!c_ptr->o_idxs.empty());
+
+ /* Pick object from the list */
+ auto o_idx = c_ptr->o_idxs.front();
+
+ object_type *o_ptr = &o_list[o_idx];
+ if (o_ptr->weight > wgt)
+ {
+ /* Too heavy to 'fetch' */
+ msg_print("The object is too heavy.");
+ return;
+ }
+
+ /* Move the object between the lists */
+ c_ptr->o_idxs.erase(c_ptr->o_idxs.begin()); // Remove
+ cave[p_ptr->py][p_ptr->px].o_idxs.push_back(o_idx); // Add
+
+ /* Update object's location */
+ o_ptr->iy = p_ptr->py;
+ o_ptr->ix = p_ptr->px;
+
+ /* Feedback */
+ char o_name[80];
+ 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;
+ }
+ }
+}
+
+/*
+ * 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_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_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;
+
+ 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;
+
+ /* 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, ESC=exit) Use which power of your %s? ",
+ label, (no_cost ? "symbiote" : "body"));
+
+ /* Save the screen */
+ character_icky = TRUE;
+ Term_save();
+
+ /* Get a spell from the user */
+ while (!flag)
+ {
+ /* Show the list */
+ {
+ byte y = 1, x = 0;
+ int ctr = 0;
+ char dummy[80];
+
+ strcpy(dummy, "");
+
+ 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);
+ }
+ }
+
+ if (!get_com(out_val, &choice))
+ {
+ flag = FALSE;
+ break;
+ }
+
+ 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 */
+ 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_FRAME);
+
+ /* 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 s32b hack_force_spell_pval = -1;
+
+boost::optional<int> get_item_hook_find_spell(object_filter_t const &)
+{
+ char buf[80];
+ strcpy(buf, "Manathrust");
+ if (!get_string("Spell name? ", buf, 79))
+ {
+ return boost::none;
+ }
+
+ int const spell = find_spell(buf);
+ if (spell == -1)
+ {
+ return boost::none;
+ }
+
+ for (int i = 0; i < INVEN_TOTAL; i++)
+ {
+ object_type *o_ptr = &p_ptr->inventory[i];
+
+ /* Extract object flags */
+ u32b f1, f2, f3, f4, f5, esp;
+ object_flags(o_ptr, &f1, &f2, &f3, &f4, &f5, &esp);
+
+ /* Must we wield it to cast from it? */
+ 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))
+ {
+ /* Does it contain the appropriate spell? */
+ if ((f5 & TR5_SPELL_CONTAIN) && (o_ptr->pval2 == spell))
+ {
+ hack_force_spell = spell;
+ hack_force_spell_pval = o_ptr->pval;
+ return i;
+ }
+ }
+ /* A random book ? */
+ else if (school_book_contains_spell(o_ptr->sval, spell))
+ {
+ hack_force_spell = spell;
+ hack_force_spell_pval = o_ptr->pval;
+ return i;
+ }
+ }
+
+ return boost::none;
+}
+
+/*
+ * Is the spell castable?
+ */
+bool_ is_ok_spell(s32b spell_idx, s32b pval)
+{
+ spell_type *spell = spell_at(spell_idx);
+
+ // Calculate availability based on caster's skill level.
+ s32b level;
+ bool_ na;
+ get_level_school(spell, 50, 0, &level, &na);
+ if (na || (level == 0))
+ {
+ return FALSE;
+ }
+ // Are we permitted to cast based on item pval? Only music
+ // spells have non-zero minimum PVAL.
+ if (pval < spell_type_minimum_pval(spell))
+ {
+ return FALSE;
+ }
+ // OK, we're permitted to cast it.
+ return TRUE;
+}
+
+
+/*
+ * Get a spell from a book
+ */
+s32b get_school_spell(cptr do_what, s16b force_book)
+{
+ int i, item;
+ s32b spell = -1;
+ int num = 0;
+ s32b where = 1;
+ int ask;
+ bool_ flag;
+ char out_val[160];
+ object_type *o_ptr, forge;
+ int tmp;
+ int sval, pval;
+ u32b f1, f2, f3, f4, f5, esp;
+
+ hack_force_spell = -1;
+ hack_force_spell_pval = -1;
+
+ /* Ok do we need to ask for a book ? */
+ if (!force_book)
+ {
+ char buf2[40];
+ char buf3[40];
+ 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,
+ hook_school_spellable(),
+ get_item_hook_find_spell))
+ {
+ 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;
+
+ /* Show choices */
+ 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;
+ }
+
+ /* Save the screen */
+ character_icky = TRUE;
+ Term_save();
+
+ /* Go */
+ if (hack_force_spell == -1)
+ {
+ num = school_book_length(sval);
+
+ /* Build a prompt (accept all spells) */
+ strnfmt(out_val, 78, "(Spells %c-%c, Descs %c-%c, 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)
+ {
+ char choice;
+
+ /* Restore and save screen; this prevents
+ subprompt from leaving garbage when going
+ around the loop multiple times. */
+ Term_load();
+ Term_save();
+
+ /* Display a list of spells */
+ where = print_book(sval, pval, o_ptr);
+
+ /* Input */
+ if (!get_com(out_val, &choice))
+ {
+ flag = FALSE;
+ break;
+ }
+
+ /* 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)
+ {
+ /* Display a list of spells */
+ where = print_book(sval, pval, o_ptr);
+ print_spell_desc(spell_x(sval, pval, i), where);
+ }
+ else
+ {
+ bool_ ok;
+
+ /* Save the spell index */
+ spell = spell_x(sval, pval, i);
+
+ /* Do we need to do some pre test */
+ ok = is_ok_spell(spell, o_ptr->pval);
+
+ /* 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
+ {
+ bool_ ok;
+
+ /* Require "okay" spells */
+ ok = is_ok_spell(hack_force_spell, hack_force_spell_pval);
+ 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 */
+ Term_load();
+ character_icky = FALSE;
+
+
+ /* Show choices */
+ 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", 0);
+
+ /* Actualy cast the choice */
+ if (spell != -1)
+ {
+ lua_cast_school_spell(spell, FALSE);
+ }
+}
+
+/* Can it contains a schooled spell ? */
+static bool hook_school_can_spellable(object_type const *o_ptr)
+{
+ u32b f1, f2, f3, f4, f5, esp;
+ object_flags(o_ptr, &f1, &f2, &f3, &f4, &f5, &esp);
+
+ return ((f5 & TR5_SPELL_CONTAIN) && (o_ptr->pval2 == -1));
+}
+
+/*
+ * Copy a spell from a bok to an object
+ */
+void do_cmd_copy_spell()
+{
+ int spell = get_school_spell("copy", 0);
+ int item;
+
+ if (spell == -1) return;
+
+ /* Spells that cannot be randomly created cannot be copied */
+ if (spell_type_random_type(spell_at(spell)) <= 0)
+ {
+ msg_print("This spell cannot be copied.");
+ return;
+ }
+
+ if (!get_item(&item,
+ "Copy to which object? ",
+ "You have no object to copy to.",
+ (USE_INVEN | USE_EQUIP),
+ hook_school_can_spellable)) return;
+ object_type *o_ptr = get_object(item);
+
+ msg_print("You copy the spell!");
+ o_ptr->pval2 = spell;
+ inven_item_describe(item);
+}
diff --git a/src/cmd5.hpp b/src/cmd5.hpp
new file mode 100644
index 00000000..1b3b062a
--- /dev/null
+++ b/src/cmd5.hpp
@@ -0,0 +1,16 @@
+#pragma once
+
+#include "h-basic.h"
+#include "object_type_fwd.hpp"
+
+extern bool_ is_magestaff(void);
+extern void do_cmd_browse_aux(object_type *o_ptr);
+extern void do_cmd_browse(void);
+extern void fetch(int dir, int wgt, bool_ require_los);
+extern void do_poly_self(void);
+extern cptr symbiote_name(bool_ capitalize);
+extern int use_symbiotic_power(int r_idx, bool_ great, bool_ only_number, bool_ no_cost);
+extern bool_ is_ok_spell(s32b spell_idx, s32b pval);
+extern s32b get_school_spell(cptr do_what, s16b force_book);
+extern void do_cmd_copy_spell(void);
+extern void cast_school_spell(void);
diff --git a/src/cmd6.c b/src/cmd6.c
deleted file mode 100644
index db89c465..00000000
--- a/src/cmd6.c
+++ /dev/null
@@ -1,7731 +0,0 @@
-/* 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/cmd6.cc b/src/cmd6.cc
new file mode 100644
index 00000000..0a5595fa
--- /dev/null
+++ b/src/cmd6.cc
@@ -0,0 +1,7928 @@
+/*
+ * 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 "cmd6.hpp"
+
+#include "artifact_type.hpp"
+#include "cave.hpp"
+#include "cave_type.hpp"
+#include "cmd1.hpp"
+#include "cmd7.hpp"
+#include "corrupt.hpp"
+#include "dungeon_info_type.hpp"
+#include "ego_item_type.hpp"
+#include "files.hpp"
+#include "hook_eat_in.hpp"
+#include "hook_eat_out.hpp"
+#include "hooks.hpp"
+#include "lua_bind.hpp"
+#include "mimic.hpp"
+#include "monster2.hpp"
+#include "monster_race.hpp"
+#include "monster_type.hpp"
+#include "object1.hpp"
+#include "object2.hpp"
+#include "object_kind.hpp"
+#include "object_type.hpp"
+#include "options.hpp"
+#include "player_type.hpp"
+#include "randart.hpp"
+#include "skills.hpp"
+#include "spell_type.hpp"
+#include "spells1.hpp"
+#include "spells2.hpp"
+#include "spells5.hpp"
+#include "stats.hpp"
+#include "store.hpp"
+#include "tables.hpp"
+#include "util.hpp"
+#include "variable.h"
+#include "variable.hpp"
+#include "wild.hpp"
+#include "wizard2.hpp"
+#include "xtra1.hpp"
+#include "xtra2.hpp"
+#include "z-rand.hpp"
+
+#include <boost/algorithm/string/predicate.hpp>
+#include <cassert>
+
+using boost::algorithm::iequals;
+
+/*
+ * Forward declare
+ */
+static bool_ activate_spell(object_type * o_ptr, byte choice);
+
+
+/*
+ * General function to find an item by its name
+ */
+static select_by_name_t select_object_by_name(std::string const &prompt)
+{
+ return [=](object_filter_t const &filter) -> boost::optional<int> {
+ // Ask for the name of the object we want to select
+ char buf[80] = "";
+ if (!get_string(prompt.c_str(), buf, 79))
+ {
+ return boost::none;
+ }
+ // Named objects must be in the inventory
+ for (size_t i = 0; i < INVEN_TOTAL; i++)
+ {
+ object_type *o_ptr = get_object(i);
+ // Must have an actual item in the slot
+ if (!o_ptr->k_idx)
+ {
+ continue;
+ }
+ // Must pass the filter
+ if (!filter(o_ptr))
+ {
+ continue;
+ }
+ // Check against the name of the object
+ // ignoring case.
+ char buf2[100];
+ object_desc(buf2, o_ptr, -1, 0);
+ if (iequals(buf, buf2))
+ {
+ return i;
+ }
+ }
+ // No match
+ return boost::none;
+ };
+}
+
+
+/*
+ * 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(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 object_filter_t const &item_tester_hook_eatable()
+{
+ using namespace object_filter;
+ static auto instance =
+ Or(
+ TVal(TV_FOOD),
+ TVal(TV_CORPSE));
+ return instance;
+}
+
+
+/*
+ * Eat some food (from the pack or floor)
+ */
+void do_cmd_eat_food(void)
+{
+ int ident, lev, fval = 0;
+
+ object_type *q_ptr, forge;
+
+ monster_race *r_ptr;
+
+ bool_ destroy = TRUE;
+
+ /* Get an item */
+ int item;
+ if (!get_item(&item,
+ "Eat which item? ",
+ "You have nothing to eat.",
+ (USE_INVEN | USE_FLOOR),
+ item_tester_hook_eatable(),
+ select_object_by_name("Food full name? ")))
+ {
+ return;
+ }
+
+ /* Get the item */
+ object_type *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 */
+ hook_eat_in in = { o_ptr };
+ hook_eat_out out = { FALSE };
+ if (process_hooks_new(HOOK_EAT, &in, &out))
+ {
+ ident = out.ident;
+ }
+ /* (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(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))
+ {
+ p_ptr->powers_mod[PWR_GROW_MOLD] = TRUE;
+ 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 ((race_flags1_p(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 (race_flags1_p(PR1_NO_FOOD))
+ {
+ if (race_flags1_p(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;
+
+ /* Get an item */
+ if (!get_item(&item,
+ "Hack up which corpse? ",
+ "You have no corpses.",
+ (USE_INVEN | USE_FLOOR),
+ object_filter::TVal(TV_CORPSE)))
+ {
+ return;
+ }
+
+ /* Get the item */
+ object_type *o_ptr = get_object(item);
+
+ monster_race *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 */
+ object_type object_type_body;
+ object_type *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 *i_ptr;
+
+ /* Get some meat */
+ if (!get_item(&item,
+ "Cure which meat? ",
+ "You have no meat to cure.",
+ (USE_INVEN | USE_FLOOR),
+ object_filter::And(item_tester_hook_eatable(), object_filter::TVal(TV_CORPSE))))
+ {
+ return;
+ }
+
+ /* Get the item */
+ object_type *o_ptr = get_object(item);
+
+ /* Get a potion */
+ if (!get_item(&item,
+ "Use which potion? ",
+ "You have no potions to use.",
+ (USE_INVEN | USE_FLOOR),
+ object_filter::TVal(TV_POTION))) 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;
+
+ cptr q = "You soak the meat.";
+ cptr 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 object_filter_t const &item_tester_hook_quaffable()
+{
+ using namespace object_filter;
+ static auto instance = Or(
+ TVal(TV_POTION),
+ TVal(TV_POTION2));
+ return instance;
+}
+
+
+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(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(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_FRAME);
+ 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)
+ {
+ msg_print("You feel more experienced.");
+ gain_exp(100000L);
+ 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:
+ {
+ /* In Theme, Melkor likes players who quaff
+ potions of corruption. */
+ if (game_module_idx == MODULE_THEME)
+ {
+ if (p_ptr->pgod == GOD_MELKOR)
+ {
+ msg_print("Your quaffing of this potion pleases Melkor!");
+ set_grace(p_ptr->grace + 2);
+ }
+ }
+
+ msg_print("You feel the dark corruptions of Morgoth coming over you!");
+ gain_random_corruption();
+ 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 = get_mimic_random_duration(pval2);
+
+ set_mimic(time, pval2, (p_ptr->lev * 2) / 3);
+
+ /* Redraw title */
+ p_ptr->redraw |= (PR_FRAME);
+
+ /* 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 ident, lev;
+
+ /* Get an item */
+ int item;
+ if (!get_item(&item,
+ "Quaff which potion? ",
+ "You have no potions to quaff.",
+ (USE_INVEN | USE_FLOOR),
+ item_tester_hook_quaffable(),
+ select_object_by_name("Potion full name? ")))
+ {
+ return;
+ }
+
+ /* Get the item */
+ object_type *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;
+
+ /* Demon Breath corruption can spoil potions. */
+ if (player_has_corruption(CORRUPT_DEMON_BREATH) && magik(9))
+ {
+ msg_print("Your demon breath spoils the potion!");
+ ident = FALSE;
+ }
+ else
+ {
+ /* Normal potion handling */
+ 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);
+ }
+
+ /* 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);
+}
+
+
+/*
+ * Fill an empty bottle
+ */
+static 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, forge;
+
+ /* 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;
+ }
+
+ /* Get an item */
+ if (!get_item(&item,
+ "Fill which bottle? ",
+ "You have no bottles to fill.",
+ (USE_INVEN),
+ object_filter::TVal(TV_BOTTLE)))
+ {
+ return;
+ }
+
+ object_type *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;
+}
+
+
+/*
+ * 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;
+ }
+}
+
+
+/*
+ * 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 object_filter_t const &item_tester_hook_readable()
+{
+ using namespace object_filter;
+ static auto instance =
+ Or(
+ TVal(TV_SCROLL),
+ TVal(TV_PARCHMENT));
+ return instance;
+}
+
+
+/*
+ * 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)
+{
+ /* 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;
+ }
+
+ /* Get an item */
+ int item;
+ if (!get_item(&item,
+ "Read which scroll? ",
+ "You have no scrolls to read.",
+ (USE_INVEN | USE_FLOOR),
+ item_tester_hook_readable(),
+ select_object_by_name("Scroll full name? ")))
+ {
+ return;
+ }
+
+ /* Get the item */
+ object_type *o_ptr = get_object(item);
+
+ /* Take a turn */
+ energy_use = 100;
+
+ /* Not identified yet */
+ int ident = FALSE;
+
+ /* Object level */
+ int lev = k_info[o_ptr->k_idx].level;
+
+ /* Assume the scroll will get used up */
+ int used_up = TRUE;
+
+ /* Corruption */
+ if (player_has_corruption(CORRUPT_BALROG_AURA) && magik(5))
+ {
+ msg_print("Your demon aura burns the scroll before you read it!");
+ used_up = TRUE;
+ ident = FALSE;
+ }
+
+ /* Scrolls */
+ else if (o_ptr->tval == TV_SCROLL)
+ {
+ /* Analyze the scroll */
+ switch (o_ptr->sval)
+ {
+ case SV_SCROLL_MASS_RESURECTION:
+ {
+ ident = TRUE;
+ msg_print("You feel the souls of the dead coming back "
+ "from the Halls of Mandos.");
+
+ for (int 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,
+ 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 (int 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 (int 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:
+ {
+ int 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);
+ }
+ 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;
+ }
+
+ case SV_SCROLL_STERILIZATION:
+ {
+ msg_print("A neutralising wave radiates from you!");
+ set_no_breeders(randint(100) + 100);
+
+ 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 */
+ cptr 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);
+}
+
+
+
+/* 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;
+ // Ensure that we're not assuming "reentrancy".
+ assert(get_level_use_stick < 0);
+ // Set up the casting mode
+ get_level_use_stick = bonus;
+ get_level_max_stick = max;
+}
+
+/* Remove 'stick mode' */
+void unset_stick_mode()
+{
+ // Ensure that we're not assuming "reentrancy".
+ assert(get_level_use_stick > 0);
+ // Unset the casting mode
+ get_level_use_stick = -1;
+ get_level_max_stick = -1;
+}
+
+
+/*
+ * Activate a device
+ */
+static void activate_stick(object_type *o_ptr, bool_ *obvious, bool_ *use_charge)
+{
+ spell_type *spell = spell_at(o_ptr->pval2);
+ casting_result ret;
+
+ assert(obvious != NULL);
+ assert(use_charge != NULL);
+
+ set_stick_mode(o_ptr);
+ ret = spell_type_produce_effect(spell);
+ unset_stick_mode();
+
+ switch (ret)
+ {
+ case NO_CAST:
+ *use_charge = FALSE;
+ *obvious = FALSE;
+ break;
+ case CAST_HIDDEN:
+ *use_charge = TRUE;
+ *obvious = FALSE;
+ break;
+ case CAST_OBVIOUS:
+ *use_charge = TRUE;
+ *obvious = TRUE;
+ break;
+ default:
+ assert(FALSE);
+ }
+}
+
+
+/*
+ * Use a staff. -RAK-
+ *
+ * One charge of one staff disappears.
+ *
+ * Hack -- staffs of identify can be "cancelled".
+ */
+void do_cmd_use_staff(void)
+{
+ bool_ obvious, use_charge;
+
+ u32b f1, f2, f3, f4, f5, esp;
+
+ /* No magic */
+ if (p_ptr->antimagic)
+ {
+ msg_print("Your anti-magic field disrupts any magic attempts.");
+ return;
+ }
+
+ /* Get an item */
+ int item;
+ if (!get_item(&item,
+ "Use which staff? ",
+ "You have no staff to use.",
+ (USE_INVEN | USE_FLOOR),
+ object_filter::TVal(TV_STAFF),
+ select_object_by_name("Staff full name? ")))
+ {
+ return;
+ }
+
+ /* Get the item */
+ object_type *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;
+ }
+
+ /* Take a turn */
+ energy_use = 100;
+
+ /* Enter device mode */
+ set_stick_mode(o_ptr);
+
+ /* get the chance */
+ int chance;
+ {
+ auto spell = spell_at(o_ptr->pval2);
+ chance = spell_chance_device(spell);
+ }
+
+ /* Leave device mode */
+ unset_stick_mode();
+
+ /* 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);
+ 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);
+ return;
+ }
+
+
+ /* Sound */
+ sound(SOUND_ZAP);
+
+ /* Analyze the staff */
+ activate_stick(o_ptr, &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)
+ {
+ 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);
+ }
+}
+
+
+/*
+ * 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)
+{
+ bool_ obvious, use_charge;
+
+ u32b f1, f2, f3, f4, f5, esp;
+
+
+ /* No magic */
+ if (p_ptr->antimagic)
+ {
+ msg_print("Your anti-magic field disrupts any magic attempts.");
+ return;
+ }
+
+ /* Get an item */
+ int item;
+ if (!get_item(&item,
+ "Aim which wand? ",
+ "You have no wand to aim.",
+ (USE_INVEN | USE_FLOOR),
+ object_filter::TVal(TV_WAND),
+ select_object_by_name("Wand full name? ")))
+ {
+ return;
+ }
+
+ /* Get the item */
+ object_type *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;
+
+ /* Enter device mode */
+ set_stick_mode(o_ptr);
+
+ /* get the chance */
+ int chance;
+ {
+ auto spell = spell_at(o_ptr->pval2);
+ chance = spell_chance_device(spell);
+ }
+
+ /* Leave device mode */
+ unset_stick_mode();
+
+ /* 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);
+ 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);
+ return;
+ }
+
+ /* Sound */
+ sound(SOUND_ZAP);
+
+ /* Analyze the wand */
+ activate_stick(o_ptr, &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)
+ {
+ 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);
+ }
+}
+
+
+
+
+
+
+/*
+ * 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 object_filter_t const &item_tester_hook_zapable()
+{
+ using namespace object_filter;
+ static auto instance =
+ Or(
+ TVal(TV_ROD),
+ TVal(TV_ROD_MAIN));
+ return instance;
+}
+
+
+/*
+ * Hook to determine if an object is attachable
+ */
+static bool item_tester_hook_attachable(object_type const *o_ptr)
+{
+ return ((o_ptr->tval == TV_ROD_MAIN) &&
+ (o_ptr->pval == SV_ROD_NOTHING));
+}
+
+
+/*
+ * Combine a rod and a rod tip
+ */
+void zap_combine_rod_tip(object_type *q_ptr, int tip_item)
+{
+ int item;
+
+ 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;
+ }
+
+ /* Get an item */
+ if (!get_item(&item,
+ "Attach the rod tip with which rod? ",
+ "You have no rod to attach to.",
+ (USE_INVEN),
+ item_tester_hook_attachable))
+ {
+ return;
+ }
+
+ /* Get the item */
+ object_type *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_kind *tip_ptr;
+
+ u32b f1, f2, f3, f4, f5, esp;
+
+ /* 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;
+ }
+
+ /* Get an item */
+ if (!get_item(&item,
+ "Zap which rod? ",
+ "You have no rod to zap.",
+ (USE_INVEN | USE_FLOOR),
+ item_tester_hook_zapable(),
+ select_object_by_name("Rod full name? ")))
+ {
+ return;
+ }
+
+ /* Get the item */
+ object_type *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:
+ 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 object_filter_t const &item_tester_hook_activate()
+{
+ using namespace object_filter;
+ static auto instance = And(
+ IsKnown(),
+ HasFlag3(TR3_ACTIVATE));
+ return instance;
+}
+
+
+/*
+ * 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),
+ (((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);
+}
+
+
+/*
+ * Eternal flame activation
+ */
+
+static int get_eternal_artifact_idx(object_type const *o_ptr)
+{
+ if ((o_ptr->tval == TV_SWORD) && (o_ptr->sval == SV_LONG_SWORD)) {
+ return 147;
+ } else if ((o_ptr->tval == TV_MSTAFF) && (o_ptr->sval == SV_MSTAFF)) {
+ return 127;
+ } else if ((o_ptr->tval == TV_BOW) && (o_ptr->sval == SV_HEAVY_XBOW)) {
+ return 152;
+ } else if ((o_ptr->tval == TV_DRAG_ARMOR) && (o_ptr->sval == SV_DRAGON_POWER)) {
+ return 17;
+ }
+
+ if (game_module_idx == MODULE_THEME)
+ {
+ if ((o_ptr->tval == TV_HAFTED) && (o_ptr->sval == SV_LUCERN_HAMMER)) {
+ return 241;
+ } else if ((o_ptr->tval == TV_POLEARM) && (o_ptr->sval == SV_TRIDENT)) {
+ return 242;
+ } else if ((o_ptr->tval == TV_AXE) && (o_ptr->sval == SV_BROAD_AXE)) {
+ return 243;
+ } else if ((o_ptr->tval == TV_BOW) && (o_ptr->sval == SV_LONG_BOW)) {
+ return 245;
+ } else if ((o_ptr->tval == TV_BOOMERANG) && (o_ptr->sval == SV_BOOM_METAL)) {
+ return 247;
+ } else if ((o_ptr->tval == TV_BOW) && (o_ptr->sval == SV_SLING)) {
+ return 246;
+ } else if ((o_ptr->tval == TV_SWORD) && (o_ptr->sval == SV_RAPIER)) {
+ return 244;
+ } else if ((o_ptr->tval == TV_AMULET) && (o_ptr->sval == SV_AMULET_SPELL)) {
+ return 248;
+ }
+ }
+
+ /* Not usable */
+ return -1;
+}
+
+static bool eternal_flame_item_tester_hook(object_type const *o_ptr)
+{
+ if ((o_ptr->name1 > 0) ||
+ (o_ptr->name2 > 0))
+ {
+ return FALSE;
+ }
+
+ return (get_eternal_artifact_idx(o_ptr) >= 0);
+}
+
+static bool activate_eternal_flame(int flame_item)
+{
+ int item;
+ int artifact_idx = -1;
+
+ if (!get_item(&item,
+ "Which object do you want to imbue?",
+ "You have no objects to imbue.",
+ USE_INVEN,
+ eternal_flame_item_tester_hook))
+ {
+ return false;
+ }
+
+ /* Get the artifact idx */
+ artifact_idx = get_eternal_artifact_idx(get_object(item));
+ assert(artifact_idx >= 0);
+
+ /* Forge the item */
+ object_type *o_ptr = get_object(item);
+ o_ptr->name1 = artifact_idx;
+
+ apply_magic(o_ptr, -1, TRUE, TRUE, TRUE);
+
+ o_ptr->found = OBJ_FOUND_SELFMADE;
+
+ inven_item_increase(flame_item, -1);
+ inven_item_describe(flame_item);
+ inven_item_optimize(flame_item);
+ return true;
+}
+
+
+/**
+ * Farmer Maggot's sling activation.
+ */
+static bool activate_maggot()
+{
+ int dir;
+ if (!get_aim_dir(&dir))
+ {
+ return false;
+ }
+
+ fire_ball(GF_TURN_ALL, dir, 40, 2);
+ return true;
+}
+
+
+/**
+ * 'Radagast' (Theme)
+ */
+static void activate_radagast()
+{
+ cmsg_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(); TODO: Do we want to implement this?
+ 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 (p_ptr->black_breath)
+ {
+ msg_print("The hold of the Black Breath on you is broken!");
+ }
+ p_ptr->black_breath = FALSE;
+
+ p_ptr->update |= PU_BONUS;
+ p_ptr->window |= PW_PLAYER;
+}
+
+
+/**
+ * 'Valaroma' (Theme)
+ */
+static void activate_valaroma()
+{
+ int power = 5 * p_ptr->lev;
+ banish_evil(power);
+}
+
+
+/*
+ * 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;
+
+ u32b f1, f2, f3, f4, f5, esp;
+
+ /* Get an item */
+ command_wrk = USE_EQUIP;
+ if (!get_item(&item,
+ "Activate which item? ",
+ "You have nothing to activate.",
+ (USE_EQUIP | USE_INVEN),
+ item_tester_hook_activate()))
+ {
+ return;
+ }
+
+ /* Get the item */
+ object_type *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);
+
+ /* 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 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!";
+
+ /* Activations always have positive numbers */
+ assert(spell > 0);
+
+ /* 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);
+
+ 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) every 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) every 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(randint(5 * oops + 1));
+
+ /* Confusing. */
+ (void)set_confused(p_ptr->confused +
+ randint(5 * oops + 1));
+ }
+
+ /* Redraw mana */
+ p_ptr->redraw |= (PR_FRAME);
+ }
+
+ 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_FRAME);
+ 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, (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, (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, (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),
+ (((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(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();
+ /* 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:
+ /* Should be handled specially by caller, so if we get here something's wrong. */
+ abort();
+ case ACT_ETERNAL_FLAME:
+ {
+ if (!doit) return "imbuing an object with the eternal fire";
+
+ if (!activate_eternal_flame(item))
+ {
+ // Eternal Flame object was NOT destroyed, so let's
+ // set the timeout.
+ o_ptr->timeout = 0;
+ }
+ break;
+ }
+ case ACT_MAGGOT:
+ {
+ if (!doit) return "terrify every 10+d50 turns";
+
+ if (activate_maggot())
+ {
+ o_ptr->timeout = 10 + randint(50);
+ }
+ break;
+ }
+ case ACT_LEBOHAUM:
+ {
+ if (!doit) return "sing a cheerful song every turn";
+
+ 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!'");
+
+ o_ptr->timeout = 3;
+
+ break;
+ }
+ case ACT_DURANDIL:
+ {
+ if (!doit) return "sing a cheerful song every turn";
+
+ 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!'");
+
+ o_ptr->timeout = 3;
+
+ break;
+ }
+ case ACT_RADAGAST:
+ {
+ if (!doit) return "purity and health every 15000 turns";
+
+ activate_radagast();
+ o_ptr->timeout = 15000;
+
+ break;
+ }
+ case ACT_VALAROMA:
+ {
+ if (!doit) return "banish evil (level x5) every 250 turns";
+
+ activate_valaroma();
+ o_ptr->timeout = 250;
+
+ break;
+ }
+ 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/cmd6.hpp b/src/cmd6.hpp
new file mode 100644
index 00000000..ad6619f6
--- /dev/null
+++ b/src/cmd6.hpp
@@ -0,0 +1,18 @@
+#pragma once
+
+#include "h-basic.h"
+#include "object_type_fwd.hpp"
+
+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_cut_corpse(void);
+extern void do_cmd_cure_meat(void);
+extern void do_cmd_drink_fountain(void);
diff --git a/src/cmd7.c b/src/cmd7.c
deleted file mode 100644
index aca14dcd..00000000
--- a/src/cmd7.c
+++ /dev/null
@@ -1,7652 +0,0 @@
-/* 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/cmd7.cc b/src/cmd7.cc
new file mode 100644
index 00000000..2317f8b9
--- /dev/null
+++ b/src/cmd7.cc
@@ -0,0 +1,4466 @@
+/*
+ * 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 "cmd7.hpp"
+
+#include "cave.hpp"
+#include "cave_type.hpp"
+#include "cmd1.hpp"
+#include "cmd5.hpp"
+#include "cmd6.hpp"
+#include "ego_item_type.hpp"
+#include "files.hpp"
+#include "hooks.hpp"
+#include "mimic.hpp"
+#include "monster2.hpp"
+#include "monster_race.hpp"
+#include "monster_type.hpp"
+#include "object1.hpp"
+#include "object2.hpp"
+#include "object_kind.hpp"
+#include "options.hpp"
+#include "player_type.hpp"
+#include "quark.hpp"
+#include "skills.hpp"
+#include "spells1.hpp"
+#include "spells2.hpp"
+#include "stats.hpp"
+#include "tables.hpp"
+#include "util.hpp"
+#include "util.h"
+#include "variable.h"
+#include "variable.hpp"
+#include "xtra1.hpp"
+#include "xtra2.hpp"
+#include "z-rand.hpp"
+
+/*
+ * 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;
+ }
+}
+
+/**
+ * Show magic powers that user can choose from
+ */
+static void display_magic_powers(
+ magic_power *powers,
+ int max_powers,
+ void (*power_info)(char *p, int power),
+ int plev,
+ int cast_stat,
+ int y,
+ int x)
+{
+ char psi_desc[80];
+ magic_power spell;
+ int i;
+ int chance = 0;
+ int minfail = 0;
+ char comment[80];
+
+ /* 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);
+}
+
+/*
+ * 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.
+ */
+static 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 info;
+
+ char choice;
+
+ char out_val[160];
+
+ cptr p = "power";
+
+ magic_power spell;
+
+ bool_ flag;
+
+
+ /* 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;
+
+ /* 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, 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();
+
+ /* Show the list */
+ display_magic_powers(powers, max_powers, power_info, plev, cast_stat, y, x);
+
+ /* Get a spell from the user */
+ while (!flag && get_com(out_val, &choice))
+ {
+ /* 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;
+
+ /* Redisplay choices */
+ display_magic_powers(powers, max_powers, power_info, plev, cast_stat, y, x);
+ continue;
+ }
+
+ /* Stop the loop */
+ flag = TRUE;
+ }
+
+ /* Restore the screen */
+ 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(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_FRAME);
+
+ /* Window stuff */
+ p_ptr->window |= (PW_PLAYER);
+}
+
+
+static int get_mimic_chance(int mimic)
+{
+ s32b chance;
+
+ chance = get_mimic_level(mimic);
+ 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_FRAME);
+
+ /* Recalculate bonuses */
+ p_ptr->update |= (PU_BONUS);
+}
+
+static bool_ mimic_forbid_travel(void *, void *, void *)
+{
+ 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_new(HOOK_FORBID_TRAVEL, mimic_forbid_travel, "mimic_forbid_travel", NULL);
+ 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(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_FRAME);
+
+ /* 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);
+}
+
+
+/*
+ * 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_WIPE | PR_FRAME | 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)
+{
+ 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, A-%c to browse, / to rename, - to comment) Select a power: ",
+ I2A(mut_max - 1), I2A(mut_max - 1) - 'a' + 'A');
+
+ prt(tmp, 0, 0);
+
+ while (1)
+ {
+ /* Print power list */
+ print_spell_batch(batch, mut_max);
+
+ /* Get a command */
+ which = inkey();
+
+ /* Abort */
+ if (which == ESCAPE)
+ {
+ /* No selection */
+ ret = NULL;
+
+ /* Leave the command loop */
+ break;
+
+ }
+
+ /* 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
+ */
+static random_spell* select_spell()
+{
+ 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)
+ {
+ Term_load();
+
+ ret = NULL;
+
+ break;
+ }
+
+ if (which == '\r')
+ {
+ if (batch_max == 0)
+ {
+ Term_load();
+
+ ret = select_spell_from_batch(0);
+
+ break;
+ }
+
+ continue;
+ }
+
+ which = tolower(which);
+ if (isalpha(which) && (A2I(which) <= batch_max))
+ {
+ Term_load();
+
+ ret = select_spell_from_batch(A2I(which));
+
+ break;
+ }
+ else
+ {
+ bell();
+ }
+ }
+
+ /* 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();
+
+ 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_FRAME);
+
+ 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_FRAME);
+}
+
+
+/*
+ * 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];
+ const char *ammo_name;
+ const 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 (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_FRAME);
+ }
+ }
+ }
+ 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 object_filter_t const &item_tester_hook_convertible()
+{
+ using namespace object_filter;
+ static auto instance =
+ Or(
+ TVal(TV_JUNK),
+ TVal(TV_SKELETON));
+ return instance;
+}
+
+
+/*
+ * 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;
+
+ /* Get an item */
+ if (!get_item(&item,
+ "Convert which item? ",
+ "You have no item to convert.",
+ (USE_INVEN | USE_FLOOR),
+ item_tester_hook_convertible())) 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;
+
+ /* Get an item */
+ if (!get_item(&item,
+ "Convert which item? ",
+ "You have no item to convert.",
+ (USE_INVEN | USE_FLOOR),
+ item_tester_hook_convertible())) 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_FRAME);
+
+ /* 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_FRAME);
+
+ /* 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(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_FRAME);
+
+ /* Window stuff */
+ p_ptr->window |= (PW_PLAYER);
+}
+
+/*
+ * Hook to determine if an object is "runestone"
+ */
+static bool item_tester_hook_runestone(object_type const *o_ptr)
+{
+ return ((o_ptr->tval == TV_RUNE2) &&
+ (o_ptr->sval == RUNE_STONE) &&
+ (o_ptr->pval == 0));
+}
+
+static bool item_tester_hook_runestone_full(object_type const *o_ptr)
+{
+ return ((o_ptr->tval == TV_RUNE2) &&
+ (o_ptr->sval == RUNE_STONE) &&
+ (o_ptr->pval != 0));
+}
+
+/*
+ * 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_FRAME);
+ 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_FRAME);
+
+ 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)
+{
+ s32b rune_combine = 0;
+
+ /* Lambda to use for selecting the secondary rune(s) */
+ auto rune2_filter = [&](object_type const *o_ptr) -> bool {
+ return ((o_ptr->tval == TV_RUNE2) &&
+ (o_ptr->sval != RUNE_STONE) &&
+ (!(rune_combine & BIT(o_ptr->sval))));
+ };
+
+ /* Prompt */
+ const char *const q = "Use which rune? ";
+ const char *const s = "You have no rune to use.";
+
+ /* Extract first rune for the base effect */
+ int type = 0;
+ {
+ int item;
+ if (!get_item(&item, q, s, (USE_INVEN | USE_FLOOR), object_filter::TVal(TV_RUNE1)))
+ {
+ return FALSE;
+ }
+
+ object_type *o_ptr = get_object(item);
+ type = o_ptr->sval;
+ }
+
+ /* Choose secondary rune(s) */
+ int rune2 = 0;
+ while (1)
+ {
+ int item;
+ if (!get_item(&item, q, nullptr, (USE_INVEN | USE_FLOOR), rune2_filter))
+ {
+ break;
+ }
+
+ object_type *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);
+ }
+
+ int power_rune = 0;
+ int plev = get_skill(SKILL_RUNECRAFT);
+ s32b 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_FRAME);
+}
+
+
+/*
+ * 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, int *s_idx)
+{
+ char tmp[160];
+
+ char out_val[30];
+
+ char which;
+
+ int mut_max = 10;
+
+ rune_spell* ret;
+
+
+ character_icky = TRUE;
+
+ 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);
+
+ while (1)
+ {
+ Term_save();
+
+ print_runespell_batch(batch, mut_max);
+
+ which = inkey();
+
+ Term_load();
+
+ 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();
+ }
+ }
+ }
+
+ character_icky = FALSE;
+
+ return (ret);
+}
+
+
+/*
+ * Pick a random spell from a menu
+ */
+
+rune_spell* select_runespell(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, 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), 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(&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_FRAME);
+}
+
+
+/*
+ * Cast a runespell from a carved runestone
+ */
+void do_cmd_runestone()
+{
+ rune_spell s_ptr;
+
+ 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;
+ }
+
+ /* Get an item */
+ if (!get_item(&item,
+ "Cast from which runestone? ",
+ "You have no runestone to cast from.",
+ (USE_INVEN | USE_FLOOR),
+ item_tester_hook_runestone_full))
+ {
+ return;
+ }
+
+ /* Get the item */
+ object_type *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_FRAME);
+}
+
+
+/*
+ * 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 learned the maximum 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_FRAME);
+}
+
+
+/*
+ * Carve a runespell onto a Runestone
+ */
+void do_cmd_rune_carve()
+{
+ rune_spell s_ptr;
+
+ 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;
+
+ /* Get an item */
+ if (!get_item(&item,
+ "Use which runestone? ",
+ "You have no runestone to use.",
+ (USE_INVEN | USE_FLOOR),
+ item_tester_hook_runestone))
+ {
+ return;
+ }
+
+ /* Get the item */
+ object_type *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_FRAME);
+}
+
+
+/*
+ * 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(&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_FRAME);
+}
+
+
+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 object_filter_t const &item_tester_hook_totemable()
+{
+ using namespace object_filter;
+ static auto instance = And(
+ TVal(TV_CORPSE),
+ Or(
+ SVal(SV_CORPSE_CORPSE),
+ SVal(SV_CORPSE_SKELETON)));
+ return instance;
+}
+
+
+/*
+ * Summoners
+ */
+void do_cmd_summoner_extract()
+{
+ object_type forge, *q_ptr;
+
+ /* 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;
+ }
+
+ /* Get an item */
+ int item;
+ if (!get_item(&item,
+ "Use which corpse? ",
+ "You have no corpse to use.",
+ (USE_INVEN | USE_FLOOR),
+ item_tester_hook_totemable()))
+ {
+ return;
+ }
+
+ /* Get the item */
+ object_type *o_ptr = get_object(item);
+
+ bool_ partial;
+ if (r_info[o_ptr->pval2].flags1 & RF1_UNIQUE)
+ {
+ partial = FALSE;
+ }
+ else
+ {
+ partial = get_check("Do you want to create a partial totem?");
+ }
+
+ int 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;
+
+ monster_type *m_ptr;
+
+
+ /* Which Totem? */
+ q = "Summon from which Totem?";
+ s = "There are no totems to summon from!";
+ if (!get_item(&item, q, s, (USE_INVEN | USE_FLOOR), object_filter::TVal(TV_TOTEM))) return;
+
+ /* Access the item */
+ object_type *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;
+ }
+ }
+}
+
+
+/*
+ * 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;
+ 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];
+ auto const r_ptr = m_ptr->race();
+
+ 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;
+
+ /* Get an item */
+ if (!get_item(&item,
+ "Awaken which monster? ",
+ "You have no monster to awaken.",
+ (USE_FLOOR),
+ object_filter::TVal(TV_HYPNOS)))
+ {
+ return;
+ }
+
+ object_type *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;
+
+ /* Window stuff */
+ p_ptr->window |= (PW_PLAYER);
+
+ /* Display the monster hitpoints */
+ p_ptr->redraw |= (PR_FRAME);
+
+ 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_FRAME);
+
+ 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(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_FRAME);
+
+ /* 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/cmd7.hpp b/src/cmd7.hpp
new file mode 100644
index 00000000..162e5461
--- /dev/null
+++ b/src/cmd7.hpp
@@ -0,0 +1,28 @@
+#pragma once
+
+#include "h-basic.h"
+#include "rune_spell_fwd.hpp"
+#include "object_type_fwd.hpp"
+
+extern void do_cmd_pray(void);
+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 void do_cmd_summoner(void);
+extern void do_cmd_mindcraft(void);
+extern void do_cmd_mimic(void);
+extern void use_ability_blade(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 do_cmd_runecrafter(void);
+extern void do_cmd_symbiotic(void);
+extern s32b sroot(s32b n);
+extern int clamp_failure_chance(int chance, int minfail);
diff --git a/src/cmovie.c b/src/cmovie.c
deleted file mode 100644
index d1459e02..00000000
--- a/src/cmovie.c
+++ /dev/null
@@ -1,496 +0,0 @@
-/* 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
index c9f460e7..8ff00f8f 100644
--- a/src/config.h
+++ b/src/config.h
@@ -30,24 +30,13 @@
* 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).
+ * and "USE_X11" (allow basic use with Unix X11).
*
* 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 */
/*
@@ -67,90 +56,11 @@
/*
- * 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
@@ -159,50 +69,6 @@
-/*
- * 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.
@@ -233,29 +99,7 @@
/*
* 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
/*
@@ -279,33 +123,6 @@
-/* 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
*/
diff --git a/src/corrupt.cc b/src/corrupt.cc
new file mode 100644
index 00000000..f182a9e2
--- /dev/null
+++ b/src/corrupt.cc
@@ -0,0 +1,1003 @@
+#include "corrupt.hpp"
+
+#include "init1.hpp"
+#include "player_race.hpp"
+#include "player_race_mod.hpp"
+#include "player_type.hpp"
+#include "stats.hpp"
+#include "util.hpp"
+#include "variable.hpp"
+#include "xtra1.hpp"
+#include "xtra2.hpp"
+#include "z-rand.hpp"
+
+#include <cassert>
+
+/**
+ * Corruptions
+ */
+typedef struct corruption_type corruption_type;
+struct corruption_type
+{
+ int modules[3]; /* Modules where this corruption is available; terminated with -1 entry */
+ byte color;
+ cptr group;
+ cptr name;
+ cptr get_text;
+ cptr lose_text; /* If NULL, the corruption is NOT removable by any means */
+ cptr desc;
+ s16b depends[5]; /* terminated by a -1 entry */
+ s16b opposes[5]; /* terminated by a -1 entry */
+ void (*gain_callback)(); /* callback to invoke when gained */
+ s16b power; /* index of granted power if >= 0, ignored otherwise */
+};
+
+/**
+ * Vampire corruption helpers
+ */
+
+static void subrace_add_power(player_race_mod *rmp_ptr, int power)
+{
+ int i;
+
+ for (i=0; i<4; i++)
+ {
+ if (rmp_ptr->powers[i] == -1)
+ {
+ rmp_ptr->powers[i] = power;
+ return;
+ }
+ }
+}
+
+static void player_gain_vampire_teeth()
+{
+ player_race_mod *rmp_ptr = NULL;
+
+ switch_subrace(SUBRACE_SAVE, TRUE);
+
+ rmp_ptr = &race_mod_info[SUBRACE_SAVE];
+ subrace_add_power(rmp_ptr, PWR_VAMPIRISM);
+ rmp_ptr->flags1 = rmp_ptr->flags1
+ | PR1_VAMPIRE
+ | PR1_UNDEAD
+ | PR1_NO_SUBRACE_CHANGE;
+}
+
+static void player_gain_vampire_strength()
+{
+ player_race_mod *rmp_ptr = &race_mod_info[SUBRACE_SAVE];
+ /* Apply the bonuses/penalities */
+ rmp_ptr->r_mhp = rmp_ptr->r_mhp + 1;
+ rmp_ptr->r_exp = rmp_ptr->r_exp + 100;
+
+ rmp_ptr->r_adj[A_STR] = rmp_ptr->r_adj[A_STR] + 3;
+ rmp_ptr->r_adj[A_INT] = rmp_ptr->r_adj[A_INT] + 2;
+ rmp_ptr->r_adj[A_WIS] = rmp_ptr->r_adj[A_WIS] - 3;
+ rmp_ptr->r_adj[A_DEX] = rmp_ptr->r_adj[A_DEX] - 2;
+ rmp_ptr->r_adj[A_CON] = rmp_ptr->r_adj[A_CON] + 1;
+ rmp_ptr->r_adj[A_CHR] = rmp_ptr->r_adj[A_CHR] - 4;
+
+ /* be reborn! */
+ do_rebirth();
+ cmsg_print(TERM_L_DARK, "You feel death slipping inside.");
+}
+
+static void player_gain_vampire()
+{
+ player_race_mod *rmp_ptr = &race_mod_info[SUBRACE_SAVE];
+
+ /* Be a Vampire and be proud of it */
+ cptr title = rmp_ptr->title;
+ if (streq(title, "Vampire"))
+ {
+ title = "Vampire";
+ rmp_ptr->place = FALSE;
+ set_subrace_title(rmp_ptr, title);
+ }
+ else
+ {
+ char buf[512];
+ sprintf(buf, "Vampire %s", title);
+ set_subrace_title(rmp_ptr, buf);
+ }
+
+ /* Bonus/and .. not bonus :) */
+ rmp_ptr->flags1 = rmp_ptr->flags1 | PR1_HURT_LITE;
+ rmp_ptr->oflags2[2] = rmp_ptr->oflags2[2]
+ | TR2_RES_POIS
+ | TR2_RES_NETHER
+ | TR2_RES_COLD
+ | TR2_RES_DARK
+ | TR2_HOLD_LIFE;
+ rmp_ptr->oflags3[2] = rmp_ptr->oflags3[2]
+ | TR3_LITE1;
+}
+
+/**
+ * Corruptions
+ */
+corruption_type corruptions[CORRUPTIONS_MAX] =
+{
+ /*
+ * BALROG corruptions
+ */
+
+ { /* 0 */
+ { MODULE_TOME, MODULE_THEME, -1 },
+ TERM_ORANGE,
+ NULL /* no group */,
+ "Balrog Aura",
+ "A corrupted wall of flames surrounds you.",
+ "The wall of corrupted flames abandons you.",
+ " Surrounds you with a fiery aura\n"
+ " But it can burn scrolls when you read them",
+ { -1 },
+ { -1 },
+ NULL,
+ -1,
+ },
+
+ { /* 1 */
+ { MODULE_TOME, MODULE_THEME, -1 },
+ TERM_ORANGE,
+ NULL /* no group */,
+ "Balrog Wings",
+ "Wings of shadow grow in your back.",
+ "The wings in your back fall apart.",
+ " Creates ugly, but working, wings allowing you to fly\n"
+ " But it reduces charisma by 4 and dexterity by 2",
+ { -1 },
+ { -1 },
+ NULL,
+ -1,
+ },
+
+ { /* 2 */
+ { MODULE_TOME, MODULE_THEME, -1 },
+ TERM_ORANGE,
+ NULL /* no group */,
+ "Balrog Strength",
+ "Your muscles get unnatural strength.",
+ "Your muscles get weaker again.",
+ " Provides 3 strength and 1 constitution\n"
+ " But it reduces charisma by 1 and dexterity by 3",
+ { -1 },
+ { -1 },
+ NULL,
+ -1,
+ },
+
+ { /* 3 */
+ { MODULE_TOME, MODULE_THEME, -1 },
+ TERM_YELLOW,
+ NULL /* no group */,
+ "Balrog Form",
+ "You feel the might of a Balrog inside you.",
+ "The presence of the Balrog seems to abandon you.",
+ " Allows you to turn into a Balrog at will\n"
+ " You need Balrog Wings, Balrog Aura and Balrog Strength to activate it",
+ { CORRUPT_BALROG_AURA, CORRUPT_BALROG_WINGS, CORRUPT_BALROG_STRENGTH },
+ { -1 },
+ NULL,
+ PWR_BALROG,
+ },
+
+ /*
+ * DEMON corruptions
+ */
+ { /* 4 */
+ { MODULE_TOME, MODULE_THEME, -1 },
+ TERM_RED,
+ NULL /* no group */,
+ "Demon Spirit",
+ "Your spirit opens to corrupted thoughts.",
+ "Your spirit closes again to the corrupted thoughts.",
+ " Increases your intelligence by 1\n"
+ " But reduce your charisma by 2",
+ { -1 },
+ { -1 },
+ NULL,
+ -1,
+ },
+
+ { /* 5 */
+ { MODULE_TOME, MODULE_THEME, -1 },
+ TERM_RED,
+ NULL /* no group */,
+ "Demon Hide",
+ "Your skin grows into a thick hide.",
+ "Your skin returns to a natural state.",
+ " Increases your armour class by your level\n"
+ " Provides immunity to fire at level 40\n"
+ " But reduces speed by your level / 7",
+ { -1 },
+ { -1 },
+ NULL,
+ -1,
+ },
+
+ { /* 6 */
+ { MODULE_TOME, MODULE_THEME, -1 },
+ TERM_RED,
+ NULL /* no group */,
+ "Demon Breath",
+ "Your breath becomes mephitic.",
+ "Your breath is once again normal.",
+ " Provides fire breath\n"
+ " But gives a small chance to spoil potions when you quaff them",
+ { -1 },
+ { -1 },
+ NULL,
+ PWR_BR_FIRE,
+ },
+
+ { /* 7 */
+ { MODULE_TOME, MODULE_THEME, -1 },
+ TERM_L_RED,
+ NULL /* no group */,
+ "Demon Realm",
+ "You feel more attuned to the demon realm.",
+ "You lose your attunement to the demon realm.",
+ " Provides access to the demon school skill and the use of demonic equipment\n"
+ " You need Demon Spirit, Demon Hide and Demon Breath to activate it",
+ { CORRUPT_DEMON_SPIRIT, CORRUPT_DEMON_HIDE, CORRUPT_DEMON_BREATH },
+ { -1 },
+ NULL,
+ -1,
+ },
+
+ /*
+ * Teleportation corruptions
+ */
+
+ { /* 8 */
+ { MODULE_TOME, MODULE_THEME, -1 },
+ TERM_GREEN,
+ NULL /* no group */,
+ "Random teleportation",
+ "Space seems to fizzle around you.",
+ "Space solidify again around you.",
+ " Randomly teleports you around",
+ { -1 },
+ { CORRUPT_ANTI_TELEPORT, -1 },
+ NULL,
+ -1,
+ },
+
+ { /* 9 */
+ { MODULE_TOME, MODULE_THEME, -1 },
+ TERM_GREEN,
+ NULL /* no group */,
+ "Anti-teleportation",
+ "Space continuum freezes around you.",
+ "Space continuum can once more be altered around you.",
+ " Prevents all teleportations, be it of you or monsters",
+ { -1 },
+ { CORRUPT_RANDOM_TELEPORT, -1 },
+ NULL,
+ POWER_COR_SPACE_TIME,
+ },
+
+ /*
+ * Troll blood
+ */
+
+ { /* 10 */
+ { MODULE_TOME, MODULE_THEME, -1 },
+ TERM_GREEN,
+ NULL /* no group */,
+ "Troll Blood",
+ "Your blood thickens, you sense corruption in it.",
+ "Your blood returns to a normal state.",
+ " Troll blood flows in your veins, granting increased regeneration\n"
+ " It also enables you to feel the presence of other troll beings\n"
+ " But it will make your presence more noticeable and aggravating",
+ { -1 },
+ { -1 },
+ NULL,
+ -1,
+ },
+
+ /*
+ * The vampire corruption set
+ */
+
+ { /* 11 */
+ { MODULE_TOME, MODULE_THEME, -1 },
+ TERM_L_DARK,
+ "Vampire",
+ "Vampiric Teeth",
+ "You grow vampiric teeth!",
+ NULL, /* cannot lose */
+ " Your teeth allow you to drain blood to feed yourself\n"
+ " However your stomach now only accepts blood.",
+ { -1 },
+ { -1 },
+ player_gain_vampire_teeth,
+ -1,
+ },
+
+ { /* 12 */
+ { MODULE_TOME, MODULE_THEME, -1 },
+ TERM_L_DARK,
+ "Vampire",
+ "Vampiric Strength",
+ "Your body seems more dead than alive.",
+ NULL, /* cannot lose */
+ " Your body seems somewhat dead\n"
+ " In this near undead state it has improved strength, constitution and intelligence\n"
+ " But reduced dexterity, wisdom and charisma.",
+ { CORRUPT_VAMPIRE_TEETH, -1 },
+ { -1 },
+ player_gain_vampire_strength,
+ -1,
+ },
+
+ { /* 13 */
+ { MODULE_TOME, MODULE_THEME, -1 },
+ TERM_L_DARK,
+ "Vampire",
+ "Vampire",
+ "You die to be reborn in a Vampire form.",
+ NULL, /* cannot lose */
+ " You are a Vampire. As such you resist cold, poison, darkness and nether.\n"
+ " Your life is sustained, but you cannot stand the light of the sun.",
+ { CORRUPT_VAMPIRE_STRENGTH, -1 },
+ { -1 },
+ player_gain_vampire,
+ -1,
+ },
+
+ /*
+ * Activatable corruptions (mutations)
+ */
+
+ { /* 14 */
+ { MODULE_THEME, -1 },
+ TERM_RED,
+ NULL /* no group */,
+ "Ancalagon's Breath",
+ "You gain the ability to spit acid.",
+ "You lose the ability to spit acid.",
+ " Fires an acid ball.\n"
+ " Damage=level Radius 1+(level/30)\n"
+ " Level=9, Cost=9, Stat=DEX, Difficulty=15",
+ { -1 },
+ { -1 },
+ NULL,
+ PWR_SPIT_ACID,
+ },
+
+ { /* 15 */
+ { MODULE_THEME, -1 },
+ TERM_RED,
+ NULL /* no group */,
+ "Smaug's Breath",
+ "You gain the ability to breathe fire.",
+ "You lose the ability to breathe fire.",
+ " Fires a fire ball.\n"
+ " Damage=2*level Radius 1+(level/20)\n"
+ " Level=20, Cost=10, Stat=CON, Difficulty=18",
+ { -1 },
+ { -1 },
+ NULL,
+ PWR_BR_FIRE,
+ },
+
+ { /* 16 */
+ { MODULE_THEME, -1 },
+ TERM_RED,
+ NULL /* no group */,
+ "Glaurung's Gaze",
+ "Your eyes look mesmerizing...",
+ "Your eyes look uninteresting.",
+ " Tries to make a monster your pet.\n"
+ " Power=level\n"
+ " Level=12, Cost=12, Stat=CHR, Difficulty=18",
+ { -1 },
+ { -1 },
+ NULL,
+ PWR_HYPN_GAZE,
+ },
+
+ { /* 17 */
+ { MODULE_THEME, -1 },
+ TERM_RED,
+ NULL /* no group */,
+ "Saruman's Power",
+ "You gain the ability to move objects telekinetically.",
+ "You lose the ability to move objects telekinetically.",
+ " Move an object in line of sight to you.\n"
+ " Max weight equal to (level) pounds\n"
+ " Level=9, Cost=9, Stat=WIS, Difficulty=14",
+ { -1 },
+ { -1 },
+ NULL,
+ PWR_TELEKINES,
+ },
+
+ { /* 18 */
+ { MODULE_THEME, -1 },
+ TERM_RED,
+ NULL /* no group */,
+ "Teleport",
+ "You gain the power of teleportation at will.",
+ "You lose the power of teleportation at will.",
+ " Teleports the player at will.\n"
+ " Distance 10+4*level squares\n"
+ " Level=7, Cost=7, Stat=WIS, Difficulty=15",
+ { -1 },
+ { -1 },
+ NULL,
+ PWR_VTELEPORT,
+ },
+
+ { /* 19 */
+ { MODULE_THEME, -1 },
+ TERM_RED,
+ NULL /* no group */,
+ "Glaurung's Spell",
+ "You gain the power of Mind Blast.",
+ "You lose the power of Mind Blast.",
+ " Fires a mind blasting bolt (psi damage).\n"
+ " Psi Damage (3+(level-1)/5)d3\n"
+ " Level=5, Cost=3, Stat=WIS, Difficulty=15",
+ { -1 },
+ { -1 },
+ NULL,
+ PWR_MIND_BLST,
+ },
+
+ { /* 20 */
+ { MODULE_THEME, -1 },
+ TERM_RED,
+ NULL /* no group */,
+ "Vampiric Drain",
+ "You become vampiric.",
+ "You are no longer vampiric.",
+ " You can drain life from a foe like a vampire.\n"
+ " Drains (level+1d(level))*(level/10) hitpoints,\n"
+ " heals you and satiates you. Doesn't work on all monsters\n"
+ " Level=4, Cost=5, Stat=CON, Difficulty=9",
+ { -1 },
+ { -1 },
+ NULL,
+ PWR_VAMPIRISM,
+ },
+
+ { /* 21 */
+ { MODULE_THEME, -1 },
+ TERM_RED,
+ NULL /* no group */,
+ "Carcharoth's Nose",
+ "You smell a metallic odour.",
+ "You no longer smell a metallic odour.",
+ " You can detect nearby precious metal (treasure).\n"
+ " Radius 25\n"
+ " Level=3, Cost=2, Stat=INT, Difficulty=12",
+ { -1 },
+ { -1 },
+ NULL,
+ PWR_SMELL_MET,
+ },
+
+ { /* 22 */
+ { MODULE_THEME, -1 },
+ TERM_RED,
+ NULL /* no group */,
+ "Huan's Nose",
+ "You smell filthy monsters.",
+ "You no longer smell filthy monsters.",
+ " You can detect nearby monsters.\n"
+ " Radius 25\n"
+ " Level=5, Cost=4, Stat=INT, Difficulty=15",
+ { -1 },
+ { -1 },
+ NULL,
+ PWR_SMELL_MON,
+ },
+
+ { /* 23 */
+ { MODULE_THEME, -1 },
+ TERM_RED,
+ NULL /* no group */,
+ "Blink",
+ "You gain the power of minor teleportation.",
+ "You lose the power of minor teleportation.",
+ " You can teleport yourself short distances (10 squares).\n"
+ " Level=3, Cost=3, Stat=WIS, Difficulty=12",
+ { -1 },
+ { -1 },
+ NULL,
+ PWR_BLINK,
+ },
+
+ { /* 24 */
+ { MODULE_THEME, -1 },
+ TERM_RED,
+ NULL /* no group */,
+ "Eat Rock",
+ "The walls look delicious.",
+ "The walls look unappetizing.",
+ " You can consume solid rock with food benefit,\n"
+ " leaving an empty space behind.\n"
+ " Level=8, Cost=12, Stat=CON, Difficulty=18",
+ { -1 },
+ { -1 },
+ NULL,
+ PWR_EAT_ROCK,
+ },
+
+ { /* 25 */
+ { MODULE_THEME, -1 },
+ TERM_RED,
+ NULL /* no group */,
+ "Swap Position",
+ "You feel like walking a mile in someone else's shoes.",
+ "You feel like staying in your own shoes.",
+ " You can switch locations with another being,\n"
+ " unless it resists teleportation.\n"
+ " Level=15, Cost=12, Stat=DEX, Difficulty=16",
+ { -1 },
+ { -1 },
+ NULL,
+ PWR_SWAP_POS,
+ },
+
+ { /* 26 */
+ { MODULE_THEME, -1 },
+ TERM_RED,
+ NULL /* no group */,
+ "Shriek",
+ "Your vocal cords get much tougher.",
+ "Your vocal cords get much weaker.",
+ " Fires a sound ball and aggravates monsters.\n"
+ " Damage=level*4, Radius=8, centered on player\n"
+ " Level=4, Cost=4, Stat=CON, Difficulty=6",
+ { -1 },
+ { -1 },
+ NULL,
+ PWR_SHRIEK,
+ },
+
+ { /* 27 */
+ { MODULE_THEME, -1 },
+ TERM_RED,
+ NULL /* no group */,
+ "Illuminate",
+ "You can light up rooms with your presence.",
+ "You can no longer light up rooms with your presence.",
+ " You can emit bright light that illuminates an area.\n"
+ " Damage=2d(level/2) Radius=(level/10)+1\n"
+ " Level=3, Cost=2, Stat=INT, Difficulty=10",
+ { -1 },
+ { -1 },
+ NULL,
+ PWR_ILLUMINE,
+ },
+
+ { /* 28 */
+ { MODULE_THEME, -1 },
+ TERM_RED,
+ NULL /* no group */,
+ "Detect Curses",
+ "You can feel evil magics.",
+ "You can no longer feel evil magics.",
+ " You can feel the danger of evil magic.\n"
+ " It detects cursed items in the inventory\n"
+ " Level=7, Cost=14, Stat=WIS, Difficulty=14",
+ { -1 },
+ { -1 },
+ NULL,
+ PWR_DET_CURSE,
+ },
+
+ { /* 29 */
+ { MODULE_THEME, -1 },
+ TERM_RED,
+ NULL /* no group */,
+ "Berserk",
+ "You feel a controlled rage.",
+ "You no longer feel a controlled rage.",
+ " You can drive yourself into a berserk frenzy.\n"
+ " It grants super-heroism. Duration=10+1d(level)\n"
+ " Level=8, Cost=8, Stat=STR, Difficulty=14",
+ { -1 },
+ { -1 },
+ NULL,
+ PWR_BERSERK,
+ },
+
+ { /* 30 */
+ { MODULE_THEME, -1 },
+ TERM_RED,
+ NULL /* no group */,
+ "Midas touch",
+ "You gain the Midas touch.",
+ "You lose the Midas touch.",
+ " You can turn ordinary items to gold.\n"
+ " Turns a non-artifact object into 1/3 its value in gold\n"
+ " Level=10, Cost=5, Stat=INT, Difficulty=12",
+ { -1 },
+ { -1 },
+ NULL,
+ PWR_MIDAS_TCH,
+ },
+
+ { /* 31 */
+ { MODULE_THEME, -1 },
+ TERM_RED,
+ NULL /* no group */,
+ "Grow Mold",
+ "You feel a sudden affinity for mold.",
+ "You feel a sudden dislike for mold.",
+ " You can cause mold to grow near you.\n"
+ " Summons up to 8 molds around the player\n"
+ " Level=1, Cost=6, Stat=CON, Difficulty=14",
+ { -1 },
+ { -1 },
+ NULL,
+ PWR_GROW_MOLD,
+ },
+
+ { /* 32 */
+ { MODULE_THEME, -1 },
+ TERM_RED,
+ NULL /* no group */,
+ "Resist Elements",
+ "You feel like you can protect yourself.",
+ "You feel like you might be vulnerable.",
+ " You can harden yourself to the ravages of the elements.\n"
+ " Level-dependent chance of gaining resistances to the four \n"
+ " elements and poison. Duration=20 + d20\n"
+ " Level=10, Cost=12, Stat=CON, Difficulty=12",
+ { -1 },
+ { -1 },
+ NULL,
+ PWR_RESIST,
+ },
+
+ { /* 33 */
+ { MODULE_THEME, -1 },
+ TERM_RED,
+ NULL /* no group */,
+ "Earthquake",
+ "You gain the ability to wreck the dungeon.",
+ "You lose the ability to wreck the dungeon.",
+ " You can bring down the dungeon around your ears.\n"
+ " Radius=10, center on the player\n"
+ " Level=12, Cost=12, Stat=STR, Difficulty=16",
+ { -1 },
+ { -1 },
+ NULL,
+ PWR_EARTHQUAKE,
+ },
+
+};
+
+/**
+ * Initialize corruptions
+ */
+void init_corruptions()
+{
+ /* Nothing needed currently */
+}
+
+/*
+ * Corruptions
+ */
+bool_ player_has_corruption(int corruption_idx)
+{
+ if (corruption_idx < 0)
+ {
+ return FALSE;
+ }
+
+ return (p_ptr->corruptions[corruption_idx]);
+}
+
+static bool_ player_can_gain_corruption(int corruption_idx)
+{
+ bool_ allowed = TRUE; /* Allowed by default */
+
+ assert(corruption_idx >= 0);
+
+ if (corruption_idx == CORRUPT_TROLL_BLOOD)
+ {
+ /* Ok trolls should not get this one. never. */
+ if (streq(rp_ptr->title, "Troll"))
+ {
+ allowed = FALSE;
+ }
+ }
+
+ /* Theme module adds additional restrictions for Maiar */
+
+ if (game_module_idx == MODULE_THEME)
+ {
+ if (streq(rp_ptr->title, "Maia"))
+ {
+ /* We use a whitelist of corruptions for Maiar */
+ bool_ allow = FALSE;
+ if ((corruption_idx == CORRUPT_BALROG_AURA) ||
+ (corruption_idx == CORRUPT_BALROG_WINGS) ||
+ (corruption_idx == CORRUPT_BALROG_STRENGTH) ||
+ (corruption_idx == CORRUPT_BALROG_FORM) ||
+ (corruption_idx == CORRUPT_DEMON_BREATH))
+ {
+ allow = TRUE;
+ };
+
+ /* Mix result into 'allowed' flag */
+ allowed = allowed & allow;
+ }
+ }
+
+ /* Result */
+ return allowed;
+}
+
+static bool_ player_allow_corruption(int corruption_idx)
+{
+ int i;
+ bool_ found = FALSE;
+ corruption_type *c_ptr = NULL;
+
+ assert(corruption_idx < CORRUPTIONS_MAX);
+ c_ptr = &corruptions[corruption_idx];
+
+ /* Must be allowed by module */
+ for (i = 0; c_ptr->modules[i] >= 0; i++)
+ {
+ if (c_ptr->modules[i] == game_module_idx)
+ {
+ found = TRUE;
+ }
+ }
+
+ if (!found)
+ {
+ return FALSE;
+ }
+
+ /* Vampire teeth is special */
+ if (corruption_idx == CORRUPT_VAMPIRE_TEETH)
+ {
+ if (race_flags1_p(PR1_NO_SUBRACE_CHANGE))
+ {
+ return TRUE;
+ }
+ else
+ {
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+static void player_set_corruption(int c, bool_ set)
+{
+ p_ptr->corruptions[c] = set;
+ p_ptr->redraw = p_ptr->redraw | PR_FRAME;
+ p_ptr->update = p_ptr->update | PU_BONUS | PU_TORCH | PU_BODY | PU_POWERS;
+
+}
+
+void player_gain_corruption(int corruption_idx)
+{
+ corruption_type *c_ptr = NULL;
+ assert(corruption_idx >= 0);
+ assert(corruption_idx < CORRUPTIONS_MAX);
+ c_ptr = &corruptions[corruption_idx];
+
+ /* Set the player's corruption flag */
+ player_set_corruption(corruption_idx, TRUE);
+
+ /* Invoke callback if necessary */
+ if (c_ptr->gain_callback)
+ {
+ c_ptr->gain_callback();
+ }
+}
+
+static void player_lose_corruption(int corruption_idx)
+{
+ assert(corruption_idx >= 0);
+ assert(corruption_idx < CORRUPTIONS_MAX);
+
+ player_set_corruption(corruption_idx, FALSE);
+
+ /* Currently no corruptions need any special handling when lost */
+}
+
+/*
+ * 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
+ */
+static bool_ test_depend_corrupt(s16b corrupt_idx, bool_ can_gain)
+{
+ s16b i;
+ corruption_type *c_ptr = NULL;
+
+ assert(corrupt_idx >= 0);
+ assert(corrupt_idx < CORRUPTIONS_MAX);
+
+ c_ptr = &corruptions[corrupt_idx];
+
+ if (can_gain)
+ {
+ if (p_ptr->corruptions[corrupt_idx])
+ {
+ return FALSE;
+ }
+ } else {
+ if (!p_ptr->corruptions[corrupt_idx])
+ {
+ return FALSE;
+ }
+ }
+
+ /* Go through all dependencies */
+ for (i=0; c_ptr->depends[i] >= 0; i++)
+ {
+ if (!test_depend_corrupt(c_ptr->depends[i], FALSE))
+ {
+ return FALSE;
+ }
+ }
+
+ /* Go through all opposers */
+ for (i=0; c_ptr->opposes[i] >= 0; i++)
+ {
+ if (test_depend_corrupt(c_ptr->opposes[i], FALSE))
+ {
+ return FALSE;
+ }
+ }
+
+ /* are we even allowed to get it? */
+ return player_can_gain_corruption(corrupt_idx);
+}
+
+void gain_random_corruption()
+{
+ s16b i, max;
+ s16b pos[CORRUPTIONS_MAX];
+
+ /* Get the list of all possible ones */
+ max = 0;
+ for (i=0; i < CORRUPTIONS_MAX; i++)
+ {
+ if (test_depend_corrupt(i, TRUE) &&
+ player_allow_corruption(i))
+ {
+ pos[max] = i;
+ max = max + 1;
+ }
+ }
+
+ /* Ok now get one of them */
+ if (max > 0)
+ {
+ s16b ret = rand_int(max);
+ int c_idx = pos[ret];
+ assert(c_idx < CORRUPTIONS_MAX);
+
+ player_gain_corruption(c_idx);
+ cmsg_print(TERM_L_RED, corruptions[c_idx].get_text);
+ }
+}
+
+static void remove_corruption(int c_idx)
+{
+ assert(c_idx >= 0 && c_idx < CORRUPTIONS_MAX);
+ assert(corruptions[c_idx].lose_text);
+
+ player_lose_corruption(c_idx);
+ cmsg_print(TERM_L_RED, corruptions[c_idx].lose_text);
+}
+
+void lose_corruption()
+{
+ s16b i, max;
+ s16b pos[CORRUPTIONS_MAX];
+
+ /* Get the list of all possible ones */
+ max = 0;
+ for (i = 0; i < CORRUPTIONS_MAX; i++)
+ {
+ bool_ is_removable = (corruptions[i].lose_text != NULL);
+ if (test_depend_corrupt(i, FALSE) && is_removable)
+ {
+ pos[max] = i;
+ max = max + 1;
+ }
+ }
+
+ /* Ok now get one of them */
+ if (max > 0)
+ {
+ s16b ret = rand_int(max);
+ int c_idx = pos[ret];
+
+ /* Remove the corruption */
+ remove_corruption(c_idx);
+
+ /* Ok now lets see if it broke some dependencies */
+ for (i = 0; i < max - 1; i++)
+ {
+ if (p_ptr->corruptions[pos[i]] != test_depend_corrupt(pos[i], FALSE))
+ {
+ remove_corruption(pos[i]);
+ }
+ }
+ }
+}
+
+
+/*
+ * Dump the corruption list
+ */
+void dump_corruptions(FILE *fff, bool_ color, bool_ header)
+{
+ int i;
+
+ assert(fff != NULL);
+
+ for (i = 0; i < CORRUPTIONS_MAX; i++)
+ {
+ corruption_type *c_ptr = &corruptions[i];
+
+ if (header)
+ {
+ fprintf(fff, "\n Corruption list:\n");
+ header = FALSE;
+ }
+
+ if (p_ptr->corruptions[i])
+ {
+ byte c = c_ptr->color;
+
+ if (color)
+ {
+ fprintf(fff, "#####%c%s:\n", conv_color[c], c_ptr->name);
+ }
+ else
+ {
+ fprintf(fff, "%s:\n", c_ptr->name);
+ }
+
+ fprintf(fff, "%s\n", c_ptr->desc);
+ }
+ }
+}
+
+/*
+ * Get the power granted by a corruption. Returns -1
+ * if the given corruption does not grant a power.
+ */
+s16b get_corruption_power(int corruption_idx)
+{
+ corruption_type *c_ptr = NULL;
+
+ assert(corruption_idx >= 0);
+ assert(corruption_idx < CORRUPTIONS_MAX);
+
+ c_ptr = &corruptions[corruption_idx];
+
+ if ((c_ptr->power >= 0) && (c_ptr->power < POWER_MAX))
+ {
+ return c_ptr->power;
+ }
+ else
+ {
+ assert(c_ptr->power == -1); /* Sanity check: Should always be the case. */
+ return -1;
+ }
+}
diff --git a/src/corrupt.hpp b/src/corrupt.hpp
new file mode 100644
index 00000000..c200762e
--- /dev/null
+++ b/src/corrupt.hpp
@@ -0,0 +1,47 @@
+#include "h-basic.h"
+
+extern void gain_random_corruption();
+extern void dump_corruptions(FILE *OutFile, bool_ color, bool_ header);
+extern void lose_corruption();
+extern bool_ player_has_corruption(int corruption_idx);
+extern void player_gain_corruption(int corruption_idx);
+extern s16b get_corruption_power(int corruption_idx);
+
+/*
+ * Corruptions
+ */
+#define CORRUPT_BALROG_AURA 0
+#define CORRUPT_BALROG_WINGS 1
+#define CORRUPT_BALROG_STRENGTH 2
+#define CORRUPT_BALROG_FORM 3
+#define CORRUPT_DEMON_SPIRIT 4
+#define CORRUPT_DEMON_HIDE 5
+#define CORRUPT_DEMON_BREATH 6
+#define CORRUPT_DEMON_REALM 7
+#define CORRUPT_RANDOM_TELEPORT 8
+#define CORRUPT_ANTI_TELEPORT 9
+#define CORRUPT_TROLL_BLOOD 10
+#define CORRUPT_VAMPIRE_TEETH 11
+#define CORRUPT_VAMPIRE_STRENGTH 12
+#define CORRUPT_VAMPIRE_VAMPIRE 13
+#define MUT1_SPIT_ACID 14
+#define MUT1_BR_FIRE 15
+#define MUT1_HYPN_GAZE 16
+#define MUT1_TELEKINES 17
+#define MUT1_VTELEPORT 18
+#define MUT1_MIND_BLST 19
+#define MUT1_VAMPIRISM 20
+#define MUT1_SMELL_MET 21
+#define MUT1_SMELL_MON 22
+#define MUT1_BLINK 23
+#define MUT1_EAT_ROCK 24
+#define MUT1_SWAP_POS 25
+#define MUT1_SHRIEK 26
+#define MUT1_ILLUMINE 27
+#define MUT1_DET_CURSE 28
+#define MUT1_BERSERK 29
+#define MUT1_MIDAS_TCH 30
+#define MUT1_GROW_MOLD 31
+#define MUT1_RESIST 32
+#define MUT1_EARTHQUAKE 33
+#define CORRUPTIONS_MAX 34
diff --git a/src/defines.h b/src/defines.h
index 850bbc7a..fc1f61f5 100644
--- a/src/defines.h
+++ b/src/defines.h
@@ -37,20 +37,13 @@
*/
#ifndef IS_CVS
-#define IS_CVS " (ah)"
-/* #define IS_CVS " (ah, git)" */
+/* #define IS_CVS " (ah)" */
+#define IS_CVS " (ah, git)"
#endif
-#define USER_PATH_VERSION "/2.3"
+#define USER_PATH_VERSION "/2.4"
-#define ANGBAND_2_8_1
-
-#define SAVEFILE_VERSION 104
-
-/*
- * This value is not currently used
- */
-#define VERSION_EXTRA 0
+#define SAVEFILE_VERSION 105
/*
* Maximum amount of Angband windows.
@@ -128,80 +121,24 @@
#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
@@ -223,6 +160,7 @@
/* Mimicry */
#define MAX_MIMIC_POWERS 5
+#define MIMIC_FORMS_MAX 14
/* Symbiosis */
#define MAX_SYMBIOTIC_POWERS 9
@@ -234,19 +172,6 @@
/*
- * 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.
@@ -304,30 +229,6 @@
#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
@@ -342,7 +243,6 @@
* 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 */
@@ -358,8 +258,6 @@
#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 */
@@ -418,7 +316,6 @@
#define NASTY_MON 50 /* 1/chance of inflated monster level */
-
/*
* Refueling constants
*/
@@ -460,7 +357,6 @@
#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
@@ -482,67 +378,11 @@
#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)
*/
@@ -589,22 +429,15 @@
#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
@@ -616,6 +449,9 @@
#define MKEY_BOULDER 21
#define MKEY_COMPANION 22
#define MKEY_PIERCING 23
+#define MKEY_DEATH_TOUCH 100
+#define MKEY_GEOMANCY 101
+#define MKEY_REACH_ATTACK 102
/*** Screen Locations ***/
@@ -668,45 +504,6 @@
#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") ***/
@@ -788,9 +585,6 @@
/* Permanent walls for quests */
#define FEAT_QUEST1 0x4B
-#define FEAT_QUEST2 0x4C
-#define FEAT_QUEST3 0x4D
-#define FEAT_QUEST4 0x4E
/* Features 0x4F - 0x53 -- unused */
@@ -862,7 +656,17 @@
/* Features 0xCF - 0xFF -- unused */
-#define MAX_BETWEEN_EXITS 2
+#define MAX_BETWEEN_EXITS 3
+
+/*
+ * Maximum number of school spells
+ */
+#define SCHOOL_SPELLS_MAX 200
+
+/*
+ * Maximum number of spell schools
+ */
+#define SCHOOLS_MAX 50
/*
* Number of effects
@@ -880,24 +684,6 @@
#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") ***/
@@ -1375,9 +1161,14 @@
#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 */
+#define ACT_GROW_MOLD 197
+#define ACT_MUSIC 200
+#define ACT_ETERNAL_FLAME 201
+#define ACT_MAGGOT 202
+#define ACT_LEBOHAUM 203
+#define ACT_DURANDIL 204
+#define ACT_RADAGAST 205 /* Theme */
+#define ACT_VALAROMA 206 /* Theme */
/*** Object "tval" and "sval" codes ***/
@@ -1398,8 +1189,6 @@
#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 ('~') */
@@ -1462,7 +1251,6 @@
/* 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
@@ -1938,6 +1726,7 @@
#define SV_SCROLL_RUMOR 51
#define SV_SCROLL_ARTIFACT 52
#define SV_SCROLL_NOTHING 53
+#define SV_SCROLL_STERILIZATION 54
/* The "sval" codes for TV_POTION */
#define SV_POTION_WATER 0
@@ -2050,27 +1839,6 @@
#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
@@ -2238,7 +2006,6 @@
#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
@@ -2275,38 +2042,9 @@
/*
* 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_FRAME 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)
@@ -2575,7 +2313,6 @@
#define SUMMON_SHADOWS 55
#define SUMMON_GHOST 56
#define SUMMON_QUYLTHULG 57
-#define SUMMON_LUA 58
/*
@@ -2674,7 +2411,10 @@
#define GF_TRAP_DEMONSOUL 108
#define GF_ATTACK 109
#define GF_CHARM_UNMOVING 110
-#define MAX_GF 111
+#define GF_INSTA_DEATH 111
+#define GF_ELEMENTAL_WALL 112
+#define GF_ELEMENTAL_GROWTH 113
+#define MAX_GF 114
/*
* Some things which induce learning
@@ -2730,7 +2470,6 @@
* 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 !!!! */
@@ -2914,9 +2653,6 @@
#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 */
@@ -2925,7 +2661,6 @@
#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
@@ -3094,11 +2829,6 @@
-/*** 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
*/
@@ -3172,7 +2902,6 @@
/*** 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
@@ -3413,7 +3142,6 @@
#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 */
/*
@@ -3520,386 +3248,10 @@
#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
@@ -3990,55 +3342,39 @@
#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
+#define BACT_DROP_ITEM 54
+#define BACT_GET_ITEM 55
+#define BACT_FIREPROOF_QUEST 56
+#define BACT_LIBRARY_QUEST 61
+#define BACT_EREBOR_KEY 66
/* If one adds new BACT_ do NOT forget to increase max_bact in variables.c */
@@ -4071,44 +3407,6 @@
#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
@@ -4191,13 +3489,7 @@
* 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
@@ -4219,14 +3511,6 @@
#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
@@ -4257,8 +3541,6 @@
#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
@@ -4273,7 +3555,6 @@
/* 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 */
@@ -4293,77 +3574,6 @@
#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
@@ -4406,7 +3616,11 @@
#define QUEST_DRAGONS 23
#define QUEST_HAUNTED 24
#define QUEST_EVIL 25
-#define MAX_Q_IDX_INIT 26
+#define QUEST_BOUNTY 26
+#define QUEST_FIREPROOF 27
+#define QUEST_LIBRARY 28
+#define QUEST_GOD 29
+#define MAX_Q_IDX 30
#define PLOT_MAIN 0
#define PLOT_BREE 1
@@ -4418,10 +3632,47 @@
#define MAX_PLOTS 7
/*
+ * Modules
+ */
+#define MODULE_TOME 0
+#define MODULE_THEME 1
+#define MAX_MODULES 2
+
+/*
+ * Races
+ */
+#define RACE_HUMAN 0
+#define RACE_HALF_ELF 1
+#define RACE_ELF 2
+#define RACE_HOBBIT 3
+#define RACE_GNOME 4
+#define RACE_DWARF 5
+#define RACE_ORC 6
+#define RACE_TROLL 7
+#define RACE_DUNADAN 8
+#define RACE_HIGH_ELF 9
+#define RACE_HALF_OGRE 10
+#define RACE_BEORNING 11
+#define RACE_KOBOLD 12 /* ToME */
+#define RACE_DRUADAN 12 /* Theme */
+#define RACE_PETTY_DWARF 13
+#define RACE_DARK_ELF 14
+#define RACE_ENT 15
+#define RACE_ROHANKNIGHT 16
+#define RACE_THUNDERLORD 17 /* ToME */
+#define RACE_EAGLE 17 /* Theme */
+#define RACE_DEATHMOLD 18 /* ToME */
+#define RACE_DRAGON 18 /* Theme */
+#define RACE_YEEK 19
+#define RACE_WOOD_ELF 20
+#define RACE_MAIA 21
+#define RACE_EASTERLING 22 /* Theme */
+#define RACE_DEMON 23 /* Theme */
+
+/*
* Hooks
*/
#define HOOK_MONSTER_DEATH 0
-#define HOOK_OPEN 1
#define HOOK_GEN_QUEST 2
#define HOOK_END_TURN 3
#define HOOK_FEELING 4
@@ -4442,84 +3693,29 @@
#define HOOK_MONSTER_AI 19
#define HOOK_PLAYER_LEVEL 20
#define HOOK_WIELD 21
-#define HOOK_INIT 22
-#define HOOK_QUAFF 23
+#define HOOK_NEW_MONSTER_END 22
#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_MON_ASK_HELP 69
#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
@@ -4548,69 +3744,6 @@
#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
@@ -4621,11 +3754,6 @@
#define MAX_MELEE 3
-/*
- * Player specialities, should be external but ti would be a mess
- */
-#define MAX_SPEC 20
-
/*
* Spellbinder triggers
@@ -4644,11 +3772,11 @@
#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))
+#define GOD_AULE 6
+#define GOD_VARDA 7
+#define GOD_ULMO 8
+#define GOD_MANDOS 9
+#define MAX_GODS 10
/*
* Command numbers for do_cmd_cli().
@@ -4689,7 +3817,63 @@
#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
+
+/**
+ * Spell school books/tomes
+ */
+#define TOME_MANA 0
+#define TOME_FIRE 1
+#define TOME_WINDS 2
+#define TOME_EARTH 3
+#define TOME_WATER 4
+#define TOME_TRANSLOCATION 5
+#define TOME_NATURE 6
+#define TOME_KNOWLEDGE 7
+#define TOME_TIME 8
+#define TOME_META 9
+#define TOME_MIND 10
+#define TOME_HELLFLAME 11
+#define TOME_ERU 20
+#define TOME_MANWE 21
+#define TOME_TULKAS 22
+#define TOME_MELKOR 23
+#define TOME_YAVANNA 24
+#define BOOK_CANTRIPS 50
+#define BOOK_TELEPORTATION 51
+#define BOOK_SUMMONING 52
+#define BOOK_DEMON_SWORD 55
+#define BOOK_DEMON_SHIELD 56
+#define BOOK_DEMON_HELM 57
+#define BOOK_DRUMS 58
+#define BOOK_HARPS 59
+#define BOOK_HORNS 60
+#define BOOK_PLAYER 61
+#define BOOK_GEOMANCY 62
+#define BOOK_AULE 63
+#define BOOK_VARDA 64
+#define BOOK_ULMO 65
+#define BOOK_MANDOS 66
+#define BOOK_RANDOM 255
+
+#define SCHOOL_BOOKS_SIZE 256
+
+/**
+ * Macro to generate a memoizing named monster lookup function.
+ *
+ * This is meant as a stopgap measure until a better method
+ * can be implemented.
+ */
+#define GENERATE_MONSTER_LOOKUP_FN(fn, name) \
+ static int fn()\
+ {\
+ static int r_idx = -1;\
+ if (r_idx < 0)\
+ {\
+ r_idx = test_monster_name(name);\
+ assert(r_idx);\
+ }\
+ return r_idx;\
+ }
diff --git a/src/deity_type.hpp b/src/deity_type.hpp
new file mode 100644
index 00000000..0dcbb818
--- /dev/null
+++ b/src/deity_type.hpp
@@ -0,0 +1,11 @@
+#pragma once
+
+/**
+ * A structure for deity information.
+ */
+struct deity_type
+{
+ int modules[3]; /* terminated with -1 */
+ char const *name;
+ char desc[10][80];
+};
diff --git a/src/deity_type_fwd.hpp b/src/deity_type_fwd.hpp
new file mode 100644
index 00000000..492bf1fa
--- /dev/null
+++ b/src/deity_type_fwd.hpp
@@ -0,0 +1,3 @@
+#pragma once
+
+struct deity_type;
diff --git a/src/device_allocation.cc b/src/device_allocation.cc
new file mode 100644
index 00000000..ec2d208c
--- /dev/null
+++ b/src/device_allocation.cc
@@ -0,0 +1,20 @@
+#include "device_allocation.hpp"
+
+#include <cassert>
+
+static void device_allocation_init(device_allocation *device_allocation, byte tval)
+{
+ assert(device_allocation != NULL);
+
+ device_allocation->tval = tval;
+ device_allocation->rarity = 0;
+ range_init(&device_allocation->base_level, 0, 0);
+ range_init(&device_allocation->max_level, 0, 0);
+}
+
+device_allocation *device_allocation_new(byte tval)
+{
+ device_allocation *d = new device_allocation;
+ device_allocation_init(d, tval);
+ return d;
+}
diff --git a/src/device_allocation.hpp b/src/device_allocation.hpp
new file mode 100644
index 00000000..28854eac
--- /dev/null
+++ b/src/device_allocation.hpp
@@ -0,0 +1,17 @@
+#pragma once
+
+#include "device_allocation_fwd.hpp"
+#include "range.hpp"
+
+/*
+ * Device allocation for skill
+ */
+struct device_allocation
+{
+ byte tval;
+ s32b rarity;
+ range_type base_level;
+ range_type max_level;
+};
+
+struct device_allocation *device_allocation_new(byte tval);
diff --git a/src/device_allocation_fwd.hpp b/src/device_allocation_fwd.hpp
new file mode 100644
index 00000000..70e53fca
--- /dev/null
+++ b/src/device_allocation_fwd.hpp
@@ -0,0 +1,8 @@
+#pragma once
+
+#include "h-basic.h"
+
+typedef struct device_allocation device_allocation;
+struct device_allocation;
+
+struct device_allocation *device_allocation_new(byte tval);
diff --git a/src/dice.cc b/src/dice.cc
new file mode 100644
index 00000000..187bae68
--- /dev/null
+++ b/src/dice.cc
@@ -0,0 +1,98 @@
+#include "dice.hpp"
+
+#include "z-rand.hpp"
+
+#include <cassert>
+
+void dice_init(dice_type *dice, long base, long num, long sides)
+{
+ assert(dice != NULL);
+
+ dice->base = base;
+ dice->num = num;
+ dice->sides = sides;
+}
+
+bool_ dice_parse(dice_type *dice, cptr s)
+{
+ long base, num, sides;
+
+ if (sscanf(s, "%ld+%ldd%ld", &base, &num, &sides) == 3)
+ {
+ dice_init(dice, base, num, sides);
+ return TRUE;
+ }
+
+ if (sscanf(s, "%ld+d%ld", &base, &sides) == 2)
+ {
+ dice_init(dice, base, 1, sides);
+ return TRUE;
+ }
+
+ if (sscanf(s, "d%ld", &sides) == 1)
+ {
+ dice_init(dice, 0, 1, sides);
+ return TRUE;
+ }
+
+ if (sscanf(s, "%ldd%ld", &num, &sides) == 2)
+ {
+ dice_init(dice, 0, num, sides);
+ return TRUE;
+ }
+
+ if (sscanf(s, "%ld", &base) == 1)
+ {
+ dice_init(dice, base, 0, 0);
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+void dice_parse_checked(dice_type *dice, cptr s)
+{
+ bool_ result = dice_parse(dice, s);
+ if (!result)
+ {
+ abort();
+ }
+}
+
+long dice_roll(dice_type *dice)
+{
+ assert(dice != NULL);
+ return dice->base + damroll(dice->num, dice->sides);
+}
+
+void dice_print(dice_type *dice, char *output)
+{
+ char buf[16];
+
+ output[0] = '\0';
+
+ if (dice->base > 0)
+ {
+ sprintf(buf, "%ld", dice->base);
+ strcat(output, buf);
+ }
+
+ if ((dice->num > 0) || (dice->sides > 0))
+ {
+ if (dice->base > 0)
+ {
+ strcat(output, "+");
+ }
+
+ if (dice->num > 1)
+ {
+ sprintf(buf, "%ld", dice->num);
+ strcat(output, buf);
+ }
+
+ strcat(output, "d");
+
+ sprintf(buf, "%ld", dice->sides);
+ strcat(output, buf);
+ }
+}
diff --git a/src/dice.hpp b/src/dice.hpp
new file mode 100644
index 00000000..40a49e37
--- /dev/null
+++ b/src/dice.hpp
@@ -0,0 +1,13 @@
+#pragma once
+
+#include "dice_fwd.hpp"
+
+/**
+ * Dice
+ */
+struct dice_type
+{
+ long base; /* Base value to which roll is added. */
+ long num; /* Number of dice */
+ long sides; /* Sides per dice */
+};
diff --git a/src/dice_fwd.hpp b/src/dice_fwd.hpp
new file mode 100644
index 00000000..72b3b5ca
--- /dev/null
+++ b/src/dice_fwd.hpp
@@ -0,0 +1,12 @@
+#pragma once
+
+#include "h-basic.h"
+
+typedef struct dice_type dice_type;
+struct dice_type;
+
+void dice_init(dice_type *dice, long base, long num, long sides);
+bool_ dice_parse(dice_type *dice, cptr s);
+void dice_parse_checked(dice_type *dice, cptr s);
+long dice_roll(dice_type *dice);
+void dice_print(dice_type *dice, char *buf);
diff --git a/src/dungeon.c b/src/dungeon.c
deleted file mode 100644
index 6d732f00..00000000
--- a/src/dungeon.c
+++ /dev/null
@@ -1,5664 +0,0 @@
-/* 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.cc b/src/dungeon.cc
new file mode 100644
index 00000000..3ec79068
--- /dev/null
+++ b/src/dungeon.cc
@@ -0,0 +1,5565 @@
+/*
+ * 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 "dungeon.hpp"
+#include "dungeon.h"
+
+#include "birth.hpp"
+#include "birth.h"
+#include "cave.hpp"
+#include "cave_type.hpp"
+#include "cmd1.hpp"
+#include "cmd2.hpp"
+#include "cmd3.hpp"
+#include "cmd4.hpp"
+#include "cmd5.hpp"
+#include "cmd6.hpp"
+#include "cmd7.hpp"
+#include "corrupt.hpp"
+#include "dungeon_info_type.hpp"
+#include "feature_type.hpp"
+#include "files.h"
+#include "files.hpp"
+#include "generate.hpp"
+#include "gen_evol.hpp"
+#include "gods.hpp"
+#include "help.hpp"
+#include "hooks.hpp"
+#include "init2.hpp"
+#include "levels.hpp"
+#include "loadsave.h"
+#include "loadsave.hpp"
+#include "lua_bind.hpp"
+#include "melee1.hpp"
+#include "melee2.hpp"
+#include "monster2.hpp"
+#include "monster3.hpp"
+#include "monster_race.hpp"
+#include "monster_type.hpp"
+#include "modules.hpp"
+#include "notes.hpp"
+#include "object1.hpp"
+#include "object2.hpp"
+#include "object_kind.hpp"
+#include "object_type.hpp"
+#include "options.hpp"
+#include "player_race.hpp"
+#include "player_race_mod.hpp"
+#include "player_spec.hpp"
+#include "player_type.hpp"
+#include "powers.hpp"
+#include "quest.hpp"
+#include "quark.hpp"
+#include "skills.hpp"
+#include "spell_type.hpp"
+#include "spells1.hpp"
+#include "spells2.hpp"
+#include "spells5.hpp"
+#include "squeltch.hpp"
+#include "stats.hpp"
+#include "store.hpp"
+#include "tables.hpp"
+#include "timer_type.hpp"
+#include "util.hpp"
+#include "util.h"
+#include "variable.h"
+#include "variable.hpp"
+#include "wild.hpp"
+#include "wilderness_map.hpp"
+#include "wilderness_type_info.hpp"
+#include "wizard2.hpp"
+#include "xtra1.hpp"
+#include "xtra2.hpp"
+#include "z-rand.hpp"
+
+#include <boost/filesystem.hpp>
+#include <cassert>
+
+#define TY_CURSE_CHANCE 100
+#define DG_CURSE_CHANCE 50
+#define AUTO_CURSE_CHANCE 15
+#define CHAINSWORD_NOISE 100
+
+/**
+ * Type of a "sense" function
+ */
+typedef byte (*sense_function_t)(object_type const *o_ptr);
+
+/*
+ * Return a "feeling" (or NULL) about an item. Method 1 (Heavy).
+ */
+static byte value_check_aux1(object_type const *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);
+}
+
+static byte value_check_aux1_magic(object_type const *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).
+ */
+static byte value_check_aux2(object_type const *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);
+}
+
+
+static byte value_check_aux2_magic(object_type const *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)
+{
+ if (praying_to(GOD_ERU))
+ {
+ if (p_ptr->grace > 100000)
+ {
+ if (magik(70)) return (TRUE);
+ else return (FALSE);
+ }
+ }
+ return (FALSE);
+}
+
+static sense_function_t select_sense(object_type *o_ptr, sense_function_t combat, sense_function_t magic)
+{
+ 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 combat;
+ }
+
+ case TV_POTION:
+ case TV_POTION2:
+ case TV_SCROLL:
+ case TV_WAND:
+ case TV_STAFF:
+ case TV_ROD:
+ case TV_ROD_MAIN:
+ {
+ return magic;
+ }
+
+ /* Dual use? */
+ case TV_DAEMON_BOOK:
+ {
+ return combat;
+ }
+ }
+
+ return nullptr;
+}
+
+/*
+ * Sense quality of specific list of objects.
+ *
+ * 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_objects(std::vector<int> const &object_idxs)
+{
+ /* 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 */
+ int combat_lev = get_skill(SKILL_COMBAT);
+
+ /* The magic skill affects magic item pseudo-ID */
+ int magic_lev = get_skill(SKILL_MAGIC);
+
+ /* Higher skill levels give the player better sense of items */
+ auto feel_combat = (combat_lev > 10) ? value_check_aux1 : value_check_aux2;
+ auto feel_magic = (magic_lev > 10) ? value_check_aux1_magic : value_check_aux2_magic;
+
+ /*** Sense everything ***/
+
+ /* Check everything */
+ for (auto i : object_idxs)
+ {
+ object_type *o_ptr = get_object(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;
+
+ /* Select appropriate sensing function, if any */
+ sense_function_t sense = select_sense(o_ptr, feel_combat, feel_magic);
+
+ /* Skip non-sensed items */
+ if (!sense)
+ {
+ continue;
+ }
+
+ /* Check for a feeling */
+ byte feel = sense(o_ptr);
+
+ /* Skip non-feelings */
+ if (feel == SENSE_NONE)
+ {
+ continue;
+ }
+
+ /* Get an object description */
+ char o_name[80];
+ object_desc(o_name, o_ptr, FALSE, 0);
+
+ /* Messages */
+ if (i < 0) {
+ // We get a message from the floor handling code, so
+ // it would be overkill to have a message here too.
+ }
+ else 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]);
+ }
+ 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();
+}
+
+void sense_inventory(void)
+{
+ static std::vector<int> idxs;
+ // Initialize static vector if necessary
+ if (idxs.empty())
+ {
+ idxs.reserve(INVEN_TOTAL);
+ for (int i = 0; i < INVEN_TOTAL; i++)
+ {
+ idxs.push_back(i);
+ }
+ }
+ sense_objects(idxs);
+}
+
+/*
+ * 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_FRAME);
+
+ /* 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_FRAME);
+
+ /* 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_FRAME);
+ }
+ }
+
+ /* Regenerate everyone */
+ for (i = 1; i < m_max; i++)
+ {
+ /* Check the i'th monster */
+ monster_type *m_ptr = &m_list[i];
+
+ /* 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 */
+ auto const r_ptr = m_ptr->race();
+ 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_FRAME);
+ }
+ }
+}
+
+
+/*
+ * Does an object decay?
+ *
+ * Should belong to object1.c, renamed to object_decays() -- pelpel
+ */
+static 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)
+{
+ spell_type *spell = spell_at(-music);
+ return spell_type_produce_effect_lasting(spell);
+}
+
+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 = 0;
+ }
+ else
+ {
+ p_ptr->csp -= use_mana;
+
+ /* Redraw mana */
+ p_ptr->redraw |= (PR_FRAME);
+
+ /* Window stuff */
+ p_ptr->window |= (PW_PLAYER);
+ }
+}
+
+
+/*
+ * Generate the feature effect
+ */
+static 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 */
+static bool_ is_recall = FALSE;
+
+
+/*
+ * Hook for corruptions
+ */
+static void process_world_corruptions()
+{
+ if (player_has_corruption(CORRUPT_RANDOM_TELEPORT))
+ {
+ if (rand_int(300) == 1)
+ {
+ if (magik(70))
+ {
+ if (get_check("Teleport?"))
+ {
+ teleport_player(50);
+ }
+ else
+ {
+ disturb(0);
+ msg_print("Your corruption takes over you, you teleport!");
+ teleport_player(50);
+ }
+ }
+ }
+ }
+
+ if (player_has_corruption(CORRUPT_ANTI_TELEPORT))
+ {
+ if (p_ptr->corrupt_anti_teleport_stopped)
+ {
+ int amt = p_ptr->msp + p_ptr->csp;
+ amt = amt / 100;
+ if (amt < 1) {
+ amt = 1;
+ }
+ increase_mana(-amt);
+ if (p_ptr->csp == 0)
+ {
+ p_ptr->corrupt_anti_teleport_stopped = FALSE;
+ msg_print("You stop controlling your corruption.");
+ p_ptr->update = p_ptr->update | PU_BONUS;
+ }
+ }
+ }
+}
+
+
+/*
+ * Shim for accessing Lua variable.
+ */
+static bool_ grace_delay_trigger()
+{
+ p_ptr->grace_delay++;
+
+ if (p_ptr->grace_delay >= 15)
+ {
+ /* reset */
+ p_ptr->grace_delay = 0;
+ /* triggered */
+ return TRUE;
+ }
+ else
+ {
+ /* not triggered */
+ return FALSE;
+ }
+}
+
+/*
+ * Hook for gods
+ */
+static void process_world_gods()
+{
+ const char *race_name = rp_ptr->title;
+ const char *subrace_name = rmp_ptr->title;
+
+ if (p_ptr->pgod == GOD_VARDA)
+ {
+ if (grace_delay_trigger())
+ {
+ /* Piety increases if in light. */
+ if (cave[p_ptr->py][p_ptr->px].info & CAVE_GLOW)
+ {
+ inc_piety(GOD_ALL, 2);
+ }
+
+ if (streq(race_name, "Orc") ||
+ streq(race_name, "Troll") ||
+ streq(race_name, "Dragon") ||
+ streq(race_name, "Demon"))
+ {
+ /* Varda hates evil races */
+ inc_piety(GOD_ALL, -2);
+ } else {
+ /* ... and everyone slightly less */
+ inc_piety(GOD_ALL, -1);
+ }
+
+ /* Prayer uses piety */
+ if (p_ptr->praying)
+ {
+ inc_piety(GOD_ALL, -1);
+ }
+ }
+ }
+
+ if (p_ptr->pgod == GOD_ULMO)
+ {
+ if (grace_delay_trigger())
+ {
+ int i;
+ /* Ulmo likes the Edain (except Easterlings) */
+ if (streq(race_name, "Human") ||
+ streq(race_name, "Dunadan") ||
+ streq(race_name, "Druadan") ||
+ streq(race_name, "RohanKnight"))
+ {
+ inc_piety(GOD_ALL, 2);
+ }
+ else if (streq(race_name, "Easterling") ||
+ streq(race_name, "Demon") ||
+ streq(race_name, "Orc"))
+ {
+ /* hated races */
+ inc_piety(GOD_ALL, -2);
+ }
+ else
+ {
+ inc_piety(GOD_ALL, 1);
+ }
+
+ if (p_ptr->praying)
+ {
+ inc_piety(GOD_ALL, -1);
+ }
+
+ /* Gain 1 point for each trident in inventory */
+ for (i = 0; i < INVEN_TOTAL; i++)
+ {
+ if ((p_ptr->inventory[i].tval == TV_POLEARM) &&
+ (p_ptr->inventory[i].sval == SV_TRIDENT))
+ {
+ inc_piety(GOD_ALL, 1);
+ }
+ }
+ }
+ }
+
+ if (p_ptr->pgod == GOD_AULE)
+ {
+ if (grace_delay_trigger())
+ {
+ int i;
+
+ /* Aule likes Dwarves and Dark Elves (Eol's
+ * influence here) */
+ if (!(streq(race_name, "Dwarf") ||
+ streq(race_name, "Petty-dwarf") ||
+ streq(race_name, "Gnome") ||
+ streq(race_name, "Dark-Elf")))
+ {
+ inc_piety(GOD_ALL, -1);
+ }
+
+ /* Search inventory for axe or hammer - Gain 1
+ * point of grace for each hammer or axe */
+ for (i = 0; i < INVEN_TOTAL; i++)
+ {
+ int tval = p_ptr->inventory[i].tval;
+ int sval = p_ptr->inventory[i].sval;
+
+ switch (tval)
+ {
+ case TV_AXE:
+ inc_piety(GOD_ALL, 1);
+ break;
+
+ case TV_HAFTED:
+ if ((sval == SV_WAR_HAMMER) ||
+ (sval == SV_LUCERN_HAMMER) ||
+ (sval == SV_GREAT_HAMMER))
+ {
+ inc_piety(GOD_ALL, 1);
+ }
+ break;
+ }
+ }
+
+ /* Praying may grant you a free stone skin
+ * once in a while */
+ if (p_ptr->praying)
+ {
+ int chance;
+ s32b grace;
+
+ inc_piety(GOD_ALL, -2);
+ grace = p_ptr->grace; /* shorthand */
+
+ chance = 1;
+ if (grace >= 50000)
+ {
+ chance = 50000;
+ }
+ else
+ {
+ chance = 50000 - grace;
+ }
+
+ if (randint(100000) <= 100000 / chance)
+ {
+ s16b type = 0;
+
+ if (grace >= 10000)
+ {
+ type = SHIELD_COUNTER;
+ }
+
+ set_shield(
+ randint(10) + 10 + (grace / 100),
+ 10 + (grace / 100),
+ type,
+ 2 + (grace / 200),
+ 3 + (grace / 400));
+
+ msg_print("Aule casts Stone Skin on you.");
+ }
+ }
+ }
+ }
+
+ if (p_ptr->pgod == GOD_MANDOS)
+ {
+ if (grace_delay_trigger())
+ {
+ /* He loves astral beings */
+ if (streq(subrace_name, "LostSoul"))
+ {
+ inc_piety(GOD_ALL, 1);
+ }
+
+ /* He likes High Elves only, though, as races */
+ if (!streq(race_name, "High-Elf"))
+ {
+ inc_piety(GOD_ALL, -1);
+ }
+
+ /* Really hates vampires and demons */
+ if (streq(subrace_name, "Vampire") ||
+ streq(race_name, "Demon"))
+ {
+ inc_piety(GOD_ALL, -10);
+ }
+ else
+ {
+ inc_piety(GOD_ALL, 2);
+ }
+ /* he really doesn't like to be disturbed */
+ if (p_ptr->praying)
+ {
+ inc_piety(GOD_ALL, -5);
+ }
+ }
+ }
+
+}
+
+/*
+ * 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))
+ {
+ /* Handle corruptions */
+ process_world_corruptions();
+
+ /* Handle gods */
+ process_world_gods();
+
+ /* 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;
+ assert(t_ptr->callback != NULL);
+ t_ptr->callback();
+ }
+ }
+
+ /* 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);
+ }
+ }
+
+ /*** Process the monsters ***/
+
+ /* Check for creature generation. */
+ if (!p_ptr->wild_mode &&
+ !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->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 (race_flags1_p(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);
+
+ /* Hack -- faint (bypass free action) */
+ (void)set_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;
+
+ 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;
+ }
+ }
+
+ /* 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);
+ }
+ else
+ {
+ regenmana(regen_amount);
+ }
+ }
+
+ /* Eru piety incraese with time */
+ if (((turn % 100) == 0) && (!p_ptr->did_nothing) && (!p_ptr->wild_mode))
+ {
+ if ((p_ptr->pgod == GOD_ERU) && !p_ptr->praying)
+ {
+ 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))
+ {
+ if (p_ptr->pgod == GOD_MANWE)
+ {
+ int dec = 4 - wisdom_scale(3);
+
+ if (p_ptr->praying)
+ {
+ dec++;
+ }
+
+ if (race_flags1_p(PR1_ELF))
+ {
+ dec -= wisdom_scale(2);
+ }
+
+ dec = std::max(1, dec);
+
+ inc_piety(GOD_MANWE, -dec);
+ }
+
+ if (p_ptr->pgod == GOD_MELKOR)
+ {
+ int dec = 8 - wisdom_scale(6);
+
+ if (p_ptr->praying)
+ {
+ dec++;
+ }
+
+ if (race_flags1_p(PR1_ELF))
+ {
+ dec += 5 - wisdom_scale(4);
+ }
+
+ dec = std::max(1, dec);
+
+ inc_piety(GOD_MELKOR, -dec);
+ }
+
+ if (praying_to(GOD_TULKAS))
+ {
+ int dec = std::max(1, 4 - wisdom_scale(3));
+
+ inc_piety(GOD_TULKAS, -dec);
+ }
+ }
+ /* Yavanna piety decrease with time */
+ if (((turn % 400) == 0) && (!p_ptr->did_nothing) && (!p_ptr->wild_mode) && (dun_level))
+ {
+ if (p_ptr->pgod == GOD_YAVANNA)
+ {
+ int dec = 5 - wisdom_scale(3);
+
+ /* Blech what an hideous hack */
+ if (!strcmp(rp_ptr->title, "Ent"))
+ {
+ dec -= wisdom_scale(2);
+ }
+
+ dec = std::max(1, dec);
+ 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 */
+ if (praying_to(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_FRAME);
+
+ /* 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);
+ }
+ }
+
+ /* True Strike */
+ if (p_ptr->strike)
+ {
+ (void)set_strike(p_ptr->strike - 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 precognition */
+ if (p_ptr->tim_precognition > 0)
+ {
+ set_tim_precognition(p_ptr->tim_precognition - 1);
+ }
+
+ /* 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 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);
+ }
+
+ /* 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);
+ }
+
+ /* 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)
+ {
+ dec_paralyzed();
+ }
+
+ /* 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);
+ }
+
+ /* 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);
+ }
+
+ 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_idxs.empty()) &&
+ ((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);
+ }
+ }
+
+
+ /*** 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);
+ 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);
+ 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 (race_flags1_p(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);
+ }
+
+ /* Redraw */
+ p_ptr->redraw |= (PR_FRAME);
+
+ /* 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);
+
+ 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_FRAME);
+
+ /* 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);
+ }
+
+ /* Redraw */
+ p_ptr->redraw |= (PR_FRAME);
+
+ /* 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);
+
+ /* 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);
+ 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)
+ {
+ if (o_ptr->timeout == 0)
+ {
+ o_ptr->pval--;
+
+ /* Notice changes */
+ if (o_ptr->pval <= 0)
+ {
+ int mx = p_ptr->px;
+ int 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);
+
+ monster_type *m_ptr = &m_list[cave[my][mx].m_idx];
+ auto const r_ptr = m_ptr->race();
+
+ if ((r_ptr->flags9 & RF9_IMPRESED) && can_create_companion())
+ {
+ msg_format("And you have given the imprint to your %s!", 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_new(HOOK_RECALL, NULL, NULL))
+ {
+ 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);
+
+ /* 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);
+}
+
+
+/*
+ * 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();
+
+ /* Parse the command */
+ switch (command_cmd)
+ {
+ /* Ignore */
+ case ESCAPE:
+ case ' ':
+ case 0:
+ {
+ break;
+ }
+
+ /* Ignore return */
+ case '\r':
+ {
+ break;
+ }
+
+
+
+ /*** 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_FRAME);
+
+ 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_FRAME);
+ 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_new(HOOK_FORBID_TRAVEL, NULL, NULL))
+ {
+ 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;
+
+ 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;
+
+ 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;
+
+ j_ptr = &p_ptr->inventory[INVEN_BOW];
+
+ 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;
+
+ do_cmd_throw();
+ break;
+ }
+
+ /* Aim a wand */
+ case 'a':
+ {
+ if (p_ptr->control) break;
+ if (p_ptr->wild_mode) 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;
+
+ 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;
+
+ 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;
+
+ 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;
+
+ 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;
+
+ 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 (race_flags1_p(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 ***/
+
+ /* 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;
+ }
+
+ /* 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.
+ */
+static void process_player(void)
+{
+ int i, j;
+
+ int speed_use;
+
+
+ /*** Apply energy ***/
+
+ /* 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);
+ }
+ }
+
+ /* 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);
+ }
+ p_ptr->redraw |= (PR_FRAME);
+ }
+ }
+
+ /* Handle "abort" */
+ if (!avoid_abort)
+ {
+ /* Check for "player abort" (semi-efficiently for resting) */
+ if (running || command_rep || (resting && !(resting & 0x0F)))
+ {
+ /* Check for a key */
+ if (inkey_scan())
+ {
+ /* Flush input */
+ flush();
+
+ /* Disturb */
+ disturb(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);
+
+ /* 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_FRAME);
+ }
+
+ 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_FRAME);
+
+ /* 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 && shimmer_monsters)
+ {
+ /* Clear the flag */
+ shimmer_monsters = FALSE;
+
+ /* Shimmer multi-hued monsters */
+ for (i = 1; i < m_max; i++)
+ {
+ /* Access monster */
+ monster_type *m_ptr = &m_list[i];
+
+ /* Skip dead monsters */
+ if (!m_ptr->r_idx) continue;
+
+ /* Access the monster race */
+ auto const r_ptr = m_ptr->race();
+
+ /* 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 && 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 &&
+ !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;
+
+
+ /* Disturb */
+ disturb(1);
+
+ /* 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_FRAME);
+
+ /* 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_new(HOOK_END_TURN, NULL, NULL);
+
+ /* 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);
+
+ /* Process that file */
+ process_pref_file(buf);
+
+ /* Access the "class" pref file */
+ sprintf(buf, "%s.prf", spp_ptr->title);
+
+ /* 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);
+
+ /* Load automatizer settings. Character-specific automatizer
+ * file gets priority over the "template" file. We do not try
+ * to merge the two files since that would require tracking
+ * the providence of rules and such to avoid the same
+ * duplication problems as caused when saving macros/keymaps. */
+ boost::filesystem::path userDirectory(ANGBAND_DIR_USER);
+ if (automatizer_load(userDirectory / (std::string(player_name) + ".atm")))
+ {
+ // Done
+ }
+ else if (automatizer_load(userDirectory / "automat.atm"))
+ {
+ // Done
+ }
+}
+
+/*
+ * 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;
+
+ /* Initialize player */
+ p_ptr = new player_type();
+
+ /* Hack -- Character is "icky" */
+ character_icky = TRUE;
+
+
+ /* Make sure main term is active */
+ Term_activate(angband_term[0]);
+
+ /* Initialise the resize hooks for all the terminals */
+ angband_term[0]->resize_hook = resize_map;
+ for (i = 1; i < ANGBAND_TERM_MAX; 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);
+ }
+ }
+
+ /* Process old character */
+ if (!new_game)
+ {
+ /* Process the player name */
+ process_player_name(FALSE);
+ }
+
+ /* 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)
+ {
+ /* Show intro */
+ modules[game_module_idx].intro();
+
+ /* 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;
+
+ /* Hack -- enter the world */
+ /* Mega-hack Vampires and Spectres start at midnight */
+ if (race_flags1_p(PR1_UNDEAD))
+ {
+ turn = (10L * DAY / 2) + 1;
+ }
+ else
+ {
+ turn = 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_quests();
+ init_hooks_help();
+ init_hooks_module();
+
+ /* 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)
+ {
+ 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_new(HOOK_GAME_START, NULL, NULL);
+
+ /* 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;
+
+ /* 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_new(HOOK_DIE, NULL, NULL))
+ {
+ 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; */
+ 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_new(HOOK_NEW_LEVEL, NULL, NULL);
+ generate_cave();
+ }
+
+ /* Close stuff */
+ close_game();
+
+ /* Quit */
+ quit(NULL);
+}
+
diff --git a/src/dungeon.h b/src/dungeon.h
new file mode 100644
index 00000000..1ce166d1
--- /dev/null
+++ b/src/dungeon.h
@@ -0,0 +1,14 @@
+#pragma once
+
+#include "h-basic.h"
+
+// C linkage required for these functions since main-* code uses them.
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern void play_game(bool_ new_game);
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
diff --git a/src/dungeon.hpp b/src/dungeon.hpp
new file mode 100644
index 00000000..bbe6da87
--- /dev/null
+++ b/src/dungeon.hpp
@@ -0,0 +1,6 @@
+#pragma once
+
+#include <vector>
+
+extern void sense_inventory();
+extern void sense_objects(std::vector<int> const &object_idxs);
diff --git a/src/dungeon.pkg b/src/dungeon.pkg
deleted file mode 100644
index f5e4045f..00000000
--- a/src/dungeon.pkg
+++ /dev/null
@@ -1,1607 +0,0 @@
-/* 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/dungeon_info_type.hpp b/src/dungeon_info_type.hpp
new file mode 100644
index 00000000..5f6fc9d0
--- /dev/null
+++ b/src/dungeon_info_type.hpp
@@ -0,0 +1,72 @@
+#pragma once
+
+#include "h-basic.h"
+#include "rule_type.hpp"
+#include "obj_theme.hpp"
+
+/**
+ * Maximum number of towns per dungeon
+ */
+constexpr int TOWN_DUNGEON = 4;
+
+/* A structure for the != dungeon types */
+struct dungeon_info_type
+{
+ const char *name; /* Name */
+ char *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 */
+};
+
diff --git a/src/dungeon_info_type_fwd.hpp b/src/dungeon_info_type_fwd.hpp
new file mode 100644
index 00000000..26ed0289
--- /dev/null
+++ b/src/dungeon_info_type_fwd.hpp
@@ -0,0 +1,3 @@
+#pragma once
+
+struct dungeon_info_type;
diff --git a/src/effect_type.hpp b/src/effect_type.hpp
new file mode 100644
index 00000000..8cd638c6
--- /dev/null
+++ b/src/effect_type.hpp
@@ -0,0 +1,17 @@
+#pragma once
+
+#include "h-basic.h"
+
+/**
+ * Lasting spell effects. (Clouds, etc.)
+ */
+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 */
+};
diff --git a/src/ego_item_type.hpp b/src/ego_item_type.hpp
new file mode 100644
index 00000000..f9b6970a
--- /dev/null
+++ b/src/ego_item_type.hpp
@@ -0,0 +1,68 @@
+#pragma once
+
+#include "h-basic.h"
+
+/*
+ * Size of flag rarity tables
+ */
+constexpr int FLAG_RARITY_MAX = 6;
+
+/**
+ * Ego item descriptors.
+ */
+struct ego_item_type
+{
+ const char *name; /* Name (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[FLAG_RARITY_MAX];
+ u32b flags1[FLAG_RARITY_MAX]; /* Ego-Item Flags, set 1 */
+ u32b flags2[FLAG_RARITY_MAX]; /* Ego-Item Flags, set 2 */
+ u32b flags3[FLAG_RARITY_MAX]; /* Ego-Item Flags, set 3 */
+ u32b flags4[FLAG_RARITY_MAX]; /* Ego-Item Flags, set 4 */
+ u32b flags5[FLAG_RARITY_MAX]; /* Ego-Item Flags, set 5 */
+ u32b esp[FLAG_RARITY_MAX]; /* ESP flags */
+ u32b oflags1[FLAG_RARITY_MAX]; /* Ego-Item Obvious Flags, set 1 */
+ u32b oflags2[FLAG_RARITY_MAX]; /* Ego-Item Obvious Flags, set 2 */
+ u32b oflags3[FLAG_RARITY_MAX]; /* Ego-Item Obvious Flags, set 3 */
+ u32b oflags4[FLAG_RARITY_MAX]; /* Ego-Item Obvious Flags, set 4 */
+ u32b oflags5[FLAG_RARITY_MAX]; /* Ego-Item Obvious Flags, set 5 */
+ u32b oesp[FLAG_RARITY_MAX]; /* Obvious ESP flags */
+ u32b fego[FLAG_RARITY_MAX]; /* 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) */
+};
diff --git a/src/ego_item_type_fwd.hpp b/src/ego_item_type_fwd.hpp
new file mode 100644
index 00000000..795f4403
--- /dev/null
+++ b/src/ego_item_type_fwd.hpp
@@ -0,0 +1,3 @@
+#pragma once
+
+struct ego_item_type;
diff --git a/src/externs.h b/src/externs.h
deleted file mode 100644
index 197c1c8a..00000000
--- a/src/externs.h
+++ /dev/null
@@ -1,1851 +0,0 @@
-/* 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/fate.hpp b/src/fate.hpp
new file mode 100644
index 00000000..906bc99d
--- /dev/null
+++ b/src/fate.hpp
@@ -0,0 +1,22 @@
+#pragma once
+
+#include "h-basic.h"
+
+/**
+ * Fate descritpor.
+ */
+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 */
+};
diff --git a/src/feature_type.hpp b/src/feature_type.hpp
new file mode 100644
index 00000000..1a79aeb3
--- /dev/null
+++ b/src/feature_type.hpp
@@ -0,0 +1,37 @@
+#pragma once
+
+#include "h-basic.h"
+
+/**
+ * Terrain feature descriptor.
+ */
+struct feature_type
+{
+ char *name; /* Name */
+
+ const char *text; /* Text. May point to shared read-only memory, DO NOT FREE! */
+ const char *tunnel; /* Text for tunneling. May point to shared read-only memory, DO NOT FREE! */
+ const char *block; /* Text for blocking. May point to shared read-only memory, DO NOT FREE! */
+
+ 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 */
+};
diff --git a/src/feature_type_fwd.hpp b/src/feature_type_fwd.hpp
new file mode 100644
index 00000000..168ec6c7
--- /dev/null
+++ b/src/feature_type_fwd.hpp
@@ -0,0 +1,3 @@
+#pragma once
+
+struct feature_type;
diff --git a/src/files.c b/src/files.c
deleted file mode 100644
index 56e57975..00000000
--- a/src/files.c
+++ /dev/null
@@ -1,6058 +0,0 @@
-/* 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/files.cc b/src/files.cc
new file mode 100644
index 00000000..cc168ba5
--- /dev/null
+++ b/src/files.cc
@@ -0,0 +1,5788 @@
+/*
+ * 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 "files.hpp"
+#include "files.h"
+
+#include "cave.hpp"
+#include "cave_type.hpp"
+#include "corrupt.hpp"
+#include "cmd3.hpp"
+#include "dungeon_info_type.hpp"
+#include "feature_type.hpp"
+#include "hiscore.hpp"
+#include "hook_chardump_in.hpp"
+#include "hooks.hpp"
+#include "init1.hpp"
+#include "levels.hpp"
+#include "loadsave.h"
+#include "loadsave.hpp"
+#include "mimic.hpp"
+#include "monster2.hpp"
+#include "monster3.hpp"
+#include "monster_ego.hpp"
+#include "monster_race.hpp"
+#include "monster_type.hpp"
+#include "notes.hpp"
+#include "object1.hpp"
+#include "object2.hpp"
+#include "object_kind.hpp"
+#include "options.hpp"
+#include "player_class.hpp"
+#include "player_race.hpp"
+#include "player_race_mod.hpp"
+#include "player_spec.hpp"
+#include "player_type.hpp"
+#include "skills.hpp"
+#include "spells2.hpp"
+#include "store_info_type.hpp"
+#include "store_type.hpp"
+#include "tables.hpp"
+#include "town_type.hpp"
+#include "trap_type.hpp"
+#include "util.hpp"
+#include "util.h"
+#include "variable.h"
+#include "variable.hpp"
+#include "wilderness_map.hpp"
+#include "wilderness_type_info.hpp"
+#include "xtra1.hpp"
+#include "z-rand.hpp"
+
+#include <memory>
+#include <unordered_set>
+
+/*
+ * 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]);
+
+ free(keymap_act[mode][i]);
+
+ keymap_act[mode][i] = strdup(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)
+ {
+ delete[] macro_template;
+ macro_template = NULL;
+
+ for (i = 0; i < max_macrotrigger; i++)
+ {
+ delete[] macro_trigger_name[i];
+ macro_trigger_name[i] = nullptr;
+ }
+ 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 = new char[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] = new char[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;
+ }
+
+ /* Race */
+ else if (streq(b + 1, "RACE"))
+ {
+ v = rp_ptr->title;
+ }
+
+ /* Race */
+ else if (streq(b + 1, "RACEMOD"))
+ {
+ v = rmp_ptr->title;
+ }
+
+ /* Class */
+ else if (streq(b + 1, "CLASS"))
+ {
+ v = spp_ptr->title;
+ }
+
+ /* 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,
+ cptr 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 */
+ if (p_ptr->pgod == GOD_ERU)
+ {
+ if ((p_ptr->grace >= 100) || (p_ptr->grace <= -100)) (*f1) |= TR1_MANA;
+ if (p_ptr->grace > 10000) (*f1) |= TR1_WIS;
+ }
+
+ if (p_ptr->pgod == 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);
+ if (p_ptr->praying)
+ {
+ if (p_ptr->grace > 5000) (*f2) |= TR2_INVIS;
+ if (p_ptr->grace > 15000) (*f2) |= TR2_IM_FIRE;
+ }
+ }
+
+ if (p_ptr->pgod == GOD_MANWE)
+ {
+ if (p_ptr->grace >= 2000) (*f3) |= TR3_FEATHER;
+ if (p_ptr->praying)
+ {
+ 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;
+ }
+ }
+
+ if (p_ptr->pgod == GOD_TULKAS)
+ {
+ if (p_ptr->grace > 5000) (*f1) |= TR1_CON;
+ if (p_ptr->grace > 10000) (*f1) |= TR1_STR;
+ }
+
+ if (p_ptr->pgod == GOD_AULE)
+ {
+ if (p_ptr->grace > 5000)
+ {
+ (*f2) |= TR2_RES_FIRE;
+ }
+ }
+
+ if (p_ptr->pgod == GOD_MANDOS)
+ {
+ (*f2) |= TR2_RES_NETHER;
+
+ if ((p_ptr->grace > 10000) &&
+ (p_ptr->praying == TRUE))
+ {
+ (*f3) |= TR3_NO_TELE;
+ }
+
+ if ((p_ptr->grace > 20000) &&
+ (p_ptr->praying == TRUE))
+ {
+ (*f4) |= TR4_IM_NETHER;
+ }
+ }
+
+ if (p_ptr->pgod == GOD_ULMO)
+ {
+ (*f5) |= TR5_WATER_BREATH;
+
+ if ((p_ptr->grace > 1000) &&
+ (p_ptr->praying == TRUE))
+ {
+ (*f2) |= TR2_RES_POIS;
+ }
+
+ if ((p_ptr->grace > 15000) &&
+ (p_ptr->praying == TRUE))
+ {
+ (*f5) |= TR5_MAGIC_BREATH;
+ }
+ }
+
+ /* 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, 5, 9);
+ c_put_str(TERM_L_BLUE, 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), 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);
+ }
+ else if (wf_info[feat].terrain_idx == TERRAIN_TOWN)
+ {
+ sprintf(desc, "in the town of %s", wf_info[feat].name);
+ }
+ else if (wf_info[feat].entrance)
+ {
+ sprintf(desc, "near %s", wf_info[feat].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);
+ }
+ else if (pwx == lwx && pwy == lwy)
+ {
+ /* Paranoia; this should have been caught above */
+ sprintf(desc, "near %s", wf_info[feat].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,
+ ns,
+ ew,
+ wf_info[landmark].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_info[store].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.
+ */
+static bool_ file_character_check_stores(std::unordered_set<store_type *> *seen_stores, wilderness_type_info *place, int store)
+{
+ town_type *town = &town_info[place->entrance];
+ store_type *st_ptr = &town->store[store];
+
+ // Already seen store?
+ if (seen_stores->find(st_ptr) != seen_stores->end())
+ {
+ return FALSE;
+ }
+
+ // Add
+ seen_stores->insert(st_ptr);
+ 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];
+
+ /* Build the filename */
+ path_build(buf, 1024, ANGBAND_DIR_USER, name);
+
+ /* 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 */
+ 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->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_info[y].name,
+ max_dlv[y], 50 * (max_dlv[y]));
+ }
+ fprintf(fff, "\n");
+
+ if (noscore)
+ fprintf(fff, "\n You have done something illegal.");
+
+ if (race_flags1_p(PR1_EXPERIMENTAL))
+ fprintf(fff, "\n You have done something experimental.");
+
+ {
+ 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)
+ {
+ mimic = get_mimic_name(p_ptr->mimic_form);
+ 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);
+ }
+
+ struct hook_chardump_in in = { fff };
+ process_hooks_new(HOOK_CHAR_DUMP, &in, NULL);
+
+ /* Date */
+ {
+ u32b days = bst(DAY, turn);
+ 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 */
+ dump_corruptions(fff, FALSE, TRUE);
+
+ /* 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 */
+ {
+ std::unordered_set<store_type *> seen_stores;
+ for (j = 0; j < max_wf_idx; j++)
+ {
+ if (wf_info[j].feat == FEAT_TOWN &&
+ file_character_check_stores(&seen_stores, &wf_info[j], 7))
+ {
+ file_character_print_store(fff, &wf_info[j], 7, full);
+ }
+ }
+ }
+
+ /* Print all Mathom-houses in the different towns */
+ {
+ std::unordered_set<store_type *> seen_stores;
+ for (j = 0; j < max_wf_idx; j++)
+ {
+ if (wf_info[j].feat == FEAT_TOWN &&
+ file_character_check_stores(&seen_stores, &wf_info[j], 57))
+ {
+ file_character_print_store(fff, &wf_info[j], 57, full);
+ }
+ }
+ }
+
+ 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;
+
+ /* 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 */
+ std::unique_ptr<hyperlink_type> h_ptr(new hyperlink_type);
+ memset(h_ptr.get(), 0, sizeof(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);
+
+ /* 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)
+ {
+ 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);
+
+ /* 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;
+
+ cptr file_ext = "html";
+ cptr link_prefix = "";
+ cptr link_suffix = "";
+
+ /* Pointer to general buffer in the above */
+ char *buf;
+
+ /* Allocate hyperlink data */
+ std::unique_ptr<hyperlink_type> h_ptr(new hyperlink_type);
+ memset(h_ptr.get(), 0, sizeof(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;
+ }
+
+ 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)
+ {
+ 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);
+
+ /* Normal return */
+ return (TRUE);
+}
+
+static 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';
+}
+
+/* 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);
+
+ /* 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);
+
+ /* 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);
+ }
+ }
+
+ /* 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++] = '_';
+ }
+
+
+#if defined(WINDOWS)
+
+ /* 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");
+
+
+ /* 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);
+ }
+
+ /* 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)");
+
+ /* 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);
+
+ /* 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-
+ */
+static 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 */
+ mult -= 1; /* maximize pentalty, always on */
+ if (auto_scum) mult -= 4;
+ if (small_levels) mult += ((always_small_level) ? 4 : 10);
+ if (empty_levels) mult += 2;
+ if (smart_learn) 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;
+
+ 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, "");
+}
+
+
+/*
+ * Display a "tomb-stone"
+ */
+static void print_tomb(void)
+{
+ cptr p;
+
+ char tmp[160];
+
+ char buf[1024];
+ char dummy[80];
+
+ FILE *fp;
+
+ time_t ct = time(nullptr);
+
+
+ /* 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];
+ }
+
+ 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);
+ 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();
+ show_equip_full();
+ prt("You are using: -more-", 0, 0);
+ if (inkey() == ESCAPE) return;
+ }
+
+ /* Inventory -- if any */
+ if (inven_cnt)
+ {
+ Term_clear();
+ show_inven_full();
+ 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;
+ }
+ }
+ }
+}
+
+
+
+
+
+/*
+ * 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 highscore_fd, 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(highscore_fd, 0)) return;
+
+ /* Hack -- Count the high scores */
+ for (i = 0; i < MAX_HISCORES; i++)
+ {
+ if (highscore_read(highscore_fd, &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 gold, when, aged;
+
+ int 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(highscore_fd, j)) break;
+ if (highscore_read(highscore_fd, &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_quest = atoi(the_score.inside_quest);
+
+ /* Hack -- extract the gold and such */
+ 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,
+ 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_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,
+ " (Date %s, Gold %s, Turn %s).",
+ 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;
+ }
+}
+
+
+/*
+ * show_highclass - selectively list highscores based on class
+ * -KMW-
+ */
+void show_highclass(int building)
+{
+
+ int i = 0, j, m = 0;
+ int pr, pc, clev;
+ high_score the_score;
+ char buf[1024], out_val[256];
+ int highscore_fd;
+
+ 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_USER, "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(highscore_fd, 0)) return;
+
+ for (i = 0; i < MAX_HISCORES; i++)
+ if (highscore_read(highscore_fd, &the_score)) break;
+
+ m = 0;
+ j = 0;
+ clev = 0;
+
+ while ((m < 9) || (j < MAX_HISCORES))
+ {
+ if (highscore_seek(highscore_fd, j)) break;
+ if (highscore_read(highscore_fd, &the_score)) break;
+ pr = atoi(the_score.p_r);
+ pc = atoi(the_score.p_c);
+ clev = atoi(the_score.cur_lev);
+ if (((pc == (building - 10)) && (building != 1)) ||
+ ((building == 1) && (clev >= PY_MAX_LEVEL)))
+ {
+ sprintf(out_val, "%3d) %s the %s (Level %2d)",
+ (m + 1), the_score.who, 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, race_info[p_ptr->prace].title, p_ptr->lev);
+ prt(out_val, (m + 8), 0);
+ }
+ else if ((building != 1))
+ {
+ if ((p_ptr->lev > clev) && (p_ptr->pclass == (building - 10)))
+ {
+ sprintf(out_val, "You) %s the %s (Level %2d)",
+ player_name, race_info[p_ptr->prace].title, p_ptr->lev);
+ prt(out_val, (m + 8), 0);
+ }
+ }
+
+ fd_close(highscore_fd);
+
+ 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)
+{
+ int i = 0, j, m = 0;
+ int pr, clev, lastlev;
+ high_score the_score;
+ char buf[1024], out_val[256], tmp_str[80];
+ int highscore_fd;
+
+ lastlev = 0;
+
+ /* rr9: TODO - pluralize the race */
+ sprintf(tmp_str, "The Greatest of all the %s", race_info[race_num].title);
+ prt(tmp_str, 5, 3);
+
+ /* Build the filename */
+ path_build(buf, 1024, ANGBAND_DIR_USER, "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(highscore_fd, 0)) return;
+
+ for (i = 0; i < MAX_HISCORES; i++)
+ {
+ if (highscore_read(highscore_fd, &the_score)) break;
+ }
+
+ m = 0;
+ j = 0;
+
+ while ((m < 10) && (j < i))
+ {
+ if (highscore_seek(highscore_fd, j)) break;
+ if (highscore_read(highscore_fd, &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,
+ 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, race_info[p_ptr->prace].title, p_ptr->lev);
+ prt(out_val, (m + 8), 0);
+ }
+
+ fd_close(highscore_fd);
+}
+
+
+/*
+ * 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.
+ */
+static errr top_twenty(void)
+{
+ int j;
+
+ high_score the_score;
+
+ time_t ct = time((time_t*)0);
+
+ char buf[1024];
+
+ int highscore_fd = 0;
+
+ /* Build the filename */
+ path_build(buf, sizeof(buf), ANGBAND_DIR_USER, "scores.raw");
+
+ /* Open the highscore file, for reading/writing */
+ highscore_fd = fd_open(buf, O_RDWR);
+
+ if (highscore_fd < 0)
+ {
+ msg_print("Score file unavailable.");
+ msg_print(NULL);
+ goto out;
+ }
+
+ /* Clear screen */
+ Term_clear();
+
+ /* Wizard-mode pre-empts scoring */
+ if (noscore & 0x000F)
+ {
+ msg_print("Score not registered for wizards.");
+ msg_print(NULL);
+ display_scores_aux(highscore_fd, 0, 10, -1, NULL);
+ goto out;
+ }
+
+ /* Borg-mode pre-empts scoring */
+ if (noscore & 0x00F0)
+ {
+ msg_print("Score not registered for borgs.");
+ msg_print(NULL);
+ display_scores_aux(highscore_fd, 0, 10, -1, NULL);
+ goto out;
+ }
+
+ /* Cheaters are not scored */
+ if (noscore & 0xFF00)
+ {
+ msg_print("Score not registered for cheaters.");
+ msg_print(NULL);
+ display_scores_aux(highscore_fd, 0, 10, -1, NULL);
+ goto out;
+ }
+
+ /* Interupted */
+ if (!total_winner && streq(died_from, "Interrupting"))
+ {
+ msg_print("Score not registered due to interruption.");
+ msg_print(NULL);
+ display_scores_aux(highscore_fd, 0, 10, -1, NULL);
+ goto out;
+ }
+
+ /* Quitter */
+ if (!total_winner && streq(died_from, "Quitting"))
+ {
+ msg_print("Score not registered due to quitting.");
+ msg_print(NULL);
+ display_scores_aux(highscore_fd, 0, 10, -1, NULL);
+ goto out;
+ }
+
+
+ /* Clear the record */
+ static_assert(std::is_pod<high_score>::value,
+ "Cannot memset a non-POD type");
+ memset(&the_score, 0, sizeof(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);
+ the_score.turns[9] = '\0';
+
+ /* Save the date in standard form (8 chars) */
+ strftime(the_score.day, 9, "%m/%d/%y", localtime(&ct));
+
+ /* Save the player name (15 chars) */
+ sprintf(the_score.who, "%-.15s", player_name);
+
+ /* Save the player info XXX XXX XXX */
+ 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.inside_quest, "%3d", p_ptr->inside_quest);
+
+ /* Save the cause of death (31 chars) */
+ sprintf(the_score.how, "%-.31s", died_from);
+
+
+ /* Add a new entry to the score list, see where it went */
+ j = highscore_add(highscore_fd, &the_score);
+
+
+ /* Hack -- Display the top fifteen scores */
+ if (j < 10)
+ {
+ display_scores_aux(highscore_fd, 0, 15, j, NULL);
+ }
+
+ /* Display the scores surrounding the player */
+ else
+ {
+ display_scores_aux(highscore_fd, 0, 5, j, NULL);
+ display_scores_aux(highscore_fd, j - 2, j + 7, j, NULL);
+ }
+
+
+out:
+ if (highscore_fd >= 0)
+ {
+ fd_close(highscore_fd);
+ }
+
+ /* Success */
+ return (0);
+}
+
+
+/*
+ * Predict the players location, and display it.
+ */
+static errr predict_score(void)
+{
+ int j;
+
+ high_score the_score;
+
+ char buf[1024];
+
+ int highscore_fd = 0;
+
+ /* Build the filename */
+ path_build(buf, sizeof(buf), ANGBAND_DIR_USER, "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);
+ goto out;
+ }
+
+ /* Clear the record */
+ static_assert(std::is_pod<high_score>::value,
+ "Cannot memset a non-POD type");
+ memset(&the_score, 0, sizeof(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);
+ 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.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.inside_quest, "%3d", p_ptr->inside_quest);
+
+ /* Hack -- no cause of death */
+ strcpy(the_score.how, "nobody (yet!)");
+
+
+ /* See where the entry would be placed */
+ j = highscore_where(highscore_fd, &the_score);
+
+
+ /* Hack -- Display the top fifteen scores */
+ if (j < 10)
+ {
+ display_scores_aux(highscore_fd, 0, 15, j, &the_score);
+ }
+
+ /* Display some "useful" scores */
+ else
+ {
+ display_scores_aux(highscore_fd, 0, 5, -1, NULL);
+ display_scores_aux(highscore_fd, j - 2, j + 7, j, &the_score);
+ }
+
+out:
+ if (highscore_fd >= 0)
+ {
+ fd_close(highscore_fd);
+ }
+
+ /* Success */
+ return (0);
+}
+
+
+void predict_score_gui(bool_ *initialized_p, bool_ *game_in_progress_p)
+{
+ char buf[1024];
+ int highscore_fd;
+
+ /* Paranoia */
+ if (!(*initialized_p) || character_icky ||
+ !(*game_in_progress_p) || !character_generated)
+ {
+ /* Can't happen but just in case */
+ plog("You may not do that right now.");
+ return;
+ }
+
+ /* Build the pathname of the score file */
+ path_build(buf, sizeof(buf), ANGBAND_DIR_USER, "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.");
+ return;
+ }
+
+ /* Mega-Hack - prevent various functions XXX XXX XXX */
+ *initialized_p = FALSE;
+
+ /* Save screen */
+ screen_save();
+
+ /* Clear screen */
+ Term_clear();
+
+ /* Prepare scores */
+ if ((*game_in_progress_p) && character_generated)
+ {
+ predict_score();
+ }
+
+ /* 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_p = TRUE;
+}
+
+
+/*
+ * 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)
+{
+ /* Handle stuff */
+ handle_stuff();
+
+ /* Flush the messages */
+ msg_print(NULL);
+
+ /* Flush the input */
+ flush();
+
+
+ /* Hack -- Character is now "icky" */
+ character_icky = TRUE;
+
+
+ /* Handle death */
+ if (death)
+ {
+ /* Handle retirement */
+ if (total_winner)
+ {
+ /* Make a note */
+ 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();
+
+ /* Make a note */
+ {
+ 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();
+
+ /* Make a note pf session end */
+ 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();
+ }
+}
+
+
+/*
+ * Grab a randomly selected line in lib/file/file_name
+ */
+errr get_rnd_line(const 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(const 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(const 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);
+}
diff --git a/src/files.h b/src/files.h
new file mode 100644
index 00000000..e3df5636
--- /dev/null
+++ b/src/files.h
@@ -0,0 +1,17 @@
+#pragma once
+
+#include "h-basic.h"
+
+// C linkage required for these functions since main-* code uses them.
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern bool_ txt_to_html(cptr head, cptr food, cptr base, cptr ext, bool_ force, bool_ recur);
+extern void process_player_name(bool_ sf);
+extern void do_cmd_save_game(void);
+extern void predict_score_gui(bool_ *initialized, bool_ *game_in_progress);
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
diff --git a/src/files.hpp b/src/files.hpp
new file mode 100644
index 00000000..52206d12
--- /dev/null
+++ b/src/files.hpp
@@ -0,0 +1,27 @@
+#pragma once
+
+#include "h-basic.h"
+#include "monster_type_fwd.hpp"
+
+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 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 get_name(void);
+extern void do_cmd_suicide(void);
+extern void autosave_checkpoint();
+extern void close_game(void);
+extern errr get_rnd_line(const char * file_name, char * output);
+extern char *get_line(const char* fname, cptr fdir, char *linbuf, int line);
+extern void race_legends(void);
+extern void show_highclass(int building);
+extern errr get_xtra_line(const char * file_name, monster_type *m_ptr, char * output);
diff --git a/src/flags_group.hpp b/src/flags_group.hpp
new file mode 100644
index 00000000..bdf5216b
--- /dev/null
+++ b/src/flags_group.hpp
@@ -0,0 +1,20 @@
+#pragma once
+
+#include "h-basic.h"
+
+/**
+ * For level gaining artifacts
+ */
+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 */
+};
diff --git a/src/gen_evol.c b/src/gen_evol.c
deleted file mode 100644
index bfdfbd68..00000000
--- a/src/gen_evol.c
+++ /dev/null
@@ -1,156 +0,0 @@
-/*
- * 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_evol.cc b/src/gen_evol.cc
new file mode 100644
index 00000000..6f3fbcba
--- /dev/null
+++ b/src/gen_evol.cc
@@ -0,0 +1,160 @@
+/*
+ * 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 "gen_evol.hpp"
+
+#include "cave.hpp"
+#include "cave_type.hpp"
+#include "feature_type.hpp"
+#include "generate.hpp"
+#include "levels.hpp"
+#include "player_type.hpp"
+#include "variable.hpp"
+#include "z-rand.hpp"
+
+/*
+ * 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_idxs.empty()) || 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_idxs.empty()) || 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_evol.hpp b/src/gen_evol.hpp
new file mode 100644
index 00000000..65b1320d
--- /dev/null
+++ b/src/gen_evol.hpp
@@ -0,0 +1,6 @@
+#pragma once
+
+#include "h-basic.h"
+
+extern bool_ level_generate_life();
+extern void evolve_level(bool_ noise);
diff --git a/src/gen_maze.c b/src/gen_maze.c
deleted file mode 100644
index 92cb482f..00000000
--- a/src/gen_maze.c
+++ /dev/null
@@ -1,294 +0,0 @@
-/*
- * 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/gen_maze.cc b/src/gen_maze.cc
new file mode 100644
index 00000000..22722e0a
--- /dev/null
+++ b/src/gen_maze.cc
@@ -0,0 +1,294 @@
+/*
+ * 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 "gen_evol.hpp"
+
+#include "cave.hpp"
+#include "generate.hpp"
+#include "levels.hpp"
+#include "variable.hpp"
+#include "z-rand.hpp"
+
+#include <memory>
+
+/*
+ * 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];
+
+static 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;
+
+ /* Allocate temporary memory */
+ std::unique_ptr<maze_row[]> maze(new maze_row[(MAX_HGT / 2) + 2]);
+
+ /*
+ * 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.get(), 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);
+ }
+ }
+ }
+
+ /* Determine the character location */
+ if (!new_player_spot(get_branch()))
+ return FALSE;
+
+ return TRUE;
+}
diff --git a/src/gen_maze.hpp b/src/gen_maze.hpp
new file mode 100644
index 00000000..28c092e3
--- /dev/null
+++ b/src/gen_maze.hpp
@@ -0,0 +1,5 @@
+#pragma once
+
+#include "h-basic.h"
+
+extern bool_ level_generate_maze();
diff --git a/src/generate.c b/src/generate.c
deleted file mode 100644
index 6d83c321..00000000
--- a/src/generate.c
+++ /dev/null
@@ -1,8890 +0,0 @@
-/* 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/generate.cc b/src/generate.cc
new file mode 100644
index 00000000..b5733682
--- /dev/null
+++ b/src/generate.cc
@@ -0,0 +1,8698 @@
+/*
+ * 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 "generate.hpp"
+
+#include "artifact_type.hpp"
+#include "cave.hpp"
+#include "cave_type.hpp"
+#include "dungeon_info_type.hpp"
+#include "feature_type.hpp"
+#include "hook_build_room1_in.hpp"
+#include "hooks.hpp"
+#include "init1.hpp"
+#include "levels.hpp"
+#include "loadsave.hpp"
+#include "monster2.hpp"
+#include "monster_race.hpp"
+#include "monster_type.hpp"
+#include "object2.hpp"
+#include "object_kind.hpp"
+#include "options.hpp"
+#include "player_type.hpp"
+#include "randart.hpp"
+#include "spells1.hpp"
+#include "tables.hpp"
+#include "town_type.hpp"
+#include "traps.hpp"
+#include "util.hpp"
+#include "variable.hpp"
+#include "vault_type.hpp"
+#include "wild.hpp"
+#include "wilderness_map.hpp"
+#include "z-rand.hpp"
+
+#include <cassert>
+#include <memory>
+#include <vector>
+
+#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)();
+
+ struct level_generator_type *next;
+};
+
+static level_generator_type *level_generators = NULL;
+
+/*
+ * Add a new generator
+ */
+void add_level_generator(cptr name, bool_ (*generator)())
+{
+ assert(name != nullptr);
+
+ level_generator_type *g = new level_generator_type;
+
+ g->name = strdup(name);
+ g->generator = generator;
+
+ 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))
+ {
+ /* 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;
+
+ /* 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 + 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_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_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;
+ }
+
+
+ /* 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_ptr->data);
+}
+
+
+
+/*
+ * 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;
+ }
+
+
+ /* 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_ptr->data);
+}
+
+/*
+ * 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 = ((static_cast<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 m, n, num_vertices;
+ 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 */
+ std::vector<int> visited(num_vertices, 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.data());
+
+ /* Fill with monsters and treasure, low difficulty */
+ fill_treasure(x1, x2, y1, y2, randint(5));
+}
+
+
+/*
+ * 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 m, n, num_vertices;
+
+ 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 */
+ std::vector<int> visited(num_vertices, 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.data());
+
+ /* 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);
+}
+
+
+/*
+ * 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
+ */
+static 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 */
+ {
+ struct hook_build_room1_in in = { y, x };
+ process_hooks_new(HOOK_BUILD_ROOM1, &in, NULL);
+ }
+
+ /* 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))
+ {
+ /* 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;
+ }
+
+ /* 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
+ */
+static void replace_all_friends()
+{
+ if (p_ptr->wild_mode)
+ {
+ return;
+ }
+
+ /* Scan every saved pet */
+ for (int i = 0; i < max_m_idx; i++)
+ {
+ if ((km_list[i].r_idx) && (km_list[i].status == MSTATUS_COMPANION))
+ {
+ int y = p_ptr->py;
+ int x = p_ptr->px;
+
+ /* Find a suitable location */
+ get_pos_player(5, &y, &x);
+ cave_type *c_ptr = &cave[y][x];
+
+ /* Get a m_idx to use */
+ c_ptr->m_idx = m_pop();
+ monster_type *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_idxs.clear(); // Objects have been removed previously by caller
+ }
+ }
+}
+
+/*
+ * Save the imprinted pets from the old level
+ */
+static void save_all_friends()
+{
+ if (p_ptr->old_wild_mode) return;
+
+ for (int i = 0; i < max_m_idx; i++) {
+ km_list[i] = m_list[i];
+ }
+}
+
+
+
+/*
+ * 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);
+ }
+ }
+ }
+}
+
+
+/**
+ * @brief double a grid tile. Used for the double-size dungeons
+ */
+static void supersize_grid_tile(int sy, int sx, int ty, int tx)
+{
+ /* Displacements for copied grid tiles */
+ constexpr std::size_t n_disp = 4;
+ int disp[n_disp][2] = {
+ { 0, 0 },
+ { 0, +1 },
+ { +1, 0 },
+ { +1, +1 }
+ };
+
+ /* Acquire the grid tile and monster */
+ cave_type *cc_ptr = &cave[sy][sx];
+ monster_type *m_ptr = &m_list[cc_ptr->m_idx];
+
+ /* Save the list of objects */
+ auto const object_idxs(cc_ptr->o_idxs);
+
+ /* Save the monster */
+ auto m_idx = cc_ptr->m_idx;
+
+ /* Create pointers to each of the target grid tiles */
+ cave_type *c_ptr[n_disp];
+ for (std::size_t i = 0; i < n_disp; i++)
+ {
+ c_ptr[i] = &cave[ty + disp[i][0]][tx + disp[i][1]];
+ }
+
+ /* Now we copy around the grid tiles. Objects and
+ monsters are "removed" for now. */
+ for (std::size_t i = 0; i < 4; i++)
+ {
+ c_ptr[i] = &cave[ty + disp[i][0]][tx + disp[i][1]];
+
+ /* Copy grid */
+ *c_ptr[i] = *cc_ptr;
+ c_ptr[i]->o_idxs.clear(); // ... except objects in the tile
+ c_ptr[i]->m_idx = 0; // ... except monsters in the tile
+
+ /* Void gates need special attention */
+ 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);
+ }
+ }
+
+ /* Scatter objects randomly into the destination grid tiles */
+ for (auto const o_idx: object_idxs)
+ {
+ std::size_t i = static_cast<std::size_t>(rand_int(4));
+ /* Put object into grid tile */
+ c_ptr[i]->o_idxs.push_back(o_idx);
+ /* Give object its location */
+ object_type *o_ptr = &o_list[o_idx];
+ o_ptr->iy = ty + disp[i][0];
+ o_ptr->ix = tx + disp[i][1];
+ }
+
+ /* Scatter move monster randomly into one of the destination grid tiles */
+ if (m_idx != 0)
+ {
+ std::size_t i = static_cast<std::size_t>(rand_int(4));
+ /* Place monster into grid tile */
+ c_ptr[i]->m_idx = cc_ptr->m_idx;
+ /* Give the monster its location */
+ m_ptr->fy = ty + disp[i][0];
+ m_ptr->fx = tx + disp[i][1];
+ }
+}
+
+
+/*
+ * Generate a new dungeon level
+ *
+ * Note that "dun_body" adds about 4000 bytes of memory to the stack.
+ */
+static bool_ cave_gen(void)
+{
+ 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())
+ return FALSE;
+ break;
+ }
+
+ generator = generator->next;
+ }
+
+ /* Generate stairs */
+ {
+ /* Is there a dungeon branch ? */
+ if (int branch = get_branch())
+ {
+ /* Place 5 down stair some walls */
+ alloc_stairs(FEAT_MORE, 5, 3, branch);
+ }
+
+ /* Is there a father dungeon branch ? */
+ if (int 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_new(HOOK_GEN_LEVEL, NULL, NULL);
+
+ /* Basic "amount" */
+ int k = (dun_level / 3);
+ if (k > 10) k = 10;
+ if (k < 2) k = 2;
+
+ /* Place monsters */
+ {
+
+ /*
+ * Pick a base number of monsters
+ */
+ int 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 (std::size_t 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 (std::size_t 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;
+ }
+ }
+ }
+
+ /* Place traps and rubble */
+ {
+ /* 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));
+ }
+
+ /* Place objects and treasure */
+ {
+ /* 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));
+ }
+
+ /* Place random features such as altars and void gates, etc. */
+ {
+ /* 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->held_m_idx = m_idx;
+ o_ptr->ix = 0;
+ o_ptr->iy = 0;
+
+ m_list[m_idx].hold_o_idxs.push_back(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->held_m_idx = m_idx;
+ o_ptr->ix = 0;
+ o_ptr->iy = 0;
+
+ m_list[m_idx].hold_o_idxs.push_back(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 move upwards
+ * to the left. This avoids the need for an extra copy of
+ * the cave array.
+ *
+ * We double the border permanent walls, too.
+ */
+ int y = cur_hgt - 1;
+ int y1 = y * 2;
+ for (; y >= 0; y--, y1 -= 2)
+ {
+ int x = cur_wid - 1;
+ int x1 = x * 2;
+ for (; x >= 0; x--, x1 -= 2)
+ {
+ supersize_grid_tile(y, x, y1, x1);
+ }
+ }
+
+ /* 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;
+}
+
+
+
+/*
+ * 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_new(HOOK_LEVEL_REGEN, NULL, NULL);
+
+ /* 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_new(HOOK_LEVEL_END_GEN, NULL, NULL);
+
+ /* 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
+ */
+static 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_new(HOOK_GEN_LEVEL_BEGIN, NULL, NULL);
+
+ /* 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++)
+ {
+ /* Wipe */
+ cave[y][x].wipe();
+
+ /* No features */
+ cave_set_feat(y, x, FEAT_PERM_INNER);
+ }
+ }
+
+ 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++)
+ {
+ /* Wipe */
+ cave[y][x].wipe();
+
+ /* No features */
+ cave_set_feat(y, x, FEAT_PERM_INNER);
+ }
+ }
+
+
+ /* 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;
+
+ /* Quest levels -KMW- */
+ if (p_ptr->inside_quest)
+ {
+ process_hooks_new(HOOK_GEN_QUEST, NULL, NULL);
+ }
+
+ /* 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();
+ }
+
+ /* 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/generate.hpp b/src/generate.hpp
new file mode 100644
index 00000000..d09907b5
--- /dev/null
+++ b/src/generate.hpp
@@ -0,0 +1,12 @@
+#pragma once
+
+#include "h-basic.h"
+
+extern bool_ new_player_spot(int branch);
+extern void add_level_generator(cptr name, bool_ (*generator)());
+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_cave(void);
+extern void build_rectangle(int y1, int x1, int y2, int x2, int feat, int info);
diff --git a/src/gf_name_type.hpp b/src/gf_name_type.hpp
new file mode 100644
index 00000000..0b17bdbf
--- /dev/null
+++ b/src/gf_name_type.hpp
@@ -0,0 +1,10 @@
+#pragma once
+
+/**
+ * GF_XXX descriptor entry.
+ */
+struct gf_name_type
+{
+ int gf;
+ char const *name;
+};
diff --git a/src/gods.c b/src/gods.c
deleted file mode 100644
index b8b8fd3a..00000000
--- a/src/gods.c
+++ /dev/null
@@ -1,139 +0,0 @@
-/* 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/gods.cc b/src/gods.cc
new file mode 100644
index 00000000..1163e9b6
--- /dev/null
+++ b/src/gods.cc
@@ -0,0 +1,212 @@
+/*
+ * 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 "gods.hpp"
+
+#include "player_type.hpp"
+#include "skills.hpp"
+#include "skill_type.hpp"
+#include "stats.hpp"
+#include "util.hpp"
+#include "util.h"
+#include "variable.h"
+#include "variable.hpp"
+#include "xtra2.hpp"
+
+#include <cassert>
+
+/*
+ * 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);
+ }
+}
+
+/*
+ * Check if god may be followed by player
+ */
+static bool_ may_follow_god(int god)
+{
+ if (god == GOD_MELKOR)
+ {
+ int i;
+
+ /* Check if player has wielded The One Ring */
+ for (i = INVEN_WIELD; i < INVEN_TOTAL; i++)
+ {
+ if (p_ptr->inventory[i].name1 == ART_POWER)
+ {
+ msg_print("The One Ring has corrupted "
+ "you, and you are rejected.");
+ return FALSE;
+ }
+ }
+ }
+ /* Default is to allow */
+ return TRUE;
+}
+
+/*
+ * 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 (!may_follow_god(god))
+ return;
+
+ if (p_ptr->pgod == GOD_NONE)
+ {
+ p_ptr->pgod = god;
+
+ /* Melkor offer Udun magic */
+ if (p_ptr->pgod == 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.");
+ }
+ }
+}
+
+/*
+ * Show religious info.
+ */
+bool_ show_god_info()
+{
+ 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;
+}
+
+/*
+ * Get deity info for a given god index.
+ * Returns NULL for the "atheist" god.
+ */
+deity_type *god_at(byte god_idx)
+{
+ assert(god_idx >= 0);
+ assert(god_idx < MAX_GODS);
+
+ if (god_idx == 0)
+ {
+ return NULL;
+ }
+
+ return &deity_info[god_idx];
+}
+
+/*
+ * Check if god is enabled for the current module
+ */
+bool_ god_enabled(struct deity_type *deity)
+{
+ int i;
+
+ for (i = 0; deity->modules[i] != -1; i++)
+ {
+ if (deity->modules[i] == game_module_idx)
+ {
+ return TRUE;
+ }
+ }
+ /* Not enabled */
+ return FALSE;
+}
+
+/* Find a god by name */
+int find_god(cptr name)
+{
+ int i;
+
+ for (i = 0; i < MAX_GODS; i++)
+ {
+ /* The name matches and god is "enabled" for the
+ current module. */
+ if (god_enabled(&deity_info[i]) &&
+ streq(deity_info[i].name, name))
+ {
+ return (i);
+ }
+ }
+ return -1;
+}
+
+bool praying_to(int god)
+{
+ return (p_ptr->pgod == god) && p_ptr->praying;
+}
diff --git a/src/gods.hpp b/src/gods.hpp
new file mode 100644
index 00000000..7035dd14
--- /dev/null
+++ b/src/gods.hpp
@@ -0,0 +1,13 @@
+#pragma once
+
+#include "h-basic.h"
+
+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);
+extern bool_ god_enabled(struct deity_type *deity);
+extern deity_type *god_at(byte god_idx);
+extern bool_ show_god_info();
+extern bool praying_to(int god);
diff --git a/src/h-basic.h b/src/h-basic.h
index b5ea5d87..a65780a5 100644
--- a/src/h-basic.h
+++ b/src/h-basic.h
@@ -1,7 +1,8 @@
-/* File: h-basic.h */
+#pragma once
-#ifndef INCLUDED_H_BASIC_H
-#define INCLUDED_H_BASIC_H
+#ifdef __cplusplus
+extern "C" {
+#endif
/*
* The most basic "include" file.
@@ -21,5 +22,6 @@
/* Basic constants and macros */
#include "h-define.h"
+#ifdef __cplusplus
+} // extern "C"
#endif
-
diff --git a/src/h-config.h b/src/h-config.h
index 53670e8f..09e9bac8 100644
--- a/src/h-config.h
+++ b/src/h-config.h
@@ -1,7 +1,8 @@
-/* File: h-config.h */
+#pragma once
-#ifndef INCLUDED_H_CONFIG_H
-#define INCLUDED_H_CONFIG_H
+#ifdef __cplusplus
+extern "C" {
+#endif
/*
* Choose the hardware, operating system, and compiler.
@@ -19,115 +20,12 @@
*/
/*
- * 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
@@ -147,7 +45,7 @@
* 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__)
+#if 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
@@ -160,34 +58,14 @@
* 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
+ * Basically, SET_UID should *only* be set for "Unix" machines.
*/
-#if !defined(MACINTOSH) && !defined(WINDOWS) && \
- !defined(MSDOS)
+#if !defined(WINDOWS)
# 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
@@ -196,79 +74,11 @@
*/
#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
+#ifdef __cplusplus
+} // extern "C"
#endif
diff --git a/src/h-define.h b/src/h-define.h
index cb36b189..76e7e339 100644
--- a/src/h-define.h
+++ b/src/h-define.h
@@ -33,19 +33,6 @@
# 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"
@@ -87,12 +74,6 @@
#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
diff --git a/src/h-system.h b/src/h-system.h
index 50cc0af8..92041742 100644
--- a/src/h-system.h
+++ b/src/h-system.h
@@ -18,27 +18,18 @@
#include <ctype.h>
#include <errno.h>
-#if defined(NeXT)
-# include <libc.h>
-#else
-# include <stdlib.h>
-#endif
+#include <stdlib.h>
#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)
+# if defined(linux)
# include <sys/time.h>
# endif
-# if !defined(SGI) && !defined(ULTRIX)
# include <sys/timeb.h>
-# endif
#endif
@@ -47,35 +38,20 @@
-#ifdef MACINTOSH
-# include <unix.h>
-#endif
-
-#if defined(WINDOWS) || defined(MSDOS)
+#if defined(WINDOWS)
# include <io.h>
#endif
-#if !defined(MACINTOSH) && \
- !defined(__MWERKS__)
-# if defined(__TURBOC__) || defined(__WATCOMC__)
-# include <mem.h>
-# else
-# include <memory.h>
-# endif
-#endif
+#include <memory.h>
-#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>
@@ -87,32 +63,12 @@
# 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
@@ -122,10 +78,6 @@ extern char *strrchr();
-#if !defined(linux) && !defined(__MWERKS__)
-extern long atol();
-#endif
-
#include <stdarg.h>
diff --git a/src/h-type.h b/src/h-type.h
index 5dbb4975..bcf013bb 100644
--- a/src/h-type.h
+++ b/src/h-type.h
@@ -3,6 +3,11 @@
#ifndef INCLUDED_H_TYPE_H
#define INCLUDED_H_TYPE_H
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
/*
* Basic "types".
*
@@ -67,17 +72,11 @@ typedef int errr;
#define uint uint_hack
/*
- * Hack -- prevent problems with MSDOS and WINDOWS
+ * Hack -- prevent problems with 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 */
@@ -109,14 +108,20 @@ typedef unsigned long huge;
/* Signed/Unsigned 16 bit value */
typedef signed short s16b;
typedef unsigned short u16b;
+#define FMTs16b "%hd"
+#define FMTu16b "%hu"
/* Signed/Unsigned 32 bit value */
#ifdef L64 /* 64 bit longs */
typedef signed int s32b;
typedef unsigned int u32b;
+#define FMTs32b "%d"
+#define FMTu32b "%u"
#else
typedef signed long s32b;
typedef unsigned long u32b;
+#define FMTs32b "%ld"
+#define FMTu32b "%lu"
#endif
@@ -174,5 +179,9 @@ typedef vptr (*func_key)(vptr);
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
#endif
diff --git a/src/help.c b/src/help.c
deleted file mode 100644
index d0bdbedf..00000000
--- a/src/help.c
+++ /dev/null
@@ -1,23 +0,0 @@
-/* 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/help.cc b/src/help.cc
new file mode 100644
index 00000000..a6d83079
--- /dev/null
+++ b/src/help.cc
@@ -0,0 +1,742 @@
+/*
+ * Copyright (c) 2001 DarkGod
+ * Copyright (c) 2012 Bardur Arantsson
+ *
+ * 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 "help.hpp"
+
+#include "cave_type.hpp"
+#include "files.hpp"
+#include "hook_get_in.hpp"
+#include "hook_identify_in.hpp"
+#include "hook_move_in.hpp"
+#include "hooks.hpp"
+#include "object1.hpp"
+#include "options.hpp"
+#include "player_type.hpp"
+#include "skills.hpp"
+#include "util.hpp"
+#include "variable.hpp"
+
+#define DESC_MAX 14
+#define TRIGGERED_HELP_MAX 18
+
+#define HELP_VOID_JUMPGATE 0
+#define HELP_FOUNTAIN 1
+#define HELP_FOUND_OBJECT 2
+#define HELP_FOUND_ALTAR 3
+#define HELP_FOUND_STAIR 4
+#define HELP_GET_RUNE 5
+#define HELP_GET_ROD 6
+#define HELP_GET_ROD_TIP 7
+#define HELP_GET_TRAP_KIT 8
+#define HELP_GET_DEVICE 9
+#define HELP_WILDERNESS 10
+#define HELP_GAME_TOME 11
+#define HELP_GAME_THEME 12
+#define HELP_1ST_LEVEL 13
+#define HELP_20TH_LEVEL 14
+#define HELP_ID_SPELL_ITM 15
+#define HELP_MELEE_SKILLS 16
+#define HELP_MON_ASK_HELP 17
+
+/**
+ * Game started?
+ */
+static bool_ game_started = FALSE;
+
+/**
+ * Struct for help triggered by a boolean condition
+ */
+typedef struct triggered_help_type triggered_help_type;
+struct triggered_help_type
+{
+ /* Help item index; see HELP_* constants above */
+ int help_index;
+ /* Hook type */
+ int hook_type;
+ /* Trigger function */
+ bool_ (*trigger_func)(void *in, void *out);
+ /* Description; NULL terminated */
+ cptr desc[DESC_MAX];
+};
+
+/**
+ * Struct for context-sensitive help
+ */
+typedef struct context_help_type context_help_type;
+struct context_help_type
+{
+ cptr key; /* Lookup key */
+ cptr file_name; /* Name of help file */
+ int anchor; /* Anchor in file */
+};
+
+/**
+ * Race help files.
+ */
+context_help_type race_table[] =
+{
+ /* ToME */
+ { "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 },
+ /* Theme */
+ { "Dragon", "r_dragon.txt", 0 },
+ { "Druadan", "r_druadan.txt", 0 },
+ { "Eagle", "r_eagle.txt", 0 },
+ { "Easterling", "r_easterl.txt", 0 },
+ { "Demon", "r_demon.txt", 0 },
+ /* End of list */
+ { NULL, NULL, 0 },
+};
+
+/**
+ * Subrace help files.
+ */
+context_help_type subrace_table[] =
+{
+ /* ToME */
+ { "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 },
+ /* Theme */
+ { "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 },
+ /* End of list */
+ { NULL, NULL, 0 },
+};
+
+/**
+ * Class help files
+ */
+context_help_type class_table[] =
+{
+ /* ToME */
+ { "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 },
+ /* Theme */
+ { "Ascetic", "c_ascet.txt", 0 },
+ { "Clairvoyant", "c_clairv.txt", 0 },
+ { "Mercenary", "c_mercen.txt", 0 },
+ { "Pacifist", "c_pacif.txt", 0 },
+ { "Peace-mage", "c_peacemag.txt", 0 },
+ { "Priest(Mandos)", "c_pr_mand.txt", 0 },
+ { "Priest(Ulmo)", "c_pr_ulmo.txt", 0 },
+ { "Priest(Varda)", "c_pr_varda.txt", 0 },
+ { "Sniper", "c_sniper.txt", 0 },
+ { "Stonewright", "c_stonewr.txt", 0 },
+ { "Trapper", "c_trapper.txt", 0 },
+ { "Wainrider", "c_wainrid.txt", 0 },
+ { "War-mage", "c_warmage.txt", 0 },
+ /* End of list */
+ { NULL, NULL, 0 },
+};
+
+/**
+ * God help files
+ */
+context_help_type god_table[] =
+{
+ /* ToME */
+ { "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 },
+ /* Theme */
+ { "Aule the Smith", "g_aule.txt", 0 },
+ { "Mandos", "g_mandos.txt", 0 },
+ { "Ulmo", "g_ulmo.txt", 0 },
+ { "Varda Elentari", "g_varda.txt", 0 },
+ /* End of list */
+ { NULL, NULL, 0 },
+};
+
+/**
+ * Skill help files
+ */
+context_help_type skill_table[] =
+{
+ { "Air", "skills.txt", 27 },
+ { "Antimagic", "skills.txt", 50 },
+ { "Archery", "skills.txt", 8 },
+ { "Axe-mastery", "skills.txt", 5 },
+ { "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", 1 },
+ { "Conveyance", "skills.txt", 30 },
+ { "Corpse-preservation", "skills.txt", 44 },
+ { "Critical-hits", "skills.txt", 4 },
+ { "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", 6 },
+ { "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", 7 },
+ { "Possession", "skills.txt", 45 },
+ { "Prayer", "skills.txt", 39 },
+ { "Runecraft", "skills.txt", 36 },
+ { "Sling-mastery", "skills.txt", 9 },
+ { "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", 3 },
+ { "Symbiosis", "skills.txt", 46 },
+ { "Temporal", "skills.txt", 32 },
+ { "Thaumaturgy", "skills.txt", 37 },
+ { "Udun", "skills.txt", 48 },
+ { "Weaponmastery", "skills.txt", 2 },
+ { "Water", "skills.txt", 26 },
+ { NULL, NULL, 0 },
+};
+
+/**
+ * Ability help files
+ */
+context_help_type ability_table[] =
+{
+ { "Spread blows", "ability.txt", 2 },
+ { "Tree walking", "ability.txt", 3 },
+ { "Perfect casting", "ability.txt", 4 },
+ { "Extra Max Blow(1)", "ability.txt", 5 },
+ { "Extra Max Blow(2)", "ability.txt", 6 },
+ { "Ammo creation", "ability.txt", 7 },
+ { "Touch of death", "ability.txt", 8 },
+ { "Far reaching attack", "ability.txt", 10 },
+ { "Trapping", "ability.txt", 11 },
+ { "Undead Form", "ability.txt", 12 },
+ { NULL, NULL, 0 },
+};
+
+/**
+ * Trigger functions
+ */
+static bool_ trigger_void_jumpgate(void *in, void *out) {
+ hook_move_in *p = (hook_move_in *) in;
+ return cave[p->y][p->x].feat == FEAT_BETWEEN;
+}
+
+static bool_ trigger_fountain(void *in, void *out) {
+ hook_move_in *p = (hook_move_in *) in;
+ return cave[p->y][p->x].feat == FEAT_FOUNTAIN;
+}
+
+static bool_ trigger_found_object(void *in, void *out) {
+ hook_move_in *p = (hook_move_in *) in;
+ return !cave[p->y][p->x].o_idxs.empty();
+}
+
+static bool_ trigger_found_altar(void *in, void *out) {
+ hook_move_in *p = (hook_move_in *) in;
+ return ((cave[p->y][p->x].feat >= FEAT_ALTAR_HEAD) &&
+ (cave[p->y][p->x].feat <= FEAT_ALTAR_TAIL));
+}
+
+static bool_ trigger_found_stairs(void *in, void *out) {
+ hook_move_in *p = (hook_move_in *) in;
+ return (cave[p->y][p->x].feat == FEAT_MORE);
+}
+
+static bool_ trigger_get_rune(void *in, void *out) {
+ hook_get_in *g = (hook_get_in *) in;
+ return ((g->o_ptr->tval == TV_RUNE1) ||
+ (g->o_ptr->tval == TV_RUNE2));
+}
+
+static bool_ trigger_get_rod(void *in, void *out) {
+ hook_get_in *g = (hook_get_in *) in;
+ return (g->o_ptr->tval == TV_ROD_MAIN);
+}
+
+static bool_ trigger_get_rod_tip(void *in, void *out) {
+ hook_get_in *g = (hook_get_in *) in;
+ return (g->o_ptr->tval == TV_ROD);
+}
+
+static bool_ trigger_get_trap_kit(void *in, void *out) {
+ hook_get_in *g = (hook_get_in *) in;
+ return (g->o_ptr->tval == TV_TRAPKIT);
+}
+
+static bool_ trigger_get_magic_device(void *in, void *out) {
+ hook_get_in *g = (hook_get_in *) in;
+ return ((g->o_ptr->tval == TV_WAND) ||
+ (g->o_ptr->tval == TV_STAFF));
+}
+
+static bool_ trigger_end_turn_wilderness(void *in, void *out) {
+ return (((p_ptr->wilderness_x != 34) ||
+ (p_ptr->wilderness_y != 21)) &&
+ (!p_ptr->astral));
+}
+
+static bool_ trigger_game_theme(void *in, void *out) {
+ return (game_module_idx == MODULE_THEME);
+}
+
+static bool_ trigger_game_tome(void *in, void *out) {
+ return (game_module_idx == MODULE_TOME);
+}
+
+static bool_ trigger_1st_level(void *in, void *out) {
+ return (p_ptr->lev > 1);
+}
+
+static bool_ trigger_20th_level(void *in, void *out) {
+ return (p_ptr->lev >= 20);
+}
+
+static bool_ trigger_identify_spell_item(void *in_, void *out) {
+ hook_identify_in *in = (hook_identify_in *) in_;
+
+ if (in->mode == IDENT_FULL)
+ {
+ u32b f1, f2, f3, f4, f5, esp;
+ object_flags(in->o_ptr, &f1, &f2, &f3, &f4, &f5, &esp);
+ if (f5 & TR5_SPELL_CONTAIN)
+ {
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+static bool_ trigger_melee_skills(void *in, void *out) {
+ return (game_started && (get_melee_skills() > 1));
+}
+
+static bool_ trigger_always(void *in, void *out) {
+ return TRUE;
+}
+
+/**
+ * Trigger-based help items
+ */
+static triggered_help_type triggered_help[TRIGGERED_HELP_MAX] =
+{
+ { HELP_VOID_JUMPGATE,
+ HOOK_MOVE,
+ trigger_void_jumpgate,
+ { "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.",
+ NULL }
+ },
+ { HELP_FOUNTAIN,
+ HOOK_MOVE,
+ trigger_fountain,
+ { "Fountains are always magical. You can quaff from them by pressing H.",
+ "Beware that unlike potions they cannot be identified.",
+ NULL }
+ },
+ { HELP_FOUND_OBJECT,
+ HOOK_MOVE,
+ trigger_found_object,
+ { "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.",
+ NULL }
+ },
+ { HELP_FOUND_ALTAR,
+ HOOK_MOVE,
+ trigger_found_altar,
+ { "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.",
+ NULL }
+ },
+ { HELP_FOUND_STAIR,
+ HOOK_MOVE,
+ trigger_found_stairs,
+ { "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.",
+ NULL }
+ },
+ { HELP_GET_RUNE,
+ HOOK_GET,
+ trigger_get_rune,
+ { "Ah, a rune! Runes are used with the Runecraft skill to allow you to",
+ "create spells on your own.",
+ NULL
+ }
+ },
+ { HELP_GET_ROD,
+ HOOK_GET,
+ trigger_get_rod,
+ { "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.",
+ NULL
+ }
+ },
+ { HELP_GET_ROD_TIP,
+ HOOK_GET,
+ trigger_get_rod_tip,
+ { "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.",
+ NULL
+ }
+ },
+ { HELP_GET_TRAP_KIT,
+ HOOK_GET,
+ trigger_get_trap_kit,
+ { "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.",
+ NULL
+ }
+ },
+ { HELP_GET_DEVICE,
+ HOOK_GET,
+ trigger_get_magic_device,
+ { "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.",
+ NULL
+ }
+ },
+ { HELP_WILDERNESS,
+ HOOK_END_TURN,
+ trigger_end_turn_wilderness,
+ { "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.",
+ NULL
+ }
+ },
+ { HELP_GAME_TOME,
+ HOOK_END_TURN,
+ trigger_game_tome,
+ { "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!",
+ NULL
+ }
+ },
+ { HELP_GAME_THEME,
+ HOOK_END_TURN,
+ trigger_game_theme,
+ { "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!",
+ NULL
+ }
+ },
+ { HELP_1ST_LEVEL,
+ HOOK_PLAYER_LEVEL,
+ trigger_1st_level,
+ { "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.",
+ NULL
+ }
+ },
+ { HELP_20TH_LEVEL,
+ HOOK_PLAYER_LEVEL,
+ trigger_20th_level,
+ { "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.",
+ NULL
+ }
+ },
+ { HELP_ID_SPELL_ITM,
+ HOOK_IDENTIFY,
+ trigger_identify_spell_item,
+ { "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.",
+ NULL
+ }
+ },
+ { HELP_MELEE_SKILLS,
+ HOOK_RECALC_SKILLS,
+ trigger_melee_skills,
+ { "Ah, you now possess more than one melee type. To switch between them press m",
+ "and select the switch melee type option.",
+ NULL
+ }
+ },
+ { HELP_MON_ASK_HELP,
+ HOOK_MON_ASK_HELP,
+ trigger_always,
+ { "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.",
+ NULL
+ }
+ }
+};
+
+static bool_ triggered_help_hook(void *data, void *in, void *out)
+{
+ triggered_help_type *triggered_help = (triggered_help_type *) data;
+ /* Not triggered before and trigger now? */
+ if ((option_ingame_help) &&
+ (!p_ptr->help.activated[triggered_help->help_index]) &&
+ triggered_help->trigger_func(in,out))
+ {
+ int i;
+
+ /* Triggered */
+ p_ptr->help.activated[triggered_help->help_index] = TRUE;
+
+ /* Show the description */
+ for (i = 0; (i < DESC_MAX) && (triggered_help->desc[i] != NULL); i++)
+ {
+ cmsg_print(TERM_YELLOW, triggered_help->desc[i]);
+ }
+ }
+ /* Don't stop processing */
+ return FALSE;
+}
+
+static bool_ hook_game_start(void *data, void *in, void *out)
+{
+ game_started = TRUE;
+ return FALSE;
+}
+
+static void setup_triggered_help_hook(int i)
+{
+ static int counter = 0;
+ char name[40];
+ triggered_help_type *h = &triggered_help[i];
+
+ /* Build name */
+ sprintf(name, "help_trigger_%d", counter);
+ counter++;
+
+ /* Add the hook */
+ add_hook_new(h->hook_type,
+ triggered_help_hook,
+ name,
+ h);
+}
+
+static void setup_triggered_help_hooks()
+{
+ int i;
+
+ for (i = 0; i < TRIGGERED_HELP_MAX; i++)
+ {
+ setup_triggered_help_hook(i);
+ }
+
+ add_hook_new(HOOK_GAME_START,
+ hook_game_start,
+ "help_game_start",
+ NULL);
+}
+
+/*
+ * Driver for the context-sensitive help system
+ */
+void init_hooks_help()
+{
+ setup_triggered_help_hooks();
+}
+
+/*
+ * Show help file
+ */
+static void show_context_help(context_help_type *context_help)
+{
+ if (context_help == NULL)
+ {
+ return;
+ }
+
+ screen_save();
+
+ show_file(context_help->file_name, 0, -context_help->anchor, 0);
+
+ screen_load();
+}
+
+/*
+ * Find context help
+ */
+static context_help_type *find_context_help(context_help_type table[], cptr key)
+{
+ int i;
+
+ for (i = 0; ; i++)
+ {
+ context_help_type *context_help = &table[i];
+
+ if (context_help->key == NULL)
+ {
+ return NULL; /* End of list */
+ }
+
+ if (streq(key, context_help->key))
+ {
+ return context_help;
+ }
+ }
+}
+
+/*
+ * Racial help
+ */
+void help_race(cptr race)
+{
+ show_context_help(find_context_help(race_table, race));
+}
+
+void help_subrace(cptr subrace)
+{
+ show_context_help(find_context_help(subrace_table, subrace));
+}
+
+void help_class(cptr klass)
+{
+ show_context_help(find_context_help(class_table, klass));
+}
+
+void help_god(cptr god)
+{
+ context_help_type *context_help =
+ find_context_help(god_table, god);
+
+ if (context_help != NULL)
+ {
+ show_context_help(context_help);
+ }
+}
+
+void help_skill(cptr skill)
+{
+ show_context_help(find_context_help(skill_table, skill));
+}
+
+void help_ability(cptr ability)
+{
+ show_context_help(find_context_help(ability_table, ability));
+}
diff --git a/src/help.hpp b/src/help.hpp
new file mode 100644
index 00000000..7c057a01
--- /dev/null
+++ b/src/help.hpp
@@ -0,0 +1,11 @@
+#pragma once
+
+#include "h-basic.h"
+
+extern void init_hooks_help();
+extern void help_race(cptr race);
+extern void help_subrace(cptr subrace);
+extern void help_class(cptr klass);
+extern void help_god(cptr god);
+extern void help_skill(cptr skill);
+extern void help_ability(cptr ability);
diff --git a/src/help_info.hpp b/src/help_info.hpp
new file mode 100644
index 00000000..ea440bb9
--- /dev/null
+++ b/src/help_info.hpp
@@ -0,0 +1,17 @@
+#pragma once
+
+#include "h-basic.h"
+
+/**
+ * Maximum number of help items.
+ */
+constexpr int HELP_MAX = 64;
+
+/**
+ * Context help runtime data.
+ */
+struct help_info
+{
+ bool_ enabled; /* ingame help enabled */
+ bool_ activated[HELP_MAX]; /* help item #i activated? */
+};
diff --git a/src/hiscore.cc b/src/hiscore.cc
new file mode 100644
index 00000000..971b84cd
--- /dev/null
+++ b/src/hiscore.cc
@@ -0,0 +1,85 @@
+#include "hiscore.hpp"
+
+#include "util.hpp"
+
+#include <cassert>
+
+int highscore_seek(int highscore_fd, int i)
+{
+ /* Seek for the requested record */
+ return (fd_seek(highscore_fd, (huge)(i) * sizeof(high_score)));
+}
+
+errr highscore_read(int highscore_fd, high_score *score)
+{
+ /* Read the record, note failure */
+ return (fd_read(highscore_fd, (char*)(score), sizeof(high_score)));
+}
+
+int highscore_write(int highscore_fd, high_score *score)
+{
+ /* Write the record, note failure */
+ return (fd_write(highscore_fd, (char*)(score), sizeof(high_score)));
+}
+
+int highscore_where(int highscore_fd, 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(highscore_fd, 0)) return ( -1);
+
+ /* Read until we get to a higher score */
+ for (i = 0; i < MAX_HISCORES; i++)
+ {
+ if (highscore_read(highscore_fd, &the_score)) return (i);
+ if (strcmp(the_score.pts, score->pts) < 0) return (i);
+ }
+
+ /* The "last" entry is always usable */
+ return (MAX_HISCORES - 1);
+}
+
+int highscore_add(int highscore_fd, 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(highscore_fd, 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(highscore_fd, i)) return ( -1);
+ if (highscore_read(highscore_fd, &tmpscore)) done = TRUE;
+
+ /* Back up and dump the score we were holding */
+ if (highscore_seek(highscore_fd, i)) return ( -1);
+ if (highscore_write(highscore_fd, &the_score)) return ( -1);
+
+ /* Hack -- Save the old score, for the next pass */
+ the_score = tmpscore;
+ }
+
+ /* Return location used */
+ return (slot);
+}
diff --git a/src/hiscore.hpp b/src/hiscore.hpp
new file mode 100644
index 00000000..0b1b713d
--- /dev/null
+++ b/src/hiscore.hpp
@@ -0,0 +1,83 @@
+#pragma once
+
+#include "h-basic.h"
+
+/**
+ * Maximum number of high scores in the high score file
+ */
+constexpr int MAX_HISCORES = 100;
+
+/*
+ * 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 unused_1[8]; /* Kept for compatibility only */
+
+ 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 unused_2[4]; /* Kept for compatibility only */
+ char unused_3[4]; /* Kept for compatibility only */
+ char inside_quest[4]; /* Did the player die in a quest? */
+ char unused_4[4]; /* Kept for compatibility only */
+
+ char how[32]; /* Method of death (string) */
+};
+
+/*
+ * Seek score 'i' in the highscore file
+ */
+int highscore_seek(int highscore_fd, int i);
+
+/*
+ * Read one score from the highscore file
+ */
+errr highscore_read(int highscore_fd, high_score *score);
+
+/*
+ * Write one score to the highscore file
+ */
+int highscore_write(int highscore_fd, high_score *score);
+
+/*
+ * Determine where a new score *would* be placed
+ * Return the location (0 is best) or -1 on failure
+ */
+int highscore_where(int highscore_fd, high_score *score);
+
+/*
+ * Place an entry into the high score file. Return the location (0 is
+ * best) or -1 on "failure"
+ */
+int highscore_add(int highscore_fd, high_score *score);
diff --git a/src/hist_type.hpp b/src/hist_type.hpp
new file mode 100644
index 00000000..2da47b7c
--- /dev/null
+++ b/src/hist_type.hpp
@@ -0,0 +1,16 @@
+#pragma once
+
+#include "h-basic.h"
+
+/**
+ * Player background descriptor.
+ */
+struct hist_type
+{
+ char *info; /* Textual History */
+
+ byte roll; /* Frequency of this entry */
+ s16b chart; /* Chart index */
+ s16b next; /* Next chart index */
+ byte bonus; /* Social Class Bonus + 50 */
+};
diff --git a/src/hist_type_fwd.hpp b/src/hist_type_fwd.hpp
new file mode 100644
index 00000000..d1cbce91
--- /dev/null
+++ b/src/hist_type_fwd.hpp
@@ -0,0 +1,3 @@
+#pragma once
+
+struct hist_type;
diff --git a/src/hook_build_room1_in.hpp b/src/hook_build_room1_in.hpp
new file mode 100644
index 00000000..e9a5d367
--- /dev/null
+++ b/src/hook_build_room1_in.hpp
@@ -0,0 +1,8 @@
+#pragma once
+
+#include "h-basic.h"
+
+struct hook_build_room1_in {
+ s32b y;
+ s32b x;
+};
diff --git a/src/hook_calculate_hp_in.hpp b/src/hook_calculate_hp_in.hpp
new file mode 100644
index 00000000..924add45
--- /dev/null
+++ b/src/hook_calculate_hp_in.hpp
@@ -0,0 +1,7 @@
+#pragma once
+
+#include "h-basic.h"
+
+struct hook_calculate_hp_in {
+ s32b mhp;
+};
diff --git a/src/hook_calculate_hp_out.hpp b/src/hook_calculate_hp_out.hpp
new file mode 100644
index 00000000..7923997f
--- /dev/null
+++ b/src/hook_calculate_hp_out.hpp
@@ -0,0 +1,7 @@
+#pragma once
+
+#include "h-basic.h"
+
+struct hook_calculate_hp_out {
+ s32b mhp;
+};
diff --git a/src/hook_chardump_in.hpp b/src/hook_chardump_in.hpp
new file mode 100644
index 00000000..c8edea62
--- /dev/null
+++ b/src/hook_chardump_in.hpp
@@ -0,0 +1,7 @@
+#pragma once
+
+#include "h-basic.h"
+
+struct hook_chardump_in {
+ FILE *file;
+};
diff --git a/src/hook_chat_in.hpp b/src/hook_chat_in.hpp
new file mode 100644
index 00000000..5062b0e6
--- /dev/null
+++ b/src/hook_chat_in.hpp
@@ -0,0 +1,7 @@
+#pragma once
+
+#include "h-basic.h"
+
+struct hook_chat_in {
+ s32b m_idx;
+};
diff --git a/src/hook_drop_in.hpp b/src/hook_drop_in.hpp
new file mode 100644
index 00000000..acaa10ff
--- /dev/null
+++ b/src/hook_drop_in.hpp
@@ -0,0 +1,5 @@
+#pragma once
+
+struct hook_drop_in {
+ int o_idx;
+};
diff --git a/src/hook_eat_in.hpp b/src/hook_eat_in.hpp
new file mode 100644
index 00000000..075bb2bf
--- /dev/null
+++ b/src/hook_eat_in.hpp
@@ -0,0 +1,7 @@
+#pragma once
+
+#include "object_type_fwd.hpp"
+
+struct hook_eat_in {
+ object_type *o_ptr;
+};
diff --git a/src/hook_eat_out.hpp b/src/hook_eat_out.hpp
new file mode 100644
index 00000000..70bb92a4
--- /dev/null
+++ b/src/hook_eat_out.hpp
@@ -0,0 +1,7 @@
+#pragma once
+
+#include "h-basic.h"
+
+struct hook_eat_out {
+ bool_ ident;
+};
diff --git a/src/hook_enter_dungeon_in.hpp b/src/hook_enter_dungeon_in.hpp
new file mode 100644
index 00000000..2f667c78
--- /dev/null
+++ b/src/hook_enter_dungeon_in.hpp
@@ -0,0 +1,7 @@
+#pragma once
+
+#include "h-basic.h"
+
+struct hook_enter_dungeon_in {
+ s32b d_idx;
+};
diff --git a/src/hook_get_in.hpp b/src/hook_get_in.hpp
new file mode 100644
index 00000000..9bc4b795
--- /dev/null
+++ b/src/hook_get_in.hpp
@@ -0,0 +1,8 @@
+#pragma once
+
+#include "object_type_fwd.hpp"
+
+struct hook_get_in {
+ object_type *o_ptr;
+ int o_idx;
+};
diff --git a/src/hook_give_in.hpp b/src/hook_give_in.hpp
new file mode 100644
index 00000000..0ef5a11d
--- /dev/null
+++ b/src/hook_give_in.hpp
@@ -0,0 +1,6 @@
+#pragma once
+
+struct hook_give_in {
+ int m_idx;
+ int item;
+};
diff --git a/src/hook_identify_in.hpp b/src/hook_identify_in.hpp
new file mode 100644
index 00000000..40a8fc79
--- /dev/null
+++ b/src/hook_identify_in.hpp
@@ -0,0 +1,9 @@
+#pragma once
+
+#include "object_type_fwd.hpp"
+#include "identify_mode.hpp"
+
+struct hook_identify_in {
+ object_type *o_ptr;
+ identify_mode mode;
+};
diff --git a/src/hook_init_quest_in.hpp b/src/hook_init_quest_in.hpp
new file mode 100644
index 00000000..5d4b274a
--- /dev/null
+++ b/src/hook_init_quest_in.hpp
@@ -0,0 +1,5 @@
+#pragma once
+
+struct hook_init_quest_in {
+ int q_idx;
+};
diff --git a/src/hook_mon_speak_in.hpp b/src/hook_mon_speak_in.hpp
new file mode 100644
index 00000000..f3a14338
--- /dev/null
+++ b/src/hook_mon_speak_in.hpp
@@ -0,0 +1,8 @@
+#pragma once
+
+#include "h-basic.h"
+
+struct hook_mon_speak_in {
+ s32b m_idx;
+ cptr m_name;
+};
diff --git a/src/hook_monster_ai_in.hpp b/src/hook_monster_ai_in.hpp
new file mode 100644
index 00000000..492006aa
--- /dev/null
+++ b/src/hook_monster_ai_in.hpp
@@ -0,0 +1,9 @@
+#pragma once
+
+#include "h-basic.h"
+#include "monster_type_fwd.hpp"
+
+struct hook_monster_ai_in {
+ s32b m_idx;
+ monster_type *m_ptr;
+};
diff --git a/src/hook_monster_ai_out.hpp b/src/hook_monster_ai_out.hpp
new file mode 100644
index 00000000..4c5ef28f
--- /dev/null
+++ b/src/hook_monster_ai_out.hpp
@@ -0,0 +1,8 @@
+#pragma once
+
+#include "h-basic.h"
+
+struct hook_monster_ai_out {
+ s32b y;
+ s32b x;
+};
diff --git a/src/hook_monster_death_in.hpp b/src/hook_monster_death_in.hpp
new file mode 100644
index 00000000..354c37d2
--- /dev/null
+++ b/src/hook_monster_death_in.hpp
@@ -0,0 +1,7 @@
+#pragma once
+
+#include "h-basic.h"
+
+struct hook_monster_death_in {
+ s32b m_idx;
+};
diff --git a/src/hook_move_in.hpp b/src/hook_move_in.hpp
new file mode 100644
index 00000000..6e299e5b
--- /dev/null
+++ b/src/hook_move_in.hpp
@@ -0,0 +1,6 @@
+#pragma once
+
+struct hook_move_in {
+ int y;
+ int x;
+};
diff --git a/src/hook_new_monster_end_in.hpp b/src/hook_new_monster_end_in.hpp
new file mode 100644
index 00000000..3c5f835b
--- /dev/null
+++ b/src/hook_new_monster_end_in.hpp
@@ -0,0 +1,7 @@
+#pragma once
+
+#include "monster_type_fwd.hpp"
+
+struct hook_new_monster_end_in {
+ monster_type *m_ptr;
+};
diff --git a/src/hook_new_monster_in.hpp b/src/hook_new_monster_in.hpp
new file mode 100644
index 00000000..10b0420c
--- /dev/null
+++ b/src/hook_new_monster_in.hpp
@@ -0,0 +1,7 @@
+#pragma once
+
+#include "h-basic.h"
+
+struct hook_new_monster_in {
+ s32b r_idx;
+};
diff --git a/src/hook_player_level_in.hpp b/src/hook_player_level_in.hpp
new file mode 100644
index 00000000..90804e27
--- /dev/null
+++ b/src/hook_player_level_in.hpp
@@ -0,0 +1,5 @@
+#pragma once
+
+struct hook_player_level_in {
+ int gained_levels;
+};
diff --git a/src/hook_quest_fail_in.hpp b/src/hook_quest_fail_in.hpp
new file mode 100644
index 00000000..2edf86a3
--- /dev/null
+++ b/src/hook_quest_fail_in.hpp
@@ -0,0 +1,7 @@
+#pragma once
+
+#include "h-basic.h"
+
+struct hook_quest_fail_in {
+ s16b q_idx;
+};
diff --git a/src/hook_quest_finish_in.hpp b/src/hook_quest_finish_in.hpp
new file mode 100644
index 00000000..55490be4
--- /dev/null
+++ b/src/hook_quest_finish_in.hpp
@@ -0,0 +1,7 @@
+#pragma once
+
+#include "h-basic.h"
+
+struct hook_quest_finish_in {
+ s32b q_idx;
+};
diff --git a/src/hook_stair_in.hpp b/src/hook_stair_in.hpp
new file mode 100644
index 00000000..884a187c
--- /dev/null
+++ b/src/hook_stair_in.hpp
@@ -0,0 +1,7 @@
+#pragma once
+
+#include "stairs_direction.hpp"
+
+struct hook_stair_in {
+ stairs_direction direction;
+};
diff --git a/src/hook_stair_out.hpp b/src/hook_stair_out.hpp
new file mode 100644
index 00000000..5e3d515a
--- /dev/null
+++ b/src/hook_stair_out.hpp
@@ -0,0 +1,7 @@
+#pragma once
+
+#include "h-basic.h"
+
+struct hook_stair_out {
+ bool_ allow;
+};
diff --git a/src/hook_wield_in.hpp b/src/hook_wield_in.hpp
new file mode 100644
index 00000000..036e62da
--- /dev/null
+++ b/src/hook_wield_in.hpp
@@ -0,0 +1,7 @@
+#pragma once
+
+#include "object_type_fwd.hpp"
+
+struct hook_wield_in {
+ object_type *o_ptr;
+};
diff --git a/src/hook_wild_gen_in.hpp b/src/hook_wild_gen_in.hpp
new file mode 100644
index 00000000..147a74db
--- /dev/null
+++ b/src/hook_wild_gen_in.hpp
@@ -0,0 +1,7 @@
+#pragma once
+
+#include "h-basic.h"
+
+struct hook_wild_gen_in {
+ bool_ small;
+};
diff --git a/src/hooks.cc b/src/hooks.cc
new file mode 100644
index 00000000..4fcc39d3
--- /dev/null
+++ b/src/hooks.cc
@@ -0,0 +1,113 @@
+/*
+ * 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 "hooks.hpp"
+
+#include <algorithm>
+#include <assert.h>
+#include <unordered_map>
+#include <vector>
+
+/******** Hooks stuff *********/
+
+struct hook_data
+{
+private:
+ hook_func_t m_hook_func;
+ void *m_hook_data;
+public:
+ hook_data(hook_func_t hook_func, void *hook_data)
+ : m_hook_func(hook_func)
+ , m_hook_data(hook_data) {
+ }
+
+ hook_data() = delete;
+
+ /**
+ * Check if the given hook points to the given function.
+ */
+ bool is(hook_func_t hook_func) const {
+ return m_hook_func == hook_func;
+ }
+
+ /**
+ * Invoke the hook with the given input and output pointers.
+ */
+ bool_ invoke(void *in, void *out) const {
+ return m_hook_func(m_hook_data, in, out);
+ }
+};
+
+std::unordered_map<size_t, std::vector<hook_data>> &hooks_instance()
+{
+ static auto instance = new std::unordered_map<size_t, std::vector<hook_data>>();
+ return *instance;
+}
+
+
+int process_hooks_restart = FALSE;
+
+static std::vector<hook_data>::iterator find_hook(std::vector<hook_data> &hooks, hook_func_t hook_func)
+{
+ return std::find_if(hooks.begin(),
+ hooks.end(),
+ [&](const hook_data &hook_data) {
+ return hook_data.is(hook_func);
+ });
+}
+
+void add_hook_new(int h_idx, hook_func_t hook_func, cptr name, void *data)
+{
+ auto &hooks = hooks_instance()[h_idx];
+ // Only insert if not already present.
+ if (find_hook(hooks, hook_func) == hooks.end()) {
+ hooks.emplace_back(hook_func, data);
+ }
+}
+
+void del_hook_new(int h_idx, hook_func_t hook_func)
+{
+ auto &hooks = hooks_instance()[h_idx];
+
+ /* Find it */
+ auto found_it = find_hook(hooks, hook_func);
+ if (found_it != hooks.end())
+ {
+ hooks.erase(found_it);
+ }
+}
+
+bool_ process_hooks_new(int h_idx, void *in, void *out)
+{
+ auto const &hooks = hooks_instance()[h_idx];
+
+ auto hooks_it = hooks.begin();
+ while (hooks_it != hooks.end())
+ {
+ auto &hook_data = *hooks_it;
+
+ /* Invoke hook function; stop processing if the hook
+ returns TRUE */
+ if (hook_data.invoke(in, out))
+ {
+ return TRUE;
+ }
+
+ /* Should we restart processing at the beginning? */
+ if (process_hooks_restart)
+ {
+ hooks_it = hooks.begin();
+ process_hooks_restart = FALSE;
+ }
+ else
+ {
+ hooks_it++;
+ }
+ }
+
+ return FALSE;
+}
diff --git a/src/hooks.hpp b/src/hooks.hpp
new file mode 100644
index 00000000..b6124e6a
--- /dev/null
+++ b/src/hooks.hpp
@@ -0,0 +1,10 @@
+#pragma once
+
+#include "h-basic.h"
+
+typedef bool_ (*hook_func_t)(void *, void *, void *);
+
+extern void add_hook_new(int h_idx, hook_func_t hook_func, cptr name, void *data);
+extern void del_hook_new(int h_idx, hook_func_t hook_func);
+extern int process_hooks_restart;
+extern bool_ process_hooks_new(int h_idx, void *in, void *out);
diff --git a/src/identify_mode.hpp b/src/identify_mode.hpp
new file mode 100644
index 00000000..687a1fae
--- /dev/null
+++ b/src/identify_mode.hpp
@@ -0,0 +1,3 @@
+#pragma once
+
+typedef enum { IDENT_NORMAL, IDENT_FULL } identify_mode;
diff --git a/src/include/tome/enum_string_map.hpp b/src/include/tome/enum_string_map.hpp
new file mode 100644
index 00000000..8ae1e115
--- /dev/null
+++ b/src/include/tome/enum_string_map.hpp
@@ -0,0 +1,55 @@
+#pragma once
+
+#include <boost/bimap.hpp>
+#include <boost/noncopyable.hpp>
+#include <string>
+#include <cassert>
+
+/**
+ * Bidirectional mapping between enumerated values
+ * and strings.
+ */
+template <class E>
+class EnumStringMap : boost::noncopyable {
+
+private:
+ typedef boost::bimap< E, std::string > bimap_type;
+ typedef typename bimap_type::value_type value_type;
+
+ bimap_type bimap;
+
+public:
+ explicit EnumStringMap(std::initializer_list< std::pair<E, const char *> > in) {
+ for (auto es : in)
+ {
+ bimap.insert(value_type(es.first, es.second));
+ }
+ // Sanity check that there were no
+ // duplicate mappings.
+ assert(bimap.size() == in.size());
+ }
+
+ const char *stringify(E e) {
+ auto i = bimap.left.find(e);
+ assert(i != bimap.left.end() && "Missing mapping for enumerated value");
+ return i->second.c_str();
+ }
+
+ E parse(const char *s) {
+ E e;
+ bool result = parse(s, &e);
+ assert(result && "Missing string->enum mapping");
+ return e;
+ }
+
+ bool parse(const char *s, E *e) {
+ auto i = bimap.right.find(s);
+ if (i == bimap.right.end())
+ {
+ return false;
+ }
+
+ *e = i->second;
+ return true;
+ }
+};
diff --git a/src/include/tome/make_array.hpp b/src/include/tome/make_array.hpp
new file mode 100644
index 00000000..23cb8ac0
--- /dev/null
+++ b/src/include/tome/make_array.hpp
@@ -0,0 +1,13 @@
+#pragma once
+
+#include <type_traits>
+
+/*
+ * Make an array of a POD type.
+ */
+template <typename T> T *make_array(std::size_t n) {
+ static_assert(std::is_pod<T>::value, "Type parameter must be POD type");
+ T *array = new T[n];
+ memset(array, 0, n*sizeof(T));
+ return array;
+}
diff --git a/src/include/tome/squelch/automatizer.hpp b/src/include/tome/squelch/automatizer.hpp
new file mode 100644
index 00000000..786ca1ae
--- /dev/null
+++ b/src/include/tome/squelch/automatizer.hpp
@@ -0,0 +1,156 @@
+#pragma once
+
+#include <boost/noncopyable.hpp>
+#include <memory>
+#include <vector>
+#include <jansson.h>
+
+#include "tome/squelch/rule_fwd.hpp"
+#include "tome/squelch/cursor_fwd.hpp"
+#include "tome/squelch/tree_printer_fwd.hpp"
+#include "tome/squelch/condition_fwd.hpp"
+#include "../object_type_fwd.hpp"
+
+namespace squelch {
+
+/**
+ * Automatizer
+ */
+class Automatizer : public boost::noncopyable
+{
+public:
+ Automatizer(std::shared_ptr<TreePrinter> tree_printer,
+ std::shared_ptr<Cursor> cursor)
+ : m_selected_rule(0)
+ , m_begin(0)
+ , m_tree_printer(tree_printer)
+ , m_cursor(cursor)
+ , m_rules() {
+ }
+
+ /**
+ * Append a rule
+ */
+ int append_rule(std::shared_ptr<Rule> rule);
+
+ /**
+ * Swap two rules
+ */
+ void swap_rules(int i, int j);
+
+ /**
+ * Apply all rules to the given object
+ */
+ bool apply_rules(object_type *o_ptr, int item_idx) const;
+
+ /**
+ * Build a JSON data structure to represent
+ * all the rules.
+ */
+ std::shared_ptr<json_t> to_json() const;
+
+ /**
+ * Load rules from a JSON data structure.
+ */
+ void load_json(json_t *json);
+
+ /**
+ * Remove currently selected condition or rule.
+ */
+ int remove_current_selection();
+
+ /**
+ * Reset view.
+ */
+ void reset_view();
+
+ /**
+ * Show current rule
+ */
+ void show_current() const;
+
+ /**
+ * Scroll view up
+ */
+ void scroll_up();
+
+ /**
+ * Scroll view down
+ */
+ void scroll_down();
+
+ /**
+ * Scroll view left
+ */
+ void scroll_left();
+
+ /**
+ * Scroll view right
+ */
+ void scroll_right();
+
+ /**
+ * Move selection up
+ */
+ void move_up();
+
+ /**
+ * Move selection down
+ */
+ void move_down();
+
+ /**
+ * Move selection left
+ */
+ void move_left();
+
+ /**
+ * Move selection right
+ */
+ void move_right();
+
+ /**
+ * Add new condition to selected rule
+ */
+ void add_new_condition(std::function<std::shared_ptr<Condition> ()> factory);
+
+ /**
+ * Get rule names. The names are not stable across multiple
+ * calls to methods on this class.
+ */
+ void get_rule_names(std::vector<const char *> *names) const;
+
+ /**
+ * Get current number of rules.
+ */
+ int rules_count() const;
+
+ /**
+ * Get the "beginning" rule.
+ */
+ int rules_begin() const;
+
+ /**
+ * Select a new rule.
+ */
+ void select_rule(int selected_rule);
+
+ /**
+ * Return selected rule index
+ */
+ int selected_rule() const;
+
+ /**
+ * Return selected rule
+ */
+ std::shared_ptr<Rule> current_rule();
+
+private:
+ int m_selected_rule;
+ int m_begin;
+ std::shared_ptr<TreePrinter> m_tree_printer;
+ std::shared_ptr<Cursor> m_cursor;
+ std::vector < std::shared_ptr < Rule > > m_rules;
+};
+
+} // namespace
diff --git a/src/include/tome/squelch/automatizer_fwd.hpp b/src/include/tome/squelch/automatizer_fwd.hpp
new file mode 100644
index 00000000..068f297a
--- /dev/null
+++ b/src/include/tome/squelch/automatizer_fwd.hpp
@@ -0,0 +1,10 @@
+#ifndef H_cbf79126_fd24_4f80_8f2d_9dd69cb7010f
+#define H_cbf79126_fd24_4f80_8f2d_9dd69cb7010f
+
+namespace squelch {
+
+class Automatizer;
+
+} // namespace
+
+#endif
diff --git a/src/include/tome/squelch/condition.hpp b/src/include/tome/squelch/condition.hpp
new file mode 100644
index 00000000..5d1240f5
--- /dev/null
+++ b/src/include/tome/squelch/condition.hpp
@@ -0,0 +1,632 @@
+#pragma once
+
+#include "tome/squelch/condition_fwd.hpp"
+
+#include <boost/noncopyable.hpp>
+#include <functional>
+#include <memory>
+#include <cstdint>
+#include <jansson.h>
+
+#include "tome/squelch/cursor_fwd.hpp"
+#include "tome/squelch/tree_printer_fwd.hpp"
+#include "tome/squelch/object_status_fwd.hpp"
+#include "tome/enum_string_map.hpp"
+#include "../object_type_fwd.hpp"
+
+namespace squelch {
+
+/**
+ * Types of matches used for conditions.
+ */
+enum class match_type {
+ AND , OR , NOT , NAME , CONTAIN ,
+ INSCRIBED, DISCOUNT, SYMBOL , STATE , STATUS ,
+ TVAL , SVAL , RACE , SUBRACE , CLASS ,
+ LEVEL , SKILL , ABILITY, INVENTORY, EQUIPMENT };
+
+/**
+ * Bidirectional map between enumeration values and strings.
+ */
+EnumStringMap<match_type> &match_mapping();
+
+/**
+ * Identification states an object can have: identified or not
+ * identified.
+ */
+enum class identification_state {
+ IDENTIFIED, NOT_IDENTIFIED };
+
+/**
+ * Biredectional map between identification_state values and strings.
+ */
+EnumStringMap<identification_state> &identification_state_mapping();
+
+/**
+ * Condition represents a tree of checks which
+ * can be applied to objects, the player, etc.
+ */
+class Condition : public boost::noncopyable
+{
+public:
+ Condition(match_type match_) : match(match_) {
+ }
+
+ void display(TreePrinter *, Cursor *) const;
+
+ virtual bool is_match(object_type *) const = 0;
+
+ virtual ~Condition() {
+ }
+
+public:
+ json_t *to_json() const;
+
+ virtual void add_child(ConditionFactory const &factory) {
+ // Default is to not support children.
+ };
+
+ virtual void remove_child(Condition *c) {
+ // Nothing to do by default.
+ }
+
+ virtual std::shared_ptr<Condition> first_child() {
+ // No children.
+ return nullptr;
+ }
+
+ virtual std::shared_ptr<Condition> previous_child(Condition *) {
+ // Default no children, so no predecessor.
+ return nullptr;
+ }
+
+ virtual std::shared_ptr<Condition> next_child(Condition *) {
+ // Default no children, so no successor.
+ return nullptr;
+ }
+
+ /**
+ * Parse condition from JSON
+ */
+ static std::shared_ptr<Condition> parse_condition(json_t *);
+
+ /**
+ * Convert an (optional) condition to JSON.
+ */
+ static json_t *optional_to_json(std::shared_ptr<Condition> condition);
+
+protected:
+ virtual void write_tree(TreePrinter *, Cursor *, uint8_t, uint8_t) const = 0;
+ virtual void to_json(json_t *) const = 0;
+
+ // What do we want to match?
+ match_type match;
+};
+
+/**
+ * Check for a specific TVAL
+ */
+class TvalCondition : public Condition
+{
+public:
+ TvalCondition(uint8_t tval)
+ : Condition(match_type::TVAL)
+ , m_tval(tval) {
+ }
+
+ bool is_match(object_type *) const override;
+
+ static std::shared_ptr<Condition> from_json(json_t *);
+
+protected:
+ void write_tree(TreePrinter *, Cursor *, uint8_t, uint8_t) const override;
+
+ void to_json(json_t *) const override;
+
+private:
+ uint8_t m_tval;
+};
+
+/**
+ * Check for object name
+ */
+class NameCondition : public Condition
+{
+public:
+ NameCondition(std::string name) :
+ Condition(match_type::NAME),
+ m_name(name) {
+ }
+
+ bool is_match(object_type *) const override;
+
+ static std::shared_ptr<Condition> from_json(json_t *);
+
+protected:
+ void write_tree(TreePrinter *, Cursor *, uint8_t, uint8_t) const override;
+
+ void to_json(json_t *) const override;
+
+private:
+ std::string m_name;
+};
+
+/**
+ * Check for infix of object name
+ */
+class ContainCondition : public Condition
+{
+public:
+ ContainCondition(std::string contain) :
+ Condition(match_type::CONTAIN),
+ m_contain(contain) {
+ }
+
+ bool is_match(object_type *) const override;
+
+ static std::shared_ptr<Condition> from_json(json_t *);
+
+protected:
+ void write_tree(TreePrinter *, Cursor *, uint8_t, uint8_t) const override;
+
+ void to_json(json_t *) const override;
+
+private:
+ std::string m_contain;
+};
+
+/**
+ * Check for specific SVAL
+ */
+class SvalCondition : public Condition
+{
+public:
+ SvalCondition(uint8_t min, uint8_t max)
+ : Condition(match_type::SVAL)
+ , m_min(min)
+ , m_max(max) {
+ }
+
+ bool is_match(object_type *) const override;
+
+ static std::shared_ptr<Condition> from_json(json_t *);
+
+protected:
+ void write_tree(TreePrinter *, Cursor *, uint8_t, uint8_t) const override;
+
+ void to_json(json_t *) const override;
+
+private:
+ uint8_t m_min;
+ uint8_t m_max;
+};
+
+/**
+ * Groupings of subconditions
+ */
+class GroupingCondition : public Condition
+{
+public:
+ GroupingCondition(match_type match,
+ std::vector< std::shared_ptr<Condition> > conditions = std::vector< std::shared_ptr<Condition> >())
+ : Condition(match)
+ , m_conditions(conditions) {
+ }
+
+ virtual void add_condition(std::shared_ptr<Condition> condition) {
+ if (condition)
+ {
+ m_conditions.push_back(condition);
+ }
+ }
+
+ // Child manipulation
+ virtual void add_child(ConditionFactory const &factory) override;
+ virtual void remove_child(Condition *condition) override;
+ virtual std::shared_ptr<Condition> first_child() override;
+ virtual std::shared_ptr<Condition> previous_child(Condition *) override;
+ virtual std::shared_ptr<Condition> next_child(Condition *current) override;
+
+ // Parse a list of conditions from JSON property
+ static std::vector< std::shared_ptr<Condition> > parse_conditions(json_t *);
+
+protected:
+ void to_json(json_t *) const override;
+
+protected:
+ std::vector< std::shared_ptr<Condition> > m_conditions;
+};
+
+/**
+ * Conditions that are AND'ed together
+ */
+class AndCondition : public GroupingCondition
+{
+public:
+ AndCondition() : GroupingCondition(match_type::AND) {
+ }
+
+ bool is_match(object_type *) const override;
+
+ static std::shared_ptr<Condition> from_json(json_t *);
+
+protected:
+ void write_tree(TreePrinter *, Cursor *, uint8_t, uint8_t) const override;
+};
+
+/**
+ * Conditions that are OR'ed together
+ */
+class OrCondition : public GroupingCondition
+{
+public:
+ OrCondition() : GroupingCondition(match_type::OR) {
+ }
+
+ bool is_match(object_type *) const override;
+
+ static std::shared_ptr<Condition> from_json(json_t *);
+
+protected:
+ void write_tree(TreePrinter *, Cursor *, uint8_t, uint8_t) const override;
+};
+
+/**
+ * Check for object status
+ */
+class StatusCondition : public Condition
+{
+public:
+ StatusCondition(status_type status)
+ : Condition(match_type::STATUS)
+ , m_status(status) {
+ }
+
+public:
+ bool is_match(object_type *) const override;
+
+ static std::shared_ptr<Condition> from_json(json_t *);
+
+protected:
+ void write_tree(TreePrinter *, Cursor *, uint8_t, uint8_t) const override;
+
+ void to_json(json_t *) const override;
+
+private:
+ status_type m_status;
+};
+
+/**
+ * Check for player race
+ */
+class RaceCondition : public Condition
+{
+public:
+ RaceCondition(std::string race)
+ : Condition(match_type::RACE)
+ , m_race(race) {
+ }
+
+ bool is_match(object_type *) const override;
+
+ static std::shared_ptr<Condition> from_json(json_t *);
+
+protected:
+ void write_tree(TreePrinter *, Cursor *, uint8_t, uint8_t) const override;
+
+ void to_json(json_t *) const override;
+
+private:
+ std::string m_race;
+};
+
+/**
+ * Check player subrace
+ */
+class SubraceCondition : public Condition
+{
+public:
+ SubraceCondition(std::string subrace)
+ : Condition(match_type::SUBRACE)
+ , m_subrace(subrace) {
+ }
+
+ bool is_match(object_type *) const override;
+
+ static std::shared_ptr<Condition> from_json(json_t *);
+
+protected:
+ void write_tree(TreePrinter *, Cursor *, uint8_t, uint8_t) const override;
+
+ void to_json(json_t *) const override;
+
+private:
+ std::string m_subrace;
+};
+
+/**
+ * Check player class
+ */
+class ClassCondition : public Condition
+{
+public:
+ ClassCondition(std::string klass)
+ : Condition(match_type::CLASS)
+ , m_class(klass) {
+ }
+
+ bool is_match(object_type *) const override;
+
+ static std::shared_ptr<Condition> from_json(json_t *);
+
+protected:
+ void write_tree(TreePrinter *, Cursor *, uint8_t, uint8_t) const override;
+
+ void to_json(json_t *) const override;
+
+private:
+ std::string m_class;
+};
+
+/**
+ * Check object inscription
+ */
+class InscriptionCondition : public Condition
+{
+public:
+ InscriptionCondition(std::string inscription)
+ : Condition(match_type::INSCRIBED)
+ , m_inscription(inscription) {
+ }
+
+ bool is_match(object_type *) const override;
+
+ static std::shared_ptr<Condition> from_json(json_t *);
+
+protected:
+ void write_tree(TreePrinter *, Cursor *, uint8_t, uint8_t) const override;
+
+ void to_json(json_t *) const override;
+
+private:
+ std::string m_inscription;
+};
+
+/**
+ * Check object discount
+ */
+class DiscountCondition : public Condition
+{
+public:
+ DiscountCondition(int min, int max)
+ : Condition(match_type::DISCOUNT)
+ , m_min(min)
+ , m_max(max) {
+ }
+
+ bool is_match(object_type *) const override;
+
+ static std::shared_ptr<Condition> from_json(json_t *);
+
+protected:
+ void write_tree(TreePrinter *, Cursor *, uint8_t, uint8_t) const override;
+
+ void to_json(json_t *) const override;
+
+private:
+ int m_min;
+ int m_max;
+};
+
+/**
+ * Check player level
+ */
+class LevelCondition : public Condition
+{
+public:
+ LevelCondition(int min, int max)
+ : Condition(match_type::LEVEL)
+ , m_min(min)
+ , m_max(max) {
+ }
+
+ bool is_match(object_type *) const override;
+
+ static std::shared_ptr<Condition> from_json(json_t *);
+
+protected:
+ void write_tree(TreePrinter *, Cursor *, uint8_t, uint8_t) const override;
+
+ void to_json(json_t *) const override;
+
+private:
+ int m_min;
+ int m_max;
+};
+
+/**
+ * Check player's skill level
+ */
+class SkillCondition : public Condition
+{
+public:
+ SkillCondition(uint16_t skill_idx, uint16_t min, uint16_t max)
+ : Condition(match_type::SKILL)
+ , m_skill_idx(skill_idx)
+ , m_min(min)
+ , m_max(max) {
+ }
+
+ bool is_match(object_type *) const override;
+
+ static std::shared_ptr<Condition> from_json(json_t *);
+
+protected:
+ void write_tree(TreePrinter *, Cursor *, uint8_t, uint8_t) const override;
+
+ void to_json(json_t *) const override;
+
+private:
+ uint16_t m_skill_idx;
+ uint16_t m_min;
+ uint16_t m_max;
+};
+
+/**
+ * Check identification state
+ */
+class StateCondition : public Condition
+{
+public:
+ StateCondition(identification_state state)
+ : Condition(match_type::STATE)
+ , m_state(state) {
+ }
+
+ bool is_match(object_type *) const override;
+
+ static std::shared_ptr<Condition> from_json(json_t *);
+
+protected:
+ void write_tree(TreePrinter *, Cursor *, uint8_t, uint8_t) const override;
+
+ void to_json(json_t *) const override;
+
+private:
+ identification_state m_state;
+};
+
+/**
+ * Check object symbol
+ */
+class SymbolCondition : public Condition
+{
+public:
+ SymbolCondition(char symbol)
+ : Condition(match_type::SYMBOL)
+ , m_symbol(symbol) {
+ }
+
+ bool is_match(object_type *) const override;
+
+ static std::shared_ptr<Condition> from_json(json_t *);
+
+protected:
+ void write_tree(TreePrinter *, Cursor *, uint8_t, uint8_t) const override;
+
+ void to_json(json_t *) const override;
+
+private:
+ char m_symbol;
+};
+
+/**
+ * Check if player has a particular ability
+ */
+class AbilityCondition : public Condition
+{
+public:
+ AbilityCondition(uint16_t ability_idx)
+ : Condition(match_type::ABILITY)
+ , m_ability_idx(ability_idx) {
+ }
+
+ bool is_match(object_type *) const override;
+
+ static std::shared_ptr<Condition> from_json(json_t *);
+
+protected:
+ void write_tree(TreePrinter *, Cursor *, uint8_t, uint8_t) const override;
+
+ void to_json(json_t *) const override;
+
+private:
+ uint16_t m_ability_idx;
+};
+
+/**
+ * Condition with a single subcondition
+ */
+class SingleSubconditionCondition : public Condition
+{
+public:
+ SingleSubconditionCondition(match_type match,
+ std::shared_ptr<Condition> subcondition)
+ : Condition(match)
+ , m_subcondition(subcondition) {
+ }
+
+ virtual void add_child(std::function< std::shared_ptr<Condition> () > const &factory) override;
+
+ virtual void remove_child(Condition *c) override;
+
+ virtual std::shared_ptr<Condition> first_child() override;
+
+protected:
+ void to_json(json_t *) const override;
+
+ static std::shared_ptr<Condition> parse_single_subcondition(
+ json_t *condition_json);
+
+protected:
+ std::shared_ptr<Condition> m_subcondition;
+};
+
+/**
+ * Condition which negates another condition
+ */
+class NotCondition : public SingleSubconditionCondition
+{
+public:
+ NotCondition(std::shared_ptr<Condition> subcondition = nullptr)
+ : SingleSubconditionCondition(match_type::NOT, subcondition) {
+ }
+
+ bool is_match(object_type *) const override;
+
+ static std::shared_ptr<Condition> from_json(json_t *);
+
+protected:
+ void write_tree(TreePrinter *, Cursor *, uint8_t, uint8_t) const override;
+};
+
+/**
+ * Condition which checks if player inventory contains object(s)
+ * satisfying another condition.
+ */
+class InventoryCondition : public SingleSubconditionCondition
+{
+public:
+ InventoryCondition(std::shared_ptr<Condition> subcondition = nullptr)
+ : SingleSubconditionCondition(match_type::INVENTORY, subcondition) {
+ }
+
+ bool is_match(object_type *) const override;
+
+ static std::shared_ptr<Condition> from_json(json_t *);
+
+protected:
+
+ void write_tree(TreePrinter *, Cursor *, uint8_t, uint8_t) const override;
+};
+
+/**
+ * Condition which checks if player equipment contains object(s)
+ * satisfying another condition.
+ */
+class EquipmentCondition : public SingleSubconditionCondition
+{
+public:
+ EquipmentCondition(std::shared_ptr<Condition> subcondition = nullptr)
+ : SingleSubconditionCondition(match_type::EQUIPMENT, subcondition) {
+ }
+
+ bool is_match(object_type *) const override;
+
+ static std::shared_ptr<Condition> from_json(json_t *);
+
+protected:
+ void write_tree(TreePrinter *, Cursor *, uint8_t, uint8_t) const override;
+};
+
+} // namespace
diff --git a/src/include/tome/squelch/condition_fwd.hpp b/src/include/tome/squelch/condition_fwd.hpp
new file mode 100644
index 00000000..744e7884
--- /dev/null
+++ b/src/include/tome/squelch/condition_fwd.hpp
@@ -0,0 +1,15 @@
+#ifndef H_1122f873_e83d_4af8_b6a8_a9e8db195473
+#define H_1122f873_e83d_4af8_b6a8_a9e8db195473
+
+#include <functional>
+#include <memory>
+
+namespace squelch {
+
+enum class match_type : int;
+class Condition;
+typedef std::function< std::shared_ptr<Condition> () > ConditionFactory;
+
+} // namespace
+
+#endif
diff --git a/src/include/tome/squelch/condition_metadata.hpp b/src/include/tome/squelch/condition_metadata.hpp
new file mode 100644
index 00000000..fbb26bc3
--- /dev/null
+++ b/src/include/tome/squelch/condition_metadata.hpp
@@ -0,0 +1,12 @@
+#ifndef H_787198a1_aa3e_45c9_bc9f_fd7f490db78c
+#define H_787198a1_aa3e_45c9_bc9f_fd7f490db78c
+
+#include "tome/squelch/condition_metadata_fwd.hpp"
+
+namespace squelch {
+
+std::shared_ptr<Condition> new_condition_interactive();
+
+} // namespace
+
+#endif
diff --git a/src/include/tome/squelch/condition_metadata_fwd.hpp b/src/include/tome/squelch/condition_metadata_fwd.hpp
new file mode 100644
index 00000000..1f57481b
--- /dev/null
+++ b/src/include/tome/squelch/condition_metadata_fwd.hpp
@@ -0,0 +1,14 @@
+#ifndef H_7922f591_bdfd_491d_8561_b11225285fea
+#define H_7922f591_bdfd_491d_8561_b11225285fea
+
+#include "tome/squelch/condition_fwd.hpp"
+
+#include <memory>
+
+namespace squelch {
+
+std::shared_ptr<Condition> new_condition_interactive();
+
+} // namespace
+
+#endif
diff --git a/src/include/tome/squelch/cursor.hpp b/src/include/tome/squelch/cursor.hpp
new file mode 100644
index 00000000..8dbfc6bf
--- /dev/null
+++ b/src/include/tome/squelch/cursor.hpp
@@ -0,0 +1,50 @@
+#ifndef H_8a10111d_64a1_4af9_a85b_24ec8922d3fa
+#define H_8a10111d_64a1_4af9_a85b_24ec8922d3fa
+
+#include <boost/noncopyable.hpp>
+#include <deque>
+
+#include "tome/squelch/condition_fwd.hpp"
+
+namespace squelch {
+
+/**
+ * Cursor which maintains selected condition(s)
+ */
+class Cursor : public boost::noncopyable
+{
+public:
+ bool is_selected(Condition const *condition) const;
+
+ void push(Condition *condition) {
+ m_conditions.push_back(condition);
+ }
+
+ Condition *pop();
+
+ Condition *current();
+
+ void clear() {
+ m_conditions.clear();
+ }
+
+ bool empty() const {
+ return m_conditions.empty();
+ }
+
+ std::size_t size() const {
+ return m_conditions.size();
+ }
+
+ void move_left();
+ void move_right();
+ void move_up();
+ void move_down();
+
+private:
+ std::deque<Condition *> m_conditions;
+};
+
+} // namespace
+
+#endif
diff --git a/src/include/tome/squelch/cursor_fwd.hpp b/src/include/tome/squelch/cursor_fwd.hpp
new file mode 100644
index 00000000..f07e9aa9
--- /dev/null
+++ b/src/include/tome/squelch/cursor_fwd.hpp
@@ -0,0 +1,10 @@
+#ifndef H_a4caa98a_1044_4192_b1af_27c2e8790cae
+#define H_a4caa98a_1044_4192_b1af_27c2e8790cae
+
+namespace squelch {
+
+class Cursor;
+
+} // namespace
+
+#endif
diff --git a/src/include/tome/squelch/object_status.hpp b/src/include/tome/squelch/object_status.hpp
new file mode 100644
index 00000000..c52a35ea
--- /dev/null
+++ b/src/include/tome/squelch/object_status.hpp
@@ -0,0 +1,28 @@
+#ifndef H_e3f9ebbe_ff9a_4687_a847_6101f094b483
+#define H_e3f9ebbe_ff9a_4687_a847_6101f094b483
+
+#include "tome/enum_string_map.hpp"
+
+namespace squelch {
+
+/**
+ * Types of statuses for objects, e.g. "special" for artifacts and
+ * "average" for plain objects with no plusses.
+ */
+enum class status_type {
+ BAD , VERY_BAD, AVERAGE, GOOD, VERY_GOOD,
+ SPECIAL, TERRIBLE, NONE, CHEST_EMPTY, CHEST_DISARMED };
+
+/**
+ * Bidirectional map between status_type values and strings.
+ */
+EnumStringMap<status_type> &status_mapping();
+
+/**
+ * Find the status of an object
+ */
+status_type object_status(object_type *o_ptr);
+
+} // namespace
+
+#endif
diff --git a/src/include/tome/squelch/object_status_fwd.hpp b/src/include/tome/squelch/object_status_fwd.hpp
new file mode 100644
index 00000000..361ea2fe
--- /dev/null
+++ b/src/include/tome/squelch/object_status_fwd.hpp
@@ -0,0 +1,12 @@
+#pragma once
+
+#include "../object_type_fwd.hpp"
+#include "tome/enum_string_map.hpp"
+
+namespace squelch {
+
+enum class status_type;
+EnumStringMap<status_type> &status_mapping();
+status_type object_status(object_type *o_ptr);
+
+} // namespace
diff --git a/src/include/tome/squelch/rule.hpp b/src/include/tome/squelch/rule.hpp
new file mode 100644
index 00000000..63f1b6c0
--- /dev/null
+++ b/src/include/tome/squelch/rule.hpp
@@ -0,0 +1,162 @@
+#pragma once
+
+#include <jansson.h>
+#include <memory>
+
+#include "tome/squelch/condition_fwd.hpp"
+#include "tome/squelch/cursor_fwd.hpp"
+#include "tome/squelch/tree_printer_fwd.hpp"
+#include "tome/enum_string_map.hpp"
+#include "../object_type_fwd.hpp"
+
+namespace squelch {
+
+/**
+ * Types of automatizer actions: destroy, pick up, and inscribe.
+ */
+enum class action_type { AUTO_DESTROY, AUTO_PICKUP, AUTO_INSCRIBE };
+
+/**
+ * Bidirectional map between rule actions and strings.
+ */
+EnumStringMap<action_type> &action_mapping();
+
+/**
+ * Rules are the representation of "when condition X is true, do Y".
+ */
+class Rule : public boost::noncopyable
+{
+public:
+ Rule(std::string name,
+ action_type action,
+ int module_idx,
+ std::shared_ptr<Condition> condition)
+ : m_name(name)
+ , m_action(action)
+ , m_module_idx(module_idx)
+ , m_condition(condition) {
+ }
+
+ /**
+ * Set the name of the rule
+ */
+ void set_name(const char *new_name);
+
+ /**
+ * Get the name of the rule
+ */
+ const char *get_name() const;
+
+ /**
+ * Get condition
+ */
+ std::shared_ptr<Condition> get_condition() const;
+
+ /**
+ * Add new condition using a factory to instantiate the
+ * condition only if the rule permits adding a condition.
+ */
+ void add_new_condition(Cursor *cursor,
+ ConditionFactory const &factory);
+
+ /**
+ * Remove currently selected condition
+ */
+ void delete_selected_condition(Cursor *cursor);
+
+ /**
+ * Write out tree representing rule
+ */
+ void write_tree(TreePrinter *p, Cursor *cursor) const;
+
+ /**
+ * Apply rule to object
+ */
+ bool apply_rule(object_type *o_ptr, int item_idx) const;
+
+ /**
+ * Convert rule to JSON
+ */
+ virtual json_t *to_json() const;
+
+ /**
+ * Parse rule from JSON
+ */
+ static std::shared_ptr<Rule> parse_rule(json_t *);
+
+protected:
+ virtual bool do_apply_rule(object_type *, int) const = 0;
+ virtual void do_write_tree(TreePrinter *p) const = 0;
+
+protected:
+ // Rule name
+ std::string m_name;
+ // What does the rule do?
+ action_type m_action;
+ // Which module does this rule apply to?
+ int m_module_idx;
+ // Condition to check
+ std::shared_ptr<Condition> m_condition;
+};
+
+/**
+ * Rule for destroying matching objects
+ */
+class DestroyRule : public Rule
+{
+public:
+ DestroyRule(std::string name,
+ int module_idx,
+ std::shared_ptr<Condition> condition)
+ : Rule(name, action_type::AUTO_DESTROY, module_idx, condition) {
+ }
+
+protected:
+ virtual bool do_apply_rule(object_type *o_ptr, int item_idx) const override;
+ virtual void do_write_tree(TreePrinter *p) const override;
+};
+
+/**
+ * Rule for picking up matching objects
+ */
+class PickUpRule : public Rule
+{
+public:
+
+ PickUpRule(std::string name,
+ int module_idx,
+ std::shared_ptr<Condition> condition)
+ : Rule(name, action_type::AUTO_PICKUP, module_idx, condition) {
+ }
+
+protected:
+ virtual void do_write_tree(TreePrinter *p) const override;
+ virtual bool do_apply_rule(object_type *o_ptr, int item_idx) const override;
+};
+
+/**
+ * Rule for inscribing matching objects
+ */
+class InscribeRule : public Rule
+{
+public:
+ InscribeRule(std::string name,
+ int module_idx,
+ std::shared_ptr<Condition> condition,
+ std::string inscription)
+ : Rule(name, action_type::AUTO_INSCRIBE, module_idx, condition)
+ , m_inscription(inscription) {
+ }
+
+ json_t *to_json() const override;
+
+protected:
+ virtual void do_write_tree(TreePrinter *p) const override;
+ virtual bool do_apply_rule(object_type *o_ptr, int) const override;
+
+private:
+ // Inscription to use for inscription rules.
+ std::string m_inscription;
+};
+
+} // namespace
diff --git a/src/include/tome/squelch/rule_fwd.hpp b/src/include/tome/squelch/rule_fwd.hpp
new file mode 100644
index 00000000..091e77ef
--- /dev/null
+++ b/src/include/tome/squelch/rule_fwd.hpp
@@ -0,0 +1,16 @@
+#ifndef H_4a8d2cfb_182c_4138_983d_606a9ac70784
+#define H_4a8d2cfb_182c_4138_983d_606a9ac70784
+
+#include "tome/enum_string_map.hpp"
+
+namespace squelch {
+
+enum class action_type;
+
+EnumStringMap<action_type> &action_mapping();
+
+class Rule;
+
+} // namespace
+
+#endif
diff --git a/src/include/tome/squelch/tree_printer.hpp b/src/include/tome/squelch/tree_printer.hpp
new file mode 100644
index 00000000..e8ee1e56
--- /dev/null
+++ b/src/include/tome/squelch/tree_printer.hpp
@@ -0,0 +1,49 @@
+#ifndef H_3d6cc652_c674_4a84_911d_e8ec35cc992a
+#define H_3d6cc652_c674_4a84_911d_e8ec35cc992a
+
+#include <boost/noncopyable.hpp>
+#include <cstdint>
+
+namespace squelch {
+
+/**
+ * Printing trees.
+ */
+class TreePrinter : boost::noncopyable
+{
+public:
+ TreePrinter();
+
+ void indent();
+
+ void dedent();
+
+ void reset();
+
+ void reset_scroll();
+
+ void scroll_up();
+
+ void scroll_down();
+
+ void scroll_left();
+
+ void scroll_right();
+
+ void write(uint8_t color, const char *line);
+
+private:
+ int m_indent;
+ int m_write_out_y;
+ int m_write_out_x;
+ int m_write_out_h;
+ int m_write_out_w;
+ int m_write_y;
+ int m_write_x;
+ int m_write_off_x;
+ int m_write_off_y;
+};
+
+} // namespace
+
+#endif
diff --git a/src/include/tome/squelch/tree_printer_fwd.hpp b/src/include/tome/squelch/tree_printer_fwd.hpp
new file mode 100644
index 00000000..d7d75453
--- /dev/null
+++ b/src/include/tome/squelch/tree_printer_fwd.hpp
@@ -0,0 +1,10 @@
+#ifndef H_4ce68eb3_c475_4fc4_8a70_0590c16dc684
+#define H_4ce68eb3_c475_4fc4_8a70_0590c16dc684
+
+namespace squelch {
+
+class TreePrinter;
+
+} // namespace
+
+#endif
diff --git a/src/init1.c b/src/init1.c
deleted file mode 100644
index 9715831d..00000000
--- a/src/init1.c
+++ /dev/null
@@ -1,11819 +0,0 @@
-/* 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/init1.cc b/src/init1.cc
new file mode 100644
index 00000000..7083a5f3
--- /dev/null
+++ b/src/init1.cc
@@ -0,0 +1,10225 @@
+#include "init1.hpp"
+
+#include "ability_type.hpp"
+#include "artifact_type.hpp"
+#include "cave.hpp"
+#include "cave_type.hpp"
+#include "dungeon_info_type.hpp"
+#include "ego_item_type.hpp"
+#include "feature_type.hpp"
+#include "files.hpp"
+#include "gods.hpp"
+#include "hist_type.hpp"
+#include "init2.hpp"
+#include "meta_class_type.hpp"
+#include "monster2.hpp"
+#include "monster_ego.hpp"
+#include "monster_race.hpp"
+#include "monster_type.hpp"
+#include "object1.hpp"
+#include "object2.hpp"
+#include "object_kind.hpp"
+#include "owner_type.hpp"
+#include "player_class.hpp"
+#include "player_race.hpp"
+#include "player_race_mod.hpp"
+#include "player_type.hpp"
+#include "randart_gen_type.hpp"
+#include "randart_part_type.hpp"
+#include "set_type.hpp"
+#include "skill_type.hpp"
+#include "skills.hpp"
+#include "spells5.hpp"
+#include "store_action_type.hpp"
+#include "store_info_type.hpp"
+#include "store_type.hpp"
+#include "tables.hpp"
+#include "town_type.hpp"
+#include "trap_type.hpp"
+#include "traps.hpp"
+#include "util.hpp"
+#include "util.h"
+#include "variable.h"
+#include "variable.hpp"
+#include "vault_type.hpp"
+#include "wilderness_map.hpp"
+#include "wilderness_type_info.hpp"
+#include "z-rand.hpp"
+
+#include <boost/algorithm/string/predicate.hpp>
+
+using boost::algorithm::iequals;
+using boost::algorithm::ends_with;
+
+
+/*
+ * 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",
+ "XXX7X20",
+ "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",
+ "XXX5",
+ "XXX5",
+ "XXX5",
+ "EASY_USE",
+ "IM_NETHER",
+ "RECHARGED",
+ "ULTIMATE",
+ "AUTO_ID",
+ "LITE2",
+ "LITE3",
+ "FUEL_LITE",
+ "XXX5",
+ "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"
+};
+
+/*
+ * 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}
+};
+
+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*/
+ "ETERNAL_FLAME", /* 201 */
+ "MAGGOT", /* 202 */
+ "LEBOHAUM", /* 203 */
+ "DURANDIL", /* 204 */
+ "RADAGAST", /* 205, Theme */
+ "VALAROMA", /* 206, Theme */
+ ""
+};
+
+/*
+ * 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;
+ }
+ }
+}
+
+/**
+ * Version of strdup() which just aborts if an allocation
+ * error occurs.
+ */
+static char *my_strdup(const char *s)
+{
+ char *p = strdup(s);
+ if (!p)
+ {
+ abort();
+ }
+ return p;
+}
+
+
+/**
+ * Append one string to the end of another, reallocating if
+ * necessary.
+ */
+static void strappend(char **s, const char *t)
+{
+ // Do we need to initialize the destination string?
+ if (*s == nullptr)
+ {
+ // Costs an extra allocation which could be avoided
+ // but this leads to simpler code.
+ *s = my_strdup("");
+ }
+ // We should really be preserving the original pointer and
+ // do something else in case of failure to realloc(), but
+ // instead we just do the lazy thing and call abort() if
+ // reallocation fails. In practice it won't.
+ *s = static_cast<char *>(realloc(*s, strlen(*s) + strlen(t) + 1));
+ if (*s == nullptr)
+ {
+ abort(); // Cannot handle failure to reallocate
+ }
+
+ /* Append 't' to the destination string */
+ strcat(*s, t);
+}
+
+/*** 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); 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); 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) */
+static int get_activation(char *activation)
+{
+ int i;
+ for ( i = 0 ; activation_names[i][0] ; i++)
+ {
+ if (!strncmp(activation_names[i], activation, 19))
+ {
+ return i;
+ }
+ }
+
+ msg_format("Unknown activation '%s'.", activation);
+ 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)
+{
+ int i = 0, z;
+ int powers = 0;
+ int lev = 1;
+ int tit_idx = 0;
+ int spec_idx = 0;
+ int cur_ab = -1;
+ char buf[1024];
+ char *s, *t;
+
+ /* 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;
+
+ /* 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 */
+ while (0 == my_fgets(fp, 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);
+
+ /* 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]);
+
+ /* Copy text */
+ assert(!bg[idx].info);
+ bg[idx].info = my_strdup(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 >= max_rp_idx) return (2);
+
+ /* Save the index */
+ error_idx = i;
+
+ /* Point at the "info" */
+ rp_ptr = &race_info[i];
+
+ /* Copy title */
+ assert(!rp_ptr->title);
+ rp_ptr->title = my_strdup(s);
+
+ /* Initialize */
+ 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;
+
+ if (!rp_ptr->desc)
+ {
+ rp_ptr->desc = my_strdup(s);
+ }
+ else
+ {
+ strappend(&rp_ptr->desc, format("\n%s", s));
+ }
+
+ /* 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 (iequals(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 >= max_rmp_idx) return (2);
+
+ /* Save the index */
+ error_idx = i;
+
+ /* Point at the "info" */
+ rmp_ptr = &race_mod_info[i];
+
+ /* Copy title */
+ assert(!rmp_ptr->title);
+ rmp_ptr->title = my_strdup(s);
+
+ /* Initialize */
+ 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;
+
+ /* Place */
+ if (buf[4] == 'A')
+ {
+ rmp_ptr->place = TRUE;
+ }
+ else
+ {
+ rmp_ptr->place = FALSE;
+ }
+
+ /* Description */
+ if (!rmp_ptr->desc)
+ {
+ rmp_ptr->desc = my_strdup(s);
+ }
+ else
+ {
+ /* Append chars to the name */
+ strappend(&rmp_ptr->desc, format("\n%s", s));
+ }
+
+ /* 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 (iequals(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 >= max_c_idx) return (2);
+
+ /* Save the index */
+ error_idx = i;
+
+ /* Point at the "info" */
+ c_ptr = &class_info[i];
+
+ /* Copy name */
+ assert(!c_ptr->title);
+ c_ptr->title = my_strdup(s);
+
+ /* Initialize */
+ 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;
+
+ switch (buf[4])
+ {
+ case '0': /* Class description */
+ if (!c_ptr->desc)
+ {
+
+ c_ptr->desc = my_strdup(s);
+ }
+ else
+ {
+ strappend(&c_ptr->desc, format("\n%s", s));
+ }
+ break;
+
+ case '1': /* Class title */
+ /* Copy */
+ assert(!c_ptr->titles[tit_idx]);
+ c_ptr->titles[tit_idx] = my_strdup(s);
+
+ /* Go to next title in array */
+ tit_idx++;
+
+ break;
+
+ default: /* Unknown */
+ 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 (iequals(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];
+
+ /* Copy title */
+ assert(!s_ptr->title);
+ s_ptr->title = my_strdup(s);
+
+ /* Initialize */
+ 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;
+
+ if (!s_ptr->desc)
+ {
+ s_ptr->desc = my_strdup(s);
+ }
+ else
+ {
+ strappend(&s_ptr->desc, format("\n%s", s));
+ }
+
+ /* 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 (class_info[i].title && iequals(s, class_info[i].title))
+ {
+ break;
+ }
+ }
+
+ if (i == max_c_idx) return (6);
+
+ mc_ptr->classes[powers++] = i;
+
+ /* Next... */
+ continue;
+ }
+
+ /* Oops */
+ return (6);
+ }
+
+ /* Success */
+ return (0);
+}
+
+
+/*
+ * Initialize the "v_info" array, by parsing an ascii "template" file
+ */
+errr init_v_info_txt(FILE *fp)
+{
+ int i;
+ char buf[1024];
+ char *s;
+
+ /* Current entry */
+ vault_type *v_ptr = NULL;
+
+ /* Just before the first record */
+ error_idx = -1;
+
+ /* Just before the first line */
+ error_line = -1;
+
+ /* Parse */
+ while (0 == my_fgets(fp, 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);
+
+ /* 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 >= max_v_idx) return (2);
+
+ /* Save the index */
+ error_idx = i;
+
+ /* Point at the "info" */
+ v_ptr = &v_info[i];
+
+ /* Initialize data -- we ignore the name, it's not
+ * used for anything */
+ v_ptr->data = my_strdup("");
+
+ /* 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;
+
+ /* Append data */
+ strappend(&v_ptr->data, 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);
+ }
+
+
+ /* 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)
+{
+ int i;
+ char buf[1024];
+ char *s, *t;
+
+ /* Current entry */
+ feature_type *f_ptr = NULL;
+
+ /* Just before the first record */
+ error_idx = -1;
+
+ /* Just before the first line */
+ error_line = -1;
+
+ /* Parse */
+ while (0 == my_fgets(fp, 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);
+
+ /* 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 >= max_f_idx) return (2);
+
+ /* Save the index */
+ error_idx = i;
+
+ /* Point at the "info" */
+ f_ptr = &f_info[i];
+
+ /* Copy name */
+ assert(!f_ptr->name);
+ f_ptr->name = my_strdup(s);
+
+ /* Initialize */
+ f_ptr->mimic = i;
+ f_ptr->text = DEFAULT_FEAT_TEXT;
+ f_ptr->tunnel = DEFAULT_FEAT_TUNNEL;
+ f_ptr->block = DEFAULT_FEAT_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;
+
+ switch (buf[2])
+ {
+ case '0':
+ assert(f_ptr->text == DEFAULT_FEAT_TEXT);
+ f_ptr->text = my_strdup(s);
+ break;
+ case '1':
+ assert(f_ptr->tunnel == DEFAULT_FEAT_TUNNEL);
+ f_ptr->tunnel = my_strdup(s);
+ break;
+ case '2':
+ assert(f_ptr->block == DEFAULT_FEAT_BLOCK);
+ f_ptr->block = my_strdup(s);
+ break;
+ default:
+ return (6);
+ }
+
+ /* 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);
+ }
+
+ /* 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)
+{
+ int i;
+ char buf[1024];
+ char *s, *t;
+
+ /* Current entry */
+ object_kind *k_ptr = NULL;
+
+
+ /* Just before the first record */
+ error_idx = -1;
+
+ /* Just before the first line */
+ error_line = -1;
+
+
+ /* Parse */
+ while (0 == my_fgets(fp, 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);
+
+
+ /* 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 >= max_k_idx) return (2);
+
+ /* Save the index */
+ error_idx = i;
+
+ /* Point at the "info" */
+ k_ptr = &k_info[i];
+
+ /* Advance and Save the name index */
+ assert(!k_ptr->name);
+ k_ptr->name = my_strdup(s);
+
+ /* Ensure empty description */
+ k_ptr->text = my_strdup("");
+
+ /* 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;
+
+ /* Append description */
+ strappend(&k_ptr->text, 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, unused, wgt;
+ long cost;
+
+ /* Scan for the values */
+ if (4 != sscanf(buf + 2, "%d:%d:%d:%ld",
+ &level, &unused, &wgt, &cost)) return (1);
+
+ /* Save the values */
+ k_ptr->level = level;
+ 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 (iequals(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')
+ {
+ k_ptr->activate = get_activation(buf + 2);
+ 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)
+ {
+ if (i >= ALLOCATION_MAX) {
+ msg_print("Too many allocation entries.");
+ return 1;
+ }
+
+ /* 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);
+ }
+
+ /* 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)
+{
+ int i;
+ char buf[1024];
+ char *s, *t;
+
+ /* Current entry */
+ artifact_type *a_ptr = NULL;
+
+
+ /* Just before the first record */
+ error_idx = -1;
+
+ /* Just before the first line */
+ error_line = -1;
+
+
+ /* Parse */
+ while (0 == my_fgets(fp, 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);
+
+ /* 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 >= max_a_idx) return (2);
+
+ /* Save the index */
+ error_idx = i;
+
+ /* Point at the "info" */
+ a_ptr = &a_info[i];
+
+ /* Copy name */
+ assert(!a_ptr->name);
+ a_ptr->name = my_strdup(s);
+
+ /* Ensure empty description */
+ a_ptr->text = my_strdup("");
+
+ /* 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;
+
+ /* Add separator if necessary */
+ if (*a_ptr->text != '\0' && !ends_with(a_ptr->text, " ")) {
+ strappend(&a_ptr->text, " ");
+ }
+
+ /* Append to description */
+ strappend(&a_ptr->text, 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 (iequals(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')
+ {
+ a_ptr->activate = get_activation(buf + 2);
+ if (a_ptr->activate == -1)
+ {
+ return 1;
+ }
+
+ /* Next... */
+ continue;
+ }
+
+
+ /* Oops */
+ return (6);
+ }
+
+ /* Success */
+ return (0);
+}
+
+/*
+* Initialize the "set_info" array, by parsing an ascii "template" file
+*/
+errr init_set_info_txt(FILE *fp)
+{
+ int i;
+ int cur_art = 0, cur_num = 0;
+ char buf[1024];
+
+ char *s, *t;
+
+ /* Current entry */
+ set_type *set_ptr = NULL;
+
+
+ /* Just before the first record */
+ error_idx = -1;
+
+ /* Just before the first line */
+ error_line = -1;
+
+
+ /* Parse */
+ while (0 == my_fgets(fp, 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);
+
+ /* 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 >= max_set_idx) return (2);
+
+ /* Save the index */
+ error_idx = i;
+
+ /* Point at the "info" */
+ set_ptr = &set_info[i];
+
+ /* Copy name */
+ assert(!set_ptr->name);
+ set_ptr->name = my_strdup(s);
+
+ /* Initialize */
+ 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;
+
+ /* Append chars to the description */
+ strappend(&set_ptr->desc, 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);
+ }
+
+ /* Success */
+ return (0);
+}
+
+
+/*
+ * Initialize the "s_info" array, by parsing an ascii "template" file
+ */
+errr init_s_info_txt(FILE *fp)
+{
+ int i, z, order = 1;
+ char buf[1024];
+ char *s;
+
+ /* Current entry */
+ skill_type *s_ptr = NULL;
+
+
+ /* Just before the first record */
+ error_idx = -1;
+
+ /* Just before the first line */
+ error_line = -1;
+
+
+ /* Parse */
+ while (0 == my_fgets(fp, 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);
+
+ /* 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 >= max_s_idx) return (2);
+
+ /* Save the index */
+ error_idx = i;
+
+ /* Point at the "info" */
+ s_ptr = &s_info[i];
+
+ /* Copy name */
+ assert(!s_ptr->name);
+ s_ptr->name = my_strdup(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;
+
+ /* Description */
+ if (!s_ptr->desc)
+ {
+ s_ptr->desc = my_strdup(s);
+ }
+ else
+ {
+ strappend(&s_ptr->desc, format("\n%s", s));
+ }
+
+ /* Next... */
+ continue;
+ }
+
+ /* Process 'A' for "Activation Description" (one line only) */
+ if (buf[0] == 'A')
+ {
+ char *txt;
+
+ /* Acquire the text */
+ s = buf + 2;
+
+ if (NULL == (txt = strchr(s, ':'))) return (1);
+ *txt = '\0';
+ txt++;
+
+ /* Copy action description */
+ assert(!s_ptr->action_desc);
+ s_ptr->action_desc = my_strdup(txt);
+
+ /* Copy mkey index */
+ s_ptr->action_mkey = atoi(s);
+
+ /* 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);
+ }
+
+ /* Success */
+ return (0);
+}
+
+/*
+ * Initialize the "ab_info" array, by parsing an ascii "template" file
+ */
+errr init_ab_info_txt(FILE *fp)
+{
+ int i, z;
+ char buf[1024];
+ char *s;
+
+ /* Current entry */
+ ability_type *ab_ptr = NULL;
+
+
+ /* Just before the first record */
+ error_idx = -1;
+
+ /* Just before the first line */
+ error_line = -1;
+
+
+ /* Parse */
+ while (0 == my_fgets(fp, 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);
+
+ /* 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 >= max_ab_idx) return (2);
+
+ /* Save the index */
+ error_idx = i;
+
+ /* Point at the "info" */
+ ab_ptr = &ab_info[i];
+
+ /* Copy name */
+ assert(!ab_ptr->name);
+ ab_ptr->name = my_strdup(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;
+
+ /* Append description */
+ if (!ab_ptr->desc)
+ {
+ ab_ptr->desc = my_strdup(s);
+ }
+ else
+ {
+ strappend(&ab_ptr->desc, format("\n%s", s));
+ }
+
+ /* 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++;
+
+ /* Copy name */
+ assert(!ab_ptr->action_desc);
+ ab_ptr->action_desc = my_strdup(txt);
+
+ /* Set mkey */
+ ab_ptr->action_mkey = atoi(s);
+
+ /* 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);
+ }
+
+ /* 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;
+ assert(n < FLAG_RARITY_MAX);
+
+ /* 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)
+{
+ int i, cur_r = -1, cur_t = 0, j;
+ char buf[1024];
+ char *s, *t;
+
+ /* 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 */
+ while (0 == my_fgets(fp, 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);
+
+ /* 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 >= max_e_idx) return (2);
+
+ /* Save the index */
+ error_idx = i;
+
+ /* Point at the "info" */
+ e_ptr = &e_info[i];
+
+ /* Copy name */
+ assert(!e_ptr->name);
+ e_ptr->name = my_strdup(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 < FLAG_RARITY_MAX; 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;
+ e_ptr->oflags1[j] = 0;
+ e_ptr->oflags2[j] = 0;
+ e_ptr->oflags3[j] = 0;
+ e_ptr->oflags4[j] = 0;
+ e_ptr->oflags5[j] = 0;
+ e_ptr->oesp[j] = 0;
+ e_ptr->fego[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;
+
+ cur_r++;
+
+ if (cur_r >= FLAG_RARITY_MAX) {
+ return 1;
+ }
+
+ /* Scan for the values */
+ if (1 != sscanf(buf + 2, "%d",
+ &rar)) return (1);
+
+ /* 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 (iequals(s, powers_type[i].name)) break;
+ }
+
+ if (i == POWER_MAX) return (6);
+
+ e_ptr->power = i;
+
+ /* Next... */
+ continue;
+ }
+
+ if (buf[0] == 'a')
+ {
+ e_ptr->activate = get_activation(buf + 2);
+ 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);
+ }
+
+ /* 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)
+{
+ int i, cur_t = 0, j, cur_g = 0;
+ char buf[1024];
+ char *s, *t;
+
+ /* 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 */
+ while (0 == my_fgets(fp, 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);
+
+ /* 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 >= max_ra_idx) 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 (iequals(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);
+ }
+
+ /* 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)
+{
+ int i;
+ char buf[1024];
+ char *s, *t;
+
+ /* Current entry */
+ monster_race *r_ptr = NULL;
+
+
+ /* Just before the first record */
+ error_idx = -1;
+
+ /* Just before the first line */
+ error_line = -1;
+
+
+ /* Parse */
+ while (0 == my_fgets(fp, 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);
+
+ /* 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 >= max_r_idx) return (2);
+
+ /* Save the index */
+ error_idx = i;
+
+ /* Point at the "info" */
+ r_ptr = &r_info[i];
+
+ /* Allocate name string. */
+ assert(!r_ptr->name); // Sanity check that we aren't overwriting anything
+ r_ptr->name = my_strdup(s);
+
+ /* Ensure empty description */
+ r_ptr->text = my_strdup("");
+
+ /* 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;
+
+ /* Append to description */
+ strappend(&r_ptr->text, 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);
+ }
+
+ /* Postprocessing */
+ 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;
+ }
+
+ /* 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)
+{
+ int i, j;
+ char buf[1024];
+ byte blow_num = 0;
+ int r_char_number = 0, nr_char_number = 0;
+
+ char *s, *t;
+
+ /* Current entry */
+ monster_ego *re_ptr = NULL;
+
+
+ /* Just before the first record */
+ error_idx = -1;
+
+ /* Just before the first line */
+ error_line = -1;
+
+ /* Parse */
+ while (0 == my_fgets(fp, 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);
+
+ /* 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 >= max_re_idx) return (2);
+
+ /* Save the index */
+ error_idx = i;
+
+ /* Point at the "info" */
+ re_ptr = &re_info[i];
+
+ /* Copy name */
+ assert(!re_ptr->name);
+ re_ptr->name = my_strdup(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);
+ }
+
+ /* 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)
+{
+ int i;
+ char buf[1024];
+ char *s, *t;
+
+ /* Current entry */
+ trap_type *t_ptr = NULL;
+
+ /* Just before the first record */
+ error_idx = -1;
+
+ /* Just before the first line */
+ error_line = -1;
+
+ /* Parse */
+ while (0 == my_fgets(fp, 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);
+
+ /* 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 >= max_t_idx) return (2);
+
+ /* Save the index */
+ error_idx = i;
+
+ /* Point at the "info" */
+ t_ptr = &t_info[i];
+
+ /* Copy name */
+ t_ptr->name = my_strdup(s);
+
+ /* Initialize */
+ t_ptr->text = my_strdup("");
+
+ /* 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;
+
+ /* Append chars to the name */
+ strappend(&t_ptr->text, 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);
+ }
+
+ /* 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)
+{
+ int i, j;
+ char buf[1024];
+
+ s16b rule_num = 0;
+
+ byte r_char_number = 0;
+
+ char *s, *t;
+
+ /* Current entry */
+ dungeon_info_type *d_ptr = NULL;
+
+
+ /* Just before the first record */
+ error_idx = -1;
+
+ /* Just before the first line */
+ error_line = -1;
+
+ /* Parse */
+ while (0 == my_fgets(fp, 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);
+
+ /* 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 >= max_d_idx) return (2);
+
+ /* Save the index */
+ error_idx = i;
+
+ /* Point at the "info" */
+ d_ptr = &d_info[i];
+
+ /* Copy name */
+ assert(!d_ptr->name);
+ d_ptr->name = my_strdup(s);
+
+ /* Initialize description */
+ d_ptr->text = my_strdup("");
+
+ /* 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;
+
+ /* Append to description */
+ strappend(&d_ptr->text, 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);
+ }
+
+ /* 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)
+{
+ int i = 0, item_idx = 0;
+ char buf[1024];
+ char *s, *t;
+
+ /* Current entry */
+ store_info_type *st_ptr = NULL;
+
+
+ /* Just before the first record */
+ error_idx = -1;
+
+ /* Just before the first line */
+ error_line = -1;
+
+ /* Parse */
+ while (0 == my_fgets(fp, 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);
+
+ /* 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 >= max_st_idx) return (2);
+
+ /* Save the index */
+ error_idx = i;
+
+ /* Point at the "info" */
+ st_ptr = &st_info[i];
+
+ /* Copy name */
+ assert(!st_ptr->name);
+ st_ptr->name = my_strdup(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;
+ assert(st_ptr->table_num <= STORE_CHOICES);
+
+ /* 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);
+ }
+
+ /* Success */
+ return (0);
+}
+
+/*
+ * Initialize the "ba_info" array, by parsing an ascii "template" file
+ */
+errr init_ba_info_txt(FILE *fp)
+{
+ int i = 0;
+ char buf[1024];
+ char *s;
+
+ /* Current entry */
+ store_action_type *ba_ptr = NULL;
+
+
+ /* Just before the first record */
+ error_idx = -1;
+
+ /* Just before the first line */
+ error_line = -1;
+
+ /* Parse */
+ while (0 == my_fgets(fp, 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);
+
+ /* 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 >= max_ba_idx) return (2);
+
+ /* Save the index */
+ error_idx = i;
+
+ /* Point at the "info" */
+ ba_ptr = &ba_info[i];
+
+ /* Copy name */
+ assert(!ba_ptr->name);
+ ba_ptr->name = my_strdup(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);
+ }
+
+ /* Success */
+ return (0);
+}
+
+/*
+ * Initialize the "ow_info" array, by parsing an ascii "template" file
+ */
+errr init_ow_info_txt(FILE *fp)
+{
+ int i;
+ char buf[1024];
+ char *s, *t;
+
+ /* Current entry */
+ owner_type *ow_ptr = NULL;
+
+ /* Just before the first record */
+ error_idx = -1;
+
+ /* Just before the first line */
+ error_line = -1;
+
+ /* Parse */
+ while (0 == my_fgets(fp, 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);
+
+ /* 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 >= max_ow_idx) return (2);
+
+ /* Save the index */
+ error_idx = i;
+
+ /* Point at the "info" */
+ ow_ptr = &ow_info[i];
+
+ /* Copy name */
+ assert(!ow_ptr->name);
+ ow_ptr->name = my_strdup(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, inf;
+
+ /* Scan for the values */
+ if (2 != sscanf(buf + 2, "%d:%d",
+ &cost, &inf)) return (1);
+
+ /* Save the values */
+ ow_ptr->max_cost = cost;
+ ow_ptr->inflation = inf;
+
+ /* 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);
+ }
+
+ /* Success */
+ return (0);
+}
+
+/*
+ * Initialize the "wf_info" array, by parsing an ascii "template" file
+ */
+errr init_wf_info_txt(FILE *fp)
+{
+ int i;
+ char buf[1024];
+ char *s;
+
+ /* Current entry */
+ wilderness_type_info *wf_ptr = NULL;
+
+ /* Just before the first record */
+ error_idx = -1;
+
+ /* Just before the first line */
+ error_line = -1;
+
+ /* Parse */
+ while (0 == my_fgets(fp, 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);
+
+ /* 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 >= max_wf_idx) return (2);
+
+ /* Save the index */
+ error_idx = i;
+
+ /* Point at the "info" */
+ wf_ptr = &wf_info[i];
+
+ /* Copy the name */
+ assert(!wf_ptr->name);
+ wf_ptr->name = my_strdup(s);
+
+ /* Next... */
+ continue;
+ }
+
+ /* There better be a current wf_ptr */
+ if (!wf_ptr) return (3);
+
+ /* Process 'D' for "Description (one line only) */
+ if (buf[0] == 'D')
+ {
+ /* Acquire the text */
+ s = buf + 2;
+
+ /* Copy description */
+ assert(!wf_ptr->text);
+ wf_ptr->text = my_strdup(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;
+ }
+
+ /* Oops */
+ return (6);
+ }
+
+ /* 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 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)
+{
+ static char pref_tmp_value[8];
+ 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;
+ }
+
+ /* Race */
+ else if (streq(b + 1, "RACE"))
+ {
+ v = rp_ptr->title;
+ }
+
+ /* Race Mod */
+ else if (streq(b + 1, "RACEMOD"))
+ {
+ v = rmp_ptr->title;
+ }
+
+ /* Class */
+ else if (streq(b + 1, "CLASS"))
+ {
+ v = cp_ptr->title;
+ }
+
+ /* 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/init1.hpp b/src/init1.hpp
new file mode 100644
index 00000000..766e467d
--- /dev/null
+++ b/src/init1.hpp
@@ -0,0 +1,26 @@
+#pragma once
+
+#include "h-basic.h"
+
+extern int color_char_to_attr(char c);
+extern byte conv_color[16];
+extern errr init_player_info_txt(FILE *fp);
+extern errr init_ab_info_txt(FILE *fp);
+extern errr init_s_info_txt(FILE *fp);
+extern errr init_set_info_txt(FILE *fp);
+extern errr init_v_info_txt(FILE *fp);
+extern errr init_f_info_txt(FILE *fp);
+extern errr init_k_info_txt(FILE *fp);
+extern errr init_a_info_txt(FILE *fp);
+extern errr init_ra_info_txt(FILE *fp);
+extern errr init_e_info_txt(FILE *fp);
+extern errr init_r_info_txt(FILE *fp);
+extern errr init_re_info_txt(FILE *fp);
+extern errr init_d_info_txt(FILE *fp);
+extern errr init_t_info_txt(FILE *fp);
+extern errr init_ba_info_txt(FILE *fp);
+extern errr init_st_info_txt(FILE *fp);
+extern errr init_ow_info_txt(FILE *fp);
+extern errr init_wf_info_txt(FILE *fp);
+extern errr grab_one_dungeon_flag(u32b *flags1, u32b *flags2, cptr what);
+extern errr process_dungeon_file(cptr name, int *yval, int *xval, int ymax, int xmax, bool_ init, bool_ full);
diff --git a/src/init2.c b/src/init2.c
deleted file mode 100644
index 5239426c..00000000
--- a/src/init2.c
+++ /dev/null
@@ -1,2918 +0,0 @@
-/* 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/init2.cc b/src/init2.cc
new file mode 100644
index 00000000..338ebf10
--- /dev/null
+++ b/src/init2.cc
@@ -0,0 +1,1494 @@
+#include "init2.hpp"
+#include "init2.h"
+
+#include "ability_type.hpp"
+#include "alloc_entry.hpp"
+#include "artifact_type.hpp"
+#include "cave.hpp"
+#include "cave_type.hpp"
+#include "cli_comm.hpp"
+#include "dungeon_info_type.hpp"
+#include "ego_item_type.hpp"
+#include "files.hpp"
+#include "feature_type.hpp"
+#include "generate.hpp"
+#include "gen_evol.hpp"
+#include "gen_maze.hpp"
+#include "hist_type.hpp"
+#include "hooks.hpp"
+#include "init1.hpp"
+#include "lua_bind.hpp"
+#include "messages.hpp"
+#include "meta_class_type.hpp"
+#include "modules.hpp"
+#include "monster_ego.hpp"
+#include "monster_race.hpp"
+#include "monster_type.hpp"
+#include "object_kind.hpp"
+#include "owner_type.hpp"
+#include "player_class.hpp"
+#include "player_race.hpp"
+#include "player_race_mod.hpp"
+#include "quark.hpp"
+#include "randart.hpp"
+#include "randart_part_type.hpp"
+#include "script.h"
+#include "set_type.hpp"
+#include "skill_type.hpp"
+#include "spells3.hpp"
+#include "squeltch.hpp"
+#include "store_action_type.hpp"
+#include "store_info_type.hpp"
+#include "store_type.hpp"
+#include "tables.hpp"
+#include "trap_type.hpp"
+#include "tome/make_array.hpp"
+#include "town_type.hpp"
+#include "util.hpp"
+#include "util.h"
+#include "variable.h"
+#include "variable.hpp"
+#include "vault_type.hpp"
+#include "wilderness_map.hpp"
+#include "wilderness_type_info.hpp"
+
+#include <cassert>
+#include <type_traits>
+
+/*
+ * 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;
+
+ assert(path != nullptr);
+
+ /*** Free everything ***/
+
+ /* Free the main path */
+ free(ANGBAND_DIR);
+
+ /* Free the sub-paths */
+ free(ANGBAND_DIR_CORE);
+ free(ANGBAND_DIR_DNGN);
+ free(ANGBAND_DIR_DATA);
+ free(ANGBAND_DIR_EDIT);
+ free(ANGBAND_DIR_FILE);
+ free(ANGBAND_DIR_HELP);
+ free(ANGBAND_DIR_INFO);
+ free(ANGBAND_DIR_MODULES);
+ free(ANGBAND_DIR_NOTE);
+ free(ANGBAND_DIR_SAVE);
+ free(ANGBAND_DIR_PREF);
+ free(ANGBAND_DIR_USER);
+ free(ANGBAND_DIR_XTRA);
+
+
+ /*** 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 = strdup(path);
+ path[pathlen - seplen] = *PATH_SEP;
+ }
+ else
+ {
+ ANGBAND_DIR = strdup(path);
+ }
+ }
+ else
+ {
+ ANGBAND_DIR = strdup(path);
+ }
+
+ /* Prepare to append to the Base Path */
+ tail = path + pathlen;
+
+
+
+ /*** Build the sub-directory names ***/
+
+ /* Build a path name */
+ strcpy(tail, "core");
+ ANGBAND_DIR_CORE = strdup(path);
+
+ /* Build a path name */
+ strcpy(tail, "dngn");
+ ANGBAND_DIR_DNGN = strdup(path);
+
+ /* Build a path name */
+ strcpy(tail, "data");
+ ANGBAND_DIR_DATA = strdup(path);
+
+ /* Build a path name */
+ strcpy(tail, "edit");
+ ANGBAND_DIR_EDIT = strdup(path);
+
+ /* Build a path name */
+ strcpy(tail, "file");
+ ANGBAND_DIR_FILE = strdup(path);
+
+ /* Build a path name */
+ strcpy(tail, "help");
+ ANGBAND_DIR_HELP = strdup(path);
+
+ /* Build a path name */
+ strcpy(tail, "info");
+ ANGBAND_DIR_INFO = strdup(path);
+
+ /* Build a path name */
+ strcpy(tail, "mods");
+ ANGBAND_DIR_MODULES = strdup(path);
+
+ /* Build a path name */
+ strcpy(tail, "pref");
+ ANGBAND_DIR_PREF = strdup(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 = strdup(user_path);
+ ANGBAND_DIR_NOTE = strdup(user_path);
+
+ /* Savefiles are in user directory */
+ strcat(user_path, "/save");
+ ANGBAND_DIR_SAVE = strdup(user_path);
+ }
+
+ /* Build a path name */
+ strcpy(tail, "xtra");
+ ANGBAND_DIR_XTRA = strdup(path);
+}
+
+
+
+/*
+ * 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.
+ */
+void init_file_paths_with_env()
+{
+ 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);
+}
+
+
+/*
+ * Hack -- help give useful error messages
+ */
+s16b error_idx;
+s16b error_line;
+
+
+/*
+ * 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();
+}
+
+
+/*
+ * Traits for data arrays
+ */
+namespace {
+
+ struct f_info_traits {
+
+ static constexpr char const *name = "f_info.txt";
+
+ static void allocate()
+ {
+ f_info = make_array<feature_type>(max_f_idx);
+ }
+
+ static errr parse(FILE *fp)
+ {
+ return init_f_info_txt(fp);
+ }
+
+ };
+
+ struct k_info_traits {
+
+ static constexpr char const *name = "k_info.txt";
+
+ static void allocate()
+ {
+ k_info = make_array<object_kind>(max_k_idx);
+ }
+
+ static errr parse(FILE *fp)
+ {
+ return init_k_info_txt(fp);
+ };
+
+ };
+
+ struct set_info_traits {
+
+ static constexpr char const *name = "set_info.txt";
+
+ static void allocate()
+ {
+ set_info = make_array<set_type>(max_set_idx);
+ }
+
+ static errr parse(FILE *fp)
+ {
+ return init_set_info_txt(fp);
+ }
+
+ };
+
+ struct a_info_traits {
+
+ static constexpr char const *name = "a_info.txt";
+
+ static void allocate()
+ {
+ a_info = make_array<artifact_type>(max_a_idx);
+ }
+
+ static errr parse(FILE *fp)
+ {
+ return init_a_info_txt(fp);
+ }
+
+ };
+
+ struct s_info_traits {
+
+ static constexpr char const *name = "s_info.txt";
+
+ static void allocate()
+ {
+ s_info = make_array<skill_type>(max_s_idx);
+ }
+
+ static errr parse(FILE *fp)
+ {
+ return init_s_info_txt(fp);
+ }
+
+ };
+
+ struct ab_info_traits {
+
+ static constexpr char const *name = "ab_info.txt";
+
+ static void allocate()
+ {
+ ab_info = make_array<ability_type>(max_ab_idx);
+ }
+
+ static errr parse(FILE *fp)
+ {
+ return init_ab_info_txt(fp);
+ }
+
+ };
+
+ struct e_info_traits {
+
+ static constexpr char const *name = "e_info.txt";
+
+ static void allocate()
+ {
+ e_info = make_array<ego_item_type>(max_e_idx);
+ }
+
+ static errr parse(FILE *fp)
+ {
+ return init_e_info_txt(fp);
+ }
+
+ };
+
+ struct ra_info_traits {
+
+ static constexpr char const *name = "ra_info.txt";
+
+ static void allocate()
+ {
+ ra_info = make_array<randart_part_type>(max_ra_idx);
+ }
+
+ static errr parse(FILE *fp)
+ {
+ return init_ra_info_txt(fp);
+ }
+
+ };
+
+ struct r_info_traits {
+
+ static constexpr char const *name = "r_info.txt";
+
+ static void allocate()
+ {
+ r_info = make_array<monster_race>(max_r_idx);
+ }
+
+ static errr parse(FILE *fp)
+ {
+ return init_r_info_txt(fp);
+ }
+
+ };
+
+ struct re_info_traits {
+
+ static constexpr char const *name = "re_info.txt";
+
+ static void allocate()
+ {
+ re_info = make_array<monster_ego>(max_re_idx);
+ }
+
+ static errr parse(FILE *fp)
+ {
+ return init_re_info_txt(fp);
+ }
+
+ };
+
+ struct d_info_traits {
+
+ static constexpr char const *name = "d_info.txt";
+
+ static void allocate()
+ {
+ d_info = make_array<dungeon_info_type>(max_d_idx);
+ }
+
+ static errr parse(FILE *fp)
+ {
+ return init_d_info_txt(fp);
+ }
+
+ };
+
+ struct st_info_traits {
+
+ static constexpr char const *name = "st_info.txt";
+
+ static void allocate()
+ {
+ st_info = make_array<store_info_type>(max_st_idx);
+ }
+
+ static errr parse(FILE *fp)
+ {
+ return init_st_info_txt(fp);
+ }
+
+ };
+
+ struct ow_info_traits {
+
+ static constexpr char const *name = "ow_info.txt";
+
+ static void allocate()
+ {
+ ow_info = make_array<owner_type>(max_ow_idx);
+ }
+
+ static errr parse(FILE *fp)
+ {
+ return init_ow_info_txt(fp);
+ }
+
+ };
+
+ struct ba_info_traits {
+
+ static constexpr char const *name = "ba_info.txt";
+
+ static void allocate()
+ {
+ ba_info = make_array<store_action_type>(max_ba_idx);
+ }
+
+ static errr parse(FILE *fp)
+ {
+ return init_ba_info_txt(fp);
+ }
+
+ };
+
+ struct wf_info_traits {
+
+ static constexpr char const *name = "wf_info.txt";
+
+ static void allocate()
+ {
+ wf_info = make_array<wilderness_type_info>(max_wf_idx);
+ }
+
+ static errr parse(FILE *fp)
+ {
+ return init_wf_info_txt(fp);
+ }
+
+ };
+
+ struct tr_info_traits {
+
+ static constexpr char const *name = "tr_info.txt";
+
+ static void allocate()
+ {
+ t_info = make_array<trap_type>(max_t_idx);
+ }
+
+ static errr parse(FILE *fp)
+ {
+ return init_t_info_txt(fp);
+ }
+
+ };
+
+ struct v_info_traits {
+
+ static constexpr char const *name = "v_info.txt";
+
+ static void allocate()
+ {
+ v_info = make_array<vault_type>(max_v_idx);
+ }
+
+ static errr parse(FILE *fp)
+ {
+ return init_v_info_txt(fp);
+ }
+
+ };
+
+ struct p_info_traits {
+
+ static constexpr char const *name = "p_info.txt";
+
+ static void allocate()
+ {
+ race_info = make_array<player_race>(max_rp_idx);
+ race_mod_info = make_array<player_race_mod>(max_rmp_idx);
+ class_info = make_array<player_class>(max_c_idx);
+ bg = make_array<hist_type>(max_bg_idx);
+ meta_class_info = make_array<meta_class_type>(max_mc_idx);
+ for (std::size_t i = 0; i < max_mc_idx; i++)
+ {
+ meta_class_info[i].classes = make_array<s16b>(max_c_idx);
+ }
+ }
+
+ static errr parse(FILE *fp)
+ {
+ return init_player_info_txt(fp);
+ }
+
+ };
+
+}
+
+template<typename T> static errr init_x_info() {
+
+ /* Allocate the data array */
+ T::allocate();
+
+ /* Build the filename */
+ boost::filesystem::path path(ANGBAND_DIR_EDIT);
+ path /= T::name;
+
+ /* Open the file */
+ FILE *fp = my_fopen(path.c_str(), "r");
+
+ /* Parse it */
+ if (!fp)
+ {
+ quit_fmt("Cannot open '%s' file.", T::name);
+ }
+
+ /* Parse the file */
+ errr err = T::parse(fp);
+
+ /* Close it */
+ my_fclose(fp);
+
+ /* Errors */
+ if (err)
+ {
+ /* Error string */
+ cptr oops = (((err > 0) && (err < 8)) ? err_str[err] : "unknown");
+
+ /* Oops */
+ msg_format("Error %d at line %d of '%s'.", err, error_line, T::name);
+ msg_format("Record %d contains a '%s' error.", error_idx, oops);
+ msg_print(NULL);
+
+ /* Quit */
+ quit_fmt("Error in '%s' file.", T::name);
+ }
+
+ /* Success */
+ return (0);
+}
+
+errr init_v_info()
+{
+ return init_x_info<v_info_traits>();
+}
+
+/*
+ * Initialize the very basic arrays
+ */
+static void init_basic()
+{
+ /* Macro variables */
+ macro__pat = make_array<char *>(MACRO_MAX);
+ macro__act = make_array<char *>(MACRO_MAX);
+ macro__cmd = make_array<bool_>(MACRO_MAX);
+
+ /* Macro action buffer */
+ macro__buf = make_array<char>(1024);
+
+ /* Extended trigger macros */
+ cli_info = make_array<cli_comm>(CLI_MAX);
+}
+
+
+/*
+ * Initialise misc. values
+ */
+static errr init_misc(void)
+{
+ int xstart = 0;
+ int ystart = 0;
+ int i;
+
+ /*** Prepare the various "bizarre" arrays ***/
+
+ /* Initialize quark subsystem */
+ quark_init();
+
+ /* Initialize messages subsystem */
+ message_init();
+
+ /* 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;
+
+ /* Initialize timers */
+ TIMER_INERTIA_CONTROL =
+ new_timer(meta_inertia_control_timer_callback,
+ 10);
+ TIMER_AGGRAVATE_EVIL =
+ new_timer(timer_aggravate_evil_callback,
+ 10);
+
+ return 0;
+}
+
+
+/*
+ * Initialise town array
+ */
+static errr init_towns(void)
+{
+ int i = 0, j = 0;
+
+ /*** Prepare the Towns ***/
+
+ /* Allocate the towns */
+ town_info = make_array<town_type>(max_towns);
+
+ for (i = 1; i < max_towns; i++)
+ {
+ if (i <= max_real_towns) town_info[i].flags |= (TOWN_REAL);
+
+ /* Allocate the stores */
+ town_info[i].store = make_array<store_type>(max_st_idx);
+
+ /* 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 */
+ st_ptr->stock = make_array<object_type>(st_ptr->stock_size);
+ }
+ t_ptr->stocked = TRUE;
+}
+
+/*
+ * Initialise wilderness map array
+ */
+static errr init_wilderness(void)
+{
+ int i;
+
+ /* Allocate the wilderness (two-dimension array) */
+ wild_map = make_array<wilderness_map *>(max_wild_y);
+
+ /* Init the other pointers */
+ for (i = 0; i < max_wild_y; i++)
+ {
+ wild_map[i] = make_array<wilderness_map>(max_wild_x);
+ }
+
+ /* No encounter right now */
+ generate_encounter = FALSE;
+
+ return 0;
+}
+
+/*
+ * Initialise some other arrays
+ */
+static errr init_other(void)
+{
+ int i, n;
+
+ /*** Prepare the "dungeon" information ***/
+
+ /* Allocate and Wipe the special gene flags */
+ m_allow_special = make_array<bool_>(max_r_idx);
+ k_allow_special = make_array<bool_>(max_k_idx);
+ a_allow_special = make_array<bool_>(max_a_idx);
+
+
+ /*** Prepare "vinfo" array ***/
+
+ /* Used by "update_view()" */
+ (void)vinfo_init();
+
+
+ /* Allocate and Wipe the object list */
+ o_list = make_array<object_type>(max_o_idx);
+
+ /* Allocate and Wipe the monster list */
+ m_list = new monster_type[max_m_idx];
+
+ /* Allocate and Wipe the to keep monster list */
+ km_list = new monster_type[max_m_idx];
+
+ /* Allocate and Wipe the max dungeon level */
+ max_dlv = make_array<s16b>(max_d_idx);
+
+ /* Allocate and Wipe the special levels */
+ for (i = 0; i < MAX_DUNGEON_DEPTH; i++)
+ {
+ special_lvl[i] = make_array<bool_>(max_d_idx);
+ }
+
+ /* Allocate and wipe each line of the cave */
+ cave = new cave_type *[MAX_HGT];
+ for (i = 0; i < MAX_HGT; i++)
+ {
+ /* Allocate one row of the cave */
+ cave[i] = new cave_type[MAX_WID];
+ }
+
+ /*** 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);
+ add_level_generator("maze", level_generate_maze);
+ add_level_generator("life", level_generate_life);
+
+ /*** 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 */
+ memset(aux, 0, MAX_DEPTH_MONSTER * sizeof(s16b));
+
+ /* Clear the "num" array */
+ memset(num, 0, MAX_DEPTH_MONSTER * sizeof(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 < ALLOCATION_MAX; 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 */
+ alloc_kind_table = make_array<alloc_entry>(alloc_kind_size);
+
+ /* 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 < ALLOCATION_MAX; 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 */
+ memset(aux, 0, MAX_DEPTH_MONSTER * sizeof(s16b));
+
+ /* Clear the "num" array */
+ memset(num, 0, MAX_DEPTH_MONSTER * sizeof(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 */
+ alloc_race_table = make_array<alloc_entry>(alloc_race_size);
+
+ /* 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 */
+static 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;
+
+ const 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_USER, "scores.raw");
+
+ /* Attempt to open the high score file */
+ fd = fd_open(buf, O_RDONLY);
+
+ /* Failure */
+ if (fd < 0)
+ {
+ /* 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");
+
+ /* Initialise some other arrays */
+ note("[Initialising scripting... (script)]");
+ init_lua_init();
+
+ /* Initialise skills info */
+ note("[Initialising arrays... (skills)]");
+ if (init_x_info<s_info_traits>()) quit("Cannot initialise skills");
+
+ /* Initialise abilities info */
+ note("[Initialising arrays... (abilities)]");
+ if (init_x_info<ab_info_traits>()) quit("Cannot initialise abilities");
+
+ /* Initialise player info */
+ note("[Initialising arrays... (players)]");
+ if (init_x_info<p_info_traits>()) quit("Cannot initialise players");
+
+ /* Initialise feature info */
+ note("[Initialising arrays... (features)]");
+ if (init_x_info<f_info_traits>()) quit("Cannot initialise features");
+
+ /* Initialise object info */
+ note("[Initialising arrays... (objects)]");
+ if (init_x_info<k_info_traits>()) quit("Cannot initialise objects");
+
+ /* Initialise artifact info */
+ note("[Initialising arrays... (artifacts)]");
+ if (init_x_info<a_info_traits>()) quit("Cannot initialise artifacts");
+
+ /* Initialise set info */
+ note("[Initialising item sets... (sets)]");
+ if (init_x_info<set_info_traits>()) quit("Cannot initialise item sets");
+ init_sets_aux();
+
+ /* Initialise ego-item info */
+ note("[Initialising arrays... (ego-items)]");
+ if (init_x_info<e_info_traits>()) quit("Cannot initialise ego-items");
+
+ /* Initialise randart parts info */
+ note("[Initialising arrays... (randarts)]");
+ if (init_x_info<ra_info_traits>()) quit("Cannot initialise randarts");
+
+ /* Initialise monster info */
+ note("[Initialising arrays... (monsters)]");
+ if (init_x_info<r_info_traits>()) quit("Cannot initialise monsters");
+
+ /* Initialise ego monster info */
+ note("[Initialising arrays... (ego monsters)]");
+ if (init_x_info<re_info_traits>()) quit("Cannot initialise ego monsters");
+
+ /* Initialise dungeon type info */
+ note("[Initialising arrays... (dungeon types)]");
+ if (init_x_info<d_info_traits>()) quit("Cannot initialise dungeon types");
+ init_guardians();
+
+ /* Initialise actions type info */
+ note("[Initialising arrays... (action types)]");
+ if (init_x_info<ba_info_traits>()) quit("Cannot initialise action types");
+
+ /* Initialise owners type info */
+ note("[Initialising arrays... (owners types)]");
+ if (init_x_info<ow_info_traits>()) quit("Cannot initialise owners types");
+
+ /* Initialise stores type info */
+ note("[Initialising arrays... (stores types)]");
+ if (init_x_info<st_info_traits>()) quit("Cannot initialise stores types");
+
+ /* Initialise wilderness features array */
+ note("[Initialising arrays... (wilderness features)]");
+ if (init_x_info<wf_info_traits>()) 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_x_info<tr_info_traits>()) 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);
+
+ /* Initialize the automatizer */
+ automatizer_init();
+
+ /*** 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);
+
+ /* Done */
+ note("[Initialisation complete]");
+}
diff --git a/src/init2.h b/src/init2.h
new file mode 100644
index 00000000..5697e4ef
--- /dev/null
+++ b/src/init2.h
@@ -0,0 +1,14 @@
+#pragma once
+
+// C linkage required for these functions since main-* code uses them.
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern void init_file_paths(char *path);
+extern void init_file_paths_with_env();
+extern void init_angband(void);
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
diff --git a/src/init2.hpp b/src/init2.hpp
new file mode 100644
index 00000000..707a2706
--- /dev/null
+++ b/src/init2.hpp
@@ -0,0 +1,9 @@
+#pragma once
+
+#include "h-basic.h"
+
+extern void init_corruptions();
+extern void create_stores_stock(int t);
+extern errr init_v_info(void);
+extern s16b error_idx;
+extern s16b error_line;
diff --git a/src/inscription_info_type.hpp b/src/inscription_info_type.hpp
new file mode 100644
index 00000000..6dbb67f1
--- /dev/null
+++ b/src/inscription_info_type.hpp
@@ -0,0 +1,14 @@
+#pragma once
+
+#include "h-basic.h"
+
+/**
+ * Inscriptions
+ */
+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 */
+};
diff --git a/src/inventory.hpp b/src/inventory.hpp
new file mode 100644
index 00000000..775f7a7e
--- /dev/null
+++ b/src/inventory.hpp
@@ -0,0 +1,35 @@
+#pragma once
+
+/*
+ * 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
+
+/*
+ * 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)
diff --git a/src/iso/.cvsignore b/src/iso/.cvsignore
deleted file mode 100644
index f8d9fd47..00000000
--- a/src/iso/.cvsignore
+++ /dev/null
@@ -1 +0,0 @@
-.sconsign
diff --git a/src/joke.cc b/src/joke.cc
new file mode 100644
index 00000000..be272115
--- /dev/null
+++ b/src/joke.cc
@@ -0,0 +1,40 @@
+#include "joke.hpp"
+
+#include "monster2.hpp"
+#include "options.hpp"
+#include "util.hpp"
+#include "variable.hpp"
+#include "z-rand.hpp"
+
+static void gen_joke_place_monster(int r_idx)
+{
+ int try_;
+
+ for (try_ = 0; try_ < 1000; try_++)
+ {
+ int x = randint(cur_hgt - 4) + 2;
+ int y = randint(cur_wid - 4) + 2;
+
+ if (place_monster_one(y, x, r_idx, 0, FALSE, MSTATUS_ENEMY))
+ {
+ return;
+ }
+ }
+}
+
+bool_ gen_joke_monsters(void *data, void *in, void *out)
+{
+ if (joke_monsters)
+ {
+ if ((dungeon_type == 20) &&
+ (dun_level == 72))
+ {
+ int r_idx = test_monster_name("Neil, the Sorceror");
+ m_allow_special[r_idx] = TRUE;
+ gen_joke_place_monster(r_idx);
+ m_allow_special[r_idx] = FALSE;
+ }
+ }
+
+ return FALSE;
+}
diff --git a/src/joke.hpp b/src/joke.hpp
new file mode 100644
index 00000000..05ac1843
--- /dev/null
+++ b/src/joke.hpp
@@ -0,0 +1,5 @@
+#pragma once
+
+#include "h-basic.h"
+
+extern bool_ gen_joke_monsters(void *data, void *in, void *out);
diff --git a/src/lauxlib.h b/src/lauxlib.h
deleted file mode 100644
index 8b6db343..00000000
--- a/src/lauxlib.h
+++ /dev/null
@@ -1,100 +0,0 @@
-/*
-** $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
deleted file mode 100644
index 71148fc5..00000000
--- a/src/levels.c
+++ /dev/null
@@ -1,234 +0,0 @@
-/* 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/levels.cc b/src/levels.cc
new file mode 100644
index 00000000..ac3aa3d3
--- /dev/null
+++ b/src/levels.cc
@@ -0,0 +1,237 @@
+/*
+ * 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 "levels.hpp"
+
+#include "dungeon_info_type.hpp"
+#include "init1.hpp"
+#include "util.hpp"
+#include "util.h"
+#include "variable.h"
+#include "variable.hpp"
+
+
+/*
+ * Return the parameter of the given command in the given file
+ */
+static int start_line = 0;
+static 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/levels.hpp b/src/levels.hpp
new file mode 100644
index 00000000..187092b1
--- /dev/null
+++ b/src/levels.hpp
@@ -0,0 +1,13 @@
+#pragma once
+
+#include "h-basic.h"
+
+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 int get_branch(void);
+extern int get_fbranch(void);
+extern int get_flevel(void);
+extern bool_ get_dungeon_save(char *buf);
diff --git a/src/loadsave.c b/src/loadsave.c
deleted file mode 100644
index 8cdb9f72..00000000
--- a/src/loadsave.c
+++ /dev/null
@@ -1,3288 +0,0 @@
-/* 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/loadsave.cc b/src/loadsave.cc
new file mode 100644
index 00000000..1806d7c8
--- /dev/null
+++ b/src/loadsave.cc
@@ -0,0 +1,2975 @@
+#include "loadsave.hpp"
+#include "loadsave.h"
+
+#include "ability_type.hpp"
+#include "artifact_type.hpp"
+#include "birth.hpp"
+#include "cave_type.hpp"
+#include "dungeon_info_type.hpp"
+#include "ego_item_type.hpp"
+#include "init1.hpp"
+#include "init2.hpp"
+#include "levels.hpp"
+#include "messages.hpp"
+#include "modules.hpp"
+#include "monster2.hpp"
+#include "monster_race.hpp"
+#include "monster_type.hpp"
+#include "object1.hpp"
+#include "object2.hpp"
+#include "object_kind.hpp"
+#include "player_class.hpp"
+#include "player_race.hpp"
+#include "player_race_mod.hpp"
+#include "player_type.hpp"
+#include "quark.hpp"
+#include "hooks.hpp"
+#include "skill_type.hpp"
+#include "store_type.hpp"
+#include "tables.hpp"
+#include "timer_type.hpp"
+#include "town_type.hpp"
+#include "trap_type.hpp"
+#include "util.hpp"
+#include "util.h"
+#include "wilderness_map.hpp"
+#include "variable.h"
+#include "variable.hpp"
+#include "xtra2.hpp"
+#include "z-rand.hpp"
+
+#include <cassert>
+#include <memory>
+
+static u32b vernum; /* Version flag */
+static FILE *fff; /* Local savefile ptr */
+
+/**
+ * Load/save flag
+ */
+enum class ls_flag_t {
+ LOAD = 3,
+ SAVE = 7
+};
+
+/*
+ * 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);
+}
+
+/*
+ * Size-aware read/write routines for the savefile, do all their
+ * work through sf_get and sf_put.
+ */
+static void do_byte(byte *v, ls_flag_t flag)
+{
+ switch (flag)
+ {
+ case ls_flag_t::LOAD:
+ {
+ *v = sf_get();
+ return;
+ }
+ case ls_flag_t::SAVE:
+ {
+ byte val = *v;
+ sf_put(val);
+ return;
+ }
+ }
+}
+
+static void do_bool(bool_ *f, ls_flag_t flag)
+{
+ byte b = *f;
+ do_byte(&b, flag);
+ if (flag == ls_flag_t::LOAD)
+ {
+ *f = b;
+ }
+}
+
+static void do_u16b(u16b *v, ls_flag_t flag)
+{
+ switch (flag)
+ {
+ case ls_flag_t::LOAD:
+ {
+ (*v) = sf_get();
+ (*v) |= ((u16b)(sf_get()) << 8);
+ return;
+ }
+ case ls_flag_t::SAVE:
+ {
+ u16b val;
+ val = *v;
+ sf_put((byte)(val & 0xFF));
+ sf_put((byte)((val >> 8) & 0xFF));
+ return;
+ }
+ }
+}
+
+static void do_s16b(s16b *ip, ls_flag_t flag)
+{
+ do_u16b((u16b *)ip, flag);
+}
+
+static void do_u32b(u32b *ip, ls_flag_t flag)
+{
+ switch(flag)
+ {
+ case ls_flag_t::LOAD:
+ {
+ (*ip) = sf_get();
+ (*ip) |= ((u32b)(sf_get()) << 8);
+ (*ip) |= ((u32b)(sf_get()) << 16);
+ (*ip) |= ((u32b)(sf_get()) << 24);
+ return;
+ }
+ case ls_flag_t::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;
+ }
+ }
+}
+
+static void do_s32b(s32b *ip, ls_flag_t flag)
+{
+ do_u32b((u32b *)ip, flag);
+}
+
+/*
+ * Do object memory and similar stuff
+ */
+static void do_xtra(int k_idx, ls_flag_t flag)
+{
+ byte tmp8u = 0;
+ object_kind *k_ptr = &k_info[k_idx];
+
+ switch(flag)
+ {
+ case ls_flag_t::SAVE:
+ {
+ if (k_ptr->aware) tmp8u |= 0x01;
+ if (k_ptr->tried) tmp8u |= 0x02;
+ if (k_ptr->artifact) tmp8u |= 0x80;
+
+ do_byte(&tmp8u, flag);
+ return;
+ }
+ case ls_flag_t::LOAD:
+ {
+ do_byte(&tmp8u, flag);
+ k_ptr->aware = ((tmp8u & 0x01) ? TRUE : FALSE);
+ k_ptr->tried = ((tmp8u & 0x02) ? TRUE : FALSE);
+ k_ptr->artifact = ((tmp8u & 0x80) ? TRUE : FALSE);
+ return;
+ }
+ }
+}
+
+static void save_string(const char *str)
+{
+ while (*str)
+ {
+ do_byte((byte*)str, ls_flag_t::SAVE);
+ str++;
+ }
+ do_byte((byte*)str, ls_flag_t::SAVE);
+}
+
+static void load_string(char *str, int max)
+{
+ int i;
+
+ /* Read the string */
+ for (i = 0; TRUE; i++)
+ {
+ byte tmp8u;
+
+ /* Read a byte */
+ do_byte(&tmp8u, ls_flag_t::LOAD);
+
+ /* Collect string while legal */
+ if (i < max) str[i] = tmp8u;
+
+ /* End of string */
+ if (!tmp8u) break;
+ }
+ /* Terminate */
+ str[max - 1] = '\0';
+}
+
+static void do_string(char *str, int max, ls_flag_t flag)
+/* Max is ignored for writing */
+{
+ switch(flag) {
+ case ls_flag_t::LOAD:
+ {
+ load_string(str, max);
+ return;
+ }
+ case ls_flag_t::SAVE:
+ {
+ save_string(str);
+ return;
+ }
+ }
+}
+
+/*
+ * Load/Save quick start data
+ */
+static void do_quick_start(ls_flag_t flag)
+{
+ s16b tmp16s;
+ u32b tmp32u;
+ 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(&tmp16s, flag);
+ do_u32b(&tmp32u, 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(ls_flag_t flag)
+{
+ player_race_mod *sr_ptr = &race_mod_info[SUBRACE_SAVE];
+ int i;
+ char buf[81];
+
+ buf[80] = '\0'; // Make sure string is always NUL terminated
+
+ if (flag == ls_flag_t::SAVE)
+ {
+ strncpy(buf, sr_ptr->title, 80);
+ }
+ do_string(buf, 80, flag);
+ if (flag == ls_flag_t::LOAD)
+ {
+ set_subrace_title(sr_ptr, buf);
+ }
+
+ if (flag == ls_flag_t::SAVE)
+ {
+ strncpy(buf, sr_ptr->desc, 80);
+ }
+ do_string(buf, 80, flag);
+ if (flag == ls_flag_t::LOAD)
+ {
+ set_subrace_description(sr_ptr, buf);
+ }
+
+ 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);
+ }
+}
+
+
+/* Load/Save the random spells info */
+static void do_spells(int i, ls_flag_t 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);
+}
+
+
+/*
+ * 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();
+}
+
+
+static void skip_ver_byte(u32b version, ls_flag_t flag)
+/* Reads and discards a byte if the savefile is as old as/older than version */
+{
+ if ((flag == ls_flag_t::LOAD) && (vernum <= version))
+ {
+ byte forget;
+ do_byte(&forget, flag);
+ }
+ return;
+}
+
+static void do_ver_s16b(s16b *v, u32b version, s16b defval, ls_flag_t flag)
+{
+ if ((flag == ls_flag_t::LOAD) && (vernum < version))
+ {
+ *v = defval;
+ return;
+ }
+ do_s16b(v, flag);
+}
+
+/*
+ * Misc. other data
+ */
+static char loaded_game_module[80];
+static bool_ do_extra(ls_flag_t flag)
+{
+ int i, j;
+ byte tmp8u = 0;
+ s16b tmp16s = 0;
+ u32b tmp32u = 0;
+ s32b tmp32s = 0;
+ u16b tmp16b = 0;
+ 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_flag_t::SAVE)
+ {
+ tmp8u = max_d_idx;
+ tmp16s = MAX_DUNGEON_DEPTH;
+ }
+ do_byte(&tmp8u, flag);
+
+ if (flag == ls_flag_t::LOAD)
+ {
+ if (tmp8u > max_d_idx)
+ {
+ note(format("Too many (%d) dungeon types!", tmp8u));
+ }
+ }
+
+ do_s16b(&tmp16s, flag);
+
+ if (flag == ls_flag_t::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_flag_t::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_flag_t::LOAD) && (tmp16s > MAX_SKILLS))
+ {
+ quit("Too many skills");
+ }
+
+ if (flag == ls_flag_t::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_flag_t::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);
+
+ 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(&tmp16s, flag);
+ do_s16b(&tmp16s, flag);
+ do_s16b(&p_ptr->inside_quest, flag);
+ do_byte(&tmp8u, 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_flag_t::SAVE) tmp8u = MAX_PLOTS;
+ do_byte(&tmp8u, flag);
+
+ if ((flag == ls_flag_t::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_flag_t::SAVE)
+ {
+ tmp8u = MAX_RANDOM_QUEST;
+ }
+ do_byte(&tmp8u, flag);
+
+ if ((flag == ls_flag_t::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_s32b(&p_ptr->grace_delay, 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_flag_t::SAVE)
+ tmp8u = max_d_idx;
+ do_byte(&tmp8u, flag);
+ for (i = 0; i < tmp8u; i++)
+ {
+ if (flag == ls_flag_t::SAVE)
+ tmp16s = max_dlv[i];
+ do_s16b(&tmp16s, flag);
+ if ((flag == ls_flag_t::LOAD) && (i <= max_d_idx))
+ max_dlv[i] = tmp16s;
+ }
+ /* Repair max player level??? */
+ if ((flag == ls_flag_t::LOAD) && (p_ptr->max_plv < p_ptr->lev))
+ p_ptr->max_plv = p_ptr->lev;
+
+ do_byte((byte*)&(p_ptr->help.enabled), flag);
+ for (i = 0; i < HELP_MAX; i++)
+ {
+ do_bool(&(p_ptr->help.activated[i]), 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_precognition, 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(&tmp16s, flag);
+ do_ver_s16b(&p_ptr->tim_poison, SAVEFILE_VERSION, 0, flag);
+ do_s16b(&tmp16s, 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(&tmp16s, flag);
+ do_s16b(&tmp16s, flag);
+ do_s16b(&p_ptr->immov_cntr, flag);
+ do_s16b(&p_ptr->strike, flag);
+ do_s16b(&tmp16s, flag);
+ do_s16b(&p_ptr->tim_reflect, flag);
+ do_s16b(&tmp16s, 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(&tmp32s, flag);
+ do_s32b(&tmp32s, flag);
+ do_s16b(&p_ptr->absorb_soul, flag);
+ do_s32b(&p_ptr->inertia_controlled_spell, flag);
+ do_s16b(&p_ptr->last_rewarded_level, flag);
+
+ do_s16b(&tmp16s, flag); /* compat */
+
+ if (flag == ls_flag_t::SAVE) { tmp16s = CORRUPTIONS_MAX; }
+ do_s16b(&tmp16s, flag);
+ if (tmp16s > CORRUPTIONS_MAX) {
+ quit("Too many corruptions");
+ }
+
+ for (i = 0; i < tmp16s; i++)
+ {
+ if (flag == ls_flag_t::SAVE)
+ tmp8u = p_ptr->corruptions[i];
+
+ do_byte(&tmp8u, flag);
+
+ if (flag == ls_flag_t::LOAD)
+ p_ptr->corruptions[i] = tmp8u;
+ }
+
+ do_byte((byte*)&p_ptr->corrupt_anti_teleport_stopped, flag);
+
+ 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(&tmp8u, 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(&tmp16s, 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(&tmp32u, flag);
+ do_u32b(&tmp32u, flag);
+ do_u32b(&tmp32u, flag);
+ do_u32b(&p_ptr->music_extra, flag);
+ do_u32b(&tmp32u, flag);
+ do_u32b(&p_ptr->necro_extra, flag);
+ do_u32b(&p_ptr->necro_extra2, flag);
+
+ do_u32b(&tmp32u, flag);
+ do_u32b(&tmp32u, flag);
+ do_u32b(&tmp32u, flag);
+ do_u32b(&tmp32u, flag);
+ do_u32b(&tmp32u, flag);
+ do_u32b(&tmp32u, flag);
+ do_u32b(&tmp32u, 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_flag_t::SAVE) tmp16s = POWER_MAX;
+ do_s16b(&tmp16s, flag);
+ if ((flag == ls_flag_t::LOAD) && (tmp16s > POWER_MAX))
+ note(format("Too many (%u) powers!", tmp16s));
+ for (i = 0; i < POWER_MAX; 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 -- kept only for load-compatibility with old savefiles. */
+ for (i = 0; i < 24; i++) {
+ tmp16s = 0; do_s16b(&tmp16s, flag);
+ tmp16s = 0; do_s16b(&tmp16s, flag);
+ }
+ tmp32u = 0; do_u32b(&tmp32u, flag);
+
+ /* Spells */
+ 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_flag_t::SAVE) tmp8u = death;
+ do_byte(&tmp8u, flag);
+ if (flag == ls_flag_t::LOAD) death = tmp8u;
+
+ /* Incompatible module? */
+ if (flag == ls_flag_t::LOAD)
+ {
+ s32b ok;
+
+ ok = module_savefile_loadable(loaded_game_module);
+
+ /* 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_flag_t::SAVE) tmp8u = feeling;
+ do_byte(&tmp8u, flag);
+ if (flag == ls_flag_t::LOAD) feeling = tmp8u;
+
+ /* Turn of last "feeling" */
+ do_s32b(&old_turn, flag);
+
+ /* Current turn */
+ do_s32b(&turn, flag);
+
+ return TRUE;
+}
+
+
+/*
+ * Read a monster
+ */
+static void do_monster(monster_type *m_ptr, ls_flag_t flag)
+{
+ int i;
+
+ /* 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_s32b(&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_flag_t::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);
+ }
+}
+
+
+
+/*
+ * 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, ls_flag_t 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_flag_t::LOAD)
+ {
+ do_byte(&old_dd, ls_flag_t::LOAD);
+ do_byte(&old_ds, ls_flag_t::LOAD);
+ }
+ if (flag == ls_flag_t::SAVE)
+ {
+ do_byte(&o_ptr->dd, ls_flag_t::SAVE);
+ do_byte(&o_ptr->ds, ls_flag_t::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_flag_t::LOAD)
+ {
+ char buf[128];
+ /* Inscription */
+ load_string(buf, 128);
+ if (buf[0])
+ {
+ o_ptr->note = quark_add(buf);
+ }
+ /* Artifact name */
+ load_string(buf, 128);
+ if (buf[0])
+ {
+ o_ptr->art_name = quark_add(buf);
+ }
+ }
+ if (flag == ls_flag_t::SAVE)
+ {
+ /* Save the inscription (if any) */
+ if (o_ptr->note)
+ {
+ save_string(quark_str(o_ptr->note));
+ }
+ else
+ {
+ save_string("");
+ }
+ if (o_ptr->art_name)
+ {
+ save_string(quark_str(o_ptr->art_name));
+ }
+ else
+ {
+ save_string("");
+ }
+ }
+
+ if (flag == ls_flag_t::SAVE) return ; /* Stick any more shared code before this. The rest
+ of this function is reserved for ls_flag_t::LOAD's
+ cleanup functions */
+ /*********** END OF ls_flag_t::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;
+ }
+}
+
+static void do_cave_type(cave_type *c_ptr, ls_flag_t flag)
+{
+ do_u16b(&c_ptr->info, flag);
+ do_byte(&c_ptr->feat, flag);
+ do_byte(&c_ptr->mimic, flag);
+ do_s16b(&c_ptr->special, flag);
+ do_s16b(&c_ptr->special2, flag);
+ do_s16b(&c_ptr->t_idx, flag);
+ do_s16b(&c_ptr->inscription, flag);
+ do_byte(&c_ptr->mana, flag);
+ do_s16b(&c_ptr->effect, flag);
+}
+
+static void do_grid(ls_flag_t flag)
+{
+ for (int y = 0; y < cur_hgt; y++)
+ {
+ for (int x = 0; x < cur_wid; x++)
+ {
+ do_cave_type(&cave[y][x], flag);
+ }
+ }
+}
+
+static void my_sentinel(const char *place, u16b value, ls_flag_t flag)
+/* This function lets us know exactly where a savefile is
+ broken by reading/writing conveniently a sentinel at this
+ spot */
+{
+ if (flag == ls_flag_t::SAVE)
+ {
+ do_u16b(&value, flag);
+ return;
+ }
+ if (flag == ls_flag_t::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);
+}
+
+
+
+/*
+ * 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(ls_flag_t 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_flag_t::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_flag_t::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_flag_t::SAVE) compact_objects(0);
+ if (flag == ls_flag_t::SAVE) compact_monsters(0);
+ if (flag == ls_flag_t::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_flag_t::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_flag_t::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_flag_t::SAVE);
+ continue; /* Saving is easy */
+ }
+ /* Until the end of the loop, this is all ls_flag_t::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_flag_t::LOAD);
+
+ /* Monster */
+ if (o_ptr->held_m_idx)
+ {
+ /* Monster */
+ monster_type *m_ptr = &m_list[o_ptr->held_m_idx];
+
+ /* Place the object */
+ m_ptr->hold_o_idxs.push_back(o_idx);
+ }
+
+ /* Dungeon */
+ else
+ {
+ /* Access the item location */
+ c_ptr = &cave[o_ptr->iy][o_ptr->ix];
+
+ /* Place the object */
+ c_ptr->o_idxs.push_back(o_idx);
+ }
+ }
+
+ /*** Monsters ***/
+
+ if (flag == ls_flag_t::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_flag_t::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_flag_t::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_flag_t::SAVE);
+ continue; /* Easy to save a monster */
+ }
+ /* From here on, it's all ls_flag_t::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_flag_t::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_flag_t::SAVE && !no_companions) ? max_m_idx : 0;
+
+ /* Read the monster count */
+ do_u16b(&tmp16b, flag);
+
+ /* Hack -- verify */
+ if ((flag == ls_flag_t::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_flag_t::LOAD) character_dungeon = TRUE;
+
+ /* Success */
+ 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_flag_t::SAVE, TRUE);
+
+ my_fclose(fff);
+}
+
+bool_ file_exist(cptr 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;
+}
+
+
+/*
+ * Handle monster lore
+ */
+static void do_lore(int r_idx, ls_flag_t 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_flag_t::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 void do_store(store_type *str, ls_flag_t flag)
+{
+ byte store_inven_max = STORE_INVEN_MAX;
+
+ /* Some basic info */
+ do_s32b(&str->store_open, flag);
+ do_u16b(&str->owner, flag);
+
+ /* Could be cleaner, done this way for benefit of the for loop later on */
+ byte num;
+ if (flag == ls_flag_t::SAVE) num = str->stock_num;
+ do_byte(&num, flag);
+
+ /* Last visit */
+ do_s32b(&str->last_visit, flag);
+
+ /* Items */
+ for (int j = 0; j < num; j++)
+ {
+ if (flag == ls_flag_t::LOAD)
+ /* Can't this be cleaner? */
+ {
+ object_type forge;
+ /* Wipe the object */
+ object_wipe(&forge);
+ /* Read the item */
+ do_item(&forge, ls_flag_t::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_flag_t::SAVE) do_item(&str->stock[j], flag);
+ }
+}
+
+/*
+ * RNG state
+ */
+static void do_randomizer(ls_flag_t 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_flag_t::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(ls_flag_t 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_flag_t::LOAD) /* There *MUST* be some nice way to unify this! */
+ {
+ u16b c;
+ do_u16b(&c, ls_flag_t::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_flag_t::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_flag_t::SAVE);
+ }
+
+ do_byte((byte*)&autosave_l, flag);
+ do_byte((byte*)&autosave_t, flag);
+ do_s16b(&autosave_freq, flag);
+
+ if (flag == ls_flag_t::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_flag_t::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);
+ }
+}
+
+
+/*
+ * 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(ls_flag_t flag)
+{
+ if (flag == ls_flag_t::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_flag_t::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_flag_t::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_flag_t::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_flag_t::SAVE); /* Sentinel */
+ }
+ /* Success */
+ return (TRUE);
+}
+
+
+
+/*
+ * Read the saved messages
+ */
+static void do_messages(ls_flag_t flag) /* FIXME! We should be able to unify this better */
+{
+ int i;
+ char buf[128];
+ byte color;
+
+ s16b num;
+
+ /* Total */
+ if (flag == ls_flag_t::SAVE) num = message_num();
+ do_s16b(&num, flag);
+
+ /* Read the messages */
+ if (flag == ls_flag_t::LOAD)
+ {
+ byte tmp8u = 0;
+ for (i = 0; i < num; i++)
+ {
+ /* Read the message */
+ do_string(buf, 128, ls_flag_t::LOAD);
+ do_byte(&color, flag);
+ do_byte(&tmp8u, flag);
+
+ /* Save the message */
+ message_add(buf, color);
+ }
+ }
+ if (flag == ls_flag_t::SAVE)
+ {
+ byte holder;
+ byte zero = 0;
+ for (i = num - 1; i >= 0; i--)
+ {
+ do_string((char *)message_str((s16b)i), 0, ls_flag_t::SAVE);
+ holder = message_color((s16b)i);
+ do_byte(&holder, flag);
+ do_byte(&zero, flag);
+ }
+ }
+}
+
+/* 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_flag_t::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_fate(int i, ls_flag_t flag)
+{
+ if ((flag == ls_flag_t::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);
+}
+
+/*
+ * Load/save timers.
+ */
+static void do_timers(ls_flag_t flag)
+{
+ timer_type *t_ptr;
+
+ for (t_ptr = gl_timers; t_ptr != NULL; t_ptr = t_ptr->next)
+ {
+ do_bool(&t_ptr->enabled, flag);
+ do_s32b(&t_ptr->delay, flag);
+ do_s32b(&t_ptr->countdown, flag);
+ }
+}
+
+/*
+ * Load/save stores.
+ */
+static void do_stores(ls_flag_t flag)
+{
+ u16b tmp16u;
+ u16b real_max = 0;
+
+ /* Note that this forbids max_towns from shrinking, but that is fine */
+ std::unique_ptr<byte[]> reals(new byte[max_towns]);
+
+ /* Find the real towns */
+ if (flag == ls_flag_t::SAVE)
+ {
+ for (int i = 1; i < max_towns; i++)
+ {
+ if (!(town_info[i].flags & (TOWN_REAL))) continue;
+ reals[real_max++] = i;
+ }
+ }
+ do_u16b(&real_max, flag);
+ for (int i = 0; i < real_max; i++)
+ {
+ do_byte((byte*)&reals[i], flag);
+ }
+
+ /* Read the stores */
+ if (flag == ls_flag_t::SAVE) tmp16u = max_st_idx;
+ do_u16b(&tmp16u, flag);
+ assert(tmp16u <= max_st_idx);
+
+ /* Ok now read the real towns */
+ for (int i = 0; i < real_max; i++)
+ {
+ int z = reals[i];
+
+ /* Ultra paranoia */
+ if (!town_info[z].stocked) create_stores_stock(z);
+
+ for (int j = 0; j < tmp16u; j++)
+ {
+ do_store(&town_info[z].store[j], flag);
+ }
+ }
+}
+
+/*
+ * 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->inside_quest = 0;
+ 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];
+}
+
+
+/*
+ * Actually read the savefile
+ */
+static bool_ do_savefile_aux(ls_flag_t flag)
+{
+ int i, j;
+
+ byte tmp8u;
+ u16b tmp16u;
+
+ /* Mention the savefile version */
+ if (flag == ls_flag_t::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_flag_t::SAVE)
+ {
+ sf_when = time((time_t *) 0); /* Note when file was saved */
+ sf_saves++; /* Increment the saves ctr */
+ }
+
+ /* Handle version bytes. FIXME! DG wants me to change this all around */
+ if (flag == ls_flag_t::LOAD)
+ {
+ u32b mt32b;
+ byte mtbyte;
+
+ /* Discard all this, we've already read it */
+ do_u32b(&mt32b, flag);
+ do_byte(&mtbyte, flag);
+ }
+ if (flag == ls_flag_t::SAVE)
+ {
+ u32b saver;
+ saver = SAVEFILE_VERSION;
+ do_u32b(&saver, flag);
+ tmp8u = (byte)rand_int(256);
+ do_byte(&tmp8u, flag); /* 'encryption' */
+ }
+
+ /* Kept only for compatibility; always set to 0 */
+ {
+ u32b tmp32u = 0;
+ do_u32b(&tmp32u, 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_flag_t::SAVE)
+ strcpy(loaded_game_module, game_module);
+ do_string(loaded_game_module, 80, flag);
+
+ /* Timers */
+ do_timers(flag);
+
+ /* Read RNG state */
+ do_randomizer(flag);
+
+ /* Automatizer state */
+ do_byte((byte*)&automatizer_enabled, flag);
+
+ /* Then the options */
+ do_options(flag);
+
+ /* Then the "messages" */
+ do_messages(flag);
+
+ /* Monster Memory */
+ if (flag == ls_flag_t::SAVE) tmp16u = max_r_idx;
+ do_u16b(&tmp16u, flag);
+
+ /* Incompatible save files */
+ if ((flag == ls_flag_t::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);
+ }
+
+ /* Object Memory */
+ if (flag == ls_flag_t::SAVE) tmp16u = max_k_idx;
+ do_u16b(&tmp16u, flag);
+
+ /* Incompatible save files */
+ if ((flag == ls_flag_t::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_flag_t::LOAD) junkinit();
+
+ {
+ u16b max_towns_ldsv;
+ u16b max_quests_ldsv;
+ if (flag == ls_flag_t::SAVE) max_towns_ldsv = max_towns;
+ /* Number of towns */
+ do_u16b(&max_towns_ldsv, flag);
+ /* Incompatible save files */
+ if ((flag == ls_flag_t::LOAD) && (max_towns_ldsv > max_towns))
+ {
+ note(format("Too many (%u) towns!", max_towns_ldsv));
+ return (FALSE);
+ }
+ /* Min of random towns */
+ if (flag == ls_flag_t::SAVE) max_towns_ldsv = TOWN_RANDOM;
+ do_u16b(&max_towns_ldsv, flag);
+ /* Incompatible save files */
+ if ((flag == ls_flag_t::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_flag_t::LOAD))
+ {
+ create_stores_stock(i);
+ }
+ }
+ }
+
+ /* Number of dungeon */
+ if (flag == ls_flag_t::SAVE) max_towns_ldsv = max_d_idx;
+ do_u16b(&max_towns_ldsv, flag);
+
+ /* Incompatible save files */
+ if ((flag == ls_flag_t::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_flag_t::SAVE) max_quests_ldsv = TOWN_DUNGEON;
+ do_u16b(&max_quests_ldsv, flag);
+ /* Incompatible save files */
+ if ((flag == ls_flag_t::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);
+ }
+
+ /* Sanity check number of quests */
+ if (flag == ls_flag_t::SAVE) max_quests_ldsv = MAX_Q_IDX;
+ do_u16b(&max_quests_ldsv, flag);
+
+ /* Incompatible save files */
+ if ((flag == ls_flag_t::LOAD) && (max_quests_ldsv != MAX_Q_IDX))
+ {
+ note(format("Invalid number of quests (%u)!", max_quests_ldsv));
+ return (FALSE);
+ }
+
+ for (i = 0; i < MAX_Q_IDX; i++)
+ {
+ do_s16b(&quest[i].status, flag);
+ for (auto &quest_data : quest[i].data)
+ {
+ do_s32b(&quest_data, flag);
+ }
+
+ /* Init the hooks */
+ if ((flag == ls_flag_t::LOAD) && (quest[i].init != NULL))
+ {
+ 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_flag_t::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_flag_t::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);
+ }
+ }
+ }
+ }
+
+ /* Load the random artifacts. */
+ if (flag == ls_flag_t::SAVE) tmp16u = MAX_RANDARTS;
+ do_u16b(&tmp16u, flag);
+ if ((flag == ls_flag_t::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_flag_t::SAVE) tmp16u = max_a_idx;
+ do_u16b(&tmp16u, flag);
+ /* Incompatible save files */
+ if ((flag == ls_flag_t::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);
+ }
+
+ /* Fates */
+ if (flag == ls_flag_t::SAVE) tmp16u = MAX_FATES;
+ do_u16b(&tmp16u, flag);
+
+ /* Incompatible save files */
+ if ((flag == ls_flag_t::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);
+ }
+
+ /* Load the Traps */
+ if (flag == ls_flag_t::SAVE) tmp16u = max_t_idx;
+ do_u16b(&tmp16u, flag);
+
+ /* Incompatible save files */
+ if ((flag == ls_flag_t::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);
+ }
+
+ /* inscription knowledge */
+ if (flag == ls_flag_t::SAVE) tmp16u = MAX_INSCRIPTIONS;
+ do_u16b(&tmp16u, flag);
+
+ /* Incompatible save files */
+ if ((flag == ls_flag_t::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);
+
+
+ /* Read the extra stuff */
+ if (!do_extra(flag))
+ return FALSE;
+
+
+ /* player_hp array */
+ if (flag == ls_flag_t::SAVE) tmp16u = PY_MAX_LEVEL;
+ do_u16b(&tmp16u, flag);
+ /* Incompatible save files */
+ if ((flag == ls_flag_t::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_flag_t::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);
+
+ /* Dripping Tread */
+ do_s16b(&p_ptr->dripping_tread, flag);
+
+ /* Read the inventory */
+ if (!do_inventory(flag) && (flag == ls_flag_t::LOAD)) /* do NOT reverse this ordering */
+ {
+ note("Unable to read inventory");
+ return (FALSE);
+ }
+
+ /* Stores */
+ do_stores(flag);
+
+ /* I'm not dead yet... */
+ if (!death)
+ {
+ /* Dead players have no dungeon */
+ if (flag == ls_flag_t::LOAD) note("Restoring Dungeon...");
+ if ((flag == ls_flag_t::LOAD) && (!do_dungeon(ls_flag_t::LOAD, FALSE)))
+ {
+ note("Error reading dungeon data");
+ return (FALSE);
+ }
+ if (flag == ls_flag_t::SAVE) do_dungeon(ls_flag_t::SAVE, FALSE);
+ my_sentinel("Before ghost data", 435, flag);
+ my_sentinel("After ghost data", 320, flag);
+ }
+
+ {
+ byte foo = 0;
+ if (flag == ls_flag_t::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_flag_t::SAVE);
+ }
+ }
+
+ /* Success */
+ return (TRUE);
+}
+
+
+
+/*
+ * Actually read the savefile
+ */
+static 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_flag_t::LOAD);
+
+ /* Check for errors */
+ if (ferror(fff)) err = -1;
+
+ /* Close the file */
+ my_fclose(fff);
+
+ /* Result */
+ return (err);
+}
+
+
+/*
+ * 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)
+ {
+ byte tmp8u = 0;
+
+ /* 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_flag_t::LOAD);
+ do_byte(&tmp8u, ls_flag_t::LOAD); // For comatibility with old savefiles
+
+ /* 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;
+
+ /* 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)
+ {
+ /* 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);
+}
+
+
+
+/*
+ * 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;
+
+ /* 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_flag_t::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);
+
+ /* 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);
+}
diff --git a/src/loadsave.h b/src/loadsave.h
new file mode 100644
index 00000000..61bfced7
--- /dev/null
+++ b/src/loadsave.h
@@ -0,0 +1,16 @@
+#pragma once
+
+#include "h-basic.h"
+
+// C linkage required for these functions since main-* code uses them.
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* loadsave.c */
+extern void save_dungeon(void);
+extern bool_ save_player(void);
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
diff --git a/src/loadsave.hpp b/src/loadsave.hpp
new file mode 100644
index 00000000..a9eb9dc8
--- /dev/null
+++ b/src/loadsave.hpp
@@ -0,0 +1,7 @@
+#pragma once
+
+#include "h-basic.h"
+
+extern bool_ file_exist(cptr buf);
+extern bool_ load_dungeon(char *ext);
+extern bool_ load_player(void);
diff --git a/src/lua/.cvsignore b/src/lua/.cvsignore
deleted file mode 100644
index 0b086004..00000000
--- a/src/lua/.cvsignore
+++ /dev/null
@@ -1,2 +0,0 @@
-tolua
-host
diff --git a/src/lua/.gitignore b/src/lua/.gitignore
deleted file mode 100644
index 26548e17..00000000
--- a/src/lua/.gitignore
+++ /dev/null
@@ -1,2 +0,0 @@
-/liblua.a
-/tolua
diff --git a/src/lua/CMakeLists.txt b/src/lua/CMakeLists.txt
deleted file mode 100644
index df2b30e7..00000000
--- a/src/lua/CMakeLists.txt
+++ /dev/null
@@ -1,11 +0,0 @@
-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
deleted file mode 100644
index 7929f8cd..00000000
--- a/src/lua/array.lua
+++ /dev/null
@@ -1,203 +0,0 @@
--- 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
deleted file mode 100644
index 2bac463f..00000000
--- a/src/lua/basic.lua
+++ /dev/null
@@ -1,190 +0,0 @@
--- 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
deleted file mode 100644
index 01385178..00000000
--- a/src/lua/class.lua
+++ /dev/null
@@ -1,85 +0,0 @@
--- 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
deleted file mode 100644
index ba08d534..00000000
--- a/src/lua/clean.lua
+++ /dev/null
@@ -1,74 +0,0 @@
--- 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
deleted file mode 100644
index 08f38ad2..00000000
--- a/src/lua/code.lua
+++ /dev/null
@@ -1,73 +0,0 @@
--- 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
deleted file mode 100644
index cbbf11c1..00000000
--- a/src/lua/container.lua
+++ /dev/null
@@ -1,311 +0,0 @@
--- 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
deleted file mode 100644
index e4d5c688..00000000
--- a/src/lua/declaration.lua
+++ /dev/null
@@ -1,399 +0,0 @@
--- 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
deleted file mode 100644
index db64db50..00000000
--- a/src/lua/define.lua
+++ /dev/null
@@ -1,72 +0,0 @@
--- 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
deleted file mode 100644
index aa184d62..00000000
--- a/src/lua/doit.lua
+++ /dev/null
@@ -1,73 +0,0 @@
--- 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
deleted file mode 100644
index 6b2b7466..00000000
--- a/src/lua/enumerate.lua
+++ /dev/null
@@ -1,93 +0,0 @@
--- 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
deleted file mode 100644
index 4a4379e1..00000000
--- a/src/lua/feature.lua
+++ /dev/null
@@ -1,72 +0,0 @@
--- 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
deleted file mode 100644
index b87e3488..00000000
--- a/src/lua/function.lua
+++ /dev/null
@@ -1,317 +0,0 @@
--- 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
deleted file mode 100644
index b597e00a..00000000
--- a/src/lua/lapi.c
+++ /dev/null
@@ -1,499 +0,0 @@
-/*
-** $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
deleted file mode 100644
index d6e1c44f..00000000
--- a/src/lua/lapi.h
+++ /dev/null
@@ -1,17 +0,0 @@
-/*
-** $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
deleted file mode 100644
index 810bca20..00000000
--- a/src/lua/lauxlib.c
+++ /dev/null
@@ -1,216 +0,0 @@
-/*
-** $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
deleted file mode 100644
index a8d35aff..00000000
--- a/src/lua/lauxlib.h
+++ /dev/null
@@ -1,100 +0,0 @@
-/*
-** $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
deleted file mode 100644
index 71c643aa..00000000
--- a/src/lua/lbaselib.c
+++ /dev/null
@@ -1,651 +0,0 @@
-/*
-** $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
deleted file mode 100644
index 89de4a55..00000000
--- a/src/lua/lcode.c
+++ /dev/null
@@ -1,701 +0,0 @@
-/*
-** $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
deleted file mode 100644
index c413c897..00000000
--- a/src/lua/lcode.h
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
-** $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
deleted file mode 100644
index 481f1d6f..00000000
--- a/src/lua/ldblib.c
+++ /dev/null
@@ -1,188 +0,0 @@
-/*
-** $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
deleted file mode 100644
index 02481b4c..00000000
--- a/src/lua/ldebug.c
+++ /dev/null
@@ -1,466 +0,0 @@
-/*
-** $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
deleted file mode 100644
index 76865616..00000000
--- a/src/lua/ldebug.h
+++ /dev/null
@@ -1,21 +0,0 @@
-/*
-** $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
deleted file mode 100644
index 5f23bfd9..00000000
--- a/src/lua/ldo.c
+++ /dev/null
@@ -1,385 +0,0 @@
-/*
-** $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
deleted file mode 100644
index d948ad35..00000000
--- a/src/lua/ldo.h
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
-** $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
deleted file mode 100644
index d3427653..00000000
--- a/src/lua/lfunc.c
+++ /dev/null
@@ -1,109 +0,0 @@
-/*
-** $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
deleted file mode 100644
index 1bd9722d..00000000
--- a/src/lua/lfunc.h
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
-** $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
deleted file mode 100644
index 4e8b234d..00000000
--- a/src/lua/lgc.c
+++ /dev/null
@@ -1,353 +0,0 @@
-/*
-** $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
deleted file mode 100644
index 2dea9e4d..00000000
--- a/src/lua/lgc.h
+++ /dev/null
@@ -1,18 +0,0 @@
-/*
-** $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
deleted file mode 100644
index 4fb385f4..00000000
--- a/src/lua/liolib.c
+++ /dev/null
@@ -1,710 +0,0 @@
-/*
-** $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
deleted file mode 100644
index 86fb69ab..00000000
--- a/src/lua/llex.c
+++ /dev/null
@@ -1,411 +0,0 @@
-/*
-** $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
deleted file mode 100644
index 5fb13c88..00000000
--- a/src/lua/llex.h
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
-** $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
deleted file mode 100644
index 39a1e0df..00000000
--- a/src/lua/llimits.h
+++ /dev/null
@@ -1,205 +0,0 @@
-/*
-** $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
deleted file mode 100644
index 8fdecef3..00000000
--- a/src/lua/lmem.c
+++ /dev/null
@@ -1,150 +0,0 @@
-/*
-** $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
deleted file mode 100644
index 0d27c336..00000000
--- a/src/lua/lmem.h
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
-** $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
deleted file mode 100644
index cd9d1f0b..00000000
--- a/src/lua/lobject.c
+++ /dev/null
@@ -1,125 +0,0 @@
-/*
-** $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
deleted file mode 100644
index ce978205..00000000
--- a/src/lua/lobject.h
+++ /dev/null
@@ -1,204 +0,0 @@
-/*
-** $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
deleted file mode 100644
index 59740896..00000000
--- a/src/lua/lopcodes.h
+++ /dev/null
@@ -1,168 +0,0 @@
-/*
-** $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
deleted file mode 100644
index 1ac1f37b..00000000
--- a/src/lua/lparser.c
+++ /dev/null
@@ -1,1129 +0,0 @@
-/*
-** $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
deleted file mode 100644
index d83fb5f1..00000000
--- a/src/lua/lparser.h
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
-** $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
deleted file mode 100644
index 6310cb7e..00000000
--- a/src/lua/lstate.c
+++ /dev/null
@@ -1,121 +0,0 @@
-/*
-** $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
deleted file mode 100644
index ee02db01..00000000
--- a/src/lua/lstate.h
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
-** $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
deleted file mode 100644
index 7293e195..00000000
--- a/src/lua/lstring.c
+++ /dev/null
@@ -1,155 +0,0 @@
-/*
-** $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
deleted file mode 100644
index f23159ec..00000000
--- a/src/lua/lstring.h
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
-** $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
deleted file mode 100644
index 051eccf7..00000000
--- a/src/lua/lstrlib.c
+++ /dev/null
@@ -1,621 +0,0 @@
-/*
-** $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
deleted file mode 100644
index 1e3eb4f5..00000000
--- a/src/lua/ltable.c
+++ /dev/null
@@ -1,303 +0,0 @@
-/*
-** $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
deleted file mode 100644
index 3bc2a5df..00000000
--- a/src/lua/ltable.h
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
-** $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
deleted file mode 100644
index 06e08f5a..00000000
--- a/src/lua/ltests.c
+++ /dev/null
@@ -1,543 +0,0 @@
-/*
-** $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
deleted file mode 100644
index 3f69a6ca..00000000
--- a/src/lua/ltm.c
+++ /dev/null
@@ -1,163 +0,0 @@
-/*
-** $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
deleted file mode 100644
index f6be13ed..00000000
--- a/src/lua/ltm.h
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
-** $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
deleted file mode 100644
index 87d64e71..00000000
--- a/src/lua/lua.h
+++ /dev/null
@@ -1,248 +0,0 @@
-/*
-** $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
deleted file mode 100644
index 3f8d1716..00000000
--- a/src/lua/lua2c.lua
+++ /dev/null
@@ -1,29 +0,0 @@
--- 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
deleted file mode 100644
index 21522445..00000000
--- a/src/lua/luadebug.h
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
-** $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
deleted file mode 100644
index 89f5519f..00000000
--- a/src/lua/lualib.h
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
-** $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
deleted file mode 100644
index 7f69573e..00000000
--- a/src/lua/lundump.c
+++ /dev/null
@@ -1,244 +0,0 @@
-/*
-** $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
deleted file mode 100644
index ec394f46..00000000
--- a/src/lua/lundump.h
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
-** $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
deleted file mode 100644
index e304e11e..00000000
--- a/src/lua/lvm.c
+++ /dev/null
@@ -1,710 +0,0 @@
-/*
-** $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
deleted file mode 100644
index ac95ae41..00000000
--- a/src/lua/lvm.h
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
-** $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
deleted file mode 100644
index 84d4a35c..00000000
--- a/src/lua/lzio.c
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
-** $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
deleted file mode 100644
index 45feeee3..00000000
--- a/src/lua/lzio.h
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
-** $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
deleted file mode 100644
index 98dffe6e..00000000
--- a/src/lua/module.lua
+++ /dev/null
@@ -1,69 +0,0 @@
--- 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
deleted file mode 100644
index 7a42cf1b..00000000
--- a/src/lua/operator.lua
+++ /dev/null
@@ -1,111 +0,0 @@
--- 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
deleted file mode 100644
index 42dbfaac..00000000
--- a/src/lua/package.lua
+++ /dev/null
@@ -1,222 +0,0 @@
--- 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
deleted file mode 100644
index 49f4c4cb..00000000
--- a/src/lua/print.h
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
-** $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
deleted file mode 100644
index 3cb09291..00000000
--- a/src/lua/tolua.c
+++ /dev/null
@@ -1,149 +0,0 @@
-/* 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
deleted file mode 100644
index ab86976c..00000000
--- a/src/lua/tolua.h
+++ /dev/null
@@ -1,127 +0,0 @@
-/* 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
deleted file mode 100644
index d36a5ce9..00000000
--- a/src/lua/tolua_bd.c
+++ /dev/null
@@ -1,214 +0,0 @@
-/*
-** 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
deleted file mode 100644
index 0709cb4c..00000000
--- a/src/lua/tolua_eh.c
+++ /dev/null
@@ -1,66 +0,0 @@
-/* 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
deleted file mode 100644
index 168ba122..00000000
--- a/src/lua/tolua_eh.h
+++ /dev/null
@@ -1,24 +0,0 @@
-/* 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
deleted file mode 100644
index 77ff0c26..00000000
--- a/src/lua/tolua_gp.c
+++ /dev/null
@@ -1,197 +0,0 @@
-/* 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
deleted file mode 100644
index 5fd4c337..00000000
--- a/src/lua/tolua_lb.c
+++ /dev/null
@@ -1,160 +0,0 @@
-/* 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
deleted file mode 100644
index 4337e9f9..00000000
--- a/src/lua/tolua_rg.c
+++ /dev/null
@@ -1,243 +0,0 @@
-/* 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
deleted file mode 100644
index 0feb6078..00000000
--- a/src/lua/tolua_rg.h
+++ /dev/null
@@ -1,22 +0,0 @@
-/* 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
deleted file mode 100644
index 8fd7b28d..00000000
--- a/src/lua/tolua_tm.c
+++ /dev/null
@@ -1,585 +0,0 @@
-/* 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
deleted file mode 100644
index c1bf06dc..00000000
--- a/src/lua/tolua_tm.h
+++ /dev/null
@@ -1,32 +0,0 @@
-/* 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
deleted file mode 100644
index 33c384c6..00000000
--- a/src/lua/tolua_tt.c
+++ /dev/null
@@ -1,316 +0,0 @@
-/* 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
deleted file mode 100644
index 941a2b02..00000000
--- a/src/lua/tolua_tt.h
+++ /dev/null
@@ -1,31 +0,0 @@
-/* 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
deleted file mode 100644
index adbb8635..00000000
--- a/src/lua/tolualua.c
+++ /dev/null
@@ -1,2975 +0,0 @@
-/*
-** 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
deleted file mode 100644
index b380dcef..00000000
--- a/src/lua/tolualua.h
+++ /dev/null
@@ -1,2713 +0,0 @@
-/* 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
deleted file mode 100644
index 1694c2c1..00000000
--- a/src/lua/tolualua.pkg
+++ /dev/null
@@ -1,21 +0,0 @@
-$[
-$<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
deleted file mode 100644
index 1633f3e6..00000000
--- a/src/lua/typedef.lua
+++ /dev/null
@@ -1,59 +0,0 @@
--- 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
deleted file mode 100644
index 310808b8..00000000
--- a/src/lua/variable.lua
+++ /dev/null
@@ -1,192 +0,0 @@
--- 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
deleted file mode 100644
index 9dae0dc3..00000000
--- a/src/lua/verbatim.lua
+++ /dev/null
@@ -1,77 +0,0 @@
--- 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
deleted file mode 100644
index 67b75ee6..00000000
--- a/src/lua_bind.c
+++ /dev/null
@@ -1,691 +0,0 @@
-/* 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/lua_bind.cc b/src/lua_bind.cc
new file mode 100644
index 00000000..aa2c3a2a
--- /dev/null
+++ b/src/lua_bind.cc
@@ -0,0 +1,277 @@
+/*
+ * 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 "lua_bind.hpp"
+
+#include "cmd7.hpp"
+#include "corrupt.hpp"
+#include "init1.hpp"
+#include "monster2.hpp"
+#include "player_type.hpp"
+#include "range.hpp"
+#include "skills.hpp"
+#include "skill_type.hpp"
+#include "spell_type.hpp"
+#include "spells2.hpp"
+#include "spells5.hpp"
+#include "tables.hpp"
+#include "timer_type.hpp"
+#include "util.hpp"
+#include "variable.hpp"
+
+#include <cassert>
+#include <functional>
+
+/*
+ * Misc
+ */
+
+/* Change this fct if I want to switch to learnable spells */
+s32b lua_get_level(spell_type *spell, s32b lvl, s32b max, s32b min, s32b bonus)
+{
+ s32b tmp;
+
+ tmp = lvl - ((spell_type_skill_level(spell) - 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;
+}
+
+/* static */ s32b get_level_device(spell_type *spell, s32b max, s32b min, s32b device_skill, std::function<s32b(spell_type *, s32b, s32b, s32b, s32b)> lua_get_level_ = lua_get_level)
+{
+ /* No max specified ? assume 50 */
+ if (max <= 0) {
+ max = 50;
+ }
+ /* No min specified ? */
+ if (min <= 0) {
+ min = 1;
+ }
+
+ int lvl = device_skill + (get_level_use_stick * SKILL_STEP);
+
+ /* Sticks are limited */
+ if (lvl - ((spell_type_skill_level(spell) + 1) * SKILL_STEP) >= get_level_max_stick * SKILL_STEP)
+ {
+ lvl = (get_level_max_stick + spell_type_skill_level(spell) - 1) * SKILL_STEP;
+ }
+
+ /* / 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;
+ lvl = lua_get_level_(spell, lvl, max, min, 0);
+
+ return lvl;
+}
+
+static s32b get_level_device_1(spell_type *spell, s32b max, s32b min)
+{
+ // Must be in "device" mode.
+ assert(get_level_use_stick > -1);
+ // Delegate
+ auto device_skill = s_info[SKILL_DEVICE].value;
+ return get_level_device(spell, max, min, device_skill);
+}
+
+static s32b get_level_school_1(spell_type *spell, s32b max, s32b min)
+{
+ // Delegate
+ s32b level;
+ bool_ na;
+ get_level_school(spell, max, min, &level, &na);
+ // Note: It is tempting to add an assertion here for "na == FALSE" here,
+ // but there are cases where we haven't actually checked if the spell is
+ // really castable before calling this function (indirectly). Thus we
+ // MUST NOT assert anything about "na" as the code currently stands.
+ return level;
+}
+
+int get_mana(s32b s)
+{
+ // Does not make sense in "device" mode.
+ assert(get_level_use_stick == -1);
+ // Extract the spell's mana range.
+ spell_type *spell = spell_at(s);
+ range_type mana_range;
+ spell_type_mana_range(spell, &mana_range);
+ // Scale
+ return get_level_school_1(spell, mana_range.max, mana_range.min);
+}
+
+/** Returns spell chance of failure for a school spell. */
+static s32b spell_chance_school(s32b s)
+{
+ spell_type *s_ptr = spell_at(s);
+ int level = get_level_school_1(s_ptr, 50, 1);
+ s32b chance = spell_type_failure_rate(s_ptr);
+ int mana = get_mana(s);
+ int cur_mana = get_power(s);
+ int stat = spell_type_casting_stat(s_ptr);
+ int stat_ind = p_ptr->stat_ind[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[stat_ind] - 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[stat_ind];
+
+ /* Must have Perfect Casting to get below 5% */
+ 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 spell_chance_device(spell_type *spell_ptr)
+{
+ // Device parameters initialized?
+ assert(get_level_use_stick > -1);
+
+ // Calculate the chance.
+ int level = get_level_device_1(spell_ptr, 50, 1);
+ s32b chance = spell_type_failure_rate(spell_ptr);
+
+ /* Reduce failure rate by "effective" level adjustment */
+ chance -= (level - 1);
+
+ /* Extract the minimum failure rate */
+ int minfail = 15 - get_skill_scale(SKILL_DEVICE, 25);
+
+ /* Return the chance */
+ return clamp_failure_chance(chance, minfail);
+}
+
+s32b spell_chance_book(s32b s)
+{
+ // Must NOT be a device!
+ assert(get_level_use_stick < 0);
+ // Delegate
+ return spell_chance_school(s);
+}
+
+s32b get_level(s32b s, s32b max, s32b min)
+{
+ auto spell = spell_at(s);
+ /** Ahah shall we use Magic device instead ? */
+ if (get_level_use_stick > -1) {
+ return get_level_device_1(spell, max, min);
+ } else {
+ return get_level_school_1(spell, max, min);
+ }
+}
+
+/* Level gen */
+void get_map_size(const 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(const 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);
+}
+
+/*
+ * 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 buf;
+ return buf;
+}
+
+char lua_msg_box(cptr title)
+{
+ int wid, hgt;
+
+ Term_get_size(&wid, &hgt);
+ return msg_box(title, hgt / 2, wid / 2);
+}
+
+
+
+void increase_mana(int delta)
+{
+ p_ptr->csp += delta;
+ p_ptr->redraw |= PR_FRAME;
+
+ if (p_ptr->csp < 0)
+ {
+ p_ptr->csp = 0;
+ }
+ if (p_ptr->csp > p_ptr->msp)
+ {
+ p_ptr->csp = p_ptr->msp;
+ }
+}
+
+timer_type *TIMER_AGGRAVATE_EVIL = 0;
+
+void timer_aggravate_evil_enable()
+{
+ TIMER_AGGRAVATE_EVIL->enabled = TRUE;
+}
+
+void timer_aggravate_evil_callback()
+{
+ if ((p_ptr->prace == RACE_MAIA) &&
+ (!player_has_corruption(CORRUPT_BALROG_AURA)) &&
+ (!player_has_corruption(CORRUPT_BALROG_WINGS)) &&
+ (!player_has_corruption(CORRUPT_BALROG_STRENGTH)) &&
+ (!player_has_corruption(CORRUPT_BALROG_FORM)))
+ {
+ dispel_evil(0);
+ }
+}
diff --git a/src/lua_bind.hpp b/src/lua_bind.hpp
new file mode 100644
index 00000000..b2a6c9a7
--- /dev/null
+++ b/src/lua_bind.hpp
@@ -0,0 +1,34 @@
+#pragma once
+
+#include "h-basic.h"
+#include "spell_type_fwd.hpp"
+#include "timer_type_fwd.hpp"
+
+/** Calculate spell failure rate for a device, i.e. a wand or staff. */
+extern s32b spell_chance_device(spell_type *spell_ptr);
+
+/** Calculate spell failure rate for a spell book. */
+extern s32b spell_chance_book(s32b s);
+
+
+extern s32b lua_get_level(struct spell_type *spell, s32b lvl, s32b max, s32b min, s32b bonus);
+extern int get_mana(s32b s);
+extern s32b get_power(s32b s);
+extern s32b get_level(s32b s, s32b max, s32b min);
+extern void get_level_school(struct spell_type *spell, s32b max, s32b min, s32b *level, bool_ *na);
+
+extern s32b get_level_max_stick;
+extern s32b get_level_use_stick;
+
+extern void get_map_size(const char *name, int *ysize, int *xsize);
+extern void load_map(const char *name, int *y, int *x);
+
+extern char *lua_input_box(cptr title, int max);
+extern char lua_msg_box(cptr title);
+
+extern void increase_mana(int delta);
+
+extern timer_type *TIMER_AGGRAVATE_EVIL;
+
+void timer_aggravate_evil_enable();
+void timer_aggravate_evil_callback();
diff --git a/src/magic_power.hpp b/src/magic_power.hpp
new file mode 100644
index 00000000..b02c6c14
--- /dev/null
+++ b/src/magic_power.hpp
@@ -0,0 +1,15 @@
+#pragma once
+
+#include "h-basic.h"
+
+/**
+ * Powers, used by Mindcrafters and Necromancers
+ */
+struct magic_power
+{
+ int min_lev;
+ int mana_cost;
+ int fail;
+ cptr name;
+ cptr desc;
+};
diff --git a/src/maid-x11.c b/src/maid-x11.c
deleted file mode 100755
index 86df2119..00000000
--- a/src/maid-x11.c
+++ /dev/null
@@ -1,855 +0,0 @@
-/* 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
deleted file mode 100644
index a4a1a742..00000000
--- a/src/main-crb.c
+++ /dev/null
@@ -1,6402 +0,0 @@
-/* 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
index 57c41703..c253daf2 100644
--- a/src/main-gcu.c
+++ b/src/main-gcu.c
@@ -38,8 +38,8 @@
* Consider the use of "savetty()" and "resetty()". XXX XXX XXX
*/
-
-#include "angband.h"
+#include "util.h"
+#include "variable.h"
#ifdef USE_GCU
@@ -82,7 +82,7 @@
# if defined(_POSIX_VERSION)
# define USE_TPOSIX
# else
-# if defined(USG) || defined(linux) || defined(SOLARIS)
+# if defined(linux)
# define USE_TERMIO
# else
# define USE_TCHARS
@@ -122,11 +122,6 @@
#include <unistd.h>
#include <dirent.h>
-/* /me pffts Solaris */
-#ifndef NAME_MAX
-#define NAME_MAX _POSIX_NAME_MAX
-#endif
-
/*
@@ -451,7 +446,7 @@ static errr Term_xtra_gcu_alive(int v)
keymap_norm();
/* Restore modes */
- nocbreak();
+ noraw();
echo();
nl();
@@ -482,7 +477,7 @@ static errr Term_xtra_gcu_alive(int v)
/* (void)wrefresh(curscr); */
/* Restore the settings */
- cbreak();
+ raw();
noecho();
nonl();
@@ -561,60 +556,6 @@ static void Term_nuke_gcu(term *t)
}
-
-
-#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)
*/
@@ -663,7 +604,6 @@ static errr Term_xtra_gcu_event(int v)
return (0);
}
-#endif /* USE_GETCH */
/*
* React to changes
@@ -721,14 +661,6 @@ static errr Term_xtra_gcu(int n, int v)
(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:
@@ -743,53 +675,6 @@ static errr Term_xtra_gcu(int n, int v)
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();
@@ -817,41 +702,13 @@ static errr Term_curs_gcu(int x, int y)
/*
- * 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;
+ int i;
#ifdef A_COLOR
/* Set the color */
@@ -864,41 +721,6 @@ static errr Term_text_gcu(int x, int y, int n, byte a, cptr s)
/* 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]);
@@ -934,17 +756,12 @@ static errr term_data_init_gcu(term_data *td, int rows, int cols, int y, int x)
/* 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;
@@ -995,7 +812,7 @@ errr init_gcu(int argc, char **argv)
continue;
}
- plog_fmt("Ignoring option: %s", argv[i]);
+ fprintf(stderr, "Ignoring option: %s", argv[i]);
}
@@ -1003,17 +820,11 @@ errr init_gcu(int argc, char **argv)
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))
@@ -1022,12 +833,6 @@ errr init_gcu(int argc, char **argv)
}
-#ifdef USE_GRAPHICS
-
- /* Set graphics flag */
- use_graphics = arg_graphics;
-
-#endif
#ifdef A_COLOR
@@ -1106,15 +911,9 @@ errr init_gcu(int argc, char **argv)
/*** Low level preparation ***/
-#ifdef USE_GETCH
-
- /* Paranoia -- Assume no waiting */
- nodelay(stdscr, FALSE);
-
-#endif
/* Prepare */
- cbreak();
+ raw();
noecho();
nonl();
diff --git a/src/main-gtk2.c b/src/main-gtk2.c
index 4830638a..ca3eff60 100644
--- a/src/main-gtk2.c
+++ b/src/main-gtk2.c
@@ -30,60 +30,14 @@
* and reorganised the file a bit.
*/
-#include "angband.h"
+#include "files.h"
+#include "util.h"
+#include "variable.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
@@ -99,19 +53,7 @@
#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 */
+#include <assert.h>
/*
@@ -134,22 +76,6 @@
* 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 */
/*
@@ -176,18 +102,8 @@ struct term_data
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;
+ char *name;
};
@@ -210,36 +126,6 @@ if ((td)->backing_store) gdk_draw_pixmap( \
(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"
*/
@@ -277,8 +163,6 @@ static bool_ use_backing_store = TRUE;
/**** Vanilla compatibility functions ****/
-#ifdef ANG293_COMPAT
-
/*
* Look up some environment variables to find font name for each window.
*/
@@ -309,69 +193,11 @@ static cptr get_default_font(int term)
}
-# 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));
-}
@@ -425,1868 +251,6 @@ static void term_data_set_fg(term_data *td, byte 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 */
@@ -2303,7 +267,7 @@ static void Term_nuke_gtk(term *t)
/* Free name */
- if (td->name) string_free(td->name);
+ if (td->name) free(td->name);
/* Forget it */
td->name = NULL;
@@ -2320,21 +284,6 @@ static void Term_nuke_gtk(term *t)
/* 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 */
}
@@ -2458,20 +407,6 @@ static errr Term_curs_gtk(int x, int y)
/* 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),
@@ -2490,299 +425,6 @@ static errr Term_curs_gtk(int x, int y)
}
-#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 */
/*
@@ -2872,58 +514,6 @@ static errr Term_xtra_gtk(int n, int v)
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);
@@ -2933,12 +523,6 @@ static errr Term_xtra_gtk(int n, int v)
/* (re-)init colours */
init_colours();
-#ifdef USE_GRAPHICS
-
- /* Initialise graphics */
- init_graphics();
-
-#endif /* USE_GRAPHICS */
/* Success */
return (0);
@@ -3095,13 +679,7 @@ static void save_game_gtk(void)
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 */
}
@@ -3208,41 +786,6 @@ static void destroy_sub_event_handler(
}
-#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
@@ -3269,20 +812,6 @@ static void load_font(term_data *td, cptr fontname)
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 */
}
@@ -3349,216 +878,6 @@ static void change_backing_store_event_handler(
}
-#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 */
/*
@@ -3586,7 +905,6 @@ static gboolean keypress_event_handler(
GdkEventKey *event,
gpointer user_data)
{
-#if 1
int i, mc, ms, mo, mx;
char msg[128];
@@ -3703,123 +1021,6 @@ static gboolean keypress_event_handler(
}
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
}
@@ -4061,7 +1262,8 @@ static errr term_data_init(term_data *td, int i)
term_init(t, td->cols, td->rows, 1024);
/* Store the name of the term */
- td->name = string_make(angband_term_name[i]);
+ assert(angband_term_name[i] != NULL);
+ td->name = strdup(angband_term_name[i]);
/* Instance names should start with a lowercase letter XXX */
for (p = (char *)td->name; *p; p++) *p = tolower(*p);
@@ -4069,17 +1271,10 @@ static errr term_data_init(term_data *td, int i)
/* 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_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 */
@@ -4112,14 +1307,6 @@ static GtkItemFactoryEntry main_menu_items[] =
{ "/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",
@@ -4171,37 +1358,6 @@ static GtkItemFactoryEntry main_menu_items[] =
{ 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,
@@ -4257,13 +1413,13 @@ static void setup_menu_paths(void)
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);
+ term_entry[i].path = (gchar*) strdup(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);
+ font_entry[i].path = (gchar*) strdup(buf);
}
}
@@ -4309,10 +1465,10 @@ static void free_menu_paths(void)
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);
+ if (term_entry[i].path) free(term_entry[i].path);
/* XXX XXX Free Font menu path */
- if (font_entry[i].path) string_free((cptr)font_entry[i].path);
+ if (font_entry[i].path) free(font_entry[i].path);
}
}
@@ -4399,18 +1555,8 @@ 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)
{
@@ -4424,10 +1570,6 @@ static void file_menu_update_handler(
}
/* 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);
}
@@ -4491,51 +1633,6 @@ static void misc_menu_update_handler(
}
-#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 */
/*
@@ -4644,23 +1741,6 @@ static void add_menu_update_callbacks()
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 */
}
@@ -4808,38 +1888,12 @@ 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
*/
@@ -4852,10 +1906,7 @@ errr init_gtk2(int argc, char **argv)
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++)
@@ -4876,71 +1927,11 @@ errr init_gtk2(int argc, char **argv)
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]);
+ fprintf(stderr, "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();
@@ -4973,52 +1964,12 @@ errr init_gtk2(int argc, char **argv)
/* 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);
}
diff --git a/src/main-sdl.c b/src/main-sdl.c
index 1b53cfc7..9a177cbb 100644
--- a/src/main-sdl.c
+++ b/src/main-sdl.c
@@ -25,23 +25,33 @@
#ifdef USE_SDL
-#include "angband.h"
+#include "loadsave.h"
+#include "util.h"
+#include "variable.h"
+
#include <SDL.h>
#include <SDL_image.h>
#include <SDL_ttf.h>
+#include <assert.h>
#include <math.h>
/*************************************************
GLOBAL SDL-ToME PROPERTIES
*************************************************/
+
+/* Default window properties - used if none are available
+from other places*/
+#define DEF_SCREEN_WIDTH 800
+#define DEF_SCREEN_HEIGHT 600
+#define DEF_SCREEN_BPP 16
/*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;
+static int arg_width = DEF_SCREEN_WIDTH;
+static int arg_height = DEF_SCREEN_HEIGHT;
+static int arg_bpp = DEF_SCREEN_BPP;
/**************/
@@ -58,21 +68,6 @@ 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
@@ -89,10 +84,6 @@ border */
/**************/
-/* 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;
@@ -109,7 +100,7 @@ static bool_ window_properties_set = FALSE;
static SDL_Surface *screen;
/* the video settings for the system */
-static SDL_VideoInfo *videoInfo;
+static const SDL_VideoInfo *videoInfo;
/* a flag to suspend updating of the screen;
this is in place so that when a large area is being
@@ -502,9 +493,7 @@ void handleEvent(SDL_Event *event)
/* handle quit requests */
DB("Emergency Blit");
redrawAllTerminals();
- save_player();
- save_dungeon();
- sdl_quit("Quitting!\n");
+ /*sdl_quit("Quitting!\n");*/
break;
}
default:
@@ -577,23 +566,6 @@ static errr Term_xtra_sdl(int n, int v)
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:
{
/*
@@ -603,9 +575,7 @@ static errr Term_xtra_sdl(int n, int v)
* 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.
+ * (and similar functions) draw directly to the screen.
*/
/* If terminal display has been held for any reason,
@@ -634,21 +604,6 @@ static errr Term_xtra_sdl(int n, int v)
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 */
@@ -714,40 +669,6 @@ static errr Term_xtra_sdl(int n, int v)
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 */
@@ -1049,33 +970,6 @@ static errr Term_curs_sdl(int x, int y)
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)
{
@@ -1140,9 +1034,6 @@ void eraseTerminal(void)
* 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)
{
@@ -1186,7 +1077,8 @@ static errr Term_text_sdl(int x, int y, int n, byte a, const char *cp)
SDL_BlitSurface(worksurf,NULL,td->surf,&base);
} else {
/* copy the desired character onto working surface */
- SDL_BlitSurface(text[*cp],NULL,worksurf,NULL);
+ assert(*cp >= 0); // Make sure cast is valid
+ SDL_BlitSurface(text[(size_t)(*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 */
@@ -1376,7 +1268,6 @@ void moveTerminal(int x, int y)
void bringToTop(int current)
{
term_data *td;
- term_data *tc;
int n = 0;
int i;
@@ -1551,8 +1442,7 @@ void manipulationMode(void)
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*/
@@ -1844,19 +1734,9 @@ static errr term_data_init(term_data *td, int i)
/* 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 */
@@ -1946,7 +1826,7 @@ This routine processes arguments, opens the SDL
window, loads fonts, etc. */
errr init_sdl(int argc, char **argv)
{
- int i, surface_type;
+ int i;
char filename[PATH_MAX + 1];
const char file_sep = '.';
/* Flags to pass to SDL_SetVideoMode */
@@ -2049,25 +1929,6 @@ errr init_sdl(int argc, char **argv)
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"))
{
@@ -2133,26 +1994,6 @@ errr init_sdl(int argc, char **argv)
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 );
@@ -2171,13 +2012,19 @@ errr init_sdl(int argc, char **argv)
DB("SDL Window Created!");
- /* Graphics! ----
- If graphics are selected, then load graphical tiles! */
- if (arg_graphics_type != NO_GRAPHICS)
- {
- /* load graphics tiles */
+ /* 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);
+
/* Initialize the working surface and crayon surface used for rendering
text in different colors. */
diff --git a/src/main-sla.c b/src/main-sla.c
deleted file mode 100644
index 3c02d61f..00000000
--- a/src/main-sla.c
+++ /dev/null
@@ -1,455 +0,0 @@
-/* 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
index 92a2a775..a2daffbe 100644
--- a/src/main-win.c
+++ b/src/main-win.c
@@ -36,14 +36,8 @@
*
* 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.
+ * In any case, some "*.fon" files (including "8X13.FON" if nothing
+ * else) must be placed into "lib/xtra/font/".
*
*
* The "Term_xtra_win_clear()" function should probably do a low-level
@@ -74,7 +68,11 @@
#include "angband.h"
-
+#include "dungeon.h"
+#include "files.h"
+#include "init2.h"
+#include "util.h"
+#include "variable.h"
#ifdef WINDOWS
@@ -101,11 +99,7 @@
#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_SCORE 120
#define IDM_FILE_EXIT 121
#define IDM_WINDOW_VIS_0 200
@@ -171,17 +165,9 @@
#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
@@ -254,9 +240,6 @@
/*
* Include the support for loading bitmaps
*/
-#ifdef USE_GRAPHICS
-# include "readdib.h"
-#endif
/*
* Hack -- Fake declarations from "dos.h" XXX XXX XXX
@@ -447,39 +430,8 @@ 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 */
/*
@@ -502,7 +454,6 @@ static cptr AngList = "AngList";
*/
static cptr ANGBAND_DIR_XTRA_FONT;
static cptr ANGBAND_DIR_XTRA_GRAF;
-static cptr ANGBAND_DIR_XTRA_SOUND;
static cptr ANGBAND_DIR_XTRA_HELP;
@@ -548,7 +499,6 @@ static BYTE win_pal[256] =
static bool_ special_key[256];
static bool_ ignore_key[256];
-#if 1
/*
* Hack -- initialization list for "special_key"
*/
@@ -574,88 +524,6 @@ static byte ignore_key_list[] = {
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
@@ -980,18 +848,6 @@ static void save_prefs(void)
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)
{
@@ -1023,7 +879,7 @@ static void load_prefs_aux(term_data *td, cptr sec_name)
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));
+ td->font_want = strdup(analyze_font(tmp, &wid, &hgt));
/* Tile size */
td->tile_wid = GetPrivateProfileInt(sec_name, "TileWid", wid, ini_file);
@@ -1048,16 +904,6 @@ static void load_prefs(void)
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)
{
@@ -1108,37 +954,16 @@ static int new_palette(void)
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);
+ pLogPal = (LPLOGPALETTE) calloc(1, pLogPalSize);
+ if (pLogPal == NULL)
+ {
+ abort();
+ }
/* Version */
pLogPal->palVersion = 0x300;
@@ -1170,14 +995,19 @@ static int new_palette(void)
}
/* Free something */
- if (lppe) rnfree(lppe, lppeSize);
+ if (lppe)
+ {
+ free(lppe);
+ lppe = NULL;
+ }
/* Create a new palette, or fail */
hNewPal = CreatePalette(pLogPal);
if (!hNewPal) quit("Cannot create palette!");
/* Free the palette */
- rnfree(pLogPal, pLogPalSize);
+ free(pLogPal);
+ pLogPal = NULL;
/* Main window */
td = &data[0];
@@ -1210,120 +1040,6 @@ static int new_palette(void)
}
-/*
- * 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
@@ -1388,9 +1104,7 @@ static errr term_force_font(term_data *td, cptr path)
if (!used) RemoveFontResource(td->font_file);
/* Free the old name */
- string_free(td->font_file);
-
- /* Forget it */
+ free(td->font_file);
td->font_file = NULL;
}
@@ -1415,7 +1129,7 @@ static errr term_force_font(term_data *td, cptr path)
if (!AddFontResource(buf)) return (1);
/* Save new font name */
- td->font_file = string_make(base);
+ td->font_file = strdup(base);
/* Remove the "suffix" */
base[strlen(base) - 4] = '\0';
@@ -1531,38 +1245,6 @@ static void term_data_redraw(term_data *td)
/*** 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
*/
@@ -1618,51 +1300,8 @@ static errr Term_xtra_win_react(void)
}
-#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 */
@@ -1789,41 +1428,6 @@ static errr Term_xtra_win_noise(void)
/*
- * 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)
@@ -1881,12 +1485,6 @@ static errr Term_xtra_win(int n, int v)
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:
{
@@ -1923,40 +1521,6 @@ static errr Term_xtra_win(int n, int v)
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);
@@ -1986,9 +1550,6 @@ static errr Term_curs_win(int x, int y)
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);
@@ -2000,34 +1561,6 @@ static errr Term_curs_win(int x, int y)
/*
- * 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.
@@ -2119,197 +1652,6 @@ static errr Term_text_win(int x, int y, int n, byte a, const char *s)
}
-/*
- * 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 ***/
@@ -2327,26 +1669,10 @@ static void term_data_link(term_data *td)
/* 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);
@@ -2373,7 +1699,7 @@ static void init_windows(void)
/* Main window */
td = &data[0];
- WIPE(td, term_data);
+ memset(td, 0, sizeof(term_data));
td->s = angband_term_name[0];
td->keys = 1024;
td->rows = 24;
@@ -2390,7 +1716,7 @@ static void init_windows(void)
for (i = 1; i < MAX_TERM_DATA; i++)
{
td = &data[i];
- WIPE(td, term_data);
+ memset(td, 0, sizeof(term_data));
td->s = angband_term_name[i];
td->keys = 16;
td->rows = 24;
@@ -2548,13 +1874,8 @@ static void setup_menus(void)
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);
@@ -2578,14 +1899,6 @@ static void setup_menus(void)
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)
{
@@ -2593,8 +1906,6 @@ static void setup_menus(void)
MF_BYCOMMAND | MF_ENABLED);
}
-#endif
-
/* Menu "File", Item "Exit" */
EnableMenuItem(hm, IDM_FILE_EXIT,
MF_BYCOMMAND | MF_ENABLED);
@@ -2700,52 +2011,18 @@ static void setup_menus(void)
}
/* 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" */
@@ -2915,102 +2192,15 @@ ofn.lStructSize = sizeof(OPENFILENAME);
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;
+ predict_score_gui(&initialized, &game_in_progress);
/* Done */
break;
}
-#endif
-
case IDM_WINDOW_VIS_0:
{
plog("You are not allowed to do that!");
@@ -3194,114 +2384,6 @@ ofn.lStructSize = sizeof(OPENFILENAME);
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 */
@@ -3343,55 +2425,12 @@ ofn.lStructSize = sizeof(OPENFILENAME);
#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;
@@ -3671,15 +2710,8 @@ LRESULT FAR PASCAL AngbandWndProc(HWND hWnd, UINT uMsg,
}
-#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;
@@ -3883,15 +2915,8 @@ LRESULT FAR PASCAL AngbandListProc(HWND hWnd, UINT uMsg,
#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;
@@ -3915,15 +2940,6 @@ WPARAM wParam, LPARAM lParam)
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:
@@ -4059,7 +3075,11 @@ static void hook_quit(cptr str)
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].font_want)
+ {
+ free(data[i].font_want);
+ data[i].font_want = NULL;
+ }
if (data[i].w) DestroyWindow(data[i].w);
data[i].w = 0;
}
@@ -4098,7 +3118,7 @@ static void init_stuff(void)
strcpy(path + strlen(path) - 4, ".INI");
/* Save the the name of the ini-file */
- ini_file = string_make(path);
+ ini_file = strdup(path);
/* Validate the ini-file */
validate_file(ini_file);
@@ -4131,12 +3151,11 @@ static void init_stuff(void)
path_build(path, 1024, ANGBAND_DIR_XTRA, "font");
/* Allocate the path */
- ANGBAND_DIR_XTRA_FONT = string_make(path);
+ ANGBAND_DIR_XTRA_FONT = strdup(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);
@@ -4157,45 +3176,15 @@ static void init_stuff(void)
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);
+ ANGBAND_DIR_XTRA_HELP = strdup(path);
/* Validate the "help" directory */
/* validate_dir(ANGBAND_DIR_XTRA_HELP); */
@@ -4252,7 +3241,6 @@ int FAR PASCAL WinMain(HINSTANCE hInst, HINSTANCE hPrevInst,
/* Temporary hooks */
plog_aux = hack_plog;
quit_aux = hack_quit;
- core_aux = hack_quit;
/* Prepare the filepaths */
init_stuff();
diff --git a/src/main-x11.c b/src/main-x11.c
index e32e2617..b4b242e5 100644
--- a/src/main-x11.c
+++ b/src/main-x11.c
@@ -92,7 +92,9 @@
*
*/
-#include "angband.h"
+#include "loadsave.h"
+#include "util.h"
+#include "variable.h"
#ifdef USE_X11
@@ -112,20 +114,86 @@
#include <sys/time.h>
-/* /me pffts Solaris */
-#ifndef NAME_MAX
-#define NAME_MAX _POSIX_NAME_MAX
-#endif
/*
- * Include some helpful X11 code.
+ * This file is designed to be "included" by "main-x11.c" or "main-xaw.c",
+ * which will have already "included" several relevant header files.
*/
-#include "maid-x11.c"
+
+#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 -- avoid some compiler warnings
+ * Hack -- Convert an RGB value to an X11 Pixel, or die.
+ *
+ * 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).
*/
-#define IGNORE_UNUSED_FUNCTIONS
+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);
+}
+
+
/*
@@ -406,15 +474,9 @@ Infowin_init_dad(D,X,Y,W,H,B,Metadpy->fg,Metadpy->bg)
#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) \
@@ -615,36 +677,6 @@ static errr Metadpy_init_2(Display *dpy, cptr name)
}
-#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
*/
@@ -690,45 +722,6 @@ static errr Infowin_set_name(cptr name)
}
-#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'.
*/
@@ -769,26 +762,6 @@ static errr Infowin_prepare(Window xid)
}
-#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.
*
@@ -807,7 +780,7 @@ static errr Infowin_init_data(Window dad, int x, int y, int w, int h,
Window xid;
/* Wipe it clean */
- (void)WIPE(Infowin, infowin);
+ memset(Infowin, 0, sizeof(struct infowin));
/*** Error Check XXX ***/
@@ -880,23 +853,6 @@ static errr Infowin_map(void)
}
-#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
*/
@@ -910,23 +866,6 @@ static errr Infowin_raise(void)
}
-#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
*/
@@ -940,23 +879,6 @@ static errr Infowin_impell(int x, int y)
}
-#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
*/
@@ -970,24 +892,6 @@ static errr Infowin_wipe(void)
}
-#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"
*
@@ -1050,109 +954,6 @@ static int Infoclr_Opcode(cptr str)
}
-#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
*
@@ -1214,7 +1015,7 @@ static errr Infoclr_init_data(Pixell fg, Pixell bg, int op, int stip)
/*** Initialize ***/
/* Wipe the iclr clean */
- (void)WIPE(iclr, infoclr);
+ memset(iclr, 0, sizeof(struct infoclr));
/* Assign the GC */
iclr->gc = gc;
@@ -1262,36 +1063,6 @@ static errr Infoclr_change_fg(Pixell fg)
-#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'
*/
@@ -1311,44 +1082,13 @@ static errr Infofnt_prepare(XFontStruct *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
+ ifnt->twid = ifnt->wid;
/* 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
*
@@ -1375,7 +1115,7 @@ static errr Infofnt_init_data(cptr name)
/*** Init the font ***/
/* Wipe the thing */
- (void)WIPE(Infofnt, infofnt);
+ memset(Infofnt, 0, sizeof(struct infofnt));
/* Attempt to prepare it */
if (Infofnt_prepare(info))
@@ -1388,7 +1128,7 @@ static errr Infofnt_init_data(cptr name)
}
/* Save a copy of the font name */
- Infofnt->name = string_make(name);
+ Infofnt->name = strdup(name);
/* Mark it as nukable */
Infofnt->nuke = 1;
@@ -1543,14 +1283,6 @@ struct term_data
infowin *win;
-#ifdef USE_GRAPHICS
-
- XImage *tiles;
-
- /* Tempory storage for overlaying tiles. */
- XImage *TmpImage;
-
-#endif
};
@@ -2433,56 +2165,6 @@ static errr Term_xtra_x11(int n, int 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());
@@ -2505,30 +2187,8 @@ 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);
+ /* 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;
@@ -2554,170 +2214,6 @@ static errr Term_text_x11(int x, int y, int n, byte a, cptr s)
}
-#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 */
@@ -2856,7 +2352,11 @@ static errr term_data_init(term_data *td, int i)
/* Prepare the standard font */
- MAKE(td->fnt, infofnt);
+ td->fnt = calloc(1, sizeof(struct infofnt));
+ if (td->fnt == NULL)
+ {
+ abort();
+ }
Infofnt_set(td->fnt);
Infofnt_init_data(font);
@@ -2868,7 +2368,11 @@ static errr term_data_init(term_data *td, int i)
hgt = rows * td->fnt->hgt + (oy + oy);
/* Create a top-window */
- MAKE(td->win, infowin);
+ td->win = calloc(1, sizeof(struct infowin));
+ if (td->win == NULL)
+ {
+ abort();
+ }
Infowin_set(td->win);
Infowin_init_top(x, y, wid, hgt, 0,
Metadpy->fg, Metadpy->bg);
@@ -2953,14 +2457,9 @@ static errr term_data_init(term_data *td, int i)
/* 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 */
@@ -2985,17 +2484,6 @@ errr init_x11(int argc, char *argv[])
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 */
@@ -3007,27 +2495,6 @@ errr init_x11(int argc, char *argv[])
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"))
{
@@ -3037,7 +2504,7 @@ errr init_x11(int argc, char *argv[])
continue;
}
- plog_fmt("Ignoring option: %s", argv[i]);
+ fprintf(stderr, "Ignoring option: %s", argv[i]);
}
@@ -3046,7 +2513,11 @@ errr init_x11(int argc, char *argv[])
/* Prepare cursor color */
- MAKE(xor, infoclr);
+ xor = calloc(1, sizeof(struct infoclr));
+ if (xor == NULL)
+ {
+ abort();
+ }
Infoclr_set(xor);
Infoclr_init_ppn(Metadpy->fg, Metadpy->bg, "xor", 0);
@@ -3056,8 +2527,11 @@ errr init_x11(int argc, char *argv[])
{
Pixell pixel;
- MAKE(clr[i], infoclr);
-
+ clr[i] = calloc(1, sizeof(struct infoclr));
+ if (clr[i] == NULL)
+ {
+ abort();
+ }
Infoclr_set(clr[i]);
/* Acquire Angband colors */
@@ -3104,102 +2578,6 @@ errr init_x11(int argc, char *argv[])
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 */
diff --git a/src/main-xaw.c b/src/main-xaw.c
deleted file mode 100644
index 8795e00d..00000000
--- a/src/main-xaw.c
+++ /dev/null
@@ -1,1888 +0,0 @@
-/* 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
deleted file mode 100644
index c80f01f0..00000000
--- a/src/main-xxx.c
+++ /dev/null
@@ -1,785 +0,0 @@
-/* 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
index 48ab3f04..680e5c5a 100644
--- a/src/main.c
+++ b/src/main.c
@@ -8,7 +8,14 @@
* are included in all such copies.
*/
-#include "angband.h"
+#include "birth.h"
+#include "dungeon.h"
+#include "files.h"
+#include "init2.h"
+#include "modules.h"
+#include "script.h"
+#include "util.h"
+#include "variable.h"
@@ -18,7 +25,7 @@
*/
-#if !defined(MACINTOSH) && !defined(WINDOWS)
+#if !defined(WINDOWS)
/*
@@ -44,51 +51,11 @@ static void quit_hook(cptr s)
/*
- * 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)
+static void init_save_dir(void)
{
char dirpath[1024];
char versionpath[1024];
@@ -101,139 +68,34 @@ static bool_ check_create_user_dir(void)
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);
+ if (!private_check_user_directory(dirpath))
+ {
+ quit_fmt("Cannot create directory '%s'", dirpath);
+ }
- /* Hack -- Add a path separator (only if needed) */
- if (!suffix(path, PATH_SEP)) strcat(path, PATH_SEP);
+ if (!private_check_user_directory(versionpath))
+ {
+ quit_fmt("Cannot create directory '%s'", versionpath);
+ }
- /* Initialize */
- init_file_paths(path);
+ if (!private_check_user_directory(savepath))
+ {
+ quit_fmt("Cannot create directory '%s'", savepath);
+ }
}
-
-/*
- * 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)
+static void init_player_name()
{
- 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;
- }
+ /* Get the user id (?) */
+ int player_uid = getuid();
- default:
- {
- quit_fmt("Bad semantics in '-d%s'", info);
- }
- }
+ /* Acquire the "user name" as a default player name */
+ user_name(player_name, player_uid);
}
+
/*
* Simple "main" function for multiple platforms.
*
@@ -249,51 +111,18 @@ int main(int argc, char *argv[])
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);
- }
+ init_file_paths_with_env();
+ /* Initialize the player name */
+ init_player_name();
+ /* Make sure save directory exists */
+ init_save_dir();
/* Process the command line arguments */
@@ -312,13 +141,6 @@ int main(int argc, char *argv[])
break;
}
- case 'F':
- case 'f':
- {
- arg_fiddle = TRUE;
- break;
- }
-
case 'W':
case 'w':
{
@@ -326,20 +148,6 @@ int main(int argc, char *argv[])
break;
}
- case 'V':
- case 'v':
- {
- arg_sound = TRUE;
- break;
- }
-
- case 'G':
- case 'g':
- {
- arg_graphics = TRUE;
- break;
- }
-
case 'R':
case 'r':
{
@@ -354,14 +162,6 @@ int main(int argc, char *argv[])
break;
}
- case 'S':
- case 's':
- {
- show_score = atoi(&argv[i][2]);
- if (show_score <= 0) show_score = 10;
- break;
- }
-
case 'u':
case 'U':
{
@@ -382,7 +182,7 @@ int main(int argc, char *argv[])
case 'M':
{
if (!argv[i][2]) goto usage;
- force_module = string_make(&argv[i][2]);
+ force_module = &argv[i][2];
break;
}
@@ -397,7 +197,8 @@ int main(int argc, char *argv[])
char *s;
int j;
- init_lua();
+ init_lua_init();
+
for (j = i + 1; j < argc; j++)
{
s = argv[j];
@@ -411,13 +212,6 @@ int main(int argc, char *argv[])
return 0;
}
- case 'd':
- case 'D':
- {
- change_path(&argv[i][2]);
- break;
- }
-
case '-':
{
if (argv[i][2] == 'h' && !strcmp((argv[i] + 2), "help"))
@@ -443,53 +237,26 @@ usage:
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
@@ -498,17 +265,10 @@ usage:
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");
@@ -539,19 +299,6 @@ usage:
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"))))
@@ -565,32 +312,6 @@ usage:
}
#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"))))
@@ -617,34 +338,6 @@ usage:
}
#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"))))
@@ -662,25 +355,15 @@ usage:
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);
diff --git a/src/martial_arts.hpp b/src/martial_arts.hpp
new file mode 100644
index 00000000..1f2f0cbe
--- /dev/null
+++ b/src/martial_arts.hpp
@@ -0,0 +1,18 @@
+#pragma once
+
+#include "h-basic.h"
+
+/**
+ * Martial arts descriptors
+ */
+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 */
+};
+
diff --git a/src/melee1.c b/src/melee1.c
deleted file mode 100644
index 4e5d3208..00000000
--- a/src/melee1.c
+++ /dev/null
@@ -1,3065 +0,0 @@
-/* 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/melee1.cc b/src/melee1.cc
new file mode 100644
index 00000000..bb4c06d1
--- /dev/null
+++ b/src/melee1.cc
@@ -0,0 +1,3048 @@
+/*
+ * 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 "melee1.hpp"
+
+#include "cave.hpp"
+#include "cmd5.hpp"
+#include "gods.hpp"
+#include "mimic.hpp"
+#include "monster2.hpp"
+#include "monster3.hpp"
+#include "monster_race.hpp"
+#include "monster_type.hpp"
+#include "object1.hpp"
+#include "object2.hpp"
+#include "player_type.hpp"
+#include "skills.hpp"
+#include "spells1.hpp"
+#include "spells2.hpp"
+#include "stats.hpp"
+#include "store.hpp"
+#include "tables.hpp"
+#include "util.hpp"
+#include "variable.hpp"
+#include "xtra1.hpp"
+#include "xtra2.hpp"
+#include "z-rand.hpp"
+
+#include <boost/algorithm/string/predicate.hpp>
+
+using boost::algorithm::iequals;
+
+/*
+ * 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);
+
+ /* 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(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);
+
+ /* 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];
+
+ 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? */
+ auto r_ptr = m_ptr->race();
+ 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);
+
+ 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 */
+ if (praying_to(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) && iequals(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_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_FRAME);
+
+ /* 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_FRAME);
+
+ /* 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));
+
+ /* Copy into inventory of monster */
+ {
+ 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 */
+ m_ptr->hold_o_idxs.push_back(o_idx);
+ }
+ }
+
+ /* 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(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))))
+ gain_corruption("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);
+
+ /* 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/melee1.hpp b/src/melee1.hpp
new file mode 100644
index 00000000..e84c8f03
--- /dev/null
+++ b/src/melee1.hpp
@@ -0,0 +1,7 @@
+#pragma once
+
+#include "h-basic.h"
+
+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);
diff --git a/src/melee2.c b/src/melee2.c
deleted file mode 100644
index 6ada6bd0..00000000
--- a/src/melee2.c
+++ /dev/null
@@ -1,7591 +0,0 @@
-/* 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/melee2.cc b/src/melee2.cc
new file mode 100644
index 00000000..b3aa5c61
--- /dev/null
+++ b/src/melee2.cc
@@ -0,0 +1,7475 @@
+/*
+ * 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 "melee2.hpp"
+
+#include "cave.hpp"
+#include "cave_type.hpp"
+#include "cmd1.hpp"
+#include "feature_type.hpp"
+#include "files.hpp"
+#include "hook_mon_speak_in.hpp"
+#include "hook_monster_ai_in.hpp"
+#include "hook_monster_ai_out.hpp"
+#include "hooks.hpp"
+#include "melee1.hpp"
+#include "messages.hpp"
+#include "monster2.hpp"
+#include "monster3.hpp"
+#include "monster_race.hpp"
+#include "monster_type.hpp"
+#include "object1.hpp"
+#include "object2.hpp"
+#include "options.hpp"
+#include "player_type.hpp"
+#include "quark.hpp"
+#include "skills.hpp"
+#include "spells1.hpp"
+#include "spells2.hpp"
+#include "stats.hpp"
+#include "tables.hpp"
+#include "traps.hpp"
+#include "util.hpp"
+#include "variable.hpp"
+#include "xtra2.hpp"
+#include "z-rand.hpp"
+
+#include <cassert>
+
+#define SPEAK_CHANCE 8
+#define GRINDNOISE 20
+
+#define FOLLOW_DISTANCE 6
+
+static void cmonster_msg(char a, cptr fmt, ...);
+
+/*
+ * 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];
+
+ /* Redraw (later) if needed */
+ if (health_who == m_idx) p_ptr->redraw |= (PR_FRAME);
+
+ /* Some monsters are immune to death */
+ auto const r_ptr = m_ptr->race();
+ 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 */
+ s32b div = p_ptr->max_plv;
+
+ /* Give some experience for the kill */
+ s32b new_exp = ((long)r_ptr->mexp * m_ptr->level) / div;
+
+ /* Handle fractional experience */
+ s32b 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);
+ }
+
+ }
+
+ /* Apply fear */
+ mon_handle_fear(m_ptr, dam, fear);
+
+ /* Not dead yet */
+ return (FALSE);
+}
+
+
+void mon_handle_fear(monster_type *m_ptr, int dam, bool_ *fear)
+{
+ assert(m_ptr != NULL);
+
+ /* 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 */
+ auto const r_ptr = m_ptr->race();
+ 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)));
+ }
+ }
+}
+
+
+/*
+* 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.
+*/
+
+
+
+/*
+* Internal probability routine
+*/
+static bool_ int_outof(std::shared_ptr<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];
+
+ u32b f4 = (*f4p);
+ u32b f5 = (*f5p);
+ u32b f6 = (*f6p);
+
+ u32b smart = 0L;
+
+
+ /* Too stupid to know anything? */
+ auto const r_ptr = m_ptr->race();
+ if (r_ptr->flags2 & (RF2_STUPID)) return;
+
+
+ /* Must be cheating or learning */
+ if (!smart_learn) return;
+
+
+ /* Update acquired knowledge */
+ if (smart_learn)
+ {
+ /* Hack -- Occasionally forget player status */
+ if (m_ptr->smart && magik(1)) m_ptr->smart = 0L;
+
+ /* Use the memorized flags */
+ smart = m_ptr->smart;
+ }
+
+
+ /* 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];
+
+ 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;
+
+ /* Stupid monsters choose randomly */
+ auto const r_ptr = m_ptr->race();
+ if (r_ptr->flags2 & (RF2_STUPID))
+ {
+ /* Pick at random */
+ return (spells[rand_int(num)]);
+ }
+
+ /* Categorize spells */
+ for (int 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];
+ auto const r_ptr = m_ptr->race();
+
+ /* 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];
+ auto const r_ptr = m_ptr->race();
+
+ /* 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);
+}
+
+
+static 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);
+
+ /* Print */
+ monster_msg_simple(buf);
+}
+
+void monster_msg_simple(cptr s)
+{
+ /* Display */
+ if (disturb_other)
+ {
+ msg_print(s);
+ }
+ else
+ {
+ message_add(s, 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(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;
+ int thrown_spell;
+ byte spell[96], num = 0;
+ char m_name[80], t_name[80];
+ char m_poss[80];
+ char ddesc[80];
+ monster_type *m_ptr = &m_list[m_idx]; /* Attacker */
+ 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 */
+ const auto r_ptr = m_ptr->race();
+ const int 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;
+
+
+ {
+ int t_idx = i;
+
+ monster_type *t_ptr = &m_list[t_idx];
+ auto const tr_ptr = t_ptr->race();
+
+ /* 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 */
+ const int 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 (int k = 0; k < 32; k++)
+ {
+ if (f4 & (1L << k)) spell[num++] = k + 32 * 3;
+ }
+
+ /* Extract the "normal" spells */
+ for (int k = 0; k < 32; k++)
+ {
+ if (f5 & (1L << k)) spell[num++] = k + 32 * 4;
+ }
+
+ /* Extract the "bizarre" spells */
+ for (int 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);
+
+ int count = 0;
+ switch (thrown_spell)
+ {
+ /* RF4_SHRIEK */
+ case 96 + 0:
+ {
+ if (!direct) break;
+ if (disturb_other) disturb(1);
+ 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);
+ if (blind || !see_m) monster_msg("%^s mumbles.", m_name);
+ else monster_msg("%^s magically summons an animal!", m_name);
+ for (int 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);
+ 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);
+ 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);
+ 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);
+
+ 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);
+ 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);
+ 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);
+ 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);
+ 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);
+ 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);
+ 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);
+ 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);
+ 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);
+ 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);
+ 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);
+ 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);
+ 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);
+ 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);
+ 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);
+ 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);
+ 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);
+ 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);
+ 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);
+ 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);
+ 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);
+ 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);
+ 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);
+ 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);
+ 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);
+ 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);
+ 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);
+ 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);
+ 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);
+ 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);
+ 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);
+ 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);
+ 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);
+ 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);
+ 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_FRAME);
+
+ /* 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);
+
+ 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);
+ 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);
+ 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);
+ 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);
+ 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);
+ 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);
+ 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);
+ 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);
+ 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);
+ 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);
+ 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);
+ 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);
+ 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);
+ 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);
+ 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);
+ 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);
+ 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);
+ 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);
+ 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);
+ 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);
+ 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);
+ 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);
+ 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);
+
+ /* 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_FRAME);
+
+ /* 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);
+ if (blind || !see_m) monster_msg("%^s mumbles.", m_name);
+ else monster_msg("%^s magically summons some animals!", m_name);
+ for (int 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);
+ 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);
+ 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);
+ 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);
+ 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);
+ if (blind || !see_m) monster_msg("%^s mumbles.", m_name);
+ else monster_msg("%^s magically codes some software bugs.", m_name);
+ for (int 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);
+ if (blind || !see_m) monster_msg("%^s mumbles.", m_name);
+ else monster_msg("%^s magically codes some RNGs.", m_name);
+ for (int 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);
+ if (blind || !see_m) monster_msg("%^s mumbles.", m_name);
+ else monster_msg("%^s magically summons a Thunderlord!", m_name);
+ for (int 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);
+ 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 (int 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);
+ 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);
+ if (blind || !see_m) monster_msg("%^s mumbles.", m_name);
+ else monster_msg("%^s magically summons help!", m_name);
+ for (int 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);
+ if (blind || !see_m) monster_msg("%^s mumbles.", m_name);
+ else monster_msg("%^s magically summons monsters!", m_name);
+ for (int 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);
+ if (blind || !see_m) monster_msg("%^s mumbles.", m_name);
+ else monster_msg("%^s magically summons ants.", m_name);
+ for (int 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);
+ if (blind || !see_m) monster_msg("%^s mumbles.", m_name);
+ else monster_msg("%^s magically summons spiders.", m_name);
+ for (int 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);
+ if (blind || !see_m) monster_msg("%^s mumbles.", m_name);
+ else monster_msg("%^s magically summons hounds.", m_name);
+ for (int 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);
+ if (blind || !see_m) monster_msg("%^s mumbles.", m_name);
+ else monster_msg("%^s magically summons hydras.", m_name);
+ for (int 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);
+ if (blind || !see_m) monster_msg("%^s mumbles.", m_name);
+ else monster_msg("%^s magically summons an angel!", m_name);
+ for (int 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);
+ if (blind || !see_m) monster_msg("%^s mumbles.", m_name);
+ else monster_msg("%^s magically summons a demon!", m_name);
+ for (int 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);
+ if (blind || !see_m) monster_msg("%^s mumbles.", m_name);
+ else monster_msg("%^s magically summons an undead adversary!", m_name);
+ for (int 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);
+ if (blind || !see_m) monster_msg("%^s mumbles.", m_name);
+ else monster_msg("%^s magically summons a dragon!", m_name);
+ for (int 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);
+ if (blind || !see_m) monster_msg("%^s mumbles.", m_name);
+ else monster_msg("%^s magically summons greater undead!", m_name);
+ for (int 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);
+ if (blind || !see_m) monster_msg("%^s mumbles.", m_name);
+ else monster_msg("%^s magically summons ancient dragons!", m_name);
+ for (int 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);
+ if (blind || !see_m) monster_msg("%^s mumbles.", m_name);
+ else monster_msg("%^s magically summons a wraith!", m_name);
+
+
+ for (int 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);
+ if (blind || !see_m) monster_msg("%^s mumbles.", m_name);
+ else monster_msg("%^s magically summons special opponents!", m_name);
+ for (int k = 0; k < 8; k++)
+ {
+ if (!friendly)
+ count += summon_specific(y, x, rlev, SUMMON_UNIQUE);
+ }
+ for (int 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.
+ *
+ * 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 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.
+ */
+static bool_ make_attack_spell(int m_idx)
+{
+ int k, chance, thrown_spell, rlev, failrate;
+ byte spell[96], num = 0;
+ u32b f4, f5, f6;
+ 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);
+
+ /* Get a pointer to the monster */
+ monster_type *m_ptr = &m_list[m_idx];
+
+ /* Extract the "see-able-ness" */
+ bool_ seen = (!blind && m_ptr->ml);
+
+ /* Assume "normal" target */
+ bool_ normal = 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 ... */
+ auto const r_ptr = m_ptr->race();
+ 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);
+
+ /* Only do spells occasionally */
+ if (rand_int(100) >= chance) return (FALSE);
+
+ /* Sometimes forbid inate attacks (breaths) */
+ if (rand_int(100) >= (chance * 2)) no_inate = TRUE;
+
+ /* 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;
+
+ /* 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);
+
+ /* 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);
+
+ /* Choose a spell to cast */
+ 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:
+ {
+ disturb(1);
+ 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);
+ 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);
+ 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);
+ 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);
+ 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);
+ 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);
+ 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);
+ 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);
+ 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);
+ 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);
+ 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);
+ 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);
+ 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);
+ 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);
+ 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);
+ 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);
+ 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);
+ 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);
+ 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);
+ 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);
+ 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);
+ 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);
+ 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);
+ 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);
+ 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);
+ 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);
+ 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);
+ 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);
+ 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);
+ 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);
+ 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);
+ 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);
+ 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);
+ 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);
+ 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);
+ 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);
+ 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);
+ 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);
+ 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);
+ 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 (p_ptr->csp)
+ {
+ int r1;
+
+ /* Disturb if legal */
+ disturb(1);
+
+ /* 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_FRAME);
+
+ /* 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_FRAME);
+
+ /* 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:
+ {
+ disturb(1);
+ 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:
+ {
+ disturb(1);
+ 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(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:
+ {
+ disturb(1);
+ 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:
+ {
+ disturb(1);
+ 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:
+ {
+ disturb(1);
+ 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:
+ {
+ disturb(1);
+ 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);
+ 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);
+ 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);
+ 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);
+ 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);
+ 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);
+ 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);
+ 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);
+ 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);
+ 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);
+ 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:
+ {
+ disturb(1);
+ 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:
+ {
+ disturb(1);
+ 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:
+ {
+ disturb(1);
+ 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:
+ {
+ disturb(1);
+ 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:
+ {
+ disturb(1);
+ 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(rand_int(4) + 4);
+ }
+ update_smart_learn(m_idx, DRS_FREE);
+ break;
+ }
+
+
+
+ /* RF6_HASTE */
+ case 160 + 0:
+ {
+ disturb(1);
+ 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);
+ 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);
+
+ /* 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_FRAME);
+
+ /* 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);
+ 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);
+ msg_format("%^s blinks away.", m_name);
+ teleport_away(m_idx, 10);
+ break;
+ }
+
+ /* RF6_TPORT */
+ case 160 + 5:
+ {
+ disturb(1);
+ msg_format("%^s teleports away.", m_name);
+ teleport_away(m_idx, MAX_SIGHT * 2 + 5);
+ break;
+ }
+
+ /* RF6_TELE_TO */
+ case 160 + 6:
+ {
+ disturb(1);
+ 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:
+ {
+ disturb(1);
+ msg_format("%^s teleports you away.", m_name);
+ teleport_player(100);
+ break;
+ }
+
+ /* RF6_TELE_LEVEL */
+ case 160 + 8:
+ {
+ disturb(1);
+ 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:
+ {
+ disturb(1);
+ 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:
+ {
+ disturb(1);
+ 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:
+ {
+ disturb(1);
+ 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);
+ 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);
+ 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);
+ 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);
+ 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);
+ 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);
+ 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);
+ 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);
+ 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);
+ 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);
+ 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);
+ 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);
+ 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);
+ 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);
+ 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);
+ 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);
+ 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);
+ 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);
+ 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);
+ 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];
+ u16b p_lev, m_lev;
+ u16b p_chp, p_mhp;
+ u16b m_chp, m_mhp;
+ u32b p_val, m_val;
+
+ /* 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);
+
+ /* 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);
+
+ /* 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)
+{
+ /* Monster flowing disabled */
+ if (!flow_by_sound) return (FALSE);
+
+ /* Monster location */
+ monster_type *m_ptr = &m_list[m_idx];
+ const int fy = m_ptr->fy;;
+ const int fx = m_ptr->fx;
+
+ /* Desired destination */
+ int y1 = fy - (*yp);
+ int 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 */
+ auto const r_ptr = m_ptr->race();
+ if (cave[fy][fx].cost > MONSTER_FLOW_DEPTH) return (FALSE);
+ if (cave[fy][fx].cost > r_ptr->aaf) return (FALSE);
+
+ /* Loop state */
+ int when = 0;
+ int gy = 0;
+ int gx = 0;
+ int score = -1;
+
+ /* Check nearby grids, diagonals first */
+ for (int i = 7; i >= 0; i--)
+ {
+ int dis, s;
+
+ /* Get the location */
+ const int y = fy + ddy_ddd[i];
+ const int 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];
+
+ 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;
+ }
+ }
+
+ /* Get the race */
+ const auto r_ptr = m_ptr->race();
+
+ /* 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)
+ {
+ struct hook_monster_ai_in in = { m_idx, &m_list[m_idx] };
+ struct hook_monster_ai_out out = { 0, 0 };
+ if (process_hooks_new(HOOK_MONSTER_AI, &in, &out))
+ {
+ y2 = out.y;
+ x2 = out.x;
+ }
+ }
+
+ 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" */
+ int y = m_ptr->fy - y2;
+ int 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 (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 (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);
+ }
+ }
+ }
+ }
+
+
+ /* Check for no move */
+ if (!x && !y) return (FALSE);
+
+ /* Extract the "absolute distances" */
+ int ay = ABS(y);
+ int ax = ABS(x);
+
+ /* 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)
+{
+ char temp[80];
+ bool_ blinked = FALSE;
+ bool_ touched = FALSE;
+ bool_ explode = FALSE;
+ bool_ fear = FALSE;
+ monster_type *t_ptr = &m_list[t_idx];
+ byte y_saver = t_ptr->fy;
+ byte x_saver = t_ptr->fx;
+
+ /* Get the racial information on the two monsters */
+ monster_type *m_ptr = &m_list[m_idx];
+ const auto r_ptr = m_ptr->race();
+ const auto tr_ptr = t_ptr->race();
+
+ /* Not allowed to attack */
+ if (r_ptr->flags1 & RF1_NEVER_BLOW) return FALSE;
+
+ /* Total armor */
+ const int ac = t_ptr->ac;
+
+ /* Extract the effective monster level */
+ const int rlev = ((m_ptr->level >= 1) ? m_ptr->level : 1);
+
+ /* Get the monster name (or "it") */
+ char m_name[80];
+ monster_desc(m_name, m_ptr, 0);
+
+ /* Get the monster name (or "it") */
+ char t_name[80];
+ monster_desc(t_name, t_ptr, 0);
+
+ /* Get the "died from" information (i.e. "a kobold") */
+ char ddesc[80];
+ 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 (int 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);
+
+ /* 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)
+ {
+ strnfmt(temp, sizeof(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;
+
+ int 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);
+
+ /* 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)
+{
+ const auto r_ptr = m_ptr->race();
+ s16b inv = p_ptr->invis;
+ s16b mlv = 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)
+{
+ int i, d, oy, ox, ny, nx;
+
+ int mm[8];
+
+ monster_type *m_ptr = &m_list[m_idx];
+ const bool_ inv = player_invis(m_ptr);
+
+ auto const r_ptr = m_ptr->race();
+ 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 */
+ bool_ xxx = FALSE;
+ 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_FRAME);
+ }
+ }
+ }
+
+ /* Handle "poisoned" */
+ if (m_ptr->poisoned)
+ {
+ int d = (m_ptr->poisoned) / 10;
+ if (d < 1) d = 1;
+
+ /* Exit if the monster dies */
+ bool_ xxx = FALSE;
+ 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_FRAME);
+ }
+ }
+ }
+
+ /* 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);
+ }
+ }
+ }
+
+ /* Do the monster get angry? */
+ bool_ gets_angry = FALSE;
+
+ /* 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 (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.... */
+
+ struct hook_mon_speak_in in = { m_idx, m_name };
+ if (!process_hooks_new(HOOK_MON_SPEAK, &in, NULL))
+ {
+ 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
+ {
+ /* Logical moves, may do nothing */
+ if (!get_moves(m_idx, mm)) return;
+ }
+
+ /* Paranoia -- quest code could delete it */
+ cave_type *c_ptr = &cave[m_ptr->fy][m_ptr->fx];
+ if (!c_ptr->m_idx) return;
+
+ /* Assume nothing */
+ bool_ do_turn = FALSE;
+ bool_ do_move = FALSE;
+ bool_ do_view = FALSE;
+
+ /* Assume nothing */
+ bool_ did_open_door = FALSE;
+ bool_ did_bash_door = FALSE;
+ bool_ did_take_item = FALSE;
+ bool_ did_kill_item = FALSE;
+ bool_ did_move_body = FALSE;
+ bool_ did_kill_body = FALSE;
+ bool_ did_pass_wall = FALSE;
+ bool_ 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 */
+ monster_type *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);
+
+ /* 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)
+ {
+ auto z_ptr = y_ptr->race();
+ 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)
+ {
+ /* 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);
+ }
+
+ /* Check for monster trap */
+ if (c_ptr->feat == FEAT_MON_TRAP)
+ {
+ if (mon_hit_trap(m_idx)) return;
+ }
+ else
+ {
+ /* Copy list of objects; we need a copy because we're mutating the list. */
+ auto const object_idxs(c_ptr->o_idxs);
+
+ /* Scan all objects in the grid */
+ for (auto const this_o_idx: object_idxs)
+ {
+ /* Acquire object */
+ object_type * o_ptr = &o_list[this_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);
+ }
+
+ /* Put into inventory of monster */
+ {
+ /* 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;
+
+ /* Carry object */
+ m_ptr->hold_o_idxs.push_back(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 &&
+ (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;
+
+ 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 */
+ monster_race *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 */
+ auto const r_ptr = m_ptr->race();
+
+ /* 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 */
+ 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/melee2.hpp b/src/melee2.hpp
new file mode 100644
index 00000000..fece0564
--- /dev/null
+++ b/src/melee2.hpp
@@ -0,0 +1,12 @@
+#pragma once
+
+#include "h-basic.h"
+#include "monster_type_fwd.hpp"
+
+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 void mon_handle_fear(monster_type *m_ptr, int dam, bool_ *fear);
+extern int check_hit2(int power, int level, int ac);
+extern void process_monsters(void);
+extern void curse_equipment(int chance, int heavy_chance);
+extern void curse_equipment_dg(int chance, int heavy_chance);
diff --git a/src/messages.cc b/src/messages.cc
new file mode 100644
index 00000000..a4ce949d
--- /dev/null
+++ b/src/messages.cc
@@ -0,0 +1,368 @@
+#include "messages.hpp"
+
+#include "tome/make_array.hpp"
+
+#include "z-term.h"
+#include "z-form.h"
+#include "z-util.h"
+
+/*
+ * OPTION: Maximum number of messages to remember (see "io.c")
+ * Default: assume maximal memorization of 2048 total messages
+ */
+#define MESSAGE_MAX 2048
+
+/*
+ * 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
+
+
+
+
+/*
+ * The next "free" index to use
+ */
+static u16b message__next;
+
+/*
+ * The index of the oldest message (none yet)
+ */
+static u16b message__last;
+
+/*
+ * The next "free" offset
+ */
+static u16b message__head;
+
+/*
+ * The offset to the oldest used char (none yet)
+ */
+static u16b message__tail;
+
+/*
+ * The array of offsets, by index [MESSAGE_MAX]
+ */
+static u16b *message__ptr;
+
+/*
+ * The array of colors, by index [MESSAGE_MAX]
+ */
+static byte *message__color;
+
+/*
+ * The array of message counts, by index [MESSAGE_MAX]
+ */
+static u16b *message__count;
+
+/*
+ * The array of chars, by offset [MESSAGE_BUF]
+ */
+static char *message__buf;
+
+
+/*
+* 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.
+*/
+
+void message_init()
+{
+ /* Message variables */
+ message__ptr = make_array<u16b>(MESSAGE_MAX);
+ message__color = make_array<byte>(MESSAGE_MAX);
+ message__count = make_array<u16b>(MESSAGE_MAX);
+ message__buf = make_array<char>(MESSAGE_BUF);
+
+ /* Hack -- No messages yet */
+ message__tail = MESSAGE_BUF;
+}
+
+/*
+* 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);
+}
+
+
+/*
+* Add a new message, with great efficiency
+*/
+void message_add(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__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__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;
+}
diff --git a/src/messages.hpp b/src/messages.hpp
new file mode 100644
index 00000000..22943ab9
--- /dev/null
+++ b/src/messages.hpp
@@ -0,0 +1,9 @@
+#pragma once
+
+#include "h-basic.h"
+
+void message_init();
+s16b message_num();
+cptr message_str(int age);
+byte message_color(int age);
+void message_add(cptr msg, byte color);
diff --git a/src/meta_class_type.hpp b/src/meta_class_type.hpp
new file mode 100644
index 00000000..e74e75b3
--- /dev/null
+++ b/src/meta_class_type.hpp
@@ -0,0 +1,10 @@
+#pragma once
+
+#include "h-basic.h"
+
+struct meta_class_type
+{
+ char name[80]; /* Name */
+ byte color;
+ s16b *classes; /* list of classes */
+};
diff --git a/src/meta_class_type_fwd.hpp b/src/meta_class_type_fwd.hpp
new file mode 100644
index 00000000..2d0e482a
--- /dev/null
+++ b/src/meta_class_type_fwd.hpp
@@ -0,0 +1,3 @@
+#pragma once
+
+struct meta_class_type;
diff --git a/src/mimic.cc b/src/mimic.cc
new file mode 100644
index 00000000..edf79f4b
--- /dev/null
+++ b/src/mimic.cc
@@ -0,0 +1,728 @@
+#include "mimic.hpp"
+
+#include "player_type.hpp"
+#include "skill_type.hpp"
+#include "stats.hpp"
+#include "variable.hpp"
+#include "xtra1.hpp"
+#include "z-rand.hpp"
+
+#include <cassert>
+
+/**
+ * Mimicry forms
+ */
+typedef struct mimic_duration_type mimic_duration_type;
+struct mimic_duration_type
+{
+ s16b min;
+ s16b max;
+};
+
+typedef struct mimic_form_type mimic_form_type;
+struct mimic_form_type
+{
+ int modules[3]; /* Modules where this mimicry form is available; terminated with a -1 entry */
+ cptr name; /* Name of mimicry form */
+ cptr obj_name; /* Object mimicry form name */
+ cptr desc; /* Description */
+ cptr realm; /* Realm of mimicry */
+ bool_ limit; /* If true, the form is not available except through special means */
+ byte level;
+ byte rarity;
+ mimic_duration_type duration;
+ s32b (*calc)(); /* Callback to calculate bonuses; return number of blows to add */
+ void (*power)(); /* Callback to calculate powers */
+};
+
+static s32b abomination_calc()
+{
+ apply_flags(TR1_SPEED + TR1_STR + TR1_INT + TR1_WIS + TR1_DEX + TR1_CON + TR1_CHR, 0, 0, 0, 0, 0, -10, 0, 0, 0, 0);
+ p_ptr->xtra_f3 |= TR3_AGGRAVATE;
+
+ return 0;
+}
+
+static s32b mouse_calc()
+{
+ /* Mice run! */
+ p_ptr->pspeed += 5 + (p_ptr->mimic_level / 7);
+
+ /* They can crawl under your armor to hit you ;) */
+ p_ptr->to_h = p_ptr->to_h + 10 + (p_ptr->mimic_level / 5);
+ p_ptr->dis_to_h = p_ptr->dis_to_h + 10 + (p_ptr->mimic_level / 5);
+
+ /* But they are not very powerfull */
+ p_ptr->to_d = p_ptr->to_d / 5;
+ p_ptr->dis_to_d = p_ptr->dis_to_d / 5;
+
+ /* But they are stealthy */
+ p_ptr->skill_stl = p_ptr->skill_stl + 10 + (p_ptr->mimic_level / 5);
+
+ /* Stat mods */
+ p_ptr->stat_add[A_STR] += -5;
+ p_ptr->stat_add[A_DEX] += 3;
+ p_ptr->stat_add[A_CON] += 1;
+
+ return 0;
+}
+
+static void mouse_power()
+{
+ if (p_ptr->mimic_level >= 30)
+ {
+ p_ptr->powers[POWER_INVISIBILITY] = TRUE;
+ }
+}
+
+static s32b eagle_calc()
+{
+ p_ptr->ffall = TRUE;
+ p_ptr->pspeed = p_ptr->pspeed + 2 + (p_ptr->mimic_level / 6);
+
+ p_ptr->stat_add[A_STR] += -3;
+ p_ptr->stat_add[A_DEX] += 2 + (p_ptr->mimic_level / 15);
+ p_ptr->stat_add[A_CON] += 4 + (p_ptr->mimic_level / 20);
+ p_ptr->stat_add[A_INT] += -1;
+ p_ptr->stat_add[A_WIS] += 1;
+ p_ptr->stat_add[A_CHR] += -1;
+
+ if (p_ptr->mimic_level >= 20)
+ {
+ p_ptr->xtra_f4 |= TR4_FLY;
+ p_ptr->xtra_f3 |= TR3_SEE_INVIS;
+ }
+
+ if (p_ptr->mimic_level >= 25)
+ {
+ p_ptr->xtra_f2 |= TR2_FREE_ACT;
+ }
+
+ if (p_ptr->mimic_level >= 30)
+ {
+ p_ptr->xtra_f2 |= TR2_RES_ELEC;
+ }
+
+ if (p_ptr->mimic_level >= 35)
+ {
+ p_ptr->xtra_f3 |= TR3_SH_ELEC;
+ }
+
+ return 0;
+}
+
+static s32b wolf_calc()
+{
+ p_ptr->stat_add[A_STR] += 2 + (p_ptr->mimic_level / 20);
+ p_ptr->stat_add[A_DEX] += 3 + (p_ptr->mimic_level / 20);
+ p_ptr->stat_add[A_INT] += -3;
+ p_ptr->stat_add[A_CHR] += -2;
+
+ p_ptr->pspeed = p_ptr->pspeed + 10 + (p_ptr->mimic_level / 5);
+
+ p_ptr->xtra_f2 |= TR2_FREE_ACT;
+ p_ptr->xtra_f2 |= TR2_RES_FEAR;
+
+ if (p_ptr->mimic_level >= 10)
+ {
+ p_ptr->xtra_f2 |= TR2_RES_COLD;
+ }
+
+ if (p_ptr->mimic_level >= 15)
+ {
+ p_ptr->xtra_f3 |= TR3_SEE_INVIS;
+ }
+
+ if (p_ptr->mimic_level >= 30)
+ {
+ p_ptr->xtra_f2 |= TR2_RES_DARK;
+ }
+
+ if (p_ptr->mimic_level >= 35)
+ {
+ p_ptr->xtra_f2 |= TR2_RES_CONF;
+ }
+
+ return 0;
+}
+
+static s32b spider_calc()
+{
+ p_ptr->stat_add[A_STR] += -4;
+ p_ptr->stat_add[A_DEX] += 1 + (p_ptr->mimic_level / 8);
+ p_ptr->stat_add[A_INT] += 1 + (p_ptr->mimic_level / 5);
+ p_ptr->stat_add[A_WIS] += 1 + (p_ptr->mimic_level / 5);
+ p_ptr->stat_add[A_CON] += -5;
+ p_ptr->stat_add[A_CHR] += -10;
+
+ p_ptr->pspeed = p_ptr->pspeed + 5;
+
+ p_ptr->xtra_f2 |= TR2_RES_POIS;
+ p_ptr->xtra_f2 |= TR2_RES_FEAR;
+ p_ptr->xtra_f2 |= TR2_RES_DARK;
+
+ if (p_ptr->mimic_level >= 40)
+ {
+ p_ptr->xtra_f4 |= TR4_CLIMB;
+ }
+
+ return 0;
+}
+
+static void spider_power()
+{
+ if (p_ptr->mimic_level >= 25)
+ {
+ p_ptr->powers[POWER_WEB] = TRUE;
+ }
+}
+
+static s32b ent_calc()
+{
+ p_ptr->pspeed = p_ptr->pspeed - 5 - (p_ptr->mimic_level / 10);
+
+ p_ptr->to_a = p_ptr->to_a + 10 + p_ptr->mimic_level;
+ p_ptr->dis_to_a = p_ptr->dis_to_a + 10 + p_ptr->mimic_level;
+
+ p_ptr->stat_add[A_STR] += p_ptr->mimic_level / 5;
+ p_ptr->stat_add[A_INT] += - (p_ptr->mimic_level / 7);
+ p_ptr->stat_add[A_WIS] += - (p_ptr->mimic_level / 7);
+ p_ptr->stat_add[A_DEX] += -4;
+ p_ptr->stat_add[A_CON] += p_ptr->mimic_level / 5;
+ p_ptr->stat_add[A_CHR] += -7;
+
+ p_ptr->xtra_f2 |= TR2_RES_POIS;
+ p_ptr->xtra_f2 |= TR2_RES_COLD;
+ p_ptr->xtra_f2 |= TR2_FREE_ACT;
+ p_ptr->xtra_f3 |= TR3_REGEN;
+ p_ptr->xtra_f3 |= TR3_SEE_INVIS;
+ p_ptr->xtra_f2 |= TR2_SENS_FIRE;
+
+ return 0;
+}
+
+static void ent_power()
+{
+ p_ptr->powers[PWR_GROW_TREE] = TRUE;
+}
+
+static s32b vapour_calc()
+{
+ p_ptr->pspeed = p_ptr->pspeed + 5;
+
+ /* Try to hit a cloud! */
+ p_ptr->to_a = p_ptr->to_a + 40 + p_ptr->mimic_level;
+ p_ptr->dis_to_a = p_ptr->dis_to_a + 40 + p_ptr->mimic_level;
+
+ /* Try to hit WITH a cloud! */
+ p_ptr->to_h = p_ptr->to_h - 40;
+ p_ptr->dis_to_h = p_ptr->dis_to_h - 40;
+
+ /* Stat mods */
+ p_ptr->stat_add[A_STR] += -4;
+ p_ptr->stat_add[A_DEX] += 5;
+ p_ptr->stat_add[A_CON] += -4;
+ p_ptr->stat_add[A_CHR] += -10;
+
+ /* But they are stealthy */
+ p_ptr->skill_stl = p_ptr->skill_stl + 10 + (p_ptr->mimic_level / 5);
+ p_ptr->xtra_f2 |= TR2_RES_POIS;
+ p_ptr->xtra_f2 |= TR2_RES_SHARDS;
+ p_ptr->xtra_f2 |= TR2_IM_COLD;
+ p_ptr->xtra_f2 |= TR2_FREE_ACT;
+ p_ptr->xtra_f3 |= TR3_REGEN;
+ p_ptr->xtra_f3 |= TR3_SEE_INVIS;
+ p_ptr->xtra_f2 |= TR2_SENS_FIRE;
+ p_ptr->xtra_f3 |= TR3_FEATHER;
+
+ return 0;
+}
+
+static s32b serpent_calc()
+{
+ p_ptr->pspeed = p_ptr->pspeed + 10 + (p_ptr->mimic_level / 6);
+
+ p_ptr->to_a = p_ptr->to_a + 3 + (p_ptr->mimic_level / 8);
+ p_ptr->dis_to_a = p_ptr->dis_to_a + 3 + (p_ptr->mimic_level / 8);
+
+ p_ptr->stat_add[A_STR] += p_ptr->mimic_level / 8;
+ p_ptr->stat_add[A_INT] += -6;
+ p_ptr->stat_add[A_WIS] += -6;
+ p_ptr->stat_add[A_DEX] += -4;
+ p_ptr->stat_add[A_CON] += p_ptr->mimic_level / 7;
+ p_ptr->stat_add[A_CHR] += -6;
+
+ p_ptr->xtra_f2 |= TR2_RES_POIS;
+ if (p_ptr->mimic_level >= 25)
+ {
+ p_ptr->xtra_f2 |= TR2_FREE_ACT;
+ }
+
+ return 0;
+}
+
+static s32b mumak_calc()
+{
+ p_ptr->pspeed = p_ptr->pspeed - 5 - (p_ptr->mimic_level / 10);
+
+ p_ptr->to_a = p_ptr->to_a + 10 + (p_ptr->mimic_level / 6);
+ p_ptr->dis_to_a = p_ptr->dis_to_a + 10 + (p_ptr->mimic_level / 6);
+ p_ptr->to_d = p_ptr->to_d + 5 + ((p_ptr->mimic_level * 2) / 3);
+ p_ptr->dis_to_d = p_ptr->dis_to_d + 5 + ((p_ptr->mimic_level * 2) / 3);
+
+ p_ptr->stat_add[A_STR] += p_ptr->mimic_level / 4;
+ p_ptr->stat_add[A_INT] += -8;
+ p_ptr->stat_add[A_WIS] += -4;
+ p_ptr->stat_add[A_DEX] += -5;
+ p_ptr->stat_add[A_CON] += p_ptr->mimic_level / 3;
+ p_ptr->stat_add[A_CHR] += -10;
+
+ if (p_ptr->mimic_level >= 10)
+ {
+ p_ptr->xtra_f2 |= TR2_RES_FEAR;
+ }
+
+ if (p_ptr->mimic_level >= 25)
+ {
+ p_ptr->xtra_f2 |= TR2_RES_CONF;
+ }
+
+ if (p_ptr->mimic_level >= 30)
+ {
+ p_ptr->xtra_f2 |= TR2_FREE_ACT;
+ }
+
+ if (p_ptr->mimic_level >= 35)
+ {
+ p_ptr->xtra_f2 |= TR2_RES_NEXUS;
+ }
+
+ return 0;
+}
+
+static s32b bear_calc()
+{
+ p_ptr->pspeed = p_ptr->pspeed - 5 + (p_ptr->mimic_level / 5);
+
+ p_ptr->to_a = p_ptr->to_a + 5 + ((p_ptr->mimic_level * 2) / 3);
+ p_ptr->dis_to_a = p_ptr->dis_to_a + 5 + ((p_ptr->mimic_level * 2) / 3);
+
+ p_ptr->stat_add[A_STR] += p_ptr->mimic_level / 11;
+ p_ptr->stat_add[A_INT] += p_ptr->mimic_level / 11;
+ p_ptr->stat_add[A_WIS] += p_ptr->mimic_level / 11;
+ p_ptr->stat_add[A_DEX] += -1;
+ p_ptr->stat_add[A_CON] += p_ptr->mimic_level / 11;
+ p_ptr->stat_add[A_CHR] += -10;
+
+ if (p_ptr->mimic_level >= 10)
+ {
+ p_ptr->xtra_f2 |= TR2_FREE_ACT;
+ }
+
+ if (p_ptr->mimic_level >= 20)
+ {
+ p_ptr->xtra_f3 |= TR3_REGEN;
+ }
+
+ if (p_ptr->mimic_level >= 30)
+ {
+ p_ptr->xtra_f2 |= TR2_RES_CONF;
+ }
+
+ if (p_ptr->mimic_level >= 35)
+ {
+ p_ptr->xtra_f2 |= TR2_RES_NEXUS;
+ }
+
+ /* activate the skill */
+ s_info[SKILL_BEAR].hidden = FALSE;
+
+ return 0;
+}
+
+static s32b balrog_calc()
+{
+ p_ptr->stat_add[A_STR] += 5 + p_ptr->mimic_level / 5;
+ p_ptr->stat_add[A_INT] += p_ptr->mimic_level / 10;
+ p_ptr->stat_add[A_WIS] += - ( 5 + p_ptr->mimic_level / 10);
+ p_ptr->stat_add[A_DEX] += p_ptr->mimic_level / 10;
+ p_ptr->stat_add[A_CON] += 5 + p_ptr->mimic_level / 5;
+ p_ptr->stat_add[A_CHR] += - ( 5 + p_ptr->mimic_level / 10);
+
+ p_ptr->xtra_f2 |= TR2_IM_ACID;
+ p_ptr->xtra_f2 |= TR2_IM_FIRE;
+ p_ptr->xtra_f2 |= TR2_IM_ELEC;
+ p_ptr->xtra_f2 |= TR2_RES_DARK;
+ p_ptr->xtra_f2 |= TR2_RES_CHAOS;
+ p_ptr->xtra_f2 |= TR2_RES_POIS;
+ p_ptr->xtra_f2 |= TR2_HOLD_LIFE;
+ p_ptr->xtra_f3 |= TR3_FEATHER;
+ p_ptr->xtra_f3 |= TR3_REGEN;
+ p_ptr->xtra_f3 |= TR3_SH_FIRE;
+ p_ptr->xtra_f3 |= TR3_LITE1;
+
+ return 1; /* Adds a blow */
+}
+
+static s32b maia_calc()
+{
+ p_ptr->stat_add[A_STR] += 5 + p_ptr->mimic_level / 5;
+ p_ptr->stat_add[A_INT] += 5 + p_ptr->mimic_level / 5;
+ p_ptr->stat_add[A_WIS] += 5 + p_ptr->mimic_level / 5;
+ p_ptr->stat_add[A_DEX] += 5 + p_ptr->mimic_level / 5;
+ p_ptr->stat_add[A_CON] += 5 + p_ptr->mimic_level / 5;
+ p_ptr->stat_add[A_CHR] += 5 + p_ptr->mimic_level / 5;
+
+ p_ptr->xtra_f2 |= TR2_IM_FIRE;
+ p_ptr->xtra_f2 |= TR2_IM_ELEC;
+ p_ptr->xtra_f2 |= TR2_IM_ACID;
+ p_ptr->xtra_f2 |= TR2_IM_COLD;
+ p_ptr->xtra_f2 |= TR2_RES_POIS;
+ p_ptr->xtra_f2 |= TR2_RES_LITE;
+ p_ptr->xtra_f2 |= TR2_RES_DARK;
+ p_ptr->xtra_f2 |= TR2_RES_CHAOS;
+ p_ptr->xtra_f2 |= TR2_HOLD_LIFE;
+ p_ptr->xtra_f3 |= TR3_FEATHER;
+ p_ptr->xtra_f3 |= TR3_REGEN;
+
+ return 2; /* Add two blows */
+}
+
+static s32b fire_elemental_calc()
+{
+ p_ptr->stat_add[A_STR] += 5 + (p_ptr->mimic_level / 5);
+ p_ptr->stat_add[A_DEX] += 5 + (p_ptr->mimic_level / 5);
+ p_ptr->stat_add[A_WIS] += -5 - (p_ptr->mimic_level / 5);
+
+ p_ptr->xtra_f2 |= TR2_IM_FIRE;
+ p_ptr->xtra_f2 |= TR2_RES_POIS;
+ p_ptr->xtra_f3 |= TR3_SH_FIRE;
+ p_ptr->xtra_f3 |= TR3_LITE1;
+
+ return 0;
+}
+
+/*
+ * Mimicry forms
+ */
+static mimic_form_type mimic_forms[MIMIC_FORMS_MAX] =
+{
+ { /* 0 */
+ { MODULE_TOME, MODULE_THEME, -1 },
+ "Abomination", /* MUST be at index 0! */
+ "Abominable Cloak",
+ "Abominations are failed experiments of powerful wizards.",
+ NULL /* no realm */,
+ FALSE,
+ 1, 101, {20, 100},
+ abomination_calc,
+ NULL,
+ },
+
+ /*
+ * Nature forms
+ */
+
+ { /* 1 */
+ { MODULE_TOME, MODULE_THEME, -1 },
+ "Mouse",
+ "Mouse Fur",
+ "Mice are small, fast and very stealthy",
+ "nature",
+ FALSE,
+ 1, 10, {20, 40},
+ mouse_calc,
+ mouse_power,
+ },
+
+ { /* 2 */
+ { MODULE_TOME, -1 },
+ "Eagle",
+ "Feathers Cloak",
+ "Eagles are master of the air, good hunters with excellent vision.",
+ "nature",
+ FALSE,
+ 10, 30, {10, 50},
+ eagle_calc,
+ NULL,
+ },
+
+ { /* 3 */
+ { MODULE_THEME, -1 },
+ "Eagle",
+ "Feathered Cloak",
+ "Eagles are master of the air, good hunters with excellent vision.",
+ "nature",
+ FALSE,
+ 10, 30, {10, 50},
+ eagle_calc,
+ NULL,
+ },
+
+ { /* 4 */
+ { MODULE_TOME, MODULE_THEME, -1 },
+ "Wolf",
+ "Wolf Pelt",
+ "Wolves are masters of movement, strong and have excellent eyesight.",
+ "nature",
+ FALSE,
+ 20, 40, {10, 50},
+ wolf_calc,
+ NULL,
+ },
+
+ { /* 5 */
+ { MODULE_TOME, MODULE_THEME, -1 },
+ "Spider",
+ "Spider Web",
+ "Spiders are clever and become good climbers.",
+ "nature",
+ FALSE,
+ 25, 50, {10, 50},
+ spider_calc,
+ spider_power,
+ },
+
+ { /* 6 */
+ { MODULE_TOME, MODULE_THEME, -1 },
+ "Elder Ent",
+ "Entish Bark",
+ "Ents are powerful tree-like beings dating from the dawn of time.",
+ "nature",
+ TRUE,
+ 40, 60, {10, 30},
+ ent_calc,
+ ent_power,
+ },
+
+ { /* 7 */
+ { MODULE_TOME, MODULE_THEME, -1 },
+ "Vapour",
+ "Cloak of Mist",
+ "A sentient cloud, darting around",
+ "nature",
+ FALSE,
+ 15, 10, {10, 40},
+ vapour_calc,
+ NULL,
+ },
+
+ { /* 8 */
+ { MODULE_TOME, MODULE_THEME, -1 },
+ "Serpent",
+ "Snakeskin Cloak",
+ "Serpents are fast, lethal predators.",
+ "nature",
+ FALSE,
+ 30, 25, {15, 20},
+ serpent_calc,
+ NULL,
+ },
+
+ { /* 9 */
+ { MODULE_TOME, MODULE_THEME, -1 },
+ "Mumak",
+ "Mumak Hide",
+ "A giant, elaphantine form.",
+ "nature",
+ FALSE,
+ 40, 40, {15, 20},
+ mumak_calc,
+ NULL,
+ },
+
+ /*
+ * Extra shapes
+ */
+
+ { /* 10 */
+ { MODULE_TOME, MODULE_THEME, -1 },
+ "Bear",
+ NULL,
+ "A fierce, terrible bear.",
+ NULL /* no realm */,
+ TRUE,
+ 1, 101, {50, 200},
+ bear_calc,
+ NULL,
+ },
+
+ { /* 11 */
+ { MODULE_TOME, MODULE_THEME, -1 },
+ "Balrog",
+ NULL,
+ "A corrupted maia.",
+ NULL /* no realm */,
+ TRUE,
+ 1, 101, {30, 70},
+ balrog_calc,
+ NULL,
+ },
+
+ { /* 12 */
+ { MODULE_TOME, MODULE_THEME, -1 },
+ "Maia",
+ NULL,
+ "A near god-like being.",
+ NULL /* no realm */,
+ TRUE,
+ 1, 101, {30, 70},
+ maia_calc,
+ NULL,
+ },
+
+ { /* 13 */
+ { MODULE_TOME, MODULE_THEME, -1 },
+ "Fire Elem.",
+ NULL,
+ "A towering column of flames",
+ NULL /* no realm */,
+ TRUE,
+ 1, 101, {10, 10},
+ fire_elemental_calc,
+ NULL,
+ },
+
+};
+
+/*
+ * Is the mimicry form enabled for the current module?
+ */
+static bool_ mimic_form_enabled(mimic_form_type *f)
+{
+ int i;
+
+ for (i = 0; f->modules[i] >= 0; i++)
+ {
+ if (f->modules[i] == game_module_idx)
+ {
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+/*
+ * Get a mimic form by index
+ */
+static mimic_form_type *get_mimic_form(int mf_idx)
+{
+ assert(mf_idx >= 0);
+ assert(mf_idx < MIMIC_FORMS_MAX);
+ return &mimic_forms[mf_idx];
+}
+
+/*
+ * Find a mimic by name
+ */
+s16b resolve_mimic_name(cptr name)
+{
+ s16b i;
+
+ for (i = 0; i < MIMIC_FORMS_MAX; i++)
+ {
+ mimic_form_type *mf_ptr = get_mimic_form(i);
+ if (mimic_form_enabled(mf_ptr) && streq(mf_ptr->name, name))
+ {
+ return i;
+ }
+ }
+
+ return -1;
+}
+
+/*
+ * Find a random mimic form
+ */
+s16b find_random_mimic_shape(byte level, bool_ limit)
+{
+ int tries = 1000;
+
+ while (tries > 0)
+ {
+ int mf_idx = 0;
+ mimic_form_type *mf_ptr = NULL;
+
+ tries = tries - 1;
+
+ mf_idx = rand_int(MIMIC_FORMS_MAX);
+ mf_ptr = get_mimic_form(mf_idx);
+
+ if (mimic_form_enabled(mf_ptr))
+ {
+ if (limit >= mf_ptr->limit)
+ {
+ if ((rand_int(mf_ptr->level * 3) < level) &&
+ (mf_ptr->rarity < 100) &&
+ (magik(100 - mf_ptr->rarity)))
+ {
+ return mf_idx;
+ }
+ }
+ }
+ }
+ /* Abomination */
+ return 0;
+}
+
+/*
+ * Get mimic name
+ */
+cptr get_mimic_name(s16b mf_idx)
+{
+ return get_mimic_form(mf_idx)->name;
+}
+
+/*
+ * Get mimic object name
+ */
+cptr get_mimic_object_name(s16b mf_idx)
+{
+ return get_mimic_form(mf_idx)->obj_name;
+}
+
+/*
+ * Get mimic object level
+ */
+byte get_mimic_level(s16b mf_idx)
+{
+ return get_mimic_form(mf_idx)->level;
+}
+
+/*
+ * Get a random duration for the given mimic form
+ */
+s32b get_mimic_random_duration(s16b mf_idx)
+{
+ mimic_form_type *mf_ptr = get_mimic_form(mf_idx);
+ return rand_range(mf_ptr->duration.min, mf_ptr->duration.max);
+}
+
+/*
+ * Calculate bonuses for player's current mimic form
+ */
+byte calc_mimic()
+{
+ mimic_form_type *mf_ptr = get_mimic_form(p_ptr->mimic_form);
+ if (mf_ptr->calc != NULL)
+ {
+ return mf_ptr->calc();
+ }
+ else
+ {
+ return 0;
+ }
+}
+
+/*
+ * Calculate powers for player's current mimic form
+ */
+void calc_mimic_power()
+{
+ mimic_form_type *mf_ptr = get_mimic_form(p_ptr->mimic_form);
+ if (mf_ptr->power != NULL)
+ {
+ mf_ptr->power();
+ }
+}
diff --git a/src/mimic.hpp b/src/mimic.hpp
new file mode 100644
index 00000000..d9c8f3bd
--- /dev/null
+++ b/src/mimic.hpp
@@ -0,0 +1,10 @@
+#include "h-basic.h"
+
+extern s16b resolve_mimic_name(cptr name);
+extern s16b find_random_mimic_shape(byte level, bool_ limit);
+extern cptr get_mimic_name(s16b mf_idx);
+extern cptr get_mimic_object_name(s16b mf_idx);
+extern byte get_mimic_level(s16b mf_idx);
+extern s32b get_mimic_random_duration(s16b mf_idx);
+extern byte calc_mimic();
+extern void calc_mimic_power();
diff --git a/src/module_type.hpp b/src/module_type.hpp
new file mode 100644
index 00000000..96938856
--- /dev/null
+++ b/src/module_type.hpp
@@ -0,0 +1,64 @@
+#pragma once
+
+#include "h-basic.h"
+
+/**
+ * Module descriptor.
+ */
+struct module_type
+{
+ /* Metadata about the module: author, description, etc. */
+ struct {
+ /* Module name */
+ cptr name;
+
+ /* Module version number */
+ struct {
+ s32b major;
+ s32b minor;
+ s32b patch;
+ } version;
+
+ /* Module author */
+ struct {
+ cptr name;
+ cptr email;
+ } author;
+
+ /* Module description */
+ cptr desc;
+
+ /* Save file tag */
+ cptr save_file_tag;
+
+ /* Module directory */
+ cptr module_dir;
+ } meta;
+
+ /* Random artifact generation chances */
+ struct {
+ s32b weapon_chance;
+ s32b armor_chance;
+ s32b jewelry_chance;
+ } randarts;
+
+ /* Max player level. */
+ int max_plev;
+
+ /* Skills */
+ struct {
+ /* Skill points per level */
+ s32b skill_per_level;
+ /* Maximum "overage" for skill points, i.e. how many skill
+ points you can go above your current level. */
+ s32b max_skill_overage;
+ } skills;
+
+ /* Function to show introduction to module */
+ void (*intro)();
+
+ /* Function to compute race status, i.e. whether monsters
+ are friendly/neutral towards the player. Returns NULL
+ to indicate that no override happens. */
+ s16b *(*race_status)(int r_idx);
+};
diff --git a/src/modules.c b/src/modules.c
deleted file mode 100644
index 39b41d20..00000000
--- a/src/modules.c
+++ /dev/null
@@ -1,274 +0,0 @@
-/* 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/modules.cc b/src/modules.cc
new file mode 100644
index 00000000..c5d065f4
--- /dev/null
+++ b/src/modules.cc
@@ -0,0 +1,1279 @@
+/*
+ * 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 "modules.hpp"
+#include "modules.h"
+
+#include "birth.hpp"
+#include "cave.hpp"
+#include "cave_type.hpp"
+#include "corrupt.hpp"
+#include "files.hpp"
+#include "hook_eat_in.hpp"
+#include "hook_give_in.hpp"
+#include "hook_move_in.hpp"
+#include "hook_stair_in.hpp"
+#include "hook_stair_out.hpp"
+#include "hook_new_monster_end_in.hpp"
+#include "hooks.hpp"
+#include "joke.hpp"
+#include "lua_bind.hpp"
+#include "monster2.hpp"
+#include "monster_race.hpp"
+#include "monster_type.hpp"
+#include "object2.hpp"
+#include "object_type.hpp"
+#include "player_type.hpp"
+#include "spells2.hpp"
+#include "stats.hpp"
+#include "tables.hpp"
+#include "util.hpp"
+#include "util.h"
+#include "variable.h"
+#include "variable.hpp"
+
+#include <cassert>
+#include <chrono>
+#include <thread>
+
+using std::this_thread::sleep_for;
+using std::chrono::milliseconds;
+
+/*
+ * 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);
+ }
+}
+
+static void module_reset_dir_aux(char **dir, cptr new_path)
+{
+ char buf[1024];
+
+ /* Build the new path */
+ strnfmt(buf, sizeof (buf), "%s%s%s", *dir, PATH_SEP, new_path);
+
+ free(*dir);
+ *dir = strdup(buf);
+
+ /* Make it if needed */
+ if (!private_check_user_directory(*dir))
+ quit(format("Unable to create module dir %s\n", *dir));
+}
+
+static void module_reset_dir(cptr dir, cptr new_path)
+{
+ char **d = 0;
+ char buf[1025];
+
+ 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, "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, "user") ||
+ !strcmp(dir, "note"))
+ {
+ 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);
+
+ free(*d);
+ *d = strdup(buf);
+
+ // Make it if needed */
+ if (!private_check_user_directory(*d))
+ {
+ quit(format("Unable to create module dir %s\n", *d));
+ }
+ }
+ 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);
+
+ free(*d);
+ *d = strdup(buf);
+ }
+}
+
+static void dump_modules(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 = ')';
+ }
+
+ strnfmt(buf, 40, "%c%c%c %s", pre, ind, post, modules[i].meta.name);
+
+ if (sel == i)
+ {
+ print_desc_aux(modules[i].meta.desc, 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(int module_idx)
+{
+ module_type *module_ptr = &modules[module_idx];
+
+ /* Initialize the module table */
+ game_module_idx = module_idx;
+
+ /* Do misc inits */
+ max_plev = module_ptr->max_plev;
+
+ RANDART_WEAPON = module_ptr->randarts.weapon_chance;
+ RANDART_ARMOR = module_ptr->randarts.armor_chance;
+ RANDART_JEWEL = module_ptr->randarts.jewelry_chance;
+
+ VERSION_MAJOR = module_ptr->meta.version.major;
+ VERSION_MINOR = module_ptr->meta.version.minor;
+ VERSION_PATCH = module_ptr->meta.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();
+}
+
+static void init_module(module_type *module_ptr)
+{
+ /* Set up module directories? */
+ cptr dir = module_ptr->meta.module_dir;
+ if (dir) {
+ module_reset_dir("core", dir);
+ module_reset_dir("data", dir);
+ module_reset_dir("dngn", dir);
+ module_reset_dir("edit", dir);
+ module_reset_dir("file", dir);
+ module_reset_dir("help", dir);
+ module_reset_dir("note", dir);
+ module_reset_dir("save", dir);
+ module_reset_dir("user", dir);
+ module_reset_dir("pref", dir);
+ }
+}
+
+bool_ module_savefile_loadable(cptr savefile_mod)
+{
+ return (strcmp(savefile_mod, modules[game_module_idx].meta.save_file_tag) == 0);
+}
+
+/* Did the player force a module on command line */
+cptr force_module = NULL;
+
+/* Find module index by name. Returns -1 if matching module not found */
+int find_module(cptr name)
+{
+ int i = 0;
+
+ for (i=0; i<MAX_MODULES; i++)
+ {
+ if (streq(name, modules[i].meta.name))
+ {
+ return i;
+ }
+ }
+
+ return -1;
+}
+
+/* Display possible modules and select one */
+bool_ select_module()
+{
+ s32b k, sel, max;
+
+ /* How many modules? */
+ max = MAX_MODULES;
+
+ /* No need to bother the player if there is only one module */
+ sel = -1;
+ if (force_module) {
+ /* Find module by name */
+ sel = find_module(force_module);
+ }
+ /* Only a single choice */
+ if (max == 1) {
+ sel = 0;
+ }
+ /* No module selected */
+ if (sel != -1)
+ {
+ /* Process the module */
+ init_module(&modules[sel]);
+
+ game_module = modules[sel].meta.name;
+
+ activate_module(sel);
+
+ 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;
+
+ if (islower(k)) x = A2I(k);
+ else x = A2I(tolower(k)) + 26;
+
+ if ((x < 0) || (x >= max)) continue;
+
+ /* Process the module */
+ init_module(&modules[x]);
+
+ game_module = modules[x].meta.name;
+
+ activate_module(x);
+
+ return (FALSE);
+ }
+ }
+
+ /* Shouldnt happen */
+ return (FALSE);
+}
+
+static bool_ dleft(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)
+ {
+ sleep_for(milliseconds(1));
+ time = 0;
+ }
+ Term_redraw_section(a - 1, y, a, y);
+ a = a + 1;
+
+ if (inkey_scan()) {
+ return TRUE;
+ }
+ }
+ }
+
+ i = i - 1;
+ }
+ return FALSE;
+}
+
+static bool_ dright(byte c, cptr str, int y, int o)
+{
+ int n = strlen(str); // Conversion to int to avoid warnings
+ int x = 39 - (n / 2) + o;
+ for (int i = 1; i <= n; i++)
+ {
+ 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) {
+ sleep_for(milliseconds(1));
+ time = 0;
+ }
+ Term_redraw_section(a, y, a + 1, y);
+ a = a - 1;
+
+ if (inkey_scan()) {
+ return TRUE;
+ }
+ }
+ }
+ }
+ return FALSE;
+}
+
+typedef struct intro_text intro_text;
+struct intro_text
+{
+ bool_ (*drop_func)(byte, cptr, int, int);
+ byte color;
+ cptr text;
+ int y0;
+ int x0;
+};
+
+static bool_ show_intro(intro_text intro_texts[])
+{
+ int i = 0;
+
+ Term_clear();
+ for (i = 0; ; i++)
+ {
+ intro_text *it = &intro_texts[i];
+ if (it->drop_func == NULL)
+ {
+ break;
+ }
+ else if (it->drop_func(it->color, it->text, it->y0, it->x0))
+ {
+ /* Abort */
+ return TRUE;
+ }
+ }
+
+ /* Wait for key */
+ Term_putch(0, 0, TERM_DARK, 32);
+ inkey();
+
+ /* Continue */
+ return FALSE;
+}
+
+void tome_intro()
+{
+ intro_text intro1[] =
+ {
+ { dleft , TERM_L_BLUE, "Art thou an adventurer,", 10, 0, },
+ { dright, TERM_L_BLUE, "One who passes through the waterfalls we call danger", 11, -1, },
+ { dleft , TERM_L_BLUE, "to find the true nature of the legends beyond them?", 12, 0, },
+ { dright, TERM_L_BLUE, "If this is so, then seeketh me.", 13, -1, },
+ { dleft , TERM_WHITE , "[Press any key to continue]", 23, -1, },
+ { NULL , TERM_WHITE , NULL, 0, 0, }
+ };
+ intro_text intro2[] =
+ {
+ { dleft , TERM_L_BLUE , "DarkGod", 8, 0, },
+ { dright, TERM_WHITE , "in collaboration with", 9, -1, },
+ { dleft , TERM_L_GREEN, "Eru Iluvatar,", 10, 0, },
+ { dright, TERM_L_GREEN, "Manwe", 11, -1, },
+ { dleft , TERM_WHITE , "and", 12, 0, },
+ { dright, TERM_L_GREEN, "All the T.o.M.E. contributors(see credits.txt)", 13, -1, },
+ { dleft , TERM_WHITE , "present", 15, 1, },
+ { dright, TERM_YELLOW , "T.o.M.E.", 16, 0, },
+ { dleft , TERM_WHITE , "[Press any key to continue]", 23, -1, },
+ { NULL , TERM_WHITE , NULL, 0, 0, }
+ };
+
+ screen_save();
+
+ /* Intro 1 */
+ if (show_intro(intro1))
+ {
+ goto exit;
+ }
+
+ /* Intro 2 */
+ if (show_intro(intro2))
+ {
+ goto exit;
+ }
+
+exit:
+ screen_load();
+}
+
+void theme_intro()
+{
+ struct intro_text intro1[] =
+ {
+ { dleft , TERM_L_BLUE , "Three Rings for the Elven-kings under the sky,", 10, 0, },
+ { dright, TERM_L_BLUE , "Seven for the Dwarf-lords in their halls of stone,", 11, -1, },
+ { dleft , TERM_L_BLUE , "Nine for Mortal Men doomed to die,", 12, 0, },
+ { dright, TERM_L_BLUE , "One for the Dark Lord on his dark throne", 13, -1, },
+ { dleft , TERM_L_BLUE , "In the land of Mordor, where the Shadows lie.", 14, 0, },
+ { dright, TERM_L_BLUE , "One Ring to rule them all, One Ring to find them,", 15, -1, },
+ { dleft , TERM_L_BLUE , "One Ring to bring them all and in the darkness bind them", 16, 0, },
+ { dright, TERM_L_BLUE , "In the land of Mordor, where the Shadows lie.", 17, -1, },
+ { dright, TERM_L_GREEN, "--J.R.R. Tolkien", 18, 0, },
+ { dleft , TERM_WHITE , "[Press any key to continue]", 23, -1, },
+ { NULL , TERM_WHITE , NULL, 0, 0, },
+ };
+ struct intro_text intro2[] =
+ {
+ { dleft , TERM_L_BLUE , "furiosity", 8, 0, },
+ { dright, TERM_WHITE , "in collaboration with", 9, -1, },
+ { dleft , TERM_L_GREEN, "DarkGod and all the ToME contributors,", 10, 0, },
+ { dright, TERM_L_GREEN, "module creators, t-o-m-e.net forum posters,", 11, -1, },
+ { dleft , TERM_WHITE , "and", 12, 0, },
+ { dright, TERM_L_GREEN, "by the grace of the Valar", 13, -1, },
+ { dleft , TERM_WHITE , "present", 15, 1, },
+ { dright, TERM_YELLOW , "Theme (a module for ToME)", 16, 0, },
+ { dleft , TERM_WHITE , "[Press any key to continue]", 23, -1, },
+ { NULL , TERM_WHITE , NULL, 0, 0, },
+ };
+
+ screen_save();
+
+ /* Intro 1 */
+ if (show_intro(intro1))
+ {
+ goto exit;
+ }
+
+ /* Intro 2 */
+ if (show_intro(intro2))
+ {
+ goto exit;
+ }
+
+exit:
+ screen_load();
+}
+
+static bool_ auto_stat_gain_hook(void *data, void *in, void *out)
+{
+ while (p_ptr->last_rewarded_level * 5 <= p_ptr->lev)
+ {
+ 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);
+
+ p_ptr->last_rewarded_level += 1;
+ }
+
+ return FALSE;
+}
+
+static bool_ drunk_takes_wine(void *data, void *in_, void *out)
+{
+ hook_give_in *in = (hook_give_in *) in_;
+ monster_type *m_ptr = &m_list[in->m_idx];
+ object_type *o_ptr = get_object(in->item);
+
+ if ((m_ptr->r_idx == test_monster_name("Singing, happy drunk")) &&
+ (o_ptr->tval == TV_FOOD) &&
+ ((o_ptr->sval == 38) ||
+ (o_ptr->sval == 39)))
+ {
+ cmsg_print(TERM_YELLOW, "'Hic!'");
+
+ /* Destroy item */
+ inc_stack_size_ex(in->item, -1, OPTIMIZE, NO_DESCRIBE);
+
+ /* Create empty bottle */
+ {
+ object_type forge;
+ object_prep(&forge, lookup_kind(TV_BOTTLE,1));
+ drop_near(&forge, 50, p_ptr->py, p_ptr->px);
+ return TRUE;
+ }
+ }
+ else
+ {
+ return FALSE;
+ }
+}
+
+static bool_ hobbit_food(void *data, void *in_, void *out)
+{
+ hook_give_in *in = (hook_give_in *) in_;
+ monster_type *m_ptr = &m_list[in->m_idx];
+ object_type *o_ptr = get_object(in->item);
+
+ if ((m_ptr->r_idx == test_monster_name("Scruffy-looking hobbit")) &&
+ (o_ptr->tval == TV_FOOD))
+ {
+ cmsg_print(TERM_YELLOW, "'Yum!'");
+
+ inc_stack_size_ex(in->item, -1, OPTIMIZE, NO_DESCRIBE);
+
+ return TRUE;
+ }
+ else
+ {
+ return FALSE;
+ }
+}
+
+static bool_ smeagol_ring(void *data, void *in_, void *out)
+{
+ hook_give_in *in = (hook_give_in *) in_;
+ monster_type *m_ptr = &m_list[in->m_idx];
+ object_type *o_ptr = get_object(in->item);
+
+ if ((m_ptr->r_idx == test_monster_name("Smeagol")) &&
+ (o_ptr->tval == TV_RING))
+ {
+ cmsg_print(TERM_YELLOW, "'MY... PRECIOUSSSSS!!!'");
+
+ inc_stack_size_ex(in->item, -1, OPTIMIZE, NO_DESCRIBE);
+
+ return TRUE;
+ }
+ else
+ {
+ return FALSE;
+ }
+}
+
+static bool_ longbottom_leaf(void *data, void *in_, void *out_)
+{
+ hook_eat_in *in = (hook_eat_in *) in_;
+
+ if ((in->o_ptr->tval == TV_FOOD) &&
+ (in->o_ptr->sval == 45))
+ {
+ msg_print("What a stress reliever!");
+ heal_insanity(1000);
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static bool_ food_vessel(void *data, void *in_, void *out)
+{
+ hook_eat_in *in = (hook_eat_in *) in_;
+
+ if (((in->o_ptr->tval == TV_FOOD) && (in->o_ptr->sval == 43)) ||
+ ((in->o_ptr->tval == TV_FOOD) && (in->o_ptr->sval == 44)))
+ {
+ object_type forge;
+
+ object_prep(&forge, lookup_kind(TV_JUNK, 3));
+
+ forge.ident |= IDENT_MENTAL | IDENT_KNOWN;
+ inven_carry(&forge, FALSE);
+
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/*
+ * Player must have appropriate keys to enter Erebor.
+ */
+static bool_ erebor_stair(void *data, void *in_, void *out_)
+{
+ hook_stair_in *in = (hook_stair_in *) in_;
+ hook_stair_out *out = (hook_stair_out *) out_;
+
+ if ((dungeon_type == 20) &&
+ (dun_level == 60) &&
+ (in->direction == STAIRS_DOWN))
+ {
+ int i, keys;
+
+ keys = 0;
+ for (i = 0; i < INVEN_TOTAL - 1; i++)
+ {
+ if ((p_ptr->inventory[i].name1 == 209) ||
+ (p_ptr->inventory[i].name1 == 210))
+ {
+ keys += 1;
+ }
+ }
+
+ if (keys >= 2)
+ {
+ msg_print("The moon-letters on the map show you "
+ "the keyhole! You use the key to enter.");
+ out->allow = TRUE;
+ }
+ else
+ {
+ msg_print("You have found a door, but you cannot "
+ "find a way to enter. Ask in Dale, perhaps?");
+ out->allow = FALSE;
+ }
+ }
+
+ return FALSE;
+}
+
+/*
+ * Orthanc requires a key.
+ */
+static bool_ orthanc_stair(void *data, void *in_, void *out_)
+{
+ hook_stair_in *in = (hook_stair_in *) in_;
+ hook_stair_out *out = (hook_stair_out *) out_;
+
+ if ((dungeon_type == 36) &&
+ (dun_level == 39) &&
+ (in->direction == STAIRS_DOWN))
+ {
+ int i, keys;
+
+ keys = 0;
+ for (i = 0; i < INVEN_TOTAL - 1; i++)
+ {
+ if (p_ptr->inventory[i].name1 == 15)
+ {
+ keys += 1;
+ }
+ }
+
+ if (keys >= 1)
+ {
+ msg_print("#BYou have the key to the tower of Orthanc! You may proceed.#w");
+ out->allow = TRUE;
+ }
+ 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...");
+ out->allow = FALSE;
+ }
+ }
+
+ return FALSE;
+}
+
+/*
+ * Movement from Theme
+ */
+static bool_ theme_push_past(void *data, void *in_, void *out_)
+{
+ hook_move_in *p = (hook_move_in *) in_;
+ cave_type *c_ptr = &cave[p->y][p->x];
+
+ if (c_ptr->m_idx > 0)
+ {
+ monster_type *m_ptr = &m_list[c_ptr->m_idx];
+ auto const mr_ptr = m_ptr->race();
+
+ if (m_ptr->status >= MSTATUS_NEUTRAL)
+ {
+ if (cave_floor_bold(p->y, p->x) ||
+ (mr_ptr->flags2 == RF2_PASS_WALL))
+ {
+ char buf[128];
+
+ monster_desc(buf, m_ptr, 0);
+ msg_print(format("You push past %s.", buf));
+
+ 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;
+ }
+ else
+ {
+ char buf[128];
+
+ monster_desc(buf, m_ptr, 0);
+ msg_print(format("%s is in your way!", buf));
+ energy_use = 0;
+
+ return TRUE;
+ }
+ }
+ }
+
+ return FALSE;
+}
+
+/*
+ * Check if monster race is in list. The list is terminated
+ * with a -1.
+ */
+static bool_ race_in_list(int r_idx, int race_idxs[])
+{
+ int i;
+
+ for (i = 0; race_idxs[i] >= 0; i++)
+ {
+ if (r_idx == race_idxs[i])
+ {
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+/*
+ * Monster racial alignment from Theme.
+ */
+s16b *theme_race_status(int r_idx)
+{
+ static s16b FRIEND_ = MSTATUS_FRIEND;
+ static s16b *FRIEND = &FRIEND_;
+ static s16b NEUTRAL_ = MSTATUS_NEUTRAL;
+ static s16b *NEUTRAL = &NEUTRAL_;
+
+ object_type *o_ptr = NULL;
+
+ switch (p_ptr->prace)
+ {
+ case RACE_MAIA:
+ {
+ int good_race_idxs[] = {
+ 25, 29, 45, 97, 109,
+ 147, 225, 335, 346, 443,
+ 581, 629, 699, 853, 984,
+ 1007, 1017, -1
+ };
+
+ if (!(player_has_corruption(CORRUPT_BALROG_AURA)) &&
+ !(player_has_corruption(CORRUPT_BALROG_WINGS)) &&
+ !(player_has_corruption(CORRUPT_BALROG_STRENGTH)) &&
+ !(player_has_corruption(CORRUPT_BALROG_FORM)) &&
+ race_in_list(r_idx, good_race_idxs))
+ {
+ /* Good beings (except swans, GWoPs, Wyrm
+ * Spirits, and some joke uniques) are
+ * coaligned with Maiar */
+ return FRIEND;
+ }
+
+ break;
+ }
+
+ case RACE_HUMAN:
+ case RACE_DUNADAN:
+ case RACE_DRUADAN:
+ case RACE_ROHANKNIGHT:
+ {
+ int nonevil_humanoid_race_idxs[] = {
+ 43, 45, 46, 83, 93,
+ 97, 109, 110, 142, 147,
+ 216, 225, 293, 345, 346,
+ 693, 699, 937, 988, 997,
+ 998, 1000, -1
+ };
+
+ if (race_in_list(r_idx, nonevil_humanoid_race_idxs))
+ {
+ return NEUTRAL;
+ }
+
+ break;
+ }
+
+ case RACE_ELF:
+ case RACE_HOBBIT:
+ case RACE_WOOD_ELF:
+ {
+ int nonevil_sentient_race_idxs[] = {
+ 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, -1
+ };
+
+ if (race_in_list(r_idx, nonevil_sentient_race_idxs))
+ {
+ return NEUTRAL;
+ }
+
+ break;
+ }
+
+ case RACE_GNOME:
+ {
+ int gnomish_race_idxs[] = {
+ 103, 281, 680, 984, 1001,
+ 1003, 1007, 1011, 1014, 1016,
+ -1
+ };
+
+ if (race_in_list(r_idx, gnomish_race_idxs))
+ {
+ return NEUTRAL;
+ }
+
+ break;
+ }
+
+ case RACE_DWARF:
+ case RACE_PETTY_DWARF:
+ {
+ int dwarvish_race_idxs[] = {
+ 111, 112, 179, 180, 181,
+ 182, -1
+ };
+
+ if (race_in_list(r_idx, dwarvish_race_idxs))
+ {
+ return NEUTRAL;
+ }
+
+ break;
+ }
+
+ case RACE_ORC:
+ {
+ int low_orc_race_idxs[] = {
+ 87, 118, 126, 149, 244,
+ 251, 264, -1
+ };
+
+ if ((p_ptr->pgod == GOD_MELKOR) &&
+ race_in_list(r_idx, low_orc_race_idxs))
+ {
+ return FRIEND;
+ }
+
+ break;
+ }
+
+ case RACE_TROLL:
+ {
+ int low_troll_race_idxs[] = {
+ 297, 401, 403, 424, 454,
+ 491, 496, 509, 538, -1
+ };
+
+ if ((p_ptr->pgod == GOD_MELKOR) &&
+ race_in_list(r_idx, low_troll_race_idxs))
+ {
+ return NEUTRAL;
+ }
+
+ break;
+ }
+
+ case RACE_HALF_OGRE:
+ {
+ int ogre_race_idxs[] = {
+ 262, 285, 415, 430, 479,
+ 745, 918, -1
+ };
+
+ if (race_in_list(r_idx, ogre_race_idxs))
+ {
+ return NEUTRAL;
+ }
+
+ break;
+ }
+
+ case RACE_BEORNING:
+ {
+ /* Bears; not werebears. */
+ int bear_race_idxs[] = {
+ 160, 173, 191, 854,
+ 855, 867, 873, -1
+ };
+
+ if (race_in_list(r_idx, bear_race_idxs))
+ {
+ return NEUTRAL;
+ }
+
+ break;
+ }
+
+ case RACE_DARK_ELF:
+ {
+ int dark_elven_race_idxs[] = {
+ 122, 178, 183, 226, 348,
+ 375, 400, 657, -1
+ };
+
+ if (race_in_list(r_idx, dark_elven_race_idxs))
+ {
+ return FRIEND;
+ }
+
+ break;
+ }
+
+ case RACE_ENT:
+ {
+ int plant_race_idxs[] = {
+ 248, 266, 317, 329, 396,
+ -1
+ };
+
+ if (race_in_list(r_idx, plant_race_idxs))
+ {
+ return FRIEND;
+ }
+
+ /* 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. */
+
+ if (p_ptr->pgod == GOD_YAVANNA)
+ {
+ int lower_animal_race_idxs[] = {
+ 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, -1
+ };
+
+ if (race_in_list(r_idx, lower_animal_race_idxs))
+ {
+ return FRIEND;
+ }
+ }
+
+ break;
+ }
+
+ case RACE_EAGLE:
+ {
+ int nonevil_nonneurtal_bird_race_idxs[] = {
+ 61, 141, 151, 279, -1
+ };
+
+ if (race_in_list(r_idx, nonevil_nonneurtal_bird_race_idxs))
+ {
+ return FRIEND;
+ }
+
+ break;
+ }
+
+ case RACE_DRAGON:
+ {
+ int hatchling_dragon_race_idxs[] = {
+ 163, 164, 165, 166, 167,
+ 204, 218, 219, 911, -1
+ };
+
+ if (race_in_list(r_idx, hatchling_dragon_race_idxs))
+ {
+ return FRIEND;
+ }
+
+ break;
+ }
+
+ case RACE_YEEK:
+ {
+ int yeek_race_idxs[] = {
+ 580, 583, 594, 653, 655,
+ 659, 661, -1
+ };
+
+ if (race_in_list(r_idx, yeek_race_idxs))
+ {
+ return NEUTRAL;
+ }
+
+ break;
+ }
+
+ };
+
+ /* 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. */
+ o_ptr = get_object(INVEN_WIELD);
+ if (o_ptr != NULL &&
+ o_ptr->name1 == ART_ANDURIL)
+ {
+ switch (p_ptr->prace)
+ {
+ case RACE_HUMAN:
+ case RACE_HALF_ELF:
+ case RACE_ELF:
+ case RACE_HOBBIT:
+ case RACE_GNOME:
+ case RACE_DWARF:
+ case RACE_ORC:
+ case RACE_TROLL:
+ case RACE_DUNADAN:
+ case RACE_HIGH_ELF:
+ case RACE_HALF_OGRE:
+ case RACE_BEORNING:
+ case RACE_DRUADAN:
+ case RACE_PETTY_DWARF:
+ case RACE_DARK_ELF:
+ case RACE_ENT:
+ case RACE_ROHANKNIGHT:
+ case RACE_YEEK:
+ case RACE_WOOD_ELF:
+ case RACE_MAIA:
+ case RACE_EASTERLING:
+ case RACE_DEMON:
+ {
+ int oathbreaker_race_idxs[] = {
+ 731, -1
+ };
+
+ if (race_in_list(r_idx, oathbreaker_race_idxs))
+ {
+ return FRIEND;
+ }
+
+ break;
+ }
+ }
+ }
+
+ /* No status override */
+ return NULL;
+}
+
+static bool_ theme_level_end_gen(void *data, void *in, void *out)
+{
+ int i = 0;
+
+ for (i = 0; i < m_max; i++)
+ {
+ monster_type *m_ptr = &m_list[i];
+ int r_idx = m_ptr->r_idx;
+ s16b *status = theme_race_status(r_idx);
+ if (status)
+ {
+ m_ptr->status = *status;
+ }
+ }
+
+ return FALSE;
+}
+
+static bool_ theme_new_monster_end(void *data, void *in_, void *out)
+{
+ hook_new_monster_end_in *in = (hook_new_monster_end_in *) in_;
+ s16b *status = theme_race_status(in->m_ptr->r_idx);
+
+ if (status)
+ {
+ in->m_ptr->status = *status;
+ }
+
+ return FALSE;
+}
+
+void init_hooks_module()
+{
+ /*
+ * Common hooks
+ */
+ add_hook_new(HOOK_GIVE,
+ drunk_takes_wine,
+ "drunk_takes_wine",
+ NULL);
+
+ add_hook_new(HOOK_LEVEL_END_GEN,
+ gen_joke_monsters,
+ "gen_joke_monsters",
+ NULL);
+
+ /*
+ * Module-specific hooks
+ */
+ switch (game_module_idx)
+ {
+ case MODULE_TOME:
+ {
+ break;
+ }
+
+ case MODULE_THEME:
+ {
+ timer_aggravate_evil_enable();
+
+ add_hook_new(HOOK_PLAYER_LEVEL,
+ auto_stat_gain_hook,
+ "auto_stat_gain",
+ NULL);
+
+ add_hook_new(HOOK_GIVE,
+ hobbit_food,
+ "hobbit_food",
+ NULL);
+
+ add_hook_new(HOOK_GIVE,
+ smeagol_ring,
+ "smeagol_ring",
+ NULL);
+
+ add_hook_new(HOOK_EAT,
+ longbottom_leaf,
+ "longbottom_leaf",
+ NULL);
+
+ add_hook_new(HOOK_EAT,
+ food_vessel,
+ "food_vessel",
+ NULL);
+
+ add_hook_new(HOOK_STAIR,
+ erebor_stair,
+ "erebor_stair",
+ NULL);
+
+ add_hook_new(HOOK_STAIR,
+ orthanc_stair,
+ "orthanc_stair",
+ NULL);
+
+ add_hook_new(HOOK_MOVE,
+ theme_push_past,
+ "__hook_push_past",
+ NULL);
+
+ add_hook_new(HOOK_LEVEL_END_GEN,
+ theme_level_end_gen,
+ "theme_level_end_gen",
+ NULL);
+
+ add_hook_new(HOOK_NEW_MONSTER_END,
+ theme_new_monster_end,
+ "theme_new_monster_end",
+ NULL);
+
+ break;
+ }
+
+ default:
+ assert(FALSE);
+ }
+}
diff --git a/src/modules.h b/src/modules.h
new file mode 100644
index 00000000..8a3b88b0
--- /dev/null
+++ b/src/modules.h
@@ -0,0 +1,15 @@
+#pragma once
+
+#include "h-basic.h"
+
+// C linkage required for these functions since main-* code uses them.
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern bool_ private_check_user_directory(cptr dirpath);
+extern cptr force_module;
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
diff --git a/src/modules.hpp b/src/modules.hpp
new file mode 100644
index 00000000..d83e3e2e
--- /dev/null
+++ b/src/modules.hpp
@@ -0,0 +1,11 @@
+#pragma once
+
+#include "h-basic.h"
+
+extern bool_ select_module(void);
+extern bool_ module_savefile_loadable(cptr savefile_mod);
+extern void tome_intro();
+extern void theme_intro();
+extern s16b *theme_race_status(int r_idx);
+extern void init_hooks_module();
+extern int find_module(cptr name);
diff --git a/src/monster.pkg b/src/monster.pkg
deleted file mode 100644
index a9efd089..00000000
--- a/src/monster.pkg
+++ /dev/null
@@ -1,2324 +0,0 @@
-/* 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
deleted file mode 100644
index 196272ce..00000000
--- a/src/monster1.c
+++ /dev/null
@@ -1,1908 +0,0 @@
-/* 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/monster1.cc b/src/monster1.cc
new file mode 100644
index 00000000..4e3e2c42
--- /dev/null
+++ b/src/monster1.cc
@@ -0,0 +1,1887 @@
+/*
+ * 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 "monster1.hpp"
+
+#include "cave_type.hpp"
+#include "monster2.hpp"
+#include "monster_ego.hpp"
+#include "monster_race.hpp"
+#include "player_type.hpp"
+#include "util.hpp"
+#include "variable.hpp"
+#include "wilderness_map.hpp"
+#include "wilderness_type_info.hpp"
+
+/*
+ * 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(std::shared_ptr<monster_race const> r_ptr)
+{
+ 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(std::shared_ptr<monster_race const> r_ptr, int i)
+{
+ 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(std::shared_ptr<monster_race> r_ptr, int remem)
+{
+ 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;
+
+ /* 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);
+ }
+
+
+ /* Treat uniques differently */
+ 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 */
+ {
+ char buf[2048];
+
+ /* Simple method */
+ strcpy(buf, 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]));
+
+ 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 = static_cast<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 = (((static_cast<long>(r_ptr->mexp) * r_ptr->level % p_ptr->lev) *
+ 1000L / p_ptr->lev + 5) / 10);
+
+ /* Mention the experience */
+ text_out(" is worth ");
+ text_out_c(TERM_ORANGE, format("%ld.%02ld", i, 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, 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_ptr))
+ {
+ /* 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 (((static_cast<int>(r_ptr->r_wake) * static_cast<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_ptr, 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 */
+ *r_ptr = save_mem;
+ }
+}
+
+/*
+ * Hack -- Display the "name" and "attr/chars" of a monster race
+ */
+static void roff_name(int r_idx, int ego)
+{
+ const auto r_ptr = race_info_idx(r_idx, ego);
+
+ /* Access the chars */
+ const char c1 = r_ptr->d_char;
+ const char c2 = r_ptr->x_char;
+
+ /* Access the attrs */
+ const byte a1 = r_ptr->d_attr;
+ const byte 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_info[ego].name, r_ptr->name));
+ }
+ else
+ {
+ Term_addstr( -1, TERM_WHITE, format("%s %s", r_ptr->name, re_info[ego].name));
+ }
+ }
+ else
+ {
+ Term_addstr( -1, TERM_WHITE, r_ptr->name);
+ }
+
+ /* Append the "standard" attr/char info */
+ Term_addstr( -1, TERM_WHITE, " ('");
+ Term_addch(a1, c1);
+ Term_addstr( -1, TERM_WHITE, "')");
+
+ /* Append the "optional" attr/char info */
+ Term_addstr( -1, TERM_WHITE, "/('");
+ Term_addch(a2, c2);
+ 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)
+{
+ auto r_ptr = race_info_idx(r_idx, ego);
+
+ /* Flush messages */
+ msg_print(NULL);
+
+ /* Begin recall */
+ Term_erase(0, 1, 255);
+
+ /* Recall monster */
+ roff_aux(r_ptr, remember);
+
+ /* Describe monster */
+ roff_top(r_idx, ego);
+}
+
+/*
+ * Describe the given monster race at the current pos of the "term" window
+ */
+void monster_description_out(int r_idx, int ego)
+{
+ auto r_ptr = race_info_idx(r_idx, ego);
+ roff_name(r_idx, ego);
+ roff_aux(r_ptr, 0);
+}
+
+/*
+ * Hack -- describe the given monster race in the current "term" window
+ */
+void display_roff(int r_idx, int ego)
+{
+ int y;
+ int hgt;
+ Term_get_size(nullptr, &hgt);
+
+ /* Erase the window */
+ for (y = 0; y < hgt; y++)
+ {
+ /* Erase the line */
+ Term_erase(0, y, 255);
+ }
+
+ /* Begin recall */
+ Term_gotoxy(0, 1);
+
+ /* Recall monster */
+ auto r_ptr = race_info_idx(r_idx, ego);
+ roff_aux(r_ptr, 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;
+}
+
+
+static 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;
+}
+
+
+static 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;
+}
+
+
+static 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;
+}
+
+
+static 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;
+}
+
+
+static 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;
+}
+
+
+static 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;
+}
+
+
+static 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;
+}
+
+
+static 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;
+}
+
+
+static 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;
+}
+
+
+static 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;
+}
+
+
+static 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, std::shared_ptr<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/monster1.hpp b/src/monster1.hpp
new file mode 100644
index 00000000..1d71fef1
--- /dev/null
+++ b/src/monster1.hpp
@@ -0,0 +1,5 @@
+#pragma once
+
+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);
diff --git a/src/monster2.c b/src/monster2.c
deleted file mode 100644
index b0753244..00000000
--- a/src/monster2.c
+++ /dev/null
@@ -1,4054 +0,0 @@
-/* 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/monster2.cc b/src/monster2.cc
new file mode 100644
index 00000000..3debb27a
--- /dev/null
+++ b/src/monster2.cc
@@ -0,0 +1,3985 @@
+/*
+ * 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 "monster2.hpp"
+
+#include "alloc_entry.hpp"
+#include "artifact_type.hpp"
+#include "cave.hpp"
+#include "cave_type.hpp"
+#include "dungeon_info_type.hpp"
+#include "files.hpp"
+#include "hook_new_monster_in.hpp"
+#include "hook_new_monster_end_in.hpp"
+#include "hooks.hpp"
+#include "levels.hpp"
+#include "mimic.hpp"
+#include "monster3.hpp"
+#include "monster_ego.hpp"
+#include "monster_race.hpp"
+#include "monster_type.hpp"
+#include "object1.hpp"
+#include "object2.hpp"
+#include "object_kind.hpp"
+#include "object_type.hpp"
+#include "options.hpp"
+#include "player_type.hpp"
+#include "randart.hpp"
+#include "spells1.hpp"
+#include "spells2.hpp"
+#include "stats.hpp"
+#include "tables.hpp"
+#include "util.hpp"
+#include "variable.hpp"
+#include "wilderness_map.hpp"
+#include "xtra1.hpp"
+#include "xtra2.hpp"
+#include "z-rand.hpp"
+
+#include <algorithm>
+#include <string>
+
+#define MAX_HORROR 20
+#define MAX_FUNNY 22
+#define MAX_COMMENT 5
+
+#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)
+
+s32b monster_exp(s16b level)
+{
+ s32b capped_level = std::min(level, static_cast<s16b>(MONSTER_LEVEL_MAX));
+ return (capped_level * capped_level * capped_level * 6);
+}
+
+/* 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 >= 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(monster_race const *r_ptr, int ego)
+{
+ monster_ego *re_ptr = &re_info[ego];
+ 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 */
+static int pick_ego_monster(monster_race const *r_ptr)
+{
+ /* 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_ptr->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_ptr, ego)) continue;
+
+ /* Not too much OoD */
+ lvl = r_ptr->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_ptr, 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
+ */
+std::shared_ptr<monster_race> race_info_idx(int r_idx, int ego)
+{
+ monster_race *r_ptr = &r_info[r_idx];
+
+ /* We don't need to allocate anything if it's an ordinary monster. */
+ if (!ego) {
+ return std::shared_ptr<monster_race>(r_ptr, [](monster_race *) {
+ // No need to delete -- will be freed when the r_info array is freed.
+ });
+ }
+
+ /* We allocate a copy of the "base" monster race to refer to. */
+ auto nr_ptr = std::make_shared<monster_race>();
+ *nr_ptr = *r_ptr;
+
+ /* Get a reference to the ego monster modifiers */
+ monster_ego *re_ptr = &re_info[ego];
+
+ /* Adjust the values */
+ for (int i = 0; i < 4; i++)
+ {
+ s32b 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;
+
+ s32b 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!"
+};
+
+
+/*
+ * Delete a monster by index.
+ *
+ * When a monster is deleted, all of its objects are deleted.
+ */
+void delete_monster_idx(int i)
+{
+ /* Get location */
+ monster_type *m_ptr = &m_list[i];
+ int y = m_ptr->fy;
+ int x = m_ptr->fx;
+
+ /* Hack -- Reduce the racial counter */
+ auto const r_ptr = m_ptr->race();
+ 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 */
+ bool_ had_lite = FALSE;
+ 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 (int 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;
+
+ /* Copy list of objects; need a copy since we're
+ * manipulating the list itself below. */
+ auto const object_idxs(m_ptr->hold_o_idxs);
+
+ /* Delete objects */
+ for (auto const this_o_idx: object_idxs)
+ {
+ /* Acquire object */
+ object_type *o_ptr = &o_list[this_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);
+ }
+
+ /* Wipe the Monster */
+ m_ptr->wipe();
+
+ /* 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)
+{
+ /* Do nothing */
+ if (i1 == i2) return;
+
+ /* Old monster */
+ monster_type *m_ptr = &m_list[i1];
+
+ /* Location */
+ int y = m_ptr->fy;
+ int x = m_ptr->fx;
+
+ /* Cave grid */
+ cave_type *c_ptr = &cave[y][x];
+
+ /* Update the cave */
+ c_ptr->m_idx = i2;
+
+ /* Repair objects being carried by monster */
+ for (auto const this_o_idx: m_ptr->hold_o_idxs)
+ {
+ /* Acquire object */
+ object_type *o_ptr = &o_list[this_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 (int 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 */
+ m_list[i2] = m_list[i1];
+
+ /* Wipe the hole */
+ m_list[i1].wipe();
+}
+
+
+/*
+ * 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];
+ auto const r_ptr = m_ptr->race();
+
+ /* 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];
+
+ /* Skip dead monsters */
+ if (!m_ptr->r_idx) continue;
+
+ /* Mega-Hack -- preserve Unique's XXX XXX XXX */
+
+ /* Hack -- Reduce the racial counter */
+ auto r_ptr = m_ptr->race();
+ r_ptr->cur_num--;
+
+ /* Monster is gone */
+ cave[m_ptr->fy][m_ptr->fx].m_idx = 0;
+
+ /* Wipe the Monster */
+ m_ptr->wipe();
+ }
+
+ /* 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)
+{
+ auto r_ptr = m_ptr->race();
+ 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_info[m_ptr->ego].name, r_ptr->name);
+ }
+ else
+ {
+ sprintf(name, "%s %s", r_ptr->name, re_info[m_ptr->ego].name);
+ }
+ }
+ else
+ {
+ sprintf(name, "%s", r_ptr->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, 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 */
+ cptr 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];
+ char name[80];
+
+ if (ego)
+ {
+ if (re_info[ego].before)
+ {
+ sprintf(name, "%s %s", re_info[ego].name, r_ptr->name);
+ }
+ else
+ {
+ sprintf(name, "%s %s", r_ptr->name, re_info[ego].name);
+ }
+ }
+ else
+ {
+ sprintf(name, "%s", r_ptr->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);
+ }
+}
+
+
+
+static void sanity_blast(monster_type * m_ptr, bool_ necro)
+{
+ bool_ happened = FALSE;
+ int power = 100;
+
+ if (!necro)
+ {
+ if (m_ptr == nullptr) {
+ return;
+ }
+
+ auto const r_ptr = m_ptr->race();
+
+ power = (m_ptr->level) + 10;
+
+ if (m_ptr != NULL)
+ {
+ char m_name[80];
+ 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 ((race_flags1_p(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(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];
+
+ /* The current monster location */
+ const int fy = m_ptr->fy;
+ const int fx = m_ptr->fx;
+
+ const 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;
+
+ auto const r_ptr = m_ptr->race();
+
+ /* Calculate distance */
+ if (full)
+ {
+ /* Distance components */
+ const int dy = (p_ptr->py > fy) ? (p_ptr->py - fy) : (fy - p_ptr->py);
+ const int dx = (p_ptr->px > fx) ? (p_ptr->px - fx) : (fx - p_ptr->px);
+
+ /* Approximate distance */
+ const int 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_FRAME);
+
+ /* 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);
+ }
+ }
+
+ /* 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_FRAME);
+
+ /* 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);
+ }
+ }
+ }
+
+
+ /* 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);
+ }
+
+ }
+ }
+
+ /* 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);
+ }
+ }
+ }
+}
+
+
+
+
+/*
+ * 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->held_m_idx = m_idx;
+ o_ptr->ix = 0;
+ o_ptr->iy = 0;
+
+ m_ptr->hold_o_idxs.push_back(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;
+static int place_monster_result = 0;
+bool_ place_monster_one_no_drop = FALSE;
+static s16b hack_m_idx_ii = 0;
+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;
+
+ /* DO NOT PLACE A MONSTER IN THE SMALL SCALE WILDERNESS !!! */
+ if (p_ptr->wild_mode)
+ {
+ return 0;
+ }
+
+ /* Verify location */
+ if (!in_bounds(y, x))
+ {
+ 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);
+ 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);
+ return 0;
+ }
+
+ /* Hack -- no creation on glyph of warding */
+ if (cave[y][x].feat == FEAT_GLYPH)
+ {
+ return 0;
+ }
+ if (cave[y][x].feat == FEAT_MINOR_GLYPH)
+ {
+ return 0;
+ }
+
+ /* Nor on the between */
+ if (cave[y][x].feat == FEAT_BETWEEN)
+ {
+ return 0;
+ }
+
+ /* Nor on the altars */
+ if ((cave[y][x].feat >= FEAT_ALTAR_HEAD)
+ && (cave[y][x].feat <= FEAT_ALTAR_TAIL))
+ {
+ return 0;
+ }
+
+ /* Nor on the Pattern */
+ if ((cave[y][x].feat >= FEAT_PATTERN_START)
+ && (cave[y][x].feat <= FEAT_PATTERN_XTRA2))
+ {
+ return 0;
+ }
+
+ /* Paranoia */
+ if (!r_idx)
+ {
+ return 0;
+ }
+
+ /* Check for original monster race flags */
+ {
+ monster_race *r_ptr = &r_info[r_idx];
+
+ /* Paranoia */
+ if (!r_ptr->name)
+ {
+ return 0;
+ }
+
+ /* Are we allowed to continue ? */
+ {
+ struct hook_new_monster_in in = { r_idx };
+ if (process_hooks_new(HOOK_NEW_MONSTER, &in, NULL))
+ {
+ return 0;
+ }
+ }
+
+ /* Ego Uniques are NOT to be created */
+ if ((r_ptr->flags1 & RF1_UNIQUE) && ego)
+ {
+ return 0;
+ }
+ }
+
+ /* Now could we generate an Ego Monster */
+ /* Grab the special race if needed */
+ auto 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");
+ 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);
+ 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);
+ return 0;
+ }
+
+ /* Fully forbid it */
+ if (r_ptr->flags9 & RF9_NEVER_GENE)
+ {
+ if (wizard) cmsg_print(TERM_L_RED, "WARNING: Refused monster: NEVER_GENE");
+ 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);
+ 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");
+ 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);
+ 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");
+ 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).", r_ptr->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).", r_ptr->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).", r_ptr->name);
+ }
+
+
+ /* Access the location */
+ cave_type *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)
+ {
+ return 0;
+ }
+
+
+ /* Get a new monster record */
+ monster_type *m_ptr = &m_list[c_ptr->m_idx];
+
+ /* Save the race */
+ m_ptr->r_idx = r_idx;
+ m_ptr->ego = ego;
+
+ /* 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_idxs.clear();
+
+ 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))
+ {
+ const bool_ good = (r_ptr->flags1 & (RF1_DROP_GOOD)) ? TRUE : FALSE;
+ const bool_ great = (r_ptr->flags1 & (RF1_DROP_GREAT)) ? TRUE : FALSE;
+
+ const bool_ do_gold = (!(r_ptr->flags1 & (RF1_ONLY_ITEM)));
+ const bool_ do_item = (!(r_ptr->flags1 & (RF1_ONLY_GOLD)));
+ const bool_ do_mimic = (r_ptr->flags9 & (RF9_MIMIC));
+
+ const 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;
+
+ /* 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();
+
+ int 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 (int 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;
+
+ /* Count monsters on the level */
+ {
+ /* Hack -- we need to modify the REAL r_info, not the fake one */
+ monster_race *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;
+ }
+
+ /* Processs hooks */
+ {
+ hook_new_monster_end_in in = { m_ptr };
+ process_hooks_new(HOOK_NEW_MONSTER_END, &in, 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_ptr), 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_ptr), 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(&r_info[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);
+}
+
+
+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;
+}
+
+/*
+ * 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);
+ }
+
+
+ if (randint(5000) <= dun_level)
+ {
+ if (alloc_horde(y, x))
+ {
+ if ((cheat_hear) || (p_ptr->precognition)) msg_print("Monster horde.");
+ return (TRUE);
+ }
+ }
+ else
+ {
+
+ /* Attempt to place the monster, allow groups */
+ if (place_monster(y, x, slp, TRUE)) return (TRUE);
+
+ }
+
+ /* 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
+ */
+static 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_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_ptr->name, "Phantom")) &&
+ !(r_ptr->flags1 & (RF1_UNIQUE)));
+ break;
+ }
+
+ case SUMMON_ELEMENTAL:
+ {
+ okay = ((strstr(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_ptr->name, "lue horror")) &&
+ !(r_ptr->flags1 & (RF1_UNIQUE)));
+ break;
+ }
+
+ case SUMMON_BUG:
+ {
+ okay = ((strstr(r_ptr->name, "Software bug")) &&
+ !(r_ptr->flags1 & (RF1_UNIQUE)));
+ break;
+ }
+
+ case SUMMON_RNG:
+ {
+ okay = ((strstr(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;
+ }
+
+ }
+
+ /* 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;
+
+ /* 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);
+
+ /* 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];
+ auto const r_ptr = m_ptr->race();
+
+ bool_ result = FALSE;
+
+ if (no_breeds)
+ {
+ msg_print("It tries to breed but it fails!");
+ return FALSE;
+ }
+
+ /* Try up to 18 times */
+ for (int i = 0; i < 18; i++)
+ {
+ /* Pick a location */
+ int x;
+ int y;
+ scatter(&y, &x, m_ptr->fy, m_ptr->fx, 1);
+
+ /* Require an "empty" floor grid */
+ if (!cave_empty_bold(y, x)) continue;
+
+ int 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 message, cptr name)
+{
+ std::string buf;
+ buf += name;
+ buf += " ";
+ buf += message;
+
+ if (hack_message_pain_may_silent)
+ {
+ monster_msg_simple(buf.c_str());
+ }
+ else
+ {
+ msg_print(buf.c_str());
+ }
+}
+
+void message_pain(int m_idx, int dam)
+{
+ monster_type *m_ptr = &m_list[m_idx];
+
+ /* Get the monster name */
+ char m_name[80];
+ monster_desc(m_name, m_ptr, 0);
+ capitalize(m_name);
+
+ /* Notice non-damage */
+ if (dam == 0)
+ {
+ message_pain_hook("is unharmed.", m_name);
+ return;
+ }
+
+ /* Note -- subtle fix -CFT */
+ long newhp = (long)(m_ptr->hp);
+ long oldhp = newhp + (long)(dam);
+ long tmp = (newhp * 100L) / oldhp;
+ int percentage = (int)(tmp);
+
+ /* Get racial information */
+ auto const r_ptr = m_ptr->race();
+
+ /* Jelly's, Mold's, Vortex's, Quthl's */
+ if (strchr("jmvQ", r_ptr->d_char))
+ {
+ if (percentage > 95)
+ message_pain_hook("barely notices.", m_name);
+ else if (percentage > 75)
+ message_pain_hook("flinches.", m_name);
+ else if (percentage > 50)
+ message_pain_hook("squelches.", m_name);
+ else if (percentage > 35)
+ message_pain_hook("quivers in pain.", m_name);
+ else if (percentage > 20)
+ message_pain_hook("writhes about.", m_name);
+ else if (percentage > 10)
+ message_pain_hook("writhes in agony.", m_name);
+ else
+ message_pain_hook("jerks limply.", m_name);
+ }
+
+ /* Dogs and Hounds */
+ else if (strchr("CZ", r_ptr->d_char))
+ {
+ if (percentage > 95)
+ message_pain_hook("shrugs off the attack.", m_name);
+ else if (percentage > 75)
+ message_pain_hook("snarls with pain.", m_name);
+ else if (percentage > 50)
+ message_pain_hook("yelps in pain.", m_name);
+ else if (percentage > 35)
+ message_pain_hook("howls in pain.", m_name);
+ else if (percentage > 20)
+ message_pain_hook("howls in agony.", m_name);
+ else if (percentage > 10)
+ message_pain_hook("writhes in agony.", m_name);
+ else
+ message_pain_hook("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("ignores the attack.", m_name);
+ else if (percentage > 75)
+ message_pain_hook("grunts with pain.", m_name);
+ else if (percentage > 50)
+ message_pain_hook("squeals in pain.", m_name);
+ else if (percentage > 35)
+ message_pain_hook("shrieks in pain.", m_name);
+ else if (percentage > 20)
+ message_pain_hook("shrieks in agony.", m_name);
+ else if (percentage > 10)
+ message_pain_hook("writhes in agony.", m_name);
+ else
+ message_pain_hook("cries out feebly.", m_name);
+ }
+
+ /* Another type of monsters (shrug,cry,scream) */
+ else
+ {
+ if (percentage > 95)
+ message_pain_hook("shrugs off the attack.", m_name);
+ else if (percentage > 75)
+ message_pain_hook("grunts with pain.", m_name);
+ else if (percentage > 50)
+ message_pain_hook("cries out in pain.", m_name);
+ else if (percentage > 35)
+ message_pain_hook("screams in pain.", m_name);
+ else if (percentage > 20)
+ message_pain_hook("screams in agony.", m_name);
+ else if (percentage > 10)
+ message_pain_hook("writhes in agony.", m_name);
+ else
+ message_pain_hook("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];
+
+ /* Not allowed to learn */
+ if (!smart_learn) return;
+
+ /* Get racial flags */
+ auto const r_ptr = m_ptr->race();
+
+ /* Too stupid to learn anything */
+ if (r_ptr->flags2 & (RF2_STUPID)) return;
+
+ /* Not intelligent, only learn sometimes */
+ if (!(r_ptr->flags2 & (RF2_SMART)) && magik(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)
+{
+ /* Copy list of objects; we need a copy since
+ we're manipulating the list itself below. */
+ auto const object_idxs(m_ptr->hold_o_idxs);
+
+ /* Drop objects being carried */
+ for (auto const this_o_idx: object_idxs)
+ {
+ /* Acquire object */
+ object_type *o_ptr = &o_list[this_o_idx];
+
+ /* Paranoia */
+ o_ptr->held_m_idx = 0;
+
+ /* Get local object */
+ object_type forge;
+ object_type *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_idxs.clear();
+}
diff --git a/src/monster2.hpp b/src/monster2.hpp
new file mode 100644
index 00000000..84f79e36
--- /dev/null
+++ b/src/monster2.hpp
@@ -0,0 +1,52 @@
+#pragma once
+
+#include "h-basic.h"
+#include "monster_race_fwd.hpp"
+#include "monster_type_fwd.hpp"
+#include "object_type_fwd.hpp"
+#include <memory>
+
+extern s32b monster_exp(s16b level);
+extern void monster_set_level(int m_idx, int level);
+extern s32b modify_aux(s32b a, s32b b, char mod);
+extern void monster_msg_simple(cptr s);
+extern bool_ mego_ok(monster_race const *r_ptr, 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 std::shared_ptr<monster_race> race_info_idx(int r_idx, int ego);
+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 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 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 void set_mon_num_hook(void);
+extern void set_mon_num2_hook(int y, int x);
+extern bool_ monster_can_cross_terrain(byte feat, std::shared_ptr<monster_race> r_ptr);
diff --git a/src/monster3.c b/src/monster3.c
deleted file mode 100644
index a2b5fb38..00000000
--- a/src/monster3.c
+++ /dev/null
@@ -1,706 +0,0 @@
-/* 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/monster3.cc b/src/monster3.cc
new file mode 100644
index 00000000..0d26538c
--- /dev/null
+++ b/src/monster3.cc
@@ -0,0 +1,722 @@
+/*
+ * 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 "monster3.hpp"
+
+#include "cave_type.hpp"
+#include "cmd2.hpp"
+#include "gods.hpp"
+#include "melee2.hpp"
+#include "monster2.hpp"
+#include "monster_race.hpp"
+#include "monster_type.hpp"
+#include "object2.hpp"
+#include "player_type.hpp"
+#include "skills.hpp"
+#include "tables.hpp"
+#include "util.hpp"
+#include "util.h"
+#include "variable.h"
+#include "variable.hpp"
+#include "xtra2.hpp"
+#include "z-rand.hpp"
+
+/*
+ * 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)
+{
+ auto const r_ptr = m_ptr->race();
+
+ /* 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)
+{
+ if (!p_ptr->control) return FALSE;
+ screen_save();
+ prt("Carried items", 0, 0);
+ (void) show_monster_inven(p_ptr->control);
+ inkey();
+ screen_load();
+ return TRUE;
+}
+
+bool_ do_control_pickup(void)
+{
+ if (!p_ptr->control) return FALSE;
+
+ monster_type *m_ptr = &m_list[p_ptr->control];
+
+ cave_type *c_ptr = &cave[m_ptr->fy][m_ptr->fx];
+
+ /* Copy list of all objects in the grid; we need a
+ * copy since we're going to be excising objects
+ * from lists. */
+ auto const object_idxs(c_ptr->o_idxs);
+
+ /* Scan all objects in the grid */
+ bool done = false;
+ for (auto const this_o_idx: object_idxs)
+ {
+ /* Acquire object */
+ object_type *o_ptr = &o_list[this_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;
+
+ /* Carry object */
+ m_ptr->hold_o_idxs.push_back(this_o_idx);
+
+ /* Picked up at least one object */
+ done = true;
+ }
+
+ /* Feedback */
+ 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/monster3.hpp b/src/monster3.hpp
new file mode 100644
index 00000000..7cf8ccd0
--- /dev/null
+++ b/src/monster3.hpp
@@ -0,0 +1,20 @@
+#pragma once
+
+#include "h-basic.h"
+#include "monster_type_fwd.hpp"
+
+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);
diff --git a/src/monster_blow.hpp b/src/monster_blow.hpp
new file mode 100644
index 00000000..0f19f64c
--- /dev/null
+++ b/src/monster_blow.hpp
@@ -0,0 +1,19 @@
+#pragma once
+
+#include "h-basic.h"
+
+/**
+ * Monster blow descriptor.
+ *
+ * - Method (RBM_*)
+ * - Effect (RBE_*)
+ * - Damage Dice
+ * - Damage Sides
+ */
+struct monster_blow
+{
+ byte method;
+ byte effect;
+ byte d_dice;
+ byte d_side;
+};
diff --git a/src/monster_ego.hpp b/src/monster_ego.hpp
new file mode 100644
index 00000000..00464c2e
--- /dev/null
+++ b/src/monster_ego.hpp
@@ -0,0 +1,81 @@
+#pragma once
+
+#include "h-basic.h"
+#include "monster_blow.hpp"
+
+/**
+ * Monster ego descriptors.
+ */
+struct monster_ego
+{
+ const char *name; /* Name */
+ 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 */
+};
diff --git a/src/monster_ego_fwd.hpp b/src/monster_ego_fwd.hpp
new file mode 100644
index 00000000..5b47f3e9
--- /dev/null
+++ b/src/monster_ego_fwd.hpp
@@ -0,0 +1,3 @@
+#pragma once
+
+struct monster_ego;
diff --git a/src/monster_power.hpp b/src/monster_power.hpp
new file mode 100644
index 00000000..03d0f8a9
--- /dev/null
+++ b/src/monster_power.hpp
@@ -0,0 +1,14 @@
+#pragma once
+
+#include "h-basic.h"
+
+/**
+ * Monster powers that players can use via e.g. Symbiosis.
+ */
+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 */
+};
diff --git a/src/monster_race.hpp b/src/monster_race.hpp
new file mode 100644
index 00000000..7e5d5082
--- /dev/null
+++ b/src/monster_race.hpp
@@ -0,0 +1,116 @@
+#pragma once
+
+#include "body.hpp"
+#include "h-basic.h"
+#include "monster_blow.hpp"
+#include "obj_theme.hpp"
+
+/**
+ * Monster race descriptors and runtime data, 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.
+ */
+struct monster_race
+{
+ const char *name; /* Name */
+ char *text; /* Text */
+
+ 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 */
+};
+
+
diff --git a/src/monster_race_fwd.hpp b/src/monster_race_fwd.hpp
new file mode 100644
index 00000000..9ee9658a
--- /dev/null
+++ b/src/monster_race_fwd.hpp
@@ -0,0 +1,3 @@
+#pragma once
+
+struct monster_race;
diff --git a/src/monster_type.cc b/src/monster_type.cc
new file mode 100644
index 00000000..5731e430
--- /dev/null
+++ b/src/monster_type.cc
@@ -0,0 +1,8 @@
+#include "monster_type_fwd.hpp"
+#include "monster_type.hpp"
+#include "monster2.hpp"
+
+std::shared_ptr<monster_race> monster_type::race() const
+{
+ return race_info_idx(r_idx, ego);
+}
diff --git a/src/monster_type.hpp b/src/monster_type.hpp
new file mode 100644
index 00000000..8353f228
--- /dev/null
+++ b/src/monster_type.hpp
@@ -0,0 +1,98 @@
+#pragma once
+
+#include "h-basic.h"
+#include "monster_blow.hpp"
+#include "monster_race_fwd.hpp"
+
+#include <cassert>
+#include <vector>
+#include <memory>
+
+/**
+ * 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).
+ */
+struct monster_type
+{
+ s16b r_idx = 0; /* Monster race index */
+
+ u16b ego = 0; /* Ego monster type */
+
+ byte fy = 0; /* Y location on map */
+ byte fx = 0; /* X location on map */
+
+ s32b hp = 0; /* Current Hit points */
+ s32b maxhp = 0; /* Max Hit points */
+
+ monster_blow blow[4] = { /* Up to four blows per round */
+ { 0, 0, 0, 0 },
+ { 0, 0, 0, 0 },
+ { 0, 0, 0, 0 },
+ { 0, 0, 0, 0 },
+ };
+
+ byte speed = 0; /* Speed (normally 110) */
+ byte level = 0; /* Level of creature */
+ s16b ac = 0; /* Armour Class */
+ s32b exp = 0; /* Experience */
+
+ s16b csleep = 0; /* Inactive counter */
+
+ byte mspeed = 0; /* Monster "speed" */
+ byte energy = 0; /* Monster "energy" */
+
+ byte stunned = 0; /* Monster is stunned */
+ byte confused = 0; /* Monster is confused */
+ byte monfear = 0; /* Monster is afraid */
+
+ s16b bleeding = 0; /* Monster is bleeding */
+ s16b poisoned = 0; /* Monster is poisoned */
+
+ byte cdis = 0; /* Current dis from player */
+
+ s32b mflag = 0; /* Extra monster flags */
+
+ bool_ ml = FALSE; /* Monster is "visible" */
+
+ std::vector<s16b> hold_o_idxs { }; /* Objects being held */
+
+ u32b smart = 0; /* Field for "smart_learn" */
+
+ s16b status = 0; /* Status(friendly, pet, companion, ..) */
+
+ s16b target = 0; /* Monster target */
+
+ s16b possessor = 0; /* Is it under the control of a possessor ? */
+
+ /**
+ * @brief get the "effective race" of the monster. This incorporates
+ * the effects of the "ego" of the monster, if any.
+ */
+ std::shared_ptr<monster_race> race() const;
+
+ /**
+ * @brief wipe the object's state
+ */
+ void wipe()
+ {
+ /* Reset to defaults */
+ *this = monster_type();
+ }
+
+ /**
+ * Get the o_idx of the object being mimicked
+ */
+ s16b mimic_o_idx() const
+ {
+ // We *should* also assert that the monster has flag RF9_MIMIC,
+ // but it's currently not safe since the functions we need for
+ // that are a) expensive, and b) side-effecting via statics.
+ assert(hold_o_idxs.size() == 1); // Mimics are defined by exactly one object
+ return hold_o_idxs.front();
+ }
+
+};
diff --git a/src/monster_type_fwd.hpp b/src/monster_type_fwd.hpp
new file mode 100644
index 00000000..a44baa9d
--- /dev/null
+++ b/src/monster_type_fwd.hpp
@@ -0,0 +1,3 @@
+#pragma once
+
+struct monster_type;
diff --git a/src/move_info_type.hpp b/src/move_info_type.hpp
new file mode 100644
index 00000000..5f8aa3d8
--- /dev/null
+++ b/src/move_info_type.hpp
@@ -0,0 +1,15 @@
+#pragma once
+
+#include "h-basic.h"
+
+/**
+ * Movement typse
+ */
+struct move_info_type
+{
+ s16b to_speed;
+ s16b to_search;
+ s16b to_stealth;
+ s16b to_percep;
+ cptr name;
+};
diff --git a/src/music.hpp b/src/music.hpp
new file mode 100644
index 00000000..5f37c570
--- /dev/null
+++ b/src/music.hpp
@@ -0,0 +1,17 @@
+#pragma once
+
+#include "h-basic.h"
+
+/**
+ * Music descriptor.
+ */
+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) */
+};
diff --git a/src/notes.c b/src/notes.c
deleted file mode 100644
index 3504f61c..00000000
--- a/src/notes.c
+++ /dev/null
@@ -1,188 +0,0 @@
-/* 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/notes.cc b/src/notes.cc
new file mode 100644
index 00000000..326381c9
--- /dev/null
+++ b/src/notes.cc
@@ -0,0 +1,185 @@
+/*
+ * 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 "notes.hpp"
+
+#include "files.hpp"
+#include "player_class.hpp"
+#include "player_type.hpp"
+#include "util.hpp"
+#include "util.h"
+#include "variable.h"
+#include "variable.hpp"
+
+/*
+ * 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];
+
+ /* 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 */
+ fprintf(fff, "%s\n", final_note);
+
+ /* 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 turn_s[50];
+ char depths[32];
+
+ /* Get the first 60 chars - so do not have an overflow */
+ memset(buf, 0, sizeof(buf));
+ strncpy(buf, note, 60);
+
+ /* Get date and time */
+ sprintf(turn_s, "Turn % 12ld", static_cast<long int>(turn));
+
+ /* Get depth */
+ if (!dun_level) strcpy(depths, " Town");
+ else sprintf(depths, "Lev%3d", dun_level);
+
+ /* Make note */
+ sprintf(final_note, "%-20s %s %c: %s", turn_s, 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 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));
+
+ /* 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);
+
+ /* 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, true_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/notes.hpp b/src/notes.hpp
new file mode 100644
index 00000000..e8c22bb7
--- /dev/null
+++ b/src/notes.hpp
@@ -0,0 +1,6 @@
+#pragma once
+
+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);
diff --git a/src/obj_theme.hpp b/src/obj_theme.hpp
new file mode 100644
index 00000000..13f185e8
--- /dev/null
+++ b/src/obj_theme.hpp
@@ -0,0 +1,15 @@
+#pragma once
+
+#include "h-basic.h"
+
+/**
+ * Object theme. Probability in percent for each class of
+ * objects to be dropped.
+ */
+struct obj_theme
+{
+ byte treasure;
+ byte combat;
+ byte magic;
+ byte tools;
+};
diff --git a/src/obj_theme_fwd.hpp b/src/obj_theme_fwd.hpp
new file mode 100644
index 00000000..6c0d19a3
--- /dev/null
+++ b/src/obj_theme_fwd.hpp
@@ -0,0 +1,3 @@
+#pragma once
+
+struct obj_theme;
diff --git a/src/object.pkg b/src/object.pkg
deleted file mode 100644
index a89dad9a..00000000
--- a/src/object.pkg
+++ /dev/null
@@ -1,1169 +0,0 @@
-/* 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
deleted file mode 100644
index fef7fb85..00000000
--- a/src/object1.c
+++ /dev/null
@@ -1,6669 +0,0 @@
-/* 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/object1.cc b/src/object1.cc
new file mode 100644
index 00000000..6bbf23e9
--- /dev/null
+++ b/src/object1.cc
@@ -0,0 +1,6698 @@
+/*
+ * 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 "object1.hpp"
+
+#include "artifact_type.hpp"
+#include "cave.hpp"
+#include "cave_type.hpp"
+#include "cmd2.hpp"
+#include "cmd6.hpp"
+#include "dungeon.hpp"
+#include "dungeon_info_type.hpp"
+#include "ego_item_type.hpp"
+#include "feature_type.hpp"
+#include "files.hpp"
+#include "hook_get_in.hpp"
+#include "hooks.hpp"
+#include "lua_bind.hpp"
+#include "mimic.hpp"
+#include "monster1.hpp"
+#include "monster2.hpp"
+#include "monster_ego.hpp"
+#include "monster_race.hpp"
+#include "monster_type.hpp"
+#include "object2.hpp"
+#include "object_kind.hpp"
+#include "object_type.hpp"
+#include "options.hpp"
+#include "player_race.hpp"
+#include "player_race_mod.hpp"
+#include "player_type.hpp"
+#include "quark.hpp"
+#include "set_type.hpp"
+#include "skills.hpp"
+#include "spell_type.hpp"
+#include "spells5.hpp"
+#include "squeltch.hpp"
+#include "stats.hpp"
+#include "store_info_type.hpp"
+#include "tables.hpp"
+#include "trap_type.hpp"
+#include "util.hpp"
+#include "util.h"
+#include "variable.h"
+#include "variable.hpp"
+#include "wilderness_type_info.hpp"
+#include "xtra1.hpp"
+#include "z-rand.hpp"
+
+#include <cassert>
+
+static bool_ apply_flags_set(s16b a_idx, s16b set_idx,
+ u32b *f1, u32b *f2, u32b *f3, u32b *f4, u32b *f5, u32b *esp);
+
+/*
+ * 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
+
+
+/**
+ * Show all equipment/inventory slots, even when empty?
+ */
+static bool item_tester_full;
+
+
+/*
+ * 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 byte 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);
+}
+
+
+/*
+ * 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:
+ {
+ 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". 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;
+ }
+
+
+ /* Normal symbols */
+ process_pref_file("font.prf");
+}
+
+
+/*
+ * Extract "xtra" flags from object.
+ */
+static void object_flags_xtra(object_type const *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 const *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 const *o_ptr, u32b *f1, u32b *f2, u32b *f3, u32b *f4, u32b *f5, u32b *esp)
+{
+ 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;
+
+ /* Artifact */
+ if (o_ptr->name1)
+ {
+ artifact_type *a_ptr = &a_info[o_ptr->name1];
+
+ /* Need full knowledge or spoilers */
+ if ((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 ((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_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 (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;
+ }
+
+ break;
+ }
+
+ /* Rings (including a few "Specials") */
+ case TV_RING:
+ {
+ /* Color the object */
+ modstr = ring_adj[indexx];
+ if (aware) append_name = TRUE;
+
+ if (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;
+ }
+
+ break;
+ }
+
+ case TV_STAFF:
+ {
+ /* Color the object */
+ modstr = staff_adj[o_ptr->pval2 % MAX_WOODS];
+ if (aware) append_name = TRUE;
+ if (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 (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 (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:
+ {
+ modstr = k_info[lookup_kind(TV_ROD, o_ptr->pval)].name;
+ break;
+ }
+
+ case TV_SCROLL:
+ {
+ /* Color the object */
+ modstr = scroll_adj[indexx];
+ if (aware) append_name = TRUE;
+ if (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
+ {
+ modstr = get_mimic_name(o_ptr->pval2);
+ }
+ if (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 (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)
+ {
+ modstr = get_mimic_object_name(o_ptr->pval2);
+ }
+ 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_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_ptr->name);
+ else
+ basenm = format("& %s #~", r_ptr->name);
+ break;
+ }
+
+ case TV_EGG:
+ {
+ monster_race* r_ptr = &r_info[o_ptr->pval2];
+ modstr = basenm;
+
+ basenm = format("& %s #~", 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_ptr->name);
+ break;
+ }
+
+ case TV_TOTEM:
+ {
+ char name[80];
+ monster_type monster;
+
+ 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_ptr->name;
+ if (o_ptr->sval == 255)
+ {
+ modstr = spell_type_name(spell_at(o_ptr->pval));
+ }
+ break;
+ }
+
+ /* Used in the "inventory" routine */
+ default:
+ {
+ strcpy(buf, "(nothing)");
+ return;
+ }
+ }
+
+ /* Mega Hack */
+ if ((!hack_name) && known && (k_ptr->flags5 & TR5_FULL_NAME))
+ {
+ basenm = 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;
+ }
+ else if (e2_ptr->before)
+ {
+ ego = e2_ptr->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_ptr->name);
+ t = object_desc_chr(t, ' ');
+ }
+ if (e2_ptr->before)
+ {
+ t = object_desc_str(t, 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_ptr->name);
+ t = object_desc_chr(t, ' ');
+ }
+ if (e2_ptr->before)
+ {
+ t = object_desc_str(t, 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_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, spell_type_name(spell_at(o_ptr->pval2)));
+ 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_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_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_ptr->name);
+ }
+ if (o_ptr->name2b && !e2_ptr->before)
+ {
+ t = object_desc_chr(t, ' ');
+ t = object_desc_str(t, e2_ptr->name);
+ }
+ }
+ }
+
+ /* It contains a spell */
+ if ((known) && (f5 & TR5_SPELL_CONTAIN) && (o_ptr->pval2 != -1))
+ {
+ t = object_desc_str(t, format(" [%s]", spell_type_name(spell_at(o_ptr->pval2))));
+ }
+
+ /* 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 (o_ptr->elevel < PY_MAX_LEVEL)
+ {
+ /* Formula from check_experience_obj(). */
+ s32b need = player_exp[o_ptr->elevel - 1] * 5 / 2;
+ t = object_desc_num(t, need - o_ptr->exp);
+ }
+ else
+ {
+ t = object_desc_str(t, "*****");
+ }
+ t = object_desc_str(t, ", L:");
+ t = object_desc_num(t, o_ptr->elevel);
+ 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_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, '(');
+ t = object_desc_num(t, 100 * o_ptr->pval / 5);
+ t = object_desc_str(t, "%)");
+ }
+
+ if ((known) && (f2 & TR2_LIFE) ) /* Can disp neg now -- Improv */
+ {
+ t = object_desc_chr(t, '(');
+ t = object_desc_num(t, 100 * o_ptr->pval / 5);
+ 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_info[lookup_kind(TV_RUNE2, mod)].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";
+ }
+ }
+ }
+
+ return activation_aux(o_ptr, FALSE, 0);
+}
+
+/* Grab the tval desc */
+static 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
+ */
+static void describe_device(object_type *o_ptr)
+{
+ char buf[128];
+
+ /* 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);
+
+ // Spell reference
+ auto spell = spell_at(o_ptr->pval2);
+
+ text_out("\nSpell description:\n");
+ spell_type_description_foreach(spell,
+ [] (std::string const &text) -> void {
+ text_out("\n");
+ text_out(text.c_str());
+ });
+
+ text_out("\nSpell level: ");
+ sprintf(buf, FMTs32b, get_level(o_ptr->pval2, 50, 0));
+ text_out_c(TERM_L_BLUE, buf);
+
+ text_out("\nMinimum Magic Device level to increase spell level: ");
+ text_out_c(TERM_L_BLUE, format("%d", spell_type_skill_level(spell)));
+
+ text_out("\nSpell fail: ");
+ sprintf(buf, FMTs32b, spell_chance_device(spell));
+ text_out_c(TERM_GREEN, buf);
+
+ text_out("\nSpell info: ");
+ text_out_c(TERM_YELLOW, spell_type_info(spell));
+
+ /* 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);
+ }
+ else
+ {
+ sprintf(str, "in %s", wf_info[level].text);
+ }
+ }
+ else
+ {
+ sprintf(str, "on level %d of %s", level, d_info[dungeon].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;
+
+ const 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_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_ptr->text);
+ text_out("\n");
+
+ if (a_ptr->set != -1)
+ {
+ text_out_c(TERM_GREEN, set_info[a_ptr->set].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)
+ {
+ 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 / 5;
+
+
+ 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));
+ }
+ else if (o_ptr->found == OBJ_FOUND_STOLEN)
+ {
+ text_out(format("\nYou stole it from the %s.",
+ st_info[o_ptr->found_aux1].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
+ */
+static 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
+ */
+static 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
+ */
+static 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 const *o_ptr, bool_ ideal)
+{
+ /* Theme has restrictions for winged races. */
+ if (game_module_idx == MODULE_THEME)
+ {
+ cptr race_name = rp_ptr->title;
+
+ if (streq(race_name, "Dragon") ||
+ streq(race_name, "Eagle"))
+ {
+ switch (o_ptr->tval)
+ {
+ case TV_CLOAK:
+ case TV_HARD_ARMOR:
+ case TV_DRAG_ARMOR:
+ return -1;
+ }
+ }
+ }
+
+ /* 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;
+ }
+
+ case TV_DAEMON_BOOK:
+ {
+ int slot = -1;
+
+ switch (o_ptr->sval)
+ {
+ case SV_DEMONBLADE : slot = INVEN_WIELD; break;
+ case SV_DEMONSHIELD: slot = INVEN_ARM; break;
+ case SV_DEMONHORN : slot = INVEN_HEAD; break;
+ }
+
+ if ((slot >= 0) && (!ideal))
+ {
+ slot = get_slot(slot);
+ }
+
+ return slot;
+ }
+ }
+
+ /* 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 const *o_ptr)
+{
+ return wield_slot_ideal(o_ptr, FALSE);
+}
+
+/*
+ * Return a string mentioning how a given item is carried
+ */
+static 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 = nullptr;
+
+ 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
+ */
+static bool item_tester_okay(object_type const *o_ptr, object_filter_t const &filter)
+{
+ /* 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 against the filter */
+ return filter(o_ptr);
+}
+
+
+
+
+static void show_equip_aux(bool_ mirror, bool_ everything, object_filter_t const &filter);
+static void show_inven_aux(bool_ mirror, bool_ everything, object_filter_t const &filter);
+
+/*
+ * Choice window "shadow" of the "show_inven()" function
+ */
+void display_inven(void)
+{
+ show_inven_aux(TRUE, inventory_no_move, object_filter::True());
+}
+
+
+
+/*
+ * Choice window "shadow" of the "show_equip()" function
+ */
+void display_equip(void)
+{
+ show_equip_aux(TRUE, inventory_no_move, object_filter::True());
+}
+
+
+
+/* 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, const object_filter_t &filter)
+{
+ 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;
+
+ /* Space for weight */
+ lim -= 9;
+
+ /* Space for icon */
+ 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, filter))
+ {
+ 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 */
+ l += 9;
+
+ /* Account for icon */
+ 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 */
+ {
+ 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,
+ col + 5);
+
+ /* Display the weight */
+ {
+ int wgt = o_ptr->weight * o_ptr->number;
+ sprintf(tmp_val, "%3d.%1d lb", wgt / 10, wgt % 10);
+ put_str(tmp_val, row + j, wid - 9);
+ }
+ }
+
+ /* Shadow windows */
+ if (mirror)
+ {
+ int hgt;
+ Term_get_size(nullptr, &hgt);
+ /* Erase the rest of the window */
+ for (j = row + k; j < 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);
+ }
+}
+
+
+static void show_inven(object_filter_t const &filter)
+{
+ show_inven_aux(FALSE, FALSE, filter);
+}
+
+void show_inven_full()
+{
+ item_tester_full = true;
+ show_inven(object_filter::True());
+ item_tester_full = false;
+}
+
+static void show_equip(object_filter_t const &filter)
+{
+ show_equip_aux(FALSE, FALSE, filter);
+}
+
+void show_equip_full()
+{
+ item_tester_full = true;
+ show_equip(object_filter::True());
+ item_tester_full = false;
+}
+
+/*
+ * Display the equipment.
+ */
+void show_equip_aux(bool_ mirror, bool_ everything, object_filter_t const &filter)
+{
+ 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 */
+ lim -= (14 + 2);
+
+ /* Require space for weight */
+ lim -= 9;
+
+ /* Require space for icon */
+ 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)", get_melee_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_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, filter))
+ {
+ 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) */
+ l += (14 + 2);
+
+ /* Increase length for weight */
+ l += 9;
+
+ /* Icon */
+ 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);
+
+ /* Show icon */
+ {
+ 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 */
+ {
+ /* Mention the use */
+ (void)sprintf(tmp_val, "%-14s: ", mention_use(out_rindex[j]));
+ put_str(tmp_val, row + j, col + 5);
+
+ /* Display the entry itself */
+ c_put_str(out_color[j], out_desc[j], row + j, col + 21);
+ }
+
+ /* Display the weight */
+ {
+ int wgt = o_ptr->weight * o_ptr->number;
+ sprintf(tmp_val, "%3d.%d lb", wgt / 10, wgt % 10);
+ put_str(tmp_val, row + j, wid - 9);
+ }
+ }
+
+
+ /* Shadow windows */
+ if (mirror)
+ {
+ int hgt;
+ Term_get_size(nullptr, &hgt);
+ /* Erase the rest of the window */
+ for (j = row + k; j < 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, object_filter_t const &filter)
+{
+ /* Illegal items */
+ if ((i < 0) || (i >= INVEN_TOTAL))
+ {
+ return (FALSE);
+ }
+
+ /* Verify the item */
+ return item_tester_okay(&p_ptr->inventory[i], filter);
+}
+
+
+
+/*
+ * 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.
+ */
+static std::vector<int> scan_floor(int y, int x, object_filter_t const &filter)
+{
+ std::vector<int> items;
+
+ /* Sanity */
+ if (!in_bounds(y, x))
+ {
+ return items;
+ }
+
+ /* Scan all objects in the grid */
+ for (auto const this_o_idx: cave[y][x].o_idxs)
+ {
+ /* Acquire object */
+ object_type * o_ptr = &o_list[this_o_idx];
+
+ /* Item tester */
+ if (!item_tester_okay(o_ptr, filter))
+ {
+ continue;
+ }
+
+ /* Accept this item */
+ items.push_back(this_o_idx);
+
+ /* XXX Hack -- Enforce limit */
+ if (items.size() == 23) break;
+ }
+
+ /* Result */
+ return items;
+}
+
+/*
+ * Display a list of the items on the floor at the given location.
+ */
+static void show_floor(int y, int x, object_filter_t const &filter)
+{
+ 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];
+
+ /* Default length */
+ len = 79 - 50;
+
+ /* Maximum space allowed for descriptions */
+ lim = 79 - 3;
+
+ /* Require space for weight */
+ lim -= 9;
+
+ /* Scan for objects in the grid, using item_tester_okay() */
+ auto const floor_list = scan_floor(y, x, filter);
+ assert(floor_list.size() <= 23);
+ int const floor_num = floor_list.size(); // "int" for warning avoidance
+
+ /* 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;
+
+ /* Account for the weight */
+ 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 */
+ {
+ 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.
+ */
+static bool_ get_item_floor(int *cp, cptr pmt, cptr str, int mode, object_filter_t const &filter, select_by_name_t const &select_by_name)
+{
+ 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_ 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_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, filter))
+ {
+ /* Success */
+ return (TRUE);
+ }
+ }
+
+ /* Verify the item */
+ else if (get_item_okay(*cp, filter))
+ {
+ /* 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_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, filter))) i1++;
+ while ((i1 <= i2) && (!get_item_okay(i2, filter))) 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, filter))) e1++;
+ while ((e1 <= e2) && (!get_item_okay(e2, filter))) e2--;
+
+
+ /* Floor items? */
+ auto const floor_list =
+ floor ? scan_floor(p_ptr->py, p_ptr->px, filter)
+ : std::vector<int>();
+ assert(floor_list.size() <= 23);
+ int const floor_num = floor_list.size(); // "int" for warning avoidance
+
+ /* Accept inventory */
+ if (i1 <= i2) allow_inven = TRUE;
+
+ /* Accept equipment */
+ if (e1 <= e2) allow_equip = TRUE;
+
+ /* Accept floor */
+ if (!floor_list.empty()) 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 */
+ {
+ 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(filter);
+ }
+
+ /* 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(filter);
+ }
+
+ /* 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, filter);
+ }
+
+ /* 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,");
+ }
+ }
+
+ /* Do we allow selection by name? */
+ if (select_by_name)
+ {
+ 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, filter))
+ {
+ 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, filter))
+ {
+ 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 '@':
+ {
+ // Ignore if not "enabled"
+ if (!select_by_name)
+ {
+ break;
+ }
+ // Find by name
+ if (auto i = select_by_name(filter))
+ {
+ (*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, filter))
+ {
+ 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();
+
+ /* Track */
+ if (item && done)
+ {
+ if (*cp >= 0)
+ {
+ object_track(&p_ptr->inventory[*cp]);
+ }
+ else
+ {
+ object_track(&o_list[0 - *cp]);
+ }
+ }
+
+ /* Clean up */
+ {
+ /* 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, object_filter_t const &filter, select_by_name_t const &select_by_name)
+{
+ automatizer_create = FALSE;
+ return get_item_floor(cp, pmt, str, mode, filter, select_by_name);
+}
+
+/*
+ * Hook to determine if an object is getable
+ */
+static bool item_tester_hook_getable(object_type const *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_FRAME);
+
+ /* Window stuff */
+ p_ptr->window |= (PW_INVEN | PW_EQUIP | PW_PLAYER);
+
+ return slot;
+}
+
+
+/*
+ * Try to pickup arrows
+ */
+void pickup_ammo()
+{
+ /* Copy list of objects since we're manipulating the list */
+ auto const object_idxs(cave[p_ptr->py][p_ptr->px].o_idxs);
+
+ /* Scan the pile of objects */
+ for (auto const this_o_idx: object_idxs)
+ {
+ /* Acquire object */
+ object_type *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.");
+ s16b slot = wear_ammo(o_ptr);
+
+ if (slot != -1)
+ {
+ /* Get the item again */
+ o_ptr = &p_ptr->inventory[slot];
+
+ /* Describe the object */
+ char o_name[80];
+ 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);
+ }
+ }
+ }
+}
+
+
+/**
+ * Check for encumberance if player were to pick up
+ * given item.
+ */
+static bool can_carry_heavy(object_type const *o_ptr)
+{
+ /* Extract the "weight limit" (in tenth pounds) */
+ int i = weight_limit();
+
+ /* Calculate current encumbarance */
+ int j = calc_total_weight();
+
+ /* Apply encumbarance from weight */
+ int old_enc = 0;
+ 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 */
+ int new_enc = 0;
+ if (j > i / 2) new_enc = ((j - (i / 2)) / (i / 10));
+
+ /* If the encumberance is the same, then we pick up without prompt */
+ return (new_enc <= old_enc);
+}
+
+/* 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
+ {
+ /* Hooks */
+ {
+ hook_get_in in = { o_ptr, this_o_idx };
+ if (process_hooks_new(HOOK_GET, &in, NULL))
+ {
+ 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();
+ }
+ }
+}
+
+
+static void absorb_gold(cave_type const *c_ptr)
+{
+ /* Copy list of objects since we're going to manipulate the list itself */
+ auto const object_idxs(c_ptr->o_idxs);
+
+ /* Go through everything */
+ for (auto const this_o_idx: object_idxs)
+ {
+ /* Acquire object */
+ object_type *o_ptr = &o_list[this_o_idx];
+
+ /* Hack -- disturb */
+ disturb(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_FRAME);
+
+ /* Window stuff */
+ p_ptr->window |= (PW_PLAYER);
+
+ /* Delete the gold */
+ delete_object_idx(this_o_idx);
+ }
+ }
+}
+
+static void sense_floor(cave_type const *c_ptr)
+{
+ /* Build a list of the floor objects. */
+ std::vector<int> floor_object_idxs;
+ {
+ /* Reserve the correct number of slots */
+ floor_object_idxs.reserve(c_ptr->o_idxs.size());
+ /* Fill in the indexes */
+ for (auto const this_o_idx: c_ptr->o_idxs)
+ {
+ // Note the "-"! We need it for get_object()
+ // lookups to function correctly.
+ floor_object_idxs.push_back(0 - this_o_idx);
+ }
+ }
+
+ /* 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)
+ {
+ for (auto const o_idx: floor_object_idxs)
+ {
+ object_type *o_ptr = get_object(o_idx);
+ object_aware(o_ptr);
+ object_known(o_ptr);
+ }
+ }
+
+ /* Sense floor tile */
+ sense_objects(floor_object_idxs);
+}
+
+void py_pickup_floor(int pickup)
+{
+ /* Get the tile */
+ auto c_ptr = &cave[p_ptr->py][p_ptr->px];
+
+ /* Hack -- ignore monster traps */
+ if (c_ptr->feat == FEAT_MON_TRAP)
+ {
+ return;
+ }
+
+ /* Try to grab ammo */
+ pickup_ammo();
+
+ /* Auto-ID and pseudo-ID */
+ sense_floor(c_ptr);
+
+ /* Squeltch the floor */
+ squeltch_grid();
+
+ /* Absorb gold on the tile */
+ absorb_gold(&cave[p_ptr->py][p_ptr->px]);
+
+ /* We handle 0, 1, or "many" items cases separately */
+ if (c_ptr->o_idxs.empty())
+ {
+ /* Nothing to do */
+ }
+ else if (c_ptr->o_idxs.size() == 1)
+ {
+ /* Acquire object */
+ auto floor_o_idx = c_ptr->o_idxs.front();
+ auto o_ptr = &o_list[floor_o_idx];
+
+ /* Describe or pick up? */
+ if (!pickup)
+ {
+ /* Describe */
+ char o_name[80] = "";
+ object_desc(o_name, o_ptr, TRUE, 3);
+
+ /* Message */
+ msg_format("You see %s.", o_name);
+ }
+ else
+ {
+ /* Are we actually going to pick up? */
+ bool_ do_pickup = TRUE;
+
+ /* Hack -- query every item */
+ if (carry_query_flag || (!can_carry_heavy(&o_list[floor_o_idx])))
+ {
+ char o_name[80] = "";
+ object_desc(o_name, o_ptr, TRUE, 3);
+
+ 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);
+ return; /* Done */
+ }
+ else
+ {
+ char out_val[160];
+ sprintf(out_val, "Pick up %s? ", o_name);
+ do_pickup = get_check(out_val);
+ }
+ }
+
+ /* Just pick it up; unless it's a symbiote and we don't have Symbiosis */
+ if (do_pickup && ((o_list[floor_o_idx].tval != TV_HYPNOS) || (get_skill(SKILL_SYMBIOTIC))))
+ {
+ object_pickup(floor_o_idx);
+ }
+ }
+ }
+ else
+ {
+ /* Describe or pick up? */
+ if (!pickup)
+ {
+ /* Message */
+ msg_format("You see a pile of %d items.", c_ptr->o_idxs.size());
+ }
+ else
+ {
+ /* Prompt for the item to pick up */
+ cptr q = "Get which item? ";
+ cptr s = "You have no room in your pack for any of the items here.";
+ int item;
+ if (get_item(&item, q, s, (USE_FLOOR), item_tester_hook_getable))
+ {
+ s16b this_o_idx = 0 - item;
+
+ bool_ do_pickup = TRUE;
+ if (!can_carry_heavy(&o_list[this_o_idx]))
+ {
+ /* Describe the object */
+ char o_name[80] = "";
+ object_desc(o_name, &o_list[this_o_idx], TRUE, 3);
+
+ /* Prompt */
+ char out_val[160];
+ sprintf(out_val, "Pick up %s? ", o_name);
+ do_pickup = get_check(out_val);
+ }
+
+ /* Pick up the item */
+ if (do_pickup)
+ {
+ object_pickup(this_o_idx);
+ }
+ }
+ }
+ }
+}
+
+/* Add a flags group */
+static void gain_flag_group(object_type *o_ptr)
+{
+ 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);
+
+ /* Message */
+ {
+ 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);
+ }
+}
+
+static 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 */
+static void gain_flag_group_flag(object_type *o_ptr)
+{
+ 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;
+ }
+
+ /* Message */
+ {
+ 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);
+ }
+ else
+ {
+ if (!o_ptr->pval3) gain_flag_group(o_ptr);
+
+ gain_flag_group_flag(o_ptr);
+
+ 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);
+ }
+ 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;
+
+ assert(s_ptr->num_use > 0);
+ s_ptr->num_use--;
+
+ if (s_ptr->num_use == s_ptr->num - 1)
+ {
+ cmsg_format(TERM_GREEN, "%s item set not complete anymore.", s_ptr->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);
+}
+
+static 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);
+}
+
+/*
+ * Return the "attr" for a given item.
+ * Use "flavor" if available.
+ * Default to user definitions.
+ */
+
+byte object_attr(object_type const *o_ptr)
+{
+ if (o_ptr->tval == TV_RANDART)
+ {
+ return random_artifacts[o_ptr->sval].attr;
+ }
+ else if (k_info[o_ptr->k_idx].flavor)
+ {
+ return misc_to_attr[k_info[o_ptr->k_idx].flavor];
+ }
+ else
+ {
+ return k_info[o_ptr->k_idx].x_attr;
+ }
+}
+
+byte object_attr_default(object_type *o_ptr)
+{
+ if (o_ptr->tval == TV_RANDART)
+ {
+ return random_artifacts[o_ptr->sval].attr;
+ }
+ else if (k_info[o_ptr->k_idx].flavor)
+ {
+ return misc_to_attr[k_info[o_ptr->k_idx].flavor];
+ }
+ else
+ {
+ return k_info[o_ptr->k_idx].d_attr;
+ }
+}
+
+/*
+ * Return the "char" for a given item.
+ * Use "flavor" if available.
+ * Default to user definitions.
+ */
+
+char object_char(object_type const *o_ptr)
+{
+ if (k_info[o_ptr->k_idx].flavor)
+ {
+ return misc_to_char[k_info[o_ptr->k_idx].flavor];
+ }
+ else
+ {
+ return k_info[o_ptr->k_idx].x_char;
+ }
+}
+
+char object_char_default(object_type const *o_ptr)
+{
+ if (k_info[o_ptr->k_idx].flavor)
+ {
+ return misc_to_char[k_info[o_ptr->k_idx].flavor];
+ }
+ else
+ {
+ return k_info[o_ptr->k_idx].d_char;
+ }
+}
+
+/**
+ * Is the given object an artifact?
+ */
+bool artifact_p(object_type const *o_ptr)
+{
+ return
+ (o_ptr->tval == TV_RANDART) ||
+ (o_ptr->name1 ? true : false) ||
+ (o_ptr->art_name ? true : false) ||
+ ((k_info[o_ptr->k_idx].flags3 & TR3_NORM_ART) ? true : false);
+}
+
+/**
+ * Is the given object an ego item?
+ */
+bool ego_item_p(object_type const *o_ptr)
+{
+ return o_ptr->name2 || (o_ptr->name2b ? TRUE : FALSE);
+}
+
+/*
+ * Is the given object an ego item of the given type?
+ */
+bool is_ego_p(object_type const *o_ptr, s16b ego)
+{
+ return (o_ptr->name2 == ego) || (o_ptr->name2b == ego);
+}
+
+/**
+ * Is the given object identified as cursed?
+ */
+bool cursed_p(object_type const *o_ptr)
+{
+ return o_ptr->ident & (IDENT_CURSED);
+}
diff --git a/src/object1.hpp b/src/object1.hpp
new file mode 100644
index 00000000..ec8f9367
--- /dev/null
+++ b/src/object1.hpp
@@ -0,0 +1,46 @@
+#pragma once
+
+#include "h-basic.h"
+#include "object_filter.hpp"
+
+#include <boost/optional.hpp>
+#include <functional>
+
+typedef std::function<boost::optional<int>(object_filter_t const &filter)> select_by_name_t;
+
+extern byte get_item_letter_color(object_type *o_ptr);
+extern void object_pickup(int this_o_idx);
+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 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 const *o_ptr, u32b *f1, u32b *f2, u32b *f3, u32b *f4, u32b *f5, u32b *esp);
+extern void object_flags_known(object_type const *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 wield_slot_ideal(object_type const *o_ptr, bool_ ideal);
+extern s16b wield_slot(object_type const *o_ptr);
+extern cptr describe_use(int i);
+extern void display_inven(void);
+extern void display_equip(void);
+extern void show_inven_full();
+extern void show_equip_full();
+extern void toggle_inven_equip(void);
+extern bool_ get_item(int *cp, cptr pmt, cptr str, int mode, object_filter_t const &filter = object_filter::True(), select_by_name_t const &select_by_name = select_by_name_t());
+extern cptr item_activation(object_type *o_ptr,byte num);
+extern void py_pickup_floor(int pickup);
+extern void object_gain_level(object_type *o_ptr);
+extern byte object_attr(object_type const *o_ptr);
+extern byte object_attr_default(object_type *o_ptr);
+extern char object_char(object_type const *o_ptr);
+extern char object_char_default(object_type const *o_ptr);
+extern bool artifact_p(object_type const *o_ptr);
+extern bool ego_item_p(object_type const *o_ptr);
+extern bool is_ego_p(object_type const *o_ptr, s16b ego);
+extern bool cursed_p(object_type const *o_ptr);
diff --git a/src/object2.c b/src/object2.c
deleted file mode 100644
index 98afb815..00000000
--- a/src/object2.c
+++ /dev/null
@@ -1,6617 +0,0 @@
-/* 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/object2.cc b/src/object2.cc
new file mode 100644
index 00000000..620037a3
--- /dev/null
+++ b/src/object2.cc
@@ -0,0 +1,6465 @@
+/*
+ * 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 "object2.hpp"
+
+#include "alloc_entry.hpp"
+#include "artifact_type.hpp"
+#include "cave.hpp"
+#include "cave_type.hpp"
+#include "spell_type.hpp"
+#include "device_allocation.hpp"
+#include "dungeon_info_type.hpp"
+#include "ego_item_type.hpp"
+#include "feature_type.hpp"
+#include "hooks.hpp"
+#include "mimic.hpp"
+#include "monster2.hpp"
+#include "monster_race.hpp"
+#include "monster_type.hpp"
+#include "object1.hpp"
+#include "object_kind.hpp"
+#include "object_type.hpp"
+#include "options.hpp"
+#include "player_type.hpp"
+#include "randart.hpp"
+#include "randart_part_type.hpp"
+#include "skills.hpp"
+#include "spells2.hpp"
+#include "spells3.hpp"
+#include "spells5.hpp"
+#include "tables.hpp"
+#include "traps.hpp"
+#include "util.hpp"
+#include "variable.hpp"
+#include "wilderness_map.hpp"
+#include "xtra1.hpp"
+#include "z-rand.hpp"
+
+#include <algorithm>
+#include <cassert>
+#include <type_traits>
+#include <vector>
+
+/*
+ * 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)
+{
+ /* Function to remove from list */
+ auto remove_it = [o_idx](std::vector<s16b> *v) -> void {
+ v->erase(
+ std::remove(
+ v->begin(),
+ v->end(),
+ o_idx),
+ v->end());
+ };
+
+ /* Object */
+ object_type *o_ptr = &o_list[o_idx];
+
+ /* Monster */
+ if (o_ptr->held_m_idx)
+ {
+ /* Monster */
+ monster_type *m_ptr = &m_list[o_ptr->held_m_idx];
+
+ /* Remove object from list of held objects, if present. */
+ remove_it(&m_ptr->hold_o_idxs);
+ }
+ /* Dungeon */
+ else
+ {
+ /* Grid */
+ cave_type *c_ptr = &cave[o_ptr->iy][o_ptr->ix];
+
+ /* Remove object from list of objects in the grid, if present. */
+ remove_it(&c_ptr->o_idxs);
+ }
+}
+
+
+/*
+ * 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)
+{
+ /* Refuse "illegal" locations */
+ if (!in_bounds(y, x)) return;
+
+ /* Grid */
+ cave_type *c_ptr = &cave[y][x];
+
+ /* Scan all objects in the grid */
+ for (auto const this_o_idx: c_ptr->o_idxs)
+ {
+ /* Acquire object */
+ object_type *o_ptr = &o_list[this_o_idx];
+
+ /* Wipe the object */
+ object_wipe(o_ptr);
+
+ /* Count objects */
+ o_cnt--;
+ }
+
+ /* Objects are gone */
+ c_ptr->o_idxs.clear();
+
+ /* 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)
+{
+ /* Do nothing */
+ if (i1 == i2) return;
+
+ /* Acquire object */
+ object_type *o_ptr = &o_list[i1];
+
+ /* Monster */
+ if (o_ptr->held_m_idx)
+ {
+ /* Acquire monster */
+ monster_type *m_ptr = &m_list[o_ptr->held_m_idx];
+
+ /* Repair monster */
+ for (auto &hold_o_idx: m_ptr->hold_o_idxs)
+ {
+ if (hold_o_idx == i1)
+ {
+ hold_o_idx = i2;
+ }
+ }
+ }
+
+ /* Dungeon */
+ else
+ {
+ /* Acquire grid */
+ cave_type *c_ptr = &cave[o_ptr->iy][o_ptr->ix];
+
+ /* Repair grid */
+ for (auto &o_idx: c_ptr->o_idxs)
+ {
+ if (o_idx == i1)
+ {
+ 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 */
+ monster_type *m_ptr = &m_list[o_ptr->held_m_idx];
+
+ /* Hack -- see above */
+ m_ptr->hold_o_idxs.clear();
+ }
+
+ /* 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_idxs.clear();
+ }
+
+ /* Wipe the object */
+ object_wipe(o_ptr);
+ }
+
+ /* 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);
+}
+
+
+
+/*
+ * Determine if a given inventory item is "known"
+ * Test One -- Check for special "known" tag
+ * Test Two -- Check for "Easy Know" + "Aware"
+ */
+bool object_known_p(object_type const *o_ptr)
+{
+ return ((o_ptr->ident & (IDENT_KNOWN)) ||
+ (k_info[o_ptr->k_idx].easy_know && k_info[o_ptr->k_idx].aware));
+}
+
+
+
+/*
+ * 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;
+}
+
+/**
+ * Is the player aware of the effects of the given object?
+ */
+bool object_aware_p(object_type const *o_ptr)
+{
+ return k_info[o_ptr->k_idx].aware;
+}
+
+
+/*
+ * 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;
+}
+
+
+/**
+ * Has the given object been "tried"?
+ */
+bool object_tried_p(object_type const *o_ptr)
+{
+ return k_info[o_ptr->k_idx].tried;
+}
+
+
+/*
+ * Return the "value" of an "unknown" item
+ * Make a guess at the value of non-aware items
+ */
+static s32b object_value_base(object_type const *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 const * 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 const *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 * spell_type_skill_level(spell_at(o_ptr->pval2));
+ 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 *= spell_type_skill_level(spell_at(o_ptr->pval2));
+ /* 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 *= spell_type_skill_level(spell_at(o_ptr->pval2));
+ /* 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 * spell_type_skill_level(spell_at(o_ptr->pval));
+ }
+ /* 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 const *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 const *o_ptr, object_type const *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:
+ {
+ /* 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;
+ }
+
+ /* 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);
+
+ /* 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 */
+ static_assert(std::is_pod<object_type>::value, "object_type must be POD type for memset to work");
+ memset(o_ptr, 0, sizeof(object_type));
+}
+
+
+/*
+ * Prepare an object based on an existing object
+ */
+void object_copy(object_type *o_ptr, object_type *j_ptr)
+{
+ /* Copy the structure */
+ *o_ptr = *j_ptr;
+}
+
+
+/*
+ * 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 */
+ object_wipe(o_ptr);
+
+ /* 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)
+{
+ bool_ ret = FALSE;
+ object_kind *k_ptr = &k_info[o_ptr->k_idx];
+
+ if (artifact_p(o_ptr) || o_ptr->name2) return (FALSE);
+
+ std::vector<size_t> ok_ego;
+
+ /* Grab the ok ego */
+ for (size_t 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 (size_t 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.push_back(i);
+ }
+
+ /* Now test them a few times */
+ for (size_t i = 0; i < ok_ego.size() * 10; i++)
+ {
+ size_t j = ok_ego[rand_int(ok_ego.size())];
+ ego_item_type *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 (size_t i = 0; i < ok_ego.size() * 10; i++)
+ {
+ int j = ok_ego[rand_int(ok_ego.size())]; // Explicit int conversion to avoid warning
+ ego_item_type *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;
+ }
+ }
+
+ /* Return */
+ return (ret);
+}
+
+
+/*
+ * Charge a new stick.
+ */
+void charge_stick(object_type *o_ptr)
+{
+ spell_type *spell = spell_at(o_ptr->pval2);
+ o_ptr->pval = spell_type_roll_charges(spell);
+}
+
+/*
+ * 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 */
+ 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 */
+ 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 = find_random_mimic_shape(level, TRUE);
+ 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 */
+ 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;
+ }
+ }
+}
+
+/*
+ * Randomized level
+ */
+static int randomized_level_in_range(range_type *range, int level)
+{
+ s32b r = range->max - range->min;
+
+ /* The basic idea is to have a max possible level of half the dungeon level */
+ if (r * 2 > level)
+ {
+ r = level / 2;
+ }
+
+ /* Randomize a bit */
+ r = m_bonus(r, dun_level);
+
+ /* get the result */
+ return range->min + r;
+}
+
+
+/*
+ * Get a random base level
+ */
+static int get_stick_base_level(byte tval, int level, int spl)
+{
+ spell_type *spell = spell_at(spl);
+ device_allocation *device_allocation = spell_type_device_allocation(spell, tval);
+ assert(device_allocation != NULL);
+ return randomized_level_in_range(&device_allocation->base_level, level);
+}
+
+/*
+ * Get a random max level
+ */
+static int get_stick_max_level(byte tval, int level, int spl)
+{
+ spell_type *spell = spell_at(spl);
+ device_allocation *device_allocation = spell_type_device_allocation(spell, tval);
+ assert(device_allocation != NULL);
+ return randomized_level_in_range(&device_allocation->max_level, level);
+}
+
+
+/*
+ * 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 */
+ 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 = get_random_spell(SKILL_MAGIC, level);
+ }
+ else
+ {
+ i = get_random_spell(SKILL_SPIRITUALITY, 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)
+ {
+ auto spl = get_random_stick(TV_WAND, dun_level);
+ if (spl == -1)
+ {
+ spl = 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 */
+ bonus_lvl = get_stick_base_level(TV_WAND, dun_level, o_ptr->pval2);
+ max_lvl = get_stick_max_level(TV_WAND, dun_level, o_ptr->pval2);
+ 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 = get_random_stick(TV_STAFF, dun_level);
+
+ if (spl == -1)
+ {
+ spl = GLOBELIGHT;
+ }
+
+ 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 */
+ bonus_lvl = get_stick_base_level(TV_STAFF, dun_level, o_ptr->pval2);
+ max_lvl = get_stick_max_level(TV_STAFF, dun_level, o_ptr->pval2);
+ 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 = find_random_mimic_shape(level, FALSE);
+ 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.
+ */
+void apply_magic(object_type *o_ptr, int lev, bool_ okay, bool_ good, bool_ great, boost::optional<int> force_power)
+{
+ 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 */
+ base_lvl = get_stick_base_level(o_ptr->tval, dun_level, o_ptr->pval2);
+ max_lvl = get_stick_max_level(o_ptr->tval, dun_level, o_ptr->pval2);
+ 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;
+ }
+
+ /* Override power with parameter? */
+ if (auto power_override = force_power)
+ {
+ power = *power_override;
+ }
+
+ /* 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 < FLAG_RARITY_MAX; 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 const &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.
+ */
+static 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:
+ // FIXME: These cases can be shortened drastically
+ 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_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.
+ */
+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;
+
+ /* Assume legal */
+ return TRUE;
+}
+
+
+/*
+ * Hack -- determine if a template is "good"
+ */
+static 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 const &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)
+ {
+ /* Acquire object */
+ object_type *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];
+
+ /* Place the object */
+ c_ptr->o_idxs.push_back(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));
+
+ /* Multiply value by 5 if selling is disabled */
+ if (no_selling)
+ j_ptr->pval *= 5;
+
+ /* 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];
+
+ /* Place the object */
+ c_ptr->o_idxs.push_back(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;
+
+ 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 (auto const this_o_idx: c_ptr->o_idxs)
+ {
+ /* Acquire object */
+ object_type *o_ptr = &o_list[this_o_idx];
+
+ /* Check for possible combination */
+ if (object_similar(o_ptr, j_ptr)) comb = TRUE;
+
+ /* Count objects */
+ k++;
+ }
+
+ /* Add new object */
+ if (!comb) k++;
+
+ /* 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 (auto const this_o_idx: c_ptr->o_idxs)
+ {
+ /* Acquire object */
+ object_type *o_ptr = &o_list[this_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 */
+ s16b o_idx = 0;
+ 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;
+
+ /* Place the object */
+ c_ptr->o_idxs.push_back(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 const *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->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.");
+}
+
+
+/*
+ * Let the floor carry an object
+ */
+s16b floor_carry(int y, int x, object_type *j_ptr)
+{
+ /* Scan objects in that grid for combination */
+ for (auto const this_o_idx: cave[y][x].o_idxs)
+ {
+ /* Acquire object */
+ object_type *o_ptr = &o_list[this_o_idx];
+
+ /* Check for combination */
+ if (object_similar(o_ptr, j_ptr))
+ {
+ /* Combine the items */
+ object_absorb(o_ptr, j_ptr);
+
+ /* Done */
+ return this_o_idx;
+ }
+ }
+
+ /* The stack is already too large */
+ if (cave[y][x].o_idxs.size() > 23)
+ {
+ return (0);
+ }
+
+ /* Make an object */
+ s16b o_idx = o_pop();
+
+ /* Success */
+ if (o_idx)
+ {
+ /* Acquire object */
+ object_type *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;
+
+ /* Place the object */
+ cave[y][x].o_idxs.push_back(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)
+{
+ if (item >= 0)
+ {
+ assert(item < INVEN_TOTAL);
+ return &p_ptr->inventory[item];
+ }
+ else
+ {
+ return &o_list[0 - item];
+ }
+}
+
diff --git a/src/object2.hpp b/src/object2.hpp
new file mode 100644
index 00000000..26d07b25
--- /dev/null
+++ b/src/object2.hpp
@@ -0,0 +1,69 @@
+#pragma once
+
+#include "h-basic.h"
+#include "object_type_fwd.hpp"
+#include "obj_theme_fwd.hpp"
+
+#include <boost/optional.hpp>
+
+typedef enum { OPTIMIZE, NO_OPTIMIZE } optimize_flag;
+typedef enum { DESCRIBE, NO_DESCRIBE } describe_flag;
+
+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 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 void init_match_theme(obj_theme const &theme);
+extern bool_ kind_is_artifactable(int k_idx);
+extern bool_ kind_is_legal(int k_idx);
+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 const *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 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 bool object_known_p(object_type const *o_ptr);
+extern void object_aware(object_type *o_ptr);
+extern bool object_aware_p(object_type const *o_ptr);
+extern void object_tried(object_type *o_ptr);
+extern bool object_tried_p(object_type const *o_ptr);
+extern s32b object_value(object_type const *o_ptr);
+extern s32b object_value_real(object_type const *o_ptr);
+extern bool_ object_similar(object_type const *o_ptr, object_type const *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 void apply_magic(object_type *o_ptr, int lev, bool_ okay, bool_ good, bool_ great, boost::optional<int> force_power = boost::none);
+extern bool_ make_object(object_type *j_ptr, bool_ good, bool_ great, obj_theme const &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 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 void combine_pack(void);
+extern void reorder_pack(void);
+extern void random_artifact_resistance (object_type * o_ptr);
+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 s16b m_bonus(int max, int level);
+extern s32b flag_cost(object_type const *o_ptr, int plusses);
diff --git a/src/object_filter.cc b/src/object_filter.cc
new file mode 100644
index 00000000..39961146
--- /dev/null
+++ b/src/object_filter.cc
@@ -0,0 +1,98 @@
+#include "object_filter.hpp"
+#include "object1.hpp"
+#include "object2.hpp"
+#include "object_type.hpp"
+
+namespace object_filter {
+
+object_filter_t TVal(byte tval) {
+ return [=](object_type const *o_ptr) -> bool {
+ return o_ptr->tval == tval;
+ };
+}
+
+object_filter_t SVal(byte sval) {
+ return [=](object_type const *o_ptr) -> bool {
+ return o_ptr->sval == sval;
+ };
+}
+
+object_filter_t HasFlag3(u32b mask) {
+ return [=](object_type const *o_ptr) -> bool {
+ // Extract the flags
+ u32b f1, f2, f3, f4, f5, esp;
+ object_flags(o_ptr, &f1, &f2, &f3, &f4, &f5, &esp);
+ // Does the item have the flag?
+ return (f3 & mask);
+ };
+}
+
+object_filter_t HasFlag4(u32b mask) {
+ return [=](object_type const *o_ptr) -> bool {
+ // Extract the flags
+ u32b f1, f2, f3, f4, f5, esp;
+ object_flags(o_ptr, &f1, &f2, &f3, &f4, &f5, &esp);
+ // Does the item have the flag?
+ return (f4 & mask);
+ };
+}
+
+object_filter_t HasFlag5(u32b mask) {
+ return [=](object_type const *o_ptr) -> bool {
+ // Extract the flags
+ u32b f1, f2, f3, f4, f5, esp;
+ object_flags(o_ptr, &f1, &f2, &f3, &f4, &f5, &esp);
+ // Does the item have the flag?
+ return (f5 & mask);
+ };
+}
+
+object_filter_t IsArtifact() {
+ return [](object_type const *o_ptr) -> bool {
+ return o_ptr->name1 > 0;
+ };
+}
+
+object_filter_t IsArtifactP() {
+ return [](object_type const *o_ptr) -> bool {
+ return artifact_p(o_ptr);
+ };
+}
+
+object_filter_t IsEgo() {
+ return [](object_type const *o_ptr) -> bool {
+ return ego_item_p(o_ptr);
+ };
+}
+
+object_filter_t IsKnown() {
+ return [](object_type const *o_ptr) -> bool {
+ return object_known_p(o_ptr);
+ };
+}
+
+object_filter_t True() {
+ return [](object_type const *o_ptr) -> bool {
+ return true;
+ };
+}
+
+object_filter_t Not(object_filter_t p) {
+ return [=](object_type const *o_ptr) -> bool {
+ return !p(o_ptr);
+ };
+}
+
+object_filter_t And() {
+ return [](object_type const *) -> bool {
+ return true;
+ };
+}
+
+object_filter_t Or() {
+ return [](object_type const *) -> bool {
+ return false;
+ };
+}
+
+}
diff --git a/src/object_filter.hpp b/src/object_filter.hpp
new file mode 100644
index 00000000..9a22090b
--- /dev/null
+++ b/src/object_filter.hpp
@@ -0,0 +1,99 @@
+#pragma once
+
+#include "h-basic.h"
+#include "object_type_fwd.hpp"
+
+#include <functional>
+#include <initializer_list>
+
+typedef std::function<bool (object_type const *)> object_filter_t;
+
+namespace object_filter {
+
+/**
+ * Is TVal equal to the given value?
+ */
+object_filter_t TVal(byte tval);
+
+/**
+ * Is SVal equal to the given value?
+ */
+object_filter_t SVal(byte sval);
+
+/**
+ * Has given bit mask in flag3 value.
+ */
+object_filter_t HasFlag3(u32b mask);
+
+/**
+ * Has given bit mask in flag4 value.
+ */
+object_filter_t HasFlag4(u32b mask);
+
+/**
+ * Has given bit mask in flag5 value.
+ */
+object_filter_t HasFlag5(u32b mask);
+
+/**
+ * Is the object an artifact?
+ */
+object_filter_t IsArtifact();
+
+/**
+ * Is the object an artifact as determined by artifact_p?
+ */
+object_filter_t IsArtifactP();
+
+/**
+ * Is the object an ego item?
+ */
+object_filter_t IsEgo();
+
+/**
+ * Is the object "known"?
+ */
+object_filter_t IsKnown();
+
+/**
+ * True always accepts all items.
+ */
+object_filter_t True();
+
+/**
+ * Invert an object filter.
+ */
+object_filter_t Not(object_filter_t p);
+
+/**
+ * Logical conjunction (AND)
+ */
+object_filter_t And();
+
+/**
+ * Logical conjunction (AND)
+ */
+template<typename Arg0, typename... Args> object_filter_t And(Arg0&& arg0, Args&&... args) {
+ auto argsFilter = And(args...);
+ return [=](object_type const *o_ptr) -> bool {
+ return arg0(o_ptr) && argsFilter(o_ptr);
+ };
+}
+
+/**
+ * Logical disjunction (OR)
+ */
+object_filter_t Or();
+
+/**
+ * Logical disjunction (OR)
+ */
+template<typename Arg0, typename... Args> object_filter_t Or(Arg0&& arg0, Args&&... args) {
+ auto argsFilter = Or(args...);
+ return [=](object_type const *o_ptr) -> bool {
+ auto x = arg0(o_ptr) || argsFilter(o_ptr);
+ return x;
+ };
+}
+
+}
diff --git a/src/object_kind.hpp b/src/object_kind.hpp
new file mode 100644
index 00000000..505f54d9
--- /dev/null
+++ b/src/object_kind.hpp
@@ -0,0 +1,83 @@
+#pragma once
+
+#include "h-basic.h"
+
+/**
+ * Size of allocation table for objects
+ */
+constexpr int ALLOCATION_MAX = 8;
+
+/**
+ * Object "kind" descriptor. Includes player knowledge.
+ *
+ * Only "aware" and "tried" are saved in the savefile
+ */
+struct object_kind
+{
+ const char *name; /* Name */
+ char *text; /* Text */
+
+ 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[ALLOCATION_MAX]; /* Allocation level(s) */
+ byte chance[ALLOCATION_MAX]; /* Allocation chance(s) */
+
+ byte level; /* Level */
+
+
+ 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 */
+
+ 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) */
+};
diff --git a/src/object_kind_fwd.hpp b/src/object_kind_fwd.hpp
new file mode 100644
index 00000000..6d26db9f
--- /dev/null
+++ b/src/object_kind_fwd.hpp
@@ -0,0 +1,3 @@
+#pragma once
+
+struct object_kind;
diff --git a/src/object_type.hpp b/src/object_type.hpp
new file mode 100644
index 00000000..d7f003e6
--- /dev/null
+++ b/src/object_type.hpp
@@ -0,0 +1,104 @@
+#pragma once
+
+#include "h-basic.h"
+
+/**
+ * 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".
+ */
+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 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 */
+};
diff --git a/src/object_type_fwd.hpp b/src/object_type_fwd.hpp
new file mode 100644
index 00000000..d99e60a6
--- /dev/null
+++ b/src/object_type_fwd.hpp
@@ -0,0 +1,3 @@
+#pragma once
+
+struct object_type;
diff --git a/src/option_type.hpp b/src/option_type.hpp
new file mode 100644
index 00000000..58834b79
--- /dev/null
+++ b/src/option_type.hpp
@@ -0,0 +1,40 @@
+#pragma once
+
+#include "h-basic.h"
+
+/**
+ * Option descriptor.
+ */
+struct option_type
+{
+ /**
+ * Address of actual option variable. NULL signals the
+ * end of the table.
+ */
+ bool_ *o_var;
+
+ /**
+ * Default value.
+ */
+ byte o_norm;
+
+ /**
+ * Option page number.
+ */
+ byte o_page;
+
+ /**
+ * Savefile bit in the page-specific list of options.
+ */
+ byte o_bit;
+
+ /**
+ * Textual name.
+ */
+ cptr o_text;
+
+ /**
+ * Textual description
+ */
+ cptr o_desc;
+};
diff --git a/src/options.cc b/src/options.cc
new file mode 100644
index 00000000..5501ab52
--- /dev/null
+++ b/src/options.cc
@@ -0,0 +1,89 @@
+#include "options.hpp"
+
+//
+// Option Set 1 -- User Interface
+//
+bool_ rogue_like_commands; /* Rogue-like commands */
+bool_ quick_messages; /* Activate quick messages */
+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_ always_repeat; /* Repeat obvious commands */
+bool_ ring_bell; /* Ring the bell (on errors, etc) */
+
+//
+// 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_ small_levels; /* Allow unusually small dungeon levels */
+bool_ empty_levels; /* Allow empty 'arena' levels */
+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_scum; /* Auto-scum for good levels */
+bool_ view_perma_grids; /* Map remembers all perma-lit grids */
+bool_ view_torch_grids; /* Map remembers all torch-lit grids */
+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_ smart_learn; /* Monsters learn from their mistakes */
+
+//
+// Option Set 4 -- Efficiency
+//
+bool_ view_reduce_lite; /* Reduce lite-radius when running */
+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) */
+bool_ center_player; /* Center view on player */
+
+//
+// Option Set 5 - ToME options
+//
+bool_ linear_stats;
+bool_ player_char_health; /* Display the player as a special symbol when in bad health ? */
+bool_ option_ingame_help; /* Ingame contextual help */
+bool_ auto_more; /* Auto more */
+bool_ inventory_no_move; /* In inventory option window, just erase the letters,
+ * rather that displaying the list without the invalid
+ * selections */
+
+//
+// Option Set 6 - Birth options
+//
+bool_ always_small_level;
+bool_ autoroll;
+bool_ fate_option;
+bool_ ironman_rooms;
+bool_ joke_monsters;
+bool_ point_based;
+bool_ preserve;
+bool_ no_selling;
diff --git a/src/options.hpp b/src/options.hpp
new file mode 100644
index 00000000..45e19cf7
--- /dev/null
+++ b/src/options.hpp
@@ -0,0 +1,89 @@
+#pragma once
+
+#include "h-basic.h"
+
+//
+// Option Set 1 -- User Interface.
+//
+extern bool_ rogue_like_commands;
+extern bool_ quick_messages;
+extern bool_ carry_query_flag;
+extern bool_ use_old_target;
+extern bool_ always_pickup;
+extern bool_ always_repeat;
+extern bool_ ring_bell;
+
+//
+// Option Set 2 -- Disturbance
+//
+extern bool_ find_ignore_stairs;
+extern bool_ find_ignore_doors;
+extern bool_ find_cut;
+extern bool_ find_examine;
+extern bool_ disturb_move;
+extern bool_ disturb_near;
+extern bool_ disturb_panel;
+extern bool_ disturb_detect;
+extern bool_ disturb_state;
+extern bool_ disturb_minor;
+extern bool_ disturb_other;
+extern bool_ alert_hitpoint;
+extern bool_ alert_failure;
+extern bool_ last_words;
+extern bool_ small_levels;
+extern bool_ empty_levels;
+extern bool_ confirm_stairs;
+extern bool_ wear_confirm;
+extern bool_ disturb_pets;
+
+//
+// Option Set 3 -- Game-Play
+//
+extern bool_ auto_scum;
+extern bool_ view_perma_grids;
+extern bool_ view_torch_grids;
+extern bool_ dungeon_align;
+extern bool_ dungeon_stair;
+extern bool_ flow_by_sound;
+extern bool_ smart_learn;
+
+//
+// Option Set 4 -- Efficiency
+//
+extern bool_ view_reduce_lite;
+extern bool_ avoid_abort;
+extern bool_ avoid_shimmer;
+extern bool_ avoid_other;
+extern bool_ flush_failure;
+extern bool_ flush_disturb;
+extern bool_ flush_command;
+extern bool_ fresh_before;
+extern bool_ fresh_after;
+extern bool_ fresh_message;
+extern bool_ hilite_player;
+extern bool_ view_yellow_lite;
+extern bool_ view_bright_lite;
+extern bool_ view_granite_lite;
+extern bool_ view_special_lite;
+extern bool_ center_player;
+
+//
+// Option Set 5 - ToME options
+//
+extern bool_ linear_stats;
+extern bool_ player_char_health;
+extern bool_ option_ingame_help;
+extern bool_ auto_more;
+extern bool_ inventory_no_move;
+
+//
+// Option Set 6 - Birth options
+//
+extern bool_ always_small_level;
+extern bool_ autoroll;
+extern bool_ fate_option;
+extern bool_ ironman_rooms;
+extern bool_ joke_monsters;
+extern bool_ point_based;
+extern bool_ preserve;
+extern bool_ no_selling;
diff --git a/src/owner_type.hpp b/src/owner_type.hpp
new file mode 100644
index 00000000..703d3159
--- /dev/null
+++ b/src/owner_type.hpp
@@ -0,0 +1,39 @@
+#pragma once
+
+#include "h-basic.h"
+
+/*
+ * Store owner descriptor.
+ */
+struct owner_type
+{
+ /**
+ * Name
+ */
+ const char *name;
+
+ /**
+ * Purse limit
+ */
+ s16b max_cost;
+
+ /**
+ * Inflation
+ */
+ s16b inflation;
+
+ /**
+ * Liked/hated races.
+ */
+ u32b races[2][2];
+
+ /**
+ * Liked/hated classes
+ */
+ u32b classes[2][2];
+
+ /**
+ * Costs for liked people
+ */
+ s16b costs[3];
+};
diff --git a/src/owner_type_fwd.hpp b/src/owner_type_fwd.hpp
new file mode 100644
index 00000000..20c25802
--- /dev/null
+++ b/src/owner_type_fwd.hpp
@@ -0,0 +1,3 @@
+#pragma once
+
+struct owner_type;
diff --git a/src/player.pkg b/src/player.pkg
deleted file mode 100644
index dfdced26..00000000
--- a/src/player.pkg
+++ /dev/null
@@ -1,3519 +0,0 @@
-/* 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
deleted file mode 100644
index f55f9325..00000000
--- a/src/player_c.pkg
+++ /dev/null
@@ -1,1060 +0,0 @@
-/* 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/player_class.hpp b/src/player_class.hpp
new file mode 100644
index 00000000..d67d1d73
--- /dev/null
+++ b/src/player_class.hpp
@@ -0,0 +1,105 @@
+#pragma once
+
+#include "body.hpp"
+#include "h-basic.h"
+#include "player_defs.hpp"
+#include "player_spec.hpp"
+
+/**
+ * Maximum number of specialties.
+ */
+constexpr int MAX_SPEC = 20;
+
+/**
+ * Player descriptor and runtime data.
+ */
+struct player_class
+{
+ const char *title; /* Type of class */
+ char *desc; /* Small desc of the class */
+ const char *titles[PY_MAX_LEVEL / 5];
+ /* Titles */
+
+ 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) */
+};
+
diff --git a/src/player_class_fwd.hpp b/src/player_class_fwd.hpp
new file mode 100644
index 00000000..2402934d
--- /dev/null
+++ b/src/player_class_fwd.hpp
@@ -0,0 +1,3 @@
+#pragma once
+
+struct player_class;
diff --git a/src/player_defs.hpp b/src/player_defs.hpp
new file mode 100644
index 00000000..2f57409c
--- /dev/null
+++ b/src/player_defs.hpp
@@ -0,0 +1,6 @@
+#pragma once
+
+/**
+ * Maximum player level
+ */
+#define PY_MAX_LEVEL 50
diff --git a/src/player_race.hpp b/src/player_race.hpp
new file mode 100644
index 00000000..edb304f2
--- /dev/null
+++ b/src/player_race.hpp
@@ -0,0 +1,83 @@
+#pragma once
+
+#include "h-basic.h"
+#include "body.hpp"
+#include "player_defs.hpp"
+#include "skills_defs.hpp"
+
+/**
+ * Player racial descriptior.
+ */
+struct player_race
+{
+ const char *title; /* Type of race */
+ char *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) */
+};
diff --git a/src/player_race_fwd.hpp b/src/player_race_fwd.hpp
new file mode 100644
index 00000000..c3c3350b
--- /dev/null
+++ b/src/player_race_fwd.hpp
@@ -0,0 +1,3 @@
+#pragma once
+
+struct player_race;
diff --git a/src/player_race_mod.hpp b/src/player_race_mod.hpp
new file mode 100644
index 00000000..72f975ce
--- /dev/null
+++ b/src/player_race_mod.hpp
@@ -0,0 +1,87 @@
+#pragma once
+
+#include "body.hpp"
+#include "h-basic.h"
+#include "skills_defs.hpp"
+
+struct player_race_mod
+{
+ char *title; /* Type of race mod */
+ char *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) */
+};
+
diff --git a/src/player_race_mod_fwd.hpp b/src/player_race_mod_fwd.hpp
new file mode 100644
index 00000000..12eb468a
--- /dev/null
+++ b/src/player_race_mod_fwd.hpp
@@ -0,0 +1,3 @@
+#pragma once
+
+struct player_race_mod;
diff --git a/src/player_sex.hpp b/src/player_sex.hpp
new file mode 100644
index 00000000..5722f1a4
--- /dev/null
+++ b/src/player_sex.hpp
@@ -0,0 +1,17 @@
+#pragma once
+
+/**
+ * Player sex descriptor.
+ */
+struct player_sex
+{
+ /**
+ * Type of sex.
+ */
+ char const *title;
+
+ /**
+ * Winner title.
+ */
+ char const *winner;
+};
diff --git a/src/player_sex_fwd.hpp b/src/player_sex_fwd.hpp
new file mode 100644
index 00000000..eabea488
--- /dev/null
+++ b/src/player_sex_fwd.hpp
@@ -0,0 +1,3 @@
+#pragma once
+
+struct player_sex;
diff --git a/src/player_spec.hpp b/src/player_spec.hpp
new file mode 100644
index 00000000..28b32830
--- /dev/null
+++ b/src/player_spec.hpp
@@ -0,0 +1,38 @@
+#pragma once
+
+#include "h-basic.h"
+#include "skills_defs.hpp"
+
+/**
+ * Player class descriptor.
+ */
+struct player_spec
+{
+ const char *title; /* Type of class spec */
+ char *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) */
+};
diff --git a/src/player_spec_fwd.hpp b/src/player_spec_fwd.hpp
new file mode 100644
index 00000000..9083acd0
--- /dev/null
+++ b/src/player_spec_fwd.hpp
@@ -0,0 +1,3 @@
+#pragma once
+
+struct player_spec;
diff --git a/src/player_type.hpp b/src/player_type.hpp
new file mode 100644
index 00000000..d9410dcb
--- /dev/null
+++ b/src/player_type.hpp
@@ -0,0 +1,423 @@
+#pragma once
+
+#include "corrupt.hpp"
+#include "h-basic.h"
+#include "help_info.hpp"
+#include "inventory.hpp"
+#include "object_type.hpp"
+#include "powers.hpp"
+
+/*
+ * 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.
+ */
+
+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 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 inside_quest; /* Inside quest level */
+
+ 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. */
+ s32b grace_delay; /* Delay factor for granting piety. */
+ 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 tim_esp; /* Timed ESP */
+ s16b tim_wraith; /* Timed wraithform */
+ s16b tim_ffall; /* Timed Levitation */
+ s16b tim_fly; /* Timed Levitation */
+ 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 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 strike; /* True Strike(+25 hit) */
+ s16b tim_reflect; /* Timed Reflection */
+ 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 */
+ 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 tim_precognition; /* Timed precognition */
+
+ s16b immov_cntr; /* Timed -- Last ``immovable'' command. */
+
+ 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 */
+
+ 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_ammo; /* Correct ammo tval */
+
+ s16b pspeed; /* Current speed */
+
+ u32b mimic_extra; /* Mimicry powers use that */
+ u32b antimagic_extra; /* Antimagic powers */
+ u32b music_extra; /* Music songs */
+ u32b necro_extra; /* Necro powers */
+ u32b necro_extra2; /* Necro powers */
+
+ 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[CORRUPTIONS_MAX];
+ bool_ corrupt_anti_teleport_stopped;
+
+ /*** 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[POWER_MAX]; /* Actual powers */
+ bool_ powers_mod[POWER_MAX]; /* 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 */
+
+ /* Dripping Tread spell timer */
+ s16b dripping_tread;
+
+ /* Help */
+ help_info help;
+
+ /* Inertia control */
+ s32b inertia_controlled_spell;
+
+ /* For automatic stat-gain */
+ s16b last_rewarded_level;
+
+ /*** Temporary fields ***/
+
+ bool_ did_nothing; /* True if the last action wasnt a real action */
+ bool_ leaving; /* True if player is leaving */
+};
+
diff --git a/src/player_type_fwd.hpp b/src/player_type_fwd.hpp
new file mode 100644
index 00000000..45a4bbcf
--- /dev/null
+++ b/src/player_type_fwd.hpp
@@ -0,0 +1,3 @@
+#pragma once
+
+struct player_type;
diff --git a/src/plots.c b/src/plots.c
deleted file mode 100644
index 53d3e1bc..00000000
--- a/src/plots.c
+++ /dev/null
@@ -1,473 +0,0 @@
-/* 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
deleted file mode 100644
index a1a11e6c..00000000
--- a/src/plots.h
+++ /dev/null
@@ -1,48 +0,0 @@
-/* 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/power_type.hpp b/src/power_type.hpp
new file mode 100644
index 00000000..6cf8c29b
--- /dev/null
+++ b/src/power_type.hpp
@@ -0,0 +1,19 @@
+#pragma once
+
+#include "h-basic.h"
+
+/**
+ * Power descriptor. (Racial, class, mutation, artifacts, ...)
+ */
+struct power_type
+{
+ const char *name; /* Name */
+ const char *desc_text; /* Text describing power */
+ const char *gain_text; /* Text displayed on gaining the power */
+ const 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 */
+};
diff --git a/src/powers.c b/src/powers.c
deleted file mode 100644
index 12b2c2c0..00000000
--- a/src/powers.c
+++ /dev/null
@@ -1,1388 +0,0 @@
-/* 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/powers.cc b/src/powers.cc
new file mode 100644
index 00000000..a7db2968
--- /dev/null
+++ b/src/powers.cc
@@ -0,0 +1,1221 @@
+/*
+ * 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 "powers.hpp"
+
+#include "cave.hpp"
+#include "cave_type.hpp"
+#include "cmd1.hpp"
+#include "cmd2.hpp"
+#include "cmd7.hpp"
+#include "feature_type.hpp"
+#include "files.hpp"
+#include "hooks.hpp"
+#include "mimic.hpp"
+#include "monster2.hpp"
+#include "monster3.hpp"
+#include "monster_race.hpp"
+#include "monster_type.hpp"
+#include "object1.hpp"
+#include "object2.hpp"
+#include "object_kind.hpp"
+#include "options.hpp"
+#include "player_type.hpp"
+#include "quark.hpp"
+#include "spells1.hpp"
+#include "spells2.hpp"
+#include "stats.hpp"
+#include "tables.hpp"
+#include "traps.hpp"
+#include "util.hpp"
+#include "util.h"
+#include "variable.h"
+#include "variable.hpp"
+#include "xtra2.hpp"
+#include "z-rand.hpp"
+
+/*
+ * Note: return value indicates the amount of mana to use
+ */
+static 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_FRAME);
+
+ /* 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_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;
+ 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];
+ auto const r_ptr = m_ptr->race();
+
+ 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;
+
+ /* Get an item */
+ q = "Awaken which monster? ";
+ s = "You have no monster to awaken.";
+ if (!get_item(&item, q, s, (USE_FLOOR), object_filter::TVal(TV_HYPNOS))) 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;
+
+ /* Get an item */
+ q = "Drain which item? ";
+ s = "You have nothing to drain.";
+ if (!get_item(&item, q, s, (USE_INVEN | USE_FLOOR), item_tester_hook_recharge())) 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:
+ {
+ if (!get_rep_dir(&dir)) return;
+ const int x = p_ptr->px + ddx[dir];
+ const int y = p_ptr->py + ddy[dir];
+ cave_type *c_ptr = &cave[y][x];
+ if (!(c_ptr->m_idx))
+ {
+ msg_print("You sense no evil there!");
+ break;
+ }
+
+ monster_type *m_ptr = &m_list[c_ptr->m_idx];
+ auto const r_ptr = m_ptr->race();
+
+ 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;
+
+ case POWER_INVISIBILITY:
+ set_invis(20 + randint(30), 30);
+ break;
+
+ case POWER_WEB:
+ /* Warning, beware of f_info changes .. I hate to do that .. */
+ grow_things(16, 1 + (p_ptr->lev / 10));
+ break;
+
+ case POWER_COR_SPACE_TIME:
+ if (p_ptr->corrupt_anti_teleport_stopped)
+ {
+ p_ptr->corrupt_anti_teleport_stopped = FALSE;
+ msg_print("You stop controlling your corruption.");
+ p_ptr->update |= PU_BONUS;
+ }
+ else
+ {
+ p_ptr->corrupt_anti_teleport_stopped = TRUE;
+ msg_print("You start controlling your corruption, teleportation works once more.");
+ p_ptr->update |= PU_BONUS;
+ }
+ break;
+
+ default:
+ abort();
+ break;
+ }
+
+ p_ptr->redraw |= (PR_FRAME);
+ p_ptr->window |= (PW_PLAYER);
+}
+
+/*
+ * Print a batch of power.
+ */
+static void print_power_batch(int *p, int start, int max)
+{
+ char buff[80];
+ power_type* spell;
+ int i = start, j = 0;
+
+ 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);
+
+ prt(buff, 2 + j, 20);
+ j++;
+ }
+ 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;
+ int p[POWER_MAX];
+
+ /* 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);
+ which = inkey();
+
+ if (which == ESCAPE)
+ {
+ *x_idx = -1;
+ ret = NULL;
+ break;
+ }
+ 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;
+ }
+
+ 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/powers.hpp b/src/powers.hpp
new file mode 100644
index 00000000..35d317b0
--- /dev/null
+++ b/src/powers.hpp
@@ -0,0 +1,74 @@
+#pragma once
+
+extern void do_cmd_power();
+
+/*
+ * Powers (mutation, activations, ...)
+ */
+#define POWER_MAX 65
+
+#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_COMPANION 58
+#define PWR_BEAR 59
+#define PWR_DODGE 60
+#define PWR_BALROG 61
+#define POWER_INVISIBILITY 62
+#define POWER_WEB 63
+#define POWER_COR_SPACE_TIME 64
diff --git a/src/q_betwen.c b/src/q_betwen.c
deleted file mode 100644
index e6452dd9..00000000
--- a/src/q_betwen.c
+++ /dev/null
@@ -1,188 +0,0 @@
-#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_betwen.cc b/src/q_betwen.cc
new file mode 100644
index 00000000..2bebe452
--- /dev/null
+++ b/src/q_betwen.cc
@@ -0,0 +1,212 @@
+#include "q_betwen.hpp"
+
+#include "cave.hpp"
+#include "cave_type.hpp"
+#include "hook_chardump_in.hpp"
+#include "hook_init_quest_in.hpp"
+#include "hook_move_in.hpp"
+#include "hook_quest_finish_in.hpp"
+#include "hooks.hpp"
+#include "init1.hpp"
+#include "monster2.hpp"
+#include "monster_type.hpp"
+#include "object2.hpp"
+#include "player_type.hpp"
+#include "tables.hpp"
+#include "util.hpp"
+#include "variable.hpp"
+
+#define cquest (quest[QUEST_BETWEEN])
+
+static bool_ quest_between_move_hook(void *, void *in_, void *)
+{
+ struct hook_move_in *in = static_cast<struct hook_move_in *>(in_);
+ s32b y = in->y;
+ s32b x = in->x;
+ cave_type *c_ptr;
+
+ 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;
+}
+
+static bool_ quest_between_gen_hook(void *, void *, void *)
+{
+ 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;
+}
+
+static bool_ quest_between_finish_hook(void *, void *in_, void *)
+{
+ struct hook_quest_finish_in *in = static_cast<struct hook_quest_finish_in *>(in_);
+ s32b q_idx = in->q_idx;
+ object_type forge, *q_ptr;
+
+ 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_new(HOOK_QUEST_FINISH, quest_between_finish_hook);
+ process_hooks_restart = TRUE;
+
+ return TRUE;
+}
+
+static bool_ quest_between_death_hook(void *, void *, void *)
+{
+ 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;
+}
+
+static bool_ quest_between_dump_hook(void *, void *in_, void *)
+{
+ struct hook_chardump_in *in = static_cast<struct hook_chardump_in *>(in_);
+ FILE *f = in->file;
+
+ if (cquest.status >= QUEST_STATUS_COMPLETED)
+ {
+ fprintf(f, "\n You established a permanent void jumpgates liaison between Minas Anor and Gondolin,");
+ fprintf(f, "\n thus allowing the last alliance to exist.");
+ }
+ return (FALSE);
+}
+
+static bool_ quest_between_forbid_hook(void *, void *in_, void *)
+{
+ hook_init_quest_in *in = static_cast<struct hook_init_quest_in *>(in_);
+ s32b q_idx = in->q_idx;
+
+ 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_new(HOOK_MOVE, quest_between_move_hook, "between_move", NULL);
+ add_hook_new(HOOK_GEN_QUEST, quest_between_gen_hook, "between_gen", NULL);
+ add_hook_new(HOOK_QUEST_FINISH, quest_between_finish_hook, "between_finish", NULL);
+ add_hook_new(HOOK_MONSTER_DEATH, quest_between_death_hook, "between_death", NULL);
+ }
+ add_hook_new(HOOK_CHAR_DUMP, quest_between_dump_hook, "between_dump", NULL);
+ add_hook_new(HOOK_INIT_QUEST, quest_between_forbid_hook, "between_forbid", NULL);
+ return (FALSE);
+}
diff --git a/src/q_betwen.hpp b/src/q_betwen.hpp
new file mode 100644
index 00000000..d2fc08f0
--- /dev/null
+++ b/src/q_betwen.hpp
@@ -0,0 +1,5 @@
+#pragma once
+
+#include "h-basic.h"
+
+bool_ quest_between_init_hook(int q_idx);
diff --git a/src/q_bounty.cc b/src/q_bounty.cc
new file mode 100644
index 00000000..bb84d48d
--- /dev/null
+++ b/src/q_bounty.cc
@@ -0,0 +1,170 @@
+#include "q_bounty.hpp"
+
+#include "monster2.hpp"
+#include "monster_race.hpp"
+#include "object1.hpp"
+#include "object2.hpp"
+#include "object_type.hpp"
+#include "player_type.hpp"
+#include "skill_type.hpp"
+#include "tables.hpp"
+#include "util.hpp"
+#include "variable.hpp"
+
+#define cquest (quest[QUEST_BOUNTY])
+
+#define bounty_quest_monster (cquest.data[0])
+
+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);
+}
+
+static int 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;
+}
+
+static bool bounty_item_tester_hook(object_type const *o_ptr)
+{
+ return ((o_ptr->tval == TV_CORPSE) && (o_ptr->pval2 == bounty_quest_monster));
+}
+
+bool_ quest_bounty_init_hook(int dummy)
+{
+ return FALSE;
+}
+
+bool_ quest_bounty_drop_item()
+{
+ char mdesc[512];
+ char msg[512];
+
+ if (cquest.status == QUEST_STATUS_UNTAKEN)
+ {
+ cquest.status = QUEST_STATUS_TAKEN;
+ bounty_quest_monster = get_new_bounty_monster(3 + (p_ptr->lev * 3) / 2);
+
+ monster_race_desc(mdesc, bounty_quest_monster, 0);
+ snprintf(msg, sizeof(msg), "You must bring me back %s corpse.", mdesc);
+ msg_print(msg);
+ }
+ else
+ {
+ monster_race_desc(mdesc, bounty_quest_monster, 0);
+ snprintf(msg, sizeof(msg), "You still must bring me back %s corpse.", mdesc);
+ msg_print(msg);
+ }
+ return FALSE;
+}
+
+bool_ quest_bounty_get_item()
+{
+ if (cquest.status != QUEST_STATUS_TAKEN)
+ {
+ msg_print("You do not have any bounty quest yet.");
+ return FALSE;
+ }
+
+ // Get the corpse.
+ int item = -1;
+ bool_ ret =
+ get_item(&item,
+ "What corpse to return?",
+ "You have no corpse to return.",
+ USE_INVEN,
+ bounty_item_tester_hook);
+ if (!ret) {
+ return FALSE;
+ }
+
+ // 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.");
+
+ skill_type *lore = &s_info[SKILL_LORE];
+ skill_type *preservation = &s_info[SKILL_PRESERVATION];
+
+ if (lore->mod == 0) {
+ lore->mod = 900;
+ lore->dev = TRUE;
+ }
+ lore->value += lore->mod;
+
+ if (preservation->mod == 0) {
+ preservation->value = 800;
+ preservation->mod = 800;
+ preservation->dev = TRUE;
+ msg_print("I see you don't know the corpse preservation skill, I shall teach you it too.");
+ }
+
+ // Need to ask for new quest.
+ cquest.status = QUEST_STATUS_UNTAKEN;
+ bounty_quest_monster = 0;
+ return FALSE;
+}
+
+bool_ quest_bounty_describe(FILE *fff)
+{
+ char mdesc[512];
+
+ if (cquest.status == QUEST_STATUS_TAKEN)
+ {
+ monster_race_desc(mdesc, bounty_quest_monster, 0);
+
+ fprintf(fff, "#####yBounty quest!\n");
+ fprintf(fff, "You must bring back %s corpse to the beastmaster.\n", mdesc);
+ fprintf(fff, "\n");
+
+ return TRUE;
+ }
+
+ return FALSE;
+}
diff --git a/src/q_bounty.hpp b/src/q_bounty.hpp
new file mode 100644
index 00000000..234c036d
--- /dev/null
+++ b/src/q_bounty.hpp
@@ -0,0 +1,8 @@
+#pragma once
+
+#include "h-basic.h"
+
+extern bool_ quest_bounty_init_hook(int q_idx);
+extern bool_ quest_bounty_drop_item();
+extern bool_ quest_bounty_get_item();
+extern bool_ quest_bounty_describe(FILE *fff);
diff --git a/src/q_dragons.c b/src/q_dragons.c
deleted file mode 100644
index 025e8ecd..00000000
--- a/src/q_dragons.c
+++ /dev/null
@@ -1,150 +0,0 @@
-#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_dragons.cc b/src/q_dragons.cc
new file mode 100644
index 00000000..6c6084d1
--- /dev/null
+++ b/src/q_dragons.cc
@@ -0,0 +1,164 @@
+#include "q_dragons.hpp"
+
+#include "cave.hpp"
+#include "cave_type.hpp"
+#include "feature_type.hpp"
+#include "hook_quest_finish_in.hpp"
+#include "hooks.hpp"
+#include "init1.hpp"
+#include "monster2.hpp"
+#include "monster_type.hpp"
+#include "player_type.hpp"
+#include "tables.hpp"
+#include "util.hpp"
+#include "variable.hpp"
+#include "z-rand.hpp"
+
+#define cquest (quest[QUEST_DRAGONS])
+
+static bool_ quest_dragons_gen_hook(void *, void *, void *)
+{
+ 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;
+}
+
+static bool_ quest_dragons_death_hook(void *, void *, void *)
+{
+ 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_new(HOOK_MONSTER_DEATH, quest_dragons_death_hook);
+ del_hook_new(HOOK_GEN_QUEST, quest_dragons_gen_hook);
+ process_hooks_restart = TRUE;
+
+ cmsg_print(TERM_YELLOW, "Gondolin is safer now.");
+ return (FALSE);
+ }
+ return FALSE;
+}
+
+static bool_ quest_dragons_finish_hook(void *, void *in_, void *)
+{
+ struct hook_quest_finish_in *in = static_cast<struct hook_quest_finish_in *>(in_);
+ s32b q_idx = in->q_idx;
+
+ 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_new(HOOK_MONSTER_DEATH, quest_dragons_death_hook, "dragons_monster_death", NULL);
+ add_hook_new(HOOK_QUEST_FINISH, quest_dragons_finish_hook, "dragons_finish", NULL);
+ add_hook_new(HOOK_GEN_QUEST, quest_dragons_gen_hook, "dragons_geb", NULL);
+ }
+ return (FALSE);
+}
diff --git a/src/q_dragons.hpp b/src/q_dragons.hpp
new file mode 100644
index 00000000..f0aa50f2
--- /dev/null
+++ b/src/q_dragons.hpp
@@ -0,0 +1,5 @@
+#pragma once
+
+#include "h-basic.h"
+
+bool_ quest_dragons_init_hook(int q_idx);
diff --git a/src/q_eol.c b/src/q_eol.c
deleted file mode 100644
index 5b1cf78e..00000000
--- a/src/q_eol.c
+++ /dev/null
@@ -1,195 +0,0 @@
-#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_eol.cc b/src/q_eol.cc
new file mode 100644
index 00000000..f27ce9df
--- /dev/null
+++ b/src/q_eol.cc
@@ -0,0 +1,226 @@
+#include "q_eol.hpp"
+
+#include "cave.hpp"
+#include "cave_type.hpp"
+#include "generate.hpp"
+#include "hook_stair_in.hpp"
+#include "hook_quest_finish_in.hpp"
+#include "hook_quest_fail_in.hpp"
+#include "hook_monster_death_in.hpp"
+#include "hooks.hpp"
+#include "monster2.hpp"
+#include "monster_race.hpp"
+#include "monster_type.hpp"
+#include "object2.hpp"
+#include "player_type.hpp"
+#include "tables.hpp"
+#include "traps.hpp"
+#include "util.hpp"
+#include "variable.hpp"
+#include "z-rand.hpp"
+
+#include <cassert>
+
+#define cquest (quest[QUEST_EOL])
+
+GENERATE_MONSTER_LOOKUP_FN(get_eol, "Eol, the Dark Elf")
+
+static bool_ quest_eol_gen_hook(void *, void *, void *)
+{
+ 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)
+ {
+ // Find Eol's r_info entry
+ int r_idx = get_eol();
+ // "Summon" Eol
+ m_allow_special[r_idx] = TRUE;
+ m_idx = place_monster_one(y, x, r_idx, 0, FALSE, MSTATUS_ENEMY);
+ m_allow_special[r_idx] = FALSE;
+ // Mark with the QUEST flag
+ 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;
+}
+
+static bool_ quest_eol_finish_hook(void *, void *in_, void *)
+{
+ struct hook_quest_finish_in *in = static_cast<struct hook_quest_finish_in *>(in_);
+ s32b q_idx = in->q_idx;
+ object_type forge, *q_ptr;
+
+ 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_new(HOOK_QUEST_FINISH, quest_eol_finish_hook);
+ process_hooks_restart = TRUE;
+
+ return TRUE;
+}
+
+static bool_ quest_eol_fail_hook(void *, void *in_, void *)
+{
+ struct hook_quest_fail_in *in = static_cast<struct hook_quest_fail_in *>(in_);
+ s32b q_idx = in->q_idx;
+
+ 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_new(HOOK_QUEST_FAIL, quest_eol_fail_hook);
+ process_hooks_restart = TRUE;
+
+ return TRUE;
+}
+
+static bool_ quest_eol_death_hook(void *, void *in_, void *)
+{
+ struct hook_monster_death_in *in = static_cast<struct hook_monster_death_in *>(in_);
+ s32b m_idx = in->m_idx;
+ s32b r_idx = m_list[m_idx].r_idx;
+
+ if (p_ptr->inside_quest != QUEST_EOL) return FALSE;
+
+ if (r_idx == get_eol())
+ {
+ cmsg_print(TERM_YELLOW, "Such a sad end...");
+ cquest.status = QUEST_STATUS_COMPLETED;
+
+ del_hook_new(HOOK_MONSTER_DEATH, quest_eol_death_hook);
+ process_hooks_restart = TRUE;
+
+ return (FALSE);
+ }
+
+ return FALSE;
+}
+
+static bool_ quest_eol_stair_hook(void *, void *in_, void *)
+{
+ struct hook_stair_in *in = static_cast<struct hook_stair_in *>(in_);
+ monster_race *r_ptr = &r_info[get_eol()];
+
+ 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 (in->direction == STAIRS_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_new(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_new(HOOK_MONSTER_DEATH, quest_eol_death_hook, "eol_death", NULL);
+ add_hook_new(HOOK_GEN_QUEST, quest_eol_gen_hook, "eol_gen", NULL);
+ add_hook_new(HOOK_STAIR, quest_eol_stair_hook, "eol_stair", NULL);
+ add_hook_new(HOOK_QUEST_FAIL, quest_eol_fail_hook, "eol_fail", NULL);
+ add_hook_new(HOOK_QUEST_FINISH, quest_eol_finish_hook, "eol_finish", NULL);
+ }
+ return (FALSE);
+}
diff --git a/src/q_eol.hpp b/src/q_eol.hpp
new file mode 100644
index 00000000..ab7f1274
--- /dev/null
+++ b/src/q_eol.hpp
@@ -0,0 +1,5 @@
+#pragma once
+
+#include "h-basic.h"
+
+bool_ quest_eol_init_hook(int q_idx);
diff --git a/src/q_evil.c b/src/q_evil.c
deleted file mode 100644
index a143f65c..00000000
--- a/src/q_evil.c
+++ /dev/null
@@ -1,117 +0,0 @@
-#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_evil.cc b/src/q_evil.cc
new file mode 100644
index 00000000..3bc953cd
--- /dev/null
+++ b/src/q_evil.cc
@@ -0,0 +1,132 @@
+#include "q_evil.hpp"
+
+#include "cave.hpp"
+#include "cave_type.hpp"
+#include "feature_type.hpp"
+#include "hook_quest_finish_in.hpp"
+#include "hooks.hpp"
+#include "init1.hpp"
+#include "monster2.hpp"
+#include "monster_type.hpp"
+#include "player_type.hpp"
+#include "tables.hpp"
+#include "util.hpp"
+#include "variable.hpp"
+#include "z-rand.hpp"
+
+#define cquest (quest[QUEST_EVIL])
+
+static bool_ quest_evil_gen_hook(void *, void *, void *)
+{
+ 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;
+}
+
+static bool_ quest_evil_death_hook(void *, void *, void *)
+{
+ 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_new(HOOK_MONSTER_DEATH, quest_evil_death_hook);
+ del_hook_new(HOOK_GEN_QUEST, quest_evil_gen_hook);
+ process_hooks_restart = TRUE;
+
+ cmsg_print(TERM_YELLOW, "Khazad-Dum is safer now.");
+ return (FALSE);
+ }
+ return FALSE;
+}
+
+static bool_ quest_evil_finish_hook(void *, void *in_, void *)
+{
+ struct hook_quest_finish_in *in = static_cast<struct hook_quest_finish_in *>(in_);
+ s32b q_idx = in->q_idx;
+
+ 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_new(HOOK_MONSTER_DEATH, quest_evil_death_hook, "evil_monster_death", NULL);
+ add_hook_new(HOOK_QUEST_FINISH, quest_evil_finish_hook, "evil_finish", NULL);
+ add_hook_new(HOOK_GEN_QUEST, quest_evil_gen_hook, "evil_geb", NULL);
+ }
+ return (FALSE);
+}
diff --git a/src/q_evil.hpp b/src/q_evil.hpp
new file mode 100644
index 00000000..06fb17e1
--- /dev/null
+++ b/src/q_evil.hpp
@@ -0,0 +1,5 @@
+#pragma once
+
+#include "h-basic.h"
+
+bool_ quest_evil_init_hook(int q_idx);
diff --git a/src/q_fireprof.cc b/src/q_fireprof.cc
new file mode 100644
index 00000000..021cf2fb
--- /dev/null
+++ b/src/q_fireprof.cc
@@ -0,0 +1,577 @@
+#include "q_fireprof.hpp"
+
+#include "cave_type.hpp"
+#include "feature_type.hpp"
+#include "hook_get_in.hpp"
+#include "hooks.hpp"
+#include "lua_bind.hpp"
+#include "object1.hpp"
+#include "object2.hpp"
+#include "object_type.hpp"
+#include "player_type.hpp"
+#include "quark.hpp"
+#include "tables.hpp"
+#include "traps.hpp"
+#include "util.hpp"
+#include "variable.hpp"
+#include "z-rand.hpp"
+
+#include <cassert>
+
+#define cquest (quest[QUEST_FIREPROOF])
+
+#define print_hook(fmt,...) do { fprintf(hook_file, fmt, ##__VA_ARGS__); } while (0)
+
+/*
+ * Per-module "settings"
+ */
+typedef struct fireproof_settings fireproof_settings;
+struct fireproof_settings
+{
+ byte tval; /* tval of object to use. */
+ cptr tval_name; /* descriptive name of tval */
+ cptr tval_name_plural; /* descriptive name of tval (plural) */
+ byte sval_max; /* max sval of object to use; sval will be 1<=X<=sval_max. */
+ s32b total_points; /* total number of points awarded */
+};
+
+static fireproof_settings const *fireproof_get_settings()
+{
+ static fireproof_settings fireproof_settings =
+ { TV_RUNE2, "rune", "runes", 5, 24 };
+ return &fireproof_settings;
+}
+
+/* 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. */
+#define FIREPROOF_BOOK_POINTS 4
+#define FIREPROOF_STAFF_POINTS 3
+#define FIREPROOF_SCROLL_POINTS 1
+
+static s32b get_item_points_remaining()
+{
+ fireproof_settings const *settings = fireproof_get_settings();
+ return settings->total_points - cquest.data[0];
+}
+
+static void set_item_points_remaining(s32b v)
+{
+ fireproof_settings const *settings = fireproof_get_settings();
+ cquest.data[0] = settings->total_points - v;
+}
+
+static void fireproof_set_sval(int sval_max)
+{
+ cquest.data[1] = sval_max;
+}
+
+static int fireproof_get_sval()
+{
+ return cquest.data[1];
+}
+
+static bool item_tester_hook_eligible(object_type const *o_ptr)
+{
+ /* check it's the 'marked' item */
+ return ((o_ptr->tval == fireproof_get_settings()->tval) &&
+ (o_ptr->sval == fireproof_get_sval()) &&
+ (o_ptr->pval2 == fireproof_get_sval()));
+}
+
+static object_filter_t const &item_tester_hook_proofable()
+{
+ using namespace object_filter;
+ static auto instance = And(
+ // Must be the correct item base type
+ Or(
+ TVal(TV_BOOK),
+ TVal(TV_SCROLL),
+ TVal(TV_STAFF)),
+ // Must NOT already be fireproof
+ Not(
+ HasFlag3(TR3_IGNORE_FIRE)));
+ return instance;
+}
+
+/*
+ * This function makes sure the player has enough 'points' left to fireproof stuff.
+ */
+static bool_ fireproof_enough_points(object_type *o_ptr, int *stack)
+{
+ int item_value;
+
+ /* are the items in a stack? */
+ if (o_ptr->number > 1)
+ {
+ /* how many to fireproof? */
+ *stack = get_quantity("How many would you like fireproofed?", o_ptr->number);
+ }
+ else
+ {
+ *stack = 1;
+ }
+
+ /* check for item type and multiply number in the stack by the
+ * amount of points per item of that type */
+ switch (o_ptr->tval)
+ {
+ case TV_BOOK:
+ item_value = FIREPROOF_BOOK_POINTS * (*stack);
+ break;
+ case TV_STAFF:
+ item_value = FIREPROOF_STAFF_POINTS * (*stack);
+ break;
+ case TV_SCROLL:
+ item_value = FIREPROOF_SCROLL_POINTS * (*stack);
+ break;
+ default:
+ assert(FALSE);
+ }
+
+ /* do we have enough points? */
+ if (item_value > get_item_points_remaining())
+ {
+ 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 */
+ set_item_points_remaining(get_item_points_remaining() - item_value);
+ }
+
+ /* Used all the points? the quest is completely rewarded. */
+ if (get_item_points_remaining() == 0)
+ {
+ cquest.status = QUEST_STATUS_REWARDED;
+ }
+
+ return TRUE;
+}
+
+static bool_ fireproof()
+{
+ int item;
+ if (!get_item(&item,
+ "Which item shall I fireproof?",
+ "You have no more items I can fireproof, come back when you have some.",
+ USE_INVEN,
+ item_tester_hook_proofable()))
+ {
+ return FALSE;
+ }
+
+ /* get the object type from the number */
+ object_type *obj2 = get_object(item);
+
+ /* check we have enough points (if we 'got' an item) */
+ int stack = 0;
+ if (!fireproof_enough_points(obj2, &stack))
+ {
+ return FALSE;
+ }
+
+ /* Do the actual fireproofing */
+ {
+ bool_ carry_it;
+ object_type *obj3;
+ object_type obj_forge;
+ s32b oldpval, oldpval2, oldpval3;
+
+ /* are we part of the items from a stack? */
+ if (obj2->number != stack) {
+
+ /* 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;
+ }
+
+ /* 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!) */
+ oldpval = obj3->pval;
+ oldpval2 = obj3->pval2;
+ 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)
+ {
+ inven_carry(obj3, TRUE);
+ }
+
+ /* id and notice it */
+ object_known(obj3);
+ object_aware(obj3);
+
+ return TRUE;
+ }
+}
+
+
+void quest_fireproof_building(bool_ *paid, bool_ *recreate)
+{
+ fireproof_settings const *settings = fireproof_get_settings();
+ int num_books, num_staff, num_scroll;
+
+ num_books = get_item_points_remaining() / FIREPROOF_BOOK_POINTS;
+ num_staff = get_item_points_remaining() / FIREPROOF_STAFF_POINTS;
+ num_scroll = get_item_points_remaining() / FIREPROOF_SCROLL_POINTS;
+
+ /* the quest hasn't been requested already, right? */
+ if (cquest.status == QUEST_STATUS_UNTAKEN)
+ {
+ /* quest has been taken now */
+ cquest.status = QUEST_STATUS_TAKEN;
+
+ /* issue instructions */
+ msg_format("I need a very special %s for a spell I am"
+ " working on. I am too old to ", settings->tval_name);
+ 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.");
+
+ *paid = FALSE;
+ *recreate = TRUE;
+ }
+
+ /* if quest completed (item was retrieved) */
+ else if (cquest.status == QUEST_STATUS_COMPLETED)
+ {
+ char p[512];
+ char pni[512];
+ int item_idx;
+ int ret;
+
+ /* generate prompt strings */
+ snprintf(p , sizeof(p) , "Which %s?", settings->tval_name);
+ snprintf(pni, sizeof(pni), "You have no %s to return", settings->tval_name_plural);
+
+ /* ask for item */
+ ret = get_item(&item_idx, p, pni, USE_INVEN, item_tester_hook_eligible);
+
+ /* didn't get the item? */
+ if (!ret)
+ {
+ return;
+ }
+
+ /* got the item! */
+ else
+ {
+ int items;
+
+ /* take item */
+ inc_stack_size_ex(item_idx, -1, OPTIMIZE, NO_DESCRIBE);
+
+ msg_print(format("Great! Let me fireproof some of your items in thanks. I can do %d books, ", num_books));
+ msg_print(format("%d staves, or %d scrolls.", num_staff, num_scroll));
+
+ /* how many items to proof? */
+ items = get_item_points_remaining();
+
+ /* repeat till up to 3 (value defined as constant) books fireproofed */
+ while (items > 0)
+ {
+ ret = fireproof();
+
+ /* don't loop the fireproof if there's nothing to fireproof */
+ if (ret == FALSE)
+ {
+ break;
+ }
+
+ /* subtract item points */
+ items = get_item_points_remaining();
+ }
+
+ /* have they all been done? */
+ if (get_item_points_remaining() == 0)
+ {
+ /* mark quest to make sure no more quests are given */
+ cquest.status = QUEST_STATUS_REWARDED;
+ }
+ else
+ {
+ /* mark in preparation of anymore books to fireproof */
+ cquest.status = QUEST_STATUS_FINISHED;
+ }
+ }
+ }
+
+ /* if the player asks for a quest when they already have it, but haven't failed it, give them some extra instructions */
+ else if (cquest.status == QUEST_STATUS_TAKEN)
+ {
+ msg_format("The %s is in a cave just behind the shop.",
+ settings->tval_name);
+ }
+
+ /* ok not all books have been fireproofed... lets do the rest */
+ else if (cquest.status == QUEST_STATUS_FINISHED)
+ {
+
+ /* how many books still to proof? */
+ int items = get_item_points_remaining();
+
+ /* repeat as necessary */
+ while (items > 0)
+ {
+ int ret = fireproof();
+
+ /* don't loop the fireproof if there's nothing to fireproof */
+ if (ret == FALSE)
+ {
+ break;
+ }
+ else
+ {
+ /* have they all been done? */
+ if (get_item_points_remaining() == 0)
+ {
+ cquest.status = QUEST_STATUS_REWARDED;
+ }
+ }
+
+ /* subtract item points */
+ items = get_item_points_remaining();
+ }
+
+ }
+
+ /* quest failed or completed, then give no more quests */
+ else if ((cquest.status == QUEST_STATUS_FAILED) ||
+ (cquest.status == QUEST_STATUS_REWARDED))
+ {
+ msg_print("I have no more quests for you");
+ }
+}
+
+static bool_ fireproof_get_hook(void *, void *in_, void *)
+{
+ struct hook_get_in *in = static_cast<struct hook_get_in *>(in_);
+ object_type *o_ptr = in->o_ptr;
+
+ /* check that player is in the quest, haven't picked up the
+ * item already, and check that it's the real item and not another one
+ * generated via random object placement */
+ if ((p_ptr->inside_quest == QUEST_FIREPROOF) &&
+ (cquest.status != QUEST_STATUS_COMPLETED) &&
+ (o_ptr->pval2 == fireproof_get_sval()))
+ {
+ /* ok mark the quest 'completed' */
+ cquest.status = QUEST_STATUS_COMPLETED;
+ cmsg_print(TERM_YELLOW, "Fine! Looks like you've found it.");
+ }
+
+ return FALSE;
+}
+
+static bool_ fireproof_stair_hook(void *, void *, void *)
+{
+ /* only ask this if player about to go up stairs of quest and
+ * hasn't retrieved item */
+ if ((p_ptr->inside_quest != QUEST_FIREPROOF) ||
+ (cquest.status == QUEST_STATUS_COMPLETED))
+ {
+ return FALSE;
+ }
+ else
+ {
+ bool_ ret;
+
+ if (cave[p_ptr->py][p_ptr->px].feat != FEAT_LESS)
+ {
+ return FALSE;
+ }
+
+ /* flush all pending input */
+ flush();
+
+ /* confirm */
+ ret = get_check("Really abandon the quest?");
+
+ /* if yes, then */
+ if (ret == TRUE)
+ {
+ /* fail the quest */
+ cquest.status = QUEST_STATUS_FAILED;
+ return FALSE;
+ }
+ else
+ {
+ /* if no, they stay in the quest */
+ return TRUE;
+ }
+ }
+}
+
+bool_ quest_fireproof_describe(FILE *hook_file)
+{
+ fireproof_settings const *settings = fireproof_get_settings();
+ int num_books, num_staff, num_scroll;
+ int status = cquest.status;
+
+ num_books = get_item_points_remaining() / FIREPROOF_BOOK_POINTS;
+ num_staff = get_item_points_remaining() / FIREPROOF_STAFF_POINTS;
+ num_scroll = get_item_points_remaining() / FIREPROOF_SCROLL_POINTS;
+
+ if (status == QUEST_STATUS_TAKEN)
+ {
+ /* Quest taken */
+ print_hook("#####yAn Old Mages Quest!\n");
+ print_hook("Retrieve the strange %s for the old mage "
+ "in Lothlorien.\n", settings->tval_name);
+ print_hook("\n");
+ }
+ else if (status == QUEST_STATUS_COMPLETED)
+ {
+ /* essence retrieved, not taken to mage */
+ print_hook("#####yAn Old Mages Quest!\n");
+ print_hook("You have retrieved the %s for the old "
+ "mage in Lothlorien. Perhaps you \n", settings->tval_name);
+ print_hook("should see about a reward.\n");
+ print_hook("\n");
+ }
+ else if ((status == QUEST_STATUS_FINISHED) &&
+ (get_item_points_remaining() > 0))
+ {
+ /* essence returned, not all books fireproofed */
+ print_hook("#####yAn Old Mages Quest!\n");
+ print_hook("You have retrieved the %s for the old "
+ "mage in Lothlorien. He will still \n", settings->tval_name);
+ print_hook("fireproof %d book(s) or %d staff/staves "
+ "or %d scroll(s) for you.\n",
+ num_books, num_staff, num_scroll);
+ print_hook("\n");
+ }
+
+ return TRUE;
+}
+
+static bool_ fireproof_gen_hook(void *, void *, void *)
+{
+ fireproof_settings const *settings = fireproof_get_settings();
+
+ /* Only if player doing this quest */
+ if (p_ptr->inside_quest != QUEST_FIREPROOF)
+ {
+ return FALSE;
+ }
+
+ /* Go ahead */
+ {
+ int traps, trap_y, trap_x;
+
+ /* load the map */
+ {
+ int x0 = 2;
+ int y0 = 2;
+ load_map("fireprof.map", &y0, &x0);
+ }
+
+ /* no teleport */
+ dungeon_flags2 = DF2_NO_TELEPORT;
+
+ /* determine type of item */
+ fireproof_set_sval(randint(settings->sval_max));
+
+ /* create essence */
+ {
+ int x, y;
+ object_type forge;
+
+ object_prep(&forge, lookup_kind(settings->tval, fireproof_get_sval()));
+
+ /* mark item */
+ forge.pval2 = fireproof_get_sval();
+ forge.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(&forge, -1, y, x);
+ }
+
+ /* how many traps to generate */
+ traps = rand_range(10, 30);
+
+ /* generate the traps */
+ while (traps > 0)
+ {
+ int tries = 0, trap_level = 0;
+
+ /* make sure it's a safe place */
+ while (tries == 0)
+ {
+ /* get grid coordinates */
+ trap_y = randint(19) + 2;
+ trap_x = randint(45) + 2;
+ cave_type *c_ptr = &cave[trap_y][trap_x];
+
+ /* are the coordinates on a stair, or a wall? */
+ if (((f_info[c_ptr->feat].flags1 & FF1_PERMANENT) != 0) ||
+ ((f_info[c_ptr->feat].flags1 & FF1_FLOOR) == 0))
+ {
+ /* try again */
+ tries = 0;
+ }
+ else
+ {
+ /* not a stair, then stop this 'while' */
+ tries = 1;
+ }
+ }
+
+ /* randomise level of trap */
+ trap_level = rand_range(20, 40);
+
+ /* put the trap there */
+ place_trap_leveled(trap_y, trap_x, trap_level);
+
+ /* that's one less trap to place */
+ traps = traps - 1;
+ }
+
+ return TRUE;
+ }
+}
+
+bool_ quest_fireproof_init_hook(int q)
+{
+ /* Only need hooks if the quest is unfinished. */
+ if ((cquest.status >= QUEST_STATUS_UNTAKEN) &&
+ (cquest.status < QUEST_STATUS_FINISHED))
+ {
+ add_hook_new(HOOK_GEN_QUEST, fireproof_gen_hook , "fireproof_gen_hook", NULL);
+ add_hook_new(HOOK_GET , fireproof_get_hook , "fireproof_get_hook", NULL);
+ add_hook_new(HOOK_STAIR , fireproof_stair_hook, "fireproof_stair_hook", NULL);
+ }
+
+ return FALSE;
+}
+
+#undef print_hook
diff --git a/src/q_fireprof.hpp b/src/q_fireprof.hpp
new file mode 100644
index 00000000..53d368b0
--- /dev/null
+++ b/src/q_fireprof.hpp
@@ -0,0 +1,7 @@
+#pragma once
+
+#include "h-basic.h"
+
+extern void quest_fireproof_building(bool_ *paid, bool_ *recreate);
+extern bool_ quest_fireproof_init_hook(int q);
+extern bool_ quest_fireproof_describe(FILE *fff);
diff --git a/src/q_god.cc b/src/q_god.cc
new file mode 100644
index 00000000..0a3b07e7
--- /dev/null
+++ b/src/q_god.cc
@@ -0,0 +1,1212 @@
+#include "q_god.hpp"
+
+#include "cave_type.hpp"
+#include "dungeon_info_type.hpp"
+#include "feature_type.hpp"
+#include "hook_chardump_in.hpp"
+#include "hook_get_in.hpp"
+#include "hook_enter_dungeon_in.hpp"
+#include "hook_player_level_in.hpp"
+#include "hooks.hpp"
+#include "object2.hpp"
+#include "player_type.hpp"
+#include "quark.hpp"
+#include "skill_type.hpp"
+#include "tables.hpp"
+#include "util.hpp"
+#include "variable.hpp"
+#include "wilderness_map.hpp"
+#include "wilderness_type_info.hpp"
+#include "z-rand.hpp"
+
+#include <assert.h>
+
+#define cquest (quest[QUEST_GOD])
+#define cquest_quests_given (cquest.data[0])
+#define cquest_relics_found (cquest.data[1])
+#define cquest_dun_mindepth (cquest.data[2])
+#define cquest_dun_maxdepth (cquest.data[3])
+#define cquest_dun_minplev (cquest.data[4])
+#define cquest_relic_gen_tries (cquest.data[5])
+#define cquest_relic_generated (cquest.data[6])
+#define cquest_dung_x (cquest.data[7])
+#define cquest_dung_y (cquest.data[8])
+
+/* d_idx of the god_quest (Lost Temple) dungeon */
+#define DUNGEON_GOD 30
+#define CHANCE_OF_GOD_QUEST 21
+
+/*
+ * 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.
+ *
+ * The returned string is allocated with strdup().
+ */
+static char *compass(int y, int x, int y2, int x2)
+{
+ 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 a copy */
+ return strdup(compass_dir);
+}
+
+/* Returns a relative approximation of the 'distance' of y2, x2 from y, x. */
+static 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";
+ }
+}
+
+static int MAX_NUM_GOD_QUESTS()
+{
+ if (game_module_idx == MODULE_TOME)
+ {
+ return 5;
+ }
+ if (game_module_idx == MODULE_THEME)
+ {
+ return 7;
+ }
+ /* Uh, oh. */
+ assert(FALSE);
+ return 0;
+}
+
+static byte get_relic_num()
+{
+ int i;
+ int sval_by_god[][2] = {
+ { GOD_ERU, 7 },
+ { GOD_MANWE, 8 },
+ { GOD_TULKAS, 9 },
+ { GOD_MELKOR, 10 },
+ { GOD_YAVANNA, 11 },
+ { GOD_AULE, 16 },
+ { GOD_VARDA, 17 },
+ { GOD_ULMO, 18 },
+ { GOD_MANDOS, 19 },
+ { -1, -1 },
+ };
+
+ for (i = 0; sval_by_god[i][1] != -1; i++)
+ {
+ if (p_ptr->pgod == sval_by_god[i][0])
+ {
+ int sval = sval_by_god[i][1];
+ return sval;
+ }
+ }
+
+ /* Uh, oh. */
+ assert(FALSE);
+}
+
+static void get_home_coordinates(int *home1_y, int *home1_x, const char **home1,
+ int *home2_y, int *home2_x, const char **home2)
+{
+ /* Which are the waypoints? */
+ if (p_ptr->pgod != GOD_MELKOR)
+ {
+ *home1 = "Bree";
+ *home2 = "Minas Anor";
+ }
+ else
+ {
+ *home1 = "the Pits of Angband";
+ *home2 = "the Land of Mordor";
+ }
+
+ /* Module specific locations */
+ if (game_module_idx == MODULE_TOME)
+ {
+ if (p_ptr->pgod != GOD_MELKOR)
+ {
+ *home1_y = 21;
+ *home1_x = 34;
+ *home2_y = 56;
+ *home2_x = 60;
+ }
+ else
+ {
+ *home1_y = 7;
+ *home1_x = 34;
+ *home2_y = 58;
+ *home2_x = 65;
+ }
+ }
+ else if (game_module_idx == MODULE_THEME)
+ {
+ if (p_ptr->pgod != GOD_MELKOR)
+ {
+ *home1_y = 21;
+ *home1_x = 35;
+ *home2_y = 56;
+ *home2_x = 60;
+ }
+ else
+ {
+ *home1_y = 7;
+ *home1_x = 11;
+ *home2_y = 49;
+ *home2_x = 70;
+ }
+ }
+ else
+ {
+ assert(FALSE); /* Uh, oh */
+ }
+}
+
+/* Print using cmsg_print. */
+static void print_using_cmsg(cptr line, void *dummy)
+{
+ cmsg_print(TERM_YELLOW, line);
+}
+
+/* Print using print_hook. */
+static void print_using_print_hook(cptr line, void *f_)
+{
+ FILE *f = (FILE *) f_;
+ fprintf(f, "%s\n", line);
+}
+
+/* Show directions */
+static void print_directions(bool_ feel_it, void (*pfunc)(cptr, void *), void *pfdata)
+{
+ int home1_y, home1_x;
+ int home2_y, home2_x;
+ const char *home1 = NULL;
+ const char *home2 = NULL;
+ char *home1_axis = NULL;
+ char *home2_axis = NULL;
+ cptr home1_distance = NULL;
+ cptr home2_distance = NULL;
+ cptr feel_it_str = feel_it ? ", I can feel it.'" : ".";
+ char buf[256];
+
+ get_home_coordinates(
+ &home1_y, &home1_x, &home1,
+ &home2_y, &home2_x, &home2);
+
+ home1_axis = compass(home1_y, home1_x, cquest_dung_y, cquest_dung_x);
+ home2_axis = compass(home2_y, home2_x, cquest_dung_y, cquest_dung_x);
+
+ home1_distance = approximate_distance(home1_y, home1_x, cquest_dung_y, cquest_dung_x);
+ home2_distance = approximate_distance(home2_y, home2_x, cquest_dung_y, cquest_dung_x);
+
+ /* Build the message */
+ if (!streq(home1_axis, "close"))
+ {
+ snprintf(buf, sizeof(buf),
+ "The temple lies %s to the %s of %s, ",
+ home1_distance,
+ home1_axis,
+ home1);
+ pfunc(buf, pfdata);
+ }
+ else
+ {
+ snprintf(buf, sizeof(buf),
+ "The temple lies very close to %s, ",
+ home1);
+ pfunc(buf, pfdata);
+ }
+
+ if (!streq(home2_axis, "close"))
+ {
+ snprintf(buf, sizeof(buf),
+ "and %s to the %s of %s%s",
+ home2_distance,
+ home2_axis,
+ home2,
+ feel_it_str);
+ pfunc(buf, pfdata);
+ }
+ else
+ {
+ snprintf(buf, sizeof(buf),
+ "and very close to %s%s",
+ home2,
+ feel_it_str);
+ pfunc(buf, pfdata);
+ }
+
+ /* Free dyanmically allocated strings */
+ free(home1_axis);
+ free(home2_axis);
+}
+
+bool_ quest_god_describe(FILE *fff)
+{
+ if (cquest.status == QUEST_STATUS_TAKEN)
+ {
+ fprintf(fff, "#####yGod quest " FMTs32b "!\n", cquest_quests_given);
+ fprintf(fff, "Thou art to find the lost temple of thy God and\n");
+ fprintf(fff, "to retrieve the lost part of the relic for thy God! \n");
+ print_directions(FALSE, print_using_print_hook, fff);
+ fprintf(fff, "\n");
+ }
+
+ return TRUE;
+}
+
+static void quest_god_place_rand_dung()
+{
+ int x = -1, y = -1, tries;
+
+ /* erase old dungeon */
+ if (cquest_quests_given > 0)
+ {
+ wild_map[cquest_dung_y][cquest_dung_x].entrance = 0;
+
+ /* erase old recall level */
+ max_dlv[DUNGEON_GOD] = 0;
+ }
+
+ /* initialise tries variable */
+ tries = 1000;
+ while (tries > 0)
+ {
+ wilderness_map *w_ptr = NULL;
+ wilderness_type_info *wf_ptr = NULL;
+ 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). */
+ x = rand_range(1, max_wild_x-2);
+ y = rand_range(1, max_wild_y-2);
+
+ /* Is there a town/dungeon/potentially impassable feature there, ? */
+ w_ptr = &wild_map[y][x];
+ wf_ptr = &wf_info[w_ptr->feat];
+
+ if ((w_ptr->entrance != 0) ||
+ (wf_ptr->entrance != 0) ||
+ (wf_ptr->terrain_idx == TERRAIN_EDGE) ||
+ (wf_ptr->terrain_idx == TERRAIN_DEEP_WATER) ||
+ (wf_ptr->terrain_idx == TERRAIN_TREES) ||
+ (wf_ptr->terrain_idx == TERRAIN_SHALLOW_LAVA) ||
+ (wf_ptr->terrain_idx == TERRAIN_DEEP_LAVA) ||
+ (wf_ptr->terrain_idx == TERRAIN_MOUNTAIN))
+ {
+ /* try again */
+ }
+ else
+ {
+ /* either player, nor wall, then stop this 'while' */
+ break;
+ }
+ }
+
+ assert(x >= 0);
+ assert(y >= 0);
+
+ if (tries == 0)
+ {
+ /* Use Bree as last resort */
+ x = 32;
+ y = 19;
+ }
+
+ /* create god dungeon in that place */
+ wild_map[y][x].entrance = 1000 + DUNGEON_GOD;
+
+ /* set quest variables */
+ cquest_dung_x = x;
+ cquest_dung_y = y;
+}
+
+static void quest_god_generate_relic()
+{
+ int tries = 1000, x = -1, y = -1;
+ object_type relic;
+
+ tries = 1000;
+
+ while (tries > 0)
+ {
+ cave_type *c_ptr;
+ 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);
+ c_ptr = &cave[y][x];
+
+ /* are the coordinates on a floor, not on a permanent feature (eg stairs), and not on a trap ? */
+ if ((f_info[c_ptr->feat].flags1 & FF1_FLOOR) &&
+ (!(f_info[c_ptr->feat].flags1 & FF1_PERMANENT)) &&
+ (c_ptr->t_idx == 0))
+ {
+ break;
+ }
+ }
+
+ /* create relic */
+ object_prep(&relic, lookup_kind(TV_JUNK, get_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)
+ {
+ /* explain it */
+ cmsg_print(TERM_L_BLUE, "You luckily stumble across the relic on the stairs!");
+
+ if (inven_carry_okay(&relic))
+ {
+ inven_carry(&relic, FALSE);
+ }
+ else
+ {
+ /* no place found, drop it on the stairs */
+ drop_near(&relic, -1, p_ptr->py, p_ptr->px);
+ }
+ }
+ else
+ {
+ /* drop it */
+ drop_near(&relic, -1, y, x);
+ }
+
+ /* Only generate once! */
+ cquest_relic_generated = TRUE;
+
+ /* Reset some variables */
+ cquest_relic_gen_tries = 0;
+}
+
+static void quest_god_set_god_dungeon_attributes_eru()
+{
+ /* The Eru temple is based on Meneltarma. */
+
+ /* W: Not too many monsters (they'll be tough though, with big
+ * levels) */
+ d_info[DUNGEON_GOD].min_m_alloc_level = 14;
+ d_info[DUNGEON_GOD].max_m_alloc_chance = 200;
+
+ /* L: Dirt and grass. More dirt at bottom, more grass at
+ * top. rocky ground would be nice */
+ d_info[DUNGEON_GOD].floor1 = 88;
+ d_info[DUNGEON_GOD].floor2 = 89;
+ d_info[DUNGEON_GOD].floor_percent1[0] = 70;
+ d_info[DUNGEON_GOD].floor_percent2[0] = 30;
+ d_info[DUNGEON_GOD].floor_percent1[1] = 10;
+ d_info[DUNGEON_GOD].floor_percent2[1] = 90;
+
+ /* A: Outer wall mountain chain. other walls granite */
+ d_info[DUNGEON_GOD].fill_type1 = 97;
+ d_info[DUNGEON_GOD].fill_percent1[0] = 100;
+ d_info[DUNGEON_GOD].outer_wall = 57;
+ d_info[DUNGEON_GOD].inner_wall = 97;
+ d_info[DUNGEON_GOD].fill_method = 2;
+
+ /* O: "At Meneltarma no weapon or tool had ever been borne"
+ * (but invaders would have left a small number) */
+ d_info[DUNGEON_GOD].objs.treasure = 45;
+ d_info[DUNGEON_GOD].objs.combat = 5;
+ d_info[DUNGEON_GOD].objs.magic = 45;
+ d_info[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?) */
+ d_info[DUNGEON_GOD].flags1 =
+ DF1_BIG | DF1_NO_DOORS | DF1_CIRCULAR_ROOMS |
+ DF1_EMPTY | DF1_TOWER | DF1_FLAT | DF1_ADJUST_LEVEL_2;
+ d_info[DUNGEON_GOD].flags2 =
+ DF2_ADJUST_LEVEL_1_2 |
+ DF2_NO_SHAFT |
+ DF2_ADJUST_LEVEL_PLAYER;
+
+ /* R: */
+ d_info[DUNGEON_GOD].rules[0].mode = 3;
+ d_info[DUNGEON_GOD].rules[0].percent = 50;
+
+ /* M: We want evil or flying characters */
+ d_info[DUNGEON_GOD].rules[0].mflags3 = RF3_EVIL;
+
+ d_info[DUNGEON_GOD].rules[1].mode = 3;
+ d_info[DUNGEON_GOD].rules[1].percent = 50;
+
+ /* M: We want evil or flying characters */
+ d_info[DUNGEON_GOD].rules[1].mflags7 = RF7_CAN_FLY;
+}
+
+static void quest_god_set_god_dungeon_attributes_manwe()
+{
+ /* Manwe's lost temple is high in the clouds */
+
+ /* W: Has average number of monsters. */
+ d_info[DUNGEON_GOD].min_m_alloc_level = 18;
+ d_info[DUNGEON_GOD].max_m_alloc_chance = 160;
+
+ /* L: floor will be 'cloud-like vapour' and pools of
+ * 'condensing water' */
+ d_info[DUNGEON_GOD].floor1 = 208;
+ d_info[DUNGEON_GOD].floor2 = 209;
+ d_info[DUNGEON_GOD].floor_percent1[0] = 85;
+ d_info[DUNGEON_GOD].floor_percent2[0] = 15;
+
+ /* A: Outer wall is 'hail stone wall', inner wall 'dense
+ * fog'. FIlled at max smoothing, like islands. */
+ d_info[DUNGEON_GOD].fill_type1 = 211;
+ d_info[DUNGEON_GOD].fill_percent1[0] = 100;
+ d_info[DUNGEON_GOD].outer_wall = 210;
+ d_info[DUNGEON_GOD].inner_wall = 211;
+ d_info[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... */
+ d_info[DUNGEON_GOD].objs.treasure = 15;
+ d_info[DUNGEON_GOD].objs.combat = 25;
+ d_info[DUNGEON_GOD].objs.magic = 55;
+ d_info[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). */
+ d_info[DUNGEON_GOD].flags1 =
+ DF1_NO_DOORS | DF1_TOWER |
+ DF1_CAVERN | DF1_ADJUST_LEVEL_2;
+ d_info[DUNGEON_GOD].flags2 =
+ DF2_NO_SHAFT | DF2_ADJUST_LEVEL_PLAYER;
+
+ /* R: */
+ d_info[DUNGEON_GOD].rules[0].mode = 3;
+ d_info[DUNGEON_GOD].rules[0].percent = 20;
+ d_info[DUNGEON_GOD].rules[1].mode = 3;
+ d_info[DUNGEON_GOD].rules[1].percent = 20;
+ d_info[DUNGEON_GOD].rules[2].mode = 3;
+ d_info[DUNGEON_GOD].rules[2].percent = 20;
+ d_info[DUNGEON_GOD].rules[3].mode = 3;
+ d_info[DUNGEON_GOD].rules[3].percent = 20;
+ d_info[DUNGEON_GOD].rules[4].mode = 3;
+ d_info[DUNGEON_GOD].rules[4].percent = 20;
+
+ /* M: We want air(poison-type) or flying characters. Orcs
+ * too. They would have ransacked his elf-loving temple :) */
+ d_info[DUNGEON_GOD].rules[0].mflags2 = RF2_INVISIBLE;
+ d_info[DUNGEON_GOD].rules[1].mflags3 = RF3_ORC | RF3_IM_POIS;
+ d_info[DUNGEON_GOD].rules[2].mflags4 = RF4_BR_POIS | RF4_BR_GRAV;
+ d_info[DUNGEON_GOD].rules[3].mflags5 = RF5_BA_POIS;
+ d_info[DUNGEON_GOD].rules[4].mflags7 = RF7_CAN_FLY;
+}
+
+static void quest_god_set_god_dungeon_attributes_tulkas()
+{
+ /* 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 */
+ d_info[DUNGEON_GOD].min_m_alloc_level = 20;
+ d_info[DUNGEON_GOD].max_m_alloc_chance = 120;
+
+ /* L: floor is normal */
+ d_info[DUNGEON_GOD].floor1 = 1;
+ d_info[DUNGEON_GOD].floor_percent1[0] = 100;
+
+ /* A: Granite walls */
+ d_info[DUNGEON_GOD].fill_type1 = 56;
+ d_info[DUNGEON_GOD].fill_percent1[0] = 100;
+ d_info[DUNGEON_GOD].outer_wall = 58;
+ d_info[DUNGEON_GOD].inner_wall = 57;
+ d_info[DUNGEON_GOD].fill_method = 0;
+
+ /* O: Loads of combat drops */
+ d_info[DUNGEON_GOD].objs.treasure = 10;
+ d_info[DUNGEON_GOD].objs.combat = 70;
+ d_info[DUNGEON_GOD].objs.magic = 5;
+ d_info[DUNGEON_GOD].objs.tools = 15;
+
+ /* F: fairly standard */
+ d_info[DUNGEON_GOD].flags1 = DF1_NO_DESTROY | DF1_ADJUST_LEVEL_2;
+ d_info[DUNGEON_GOD].flags2 = DF2_ADJUST_LEVEL_PLAYER;
+
+ /* R: */
+ d_info[DUNGEON_GOD].rules[0].mode = 3;
+ d_info[DUNGEON_GOD].rules[0].percent = 100;
+
+ /* M: plenty demons please */
+ d_info[DUNGEON_GOD].rules[0].mflags3 = RF3_DEMON | RF3_EVIL;
+}
+
+static void quest_god_set_god_dungeon_attributes_melkor()
+{
+ /* Melkors dungeon will be dark, fiery and stuff */
+
+ /* Many many monsters! (but prob ADJUST_LEVEL_1_2) */
+ d_info[DUNGEON_GOD].min_m_alloc_level = 24;
+ d_info[DUNGEON_GOD].max_m_alloc_chance = 80;
+
+ /* L: floor is dirt/mud/nether */
+ d_info[DUNGEON_GOD].floor1 = 88;
+ d_info[DUNGEON_GOD].floor2 = 94;
+ d_info[DUNGEON_GOD].floor3 = 102;
+ d_info[DUNGEON_GOD].floor_percent1[0] = 45;
+ d_info[DUNGEON_GOD].floor_percent2[0] = 45;
+ d_info[DUNGEON_GOD].floor_percent3[0] = 10;
+ d_info[DUNGEON_GOD].floor_percent1[1] = 35;
+ d_info[DUNGEON_GOD].floor_percent2[1] = 35;
+ d_info[DUNGEON_GOD].floor_percent3[1] = 30;
+
+ /* A: Granite walls to fill but glass walls for room
+ * perimeters (you can see the nasty monsters coming) */
+ d_info[DUNGEON_GOD].fill_type1 = 188;
+ d_info[DUNGEON_GOD].fill_percent1[0] = 100;
+ d_info[DUNGEON_GOD].outer_wall = 188;
+ d_info[DUNGEON_GOD].inner_wall = 57;
+ d_info[DUNGEON_GOD].fill_method = 1;
+
+ /* O: Even drops */
+ d_info[DUNGEON_GOD].objs.treasure = 25;
+ d_info[DUNGEON_GOD].objs.combat = 25;
+ d_info[DUNGEON_GOD].objs.magic = 25;
+ d_info[DUNGEON_GOD].objs.tools = 25;
+
+ /* F: Small, lava rivers, nasty monsters hehehehehe */
+ d_info[DUNGEON_GOD].flags1 = DF1_SMALL | DF1_LAVA_RIVERS | DF1_ADJUST_LEVEL_1;
+ d_info[DUNGEON_GOD].flags2 = DF2_ADJUST_LEVEL_1_2 | DF2_ADJUST_LEVEL_PLAYER;
+
+ /* R: No restrictions on monsters here */
+ d_info[DUNGEON_GOD].rules[0].mode = 0;
+ d_info[DUNGEON_GOD].rules[0].percent = 80;
+
+ /* R: Apart from making sure we have some GOOD ones */
+ d_info[DUNGEON_GOD].rules[1].mode = 3;
+ d_info[DUNGEON_GOD].rules[1].percent = 20;
+
+ /* M: */
+ d_info[DUNGEON_GOD].rules[1].mflags3 = RF3_GOOD;
+}
+
+static void quest_god_set_god_dungeon_attributes_yavanna()
+{
+ /* Yavannas dungeon will be very natural, tress and stuff. */
+
+ d_info[DUNGEON_GOD].min_m_alloc_level = 22;
+ d_info[DUNGEON_GOD].max_m_alloc_chance = 100;
+
+ /* L: floor is grass/flowers, plus dirt so not always
+ * regenerating quick! */
+ d_info[DUNGEON_GOD].floor1 = 89;
+ d_info[DUNGEON_GOD].floor2 = 199;
+ d_info[DUNGEON_GOD].floor3 = 88;
+ d_info[DUNGEON_GOD].floor_percent1[0] = 40;
+ d_info[DUNGEON_GOD].floor_percent2[0] = 15;
+ d_info[DUNGEON_GOD].floor_percent3[0] = 45;
+
+ /* A: Tree walls to fill, small trees for inner walls */
+ d_info[DUNGEON_GOD].fill_type1 = 96;
+ d_info[DUNGEON_GOD].fill_percent1[0] = 100;
+ d_info[DUNGEON_GOD].outer_wall = 202;
+ d_info[DUNGEON_GOD].inner_wall = 96;
+ d_info[DUNGEON_GOD].fill_method = 1;
+
+ /* O: not much combat.. tools where ransackers have tried to
+ * chop trees down. */
+ d_info[DUNGEON_GOD].objs.treasure = 20;
+ d_info[DUNGEON_GOD].objs.combat = 10;
+ d_info[DUNGEON_GOD].objs.magic = 30;
+ d_info[DUNGEON_GOD].objs.tools = 40;
+
+ /* F: Natural looking */
+ d_info[DUNGEON_GOD].flags1 =
+ DF1_NO_DOORS | DF1_WATER_RIVERS |
+ DF1_NO_DESTROY | DF1_ADJUST_LEVEL_1 |
+ DF1_NO_RECALL;
+ d_info[DUNGEON_GOD].flags2 =
+ DF2_ADJUST_LEVEL_1_2 | DF2_NO_SHAFT |
+ DF2_NO_GENO | DF2_ADJUST_LEVEL_PLAYER;
+
+ /* R: Demons, Undead, non-living */
+ d_info[DUNGEON_GOD].rules[0].mode = 3;
+ d_info[DUNGEON_GOD].rules[0].percent = 100;
+
+ /* M: */
+ d_info[DUNGEON_GOD].rules[0].mflags3 =
+ RF3_DEMON | RF3_UNDEAD | RF3_NONLIVING;
+}
+
+static void quest_god_set_god_dungeon_attributes_aule()
+{
+ d_info[DUNGEON_GOD].min_m_alloc_level = 24;
+ d_info[DUNGEON_GOD].max_m_alloc_chance = 80;
+
+ /* L: floor is dirt/mud/shallow water */
+ d_info[DUNGEON_GOD].floor1 = 88;
+ d_info[DUNGEON_GOD].floor2 = 94;
+ d_info[DUNGEON_GOD].floor3 = 84;
+ d_info[DUNGEON_GOD].floor_percent1[0] = 45;
+ d_info[DUNGEON_GOD].floor_percent2[0] = 45;
+ d_info[DUNGEON_GOD].floor_percent3[0] = 10;
+ d_info[DUNGEON_GOD].floor_percent1[1] = 35;
+ d_info[DUNGEON_GOD].floor_percent2[1] = 35;
+ d_info[DUNGEON_GOD].floor_percent3[1] = 30;
+
+ /* A: Grey mountains, inner walls are low hills */
+ d_info[DUNGEON_GOD].fill_type1 = 216;
+ d_info[DUNGEON_GOD].fill_percent1[0] = 100;
+ d_info[DUNGEON_GOD].outer_wall = 216;
+ d_info[DUNGEON_GOD].inner_wall = 213;
+ d_info[DUNGEON_GOD].fill_method = 1;
+
+ /* O: Weapons and tools only */
+ d_info[DUNGEON_GOD].objs.treasure = 0;
+ d_info[DUNGEON_GOD].objs.combat = 50;
+ d_info[DUNGEON_GOD].objs.magic = 0;
+ d_info[DUNGEON_GOD].objs.tools = 50;
+
+ /* F: Small, no destroyed levels, min monster level = dungeon
+ * level */
+ d_info[DUNGEON_GOD].flags1 =
+ DF1_SMALL | DF1_NO_DESTROY |
+ DF1_ADJUST_LEVEL_1 | DF1_NO_STREAMERS;
+
+ /* R: No restrictions on monsters here */
+ d_info[DUNGEON_GOD].rules[0].mode = 0;
+ d_info[DUNGEON_GOD].rules[0].percent = 80;
+}
+
+static void quest_god_set_god_dungeon_attributes_varda()
+{
+ /* Varda lives with Manwe, so high in the clouds */
+
+ /* W: Has average number of monsters. */
+ d_info[DUNGEON_GOD].min_m_alloc_level = 18;
+ d_info[DUNGEON_GOD].max_m_alloc_chance = 160;
+
+ /* L: floor will be grass and flowers */
+ d_info[DUNGEON_GOD].floor1 = 89;
+ d_info[DUNGEON_GOD].floor2 = 82;
+ d_info[DUNGEON_GOD].floor_percent1[0] = 85;
+ d_info[DUNGEON_GOD].floor_percent2[0] = 15;
+
+ /* A: Outer wall is 'hail stone wall', inner wall 'dense
+ * fog'. Filled at max smoothing, like islands. */
+ d_info[DUNGEON_GOD].fill_type1 = 211;
+ d_info[DUNGEON_GOD].fill_percent1[0] = 100;
+ d_info[DUNGEON_GOD].outer_wall = 210;
+ d_info[DUNGEON_GOD].inner_wall = 211;
+ d_info[DUNGEON_GOD].fill_method = 4;
+
+ /* O: Varda likes magical items and tools, not much treasure
+ * or weapons */
+ d_info[DUNGEON_GOD].objs.treasure = 15;
+ d_info[DUNGEON_GOD].objs.combat = 5;
+ d_info[DUNGEON_GOD].objs.magic = 55;
+ d_info[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). */
+ d_info[DUNGEON_GOD].flags1 =
+ DF1_NO_DOORS | DF1_TOWER |
+ DF1_CAVERN | DF1_ADJUST_LEVEL_1;
+ d_info[DUNGEON_GOD].flags2 =
+ DF2_NO_SHAFT | DF2_ADJUST_LEVEL_PLAYER;
+
+ /* R: */
+ d_info[DUNGEON_GOD].rules[0].mode = 3;
+ d_info[DUNGEON_GOD].rules[0].percent = 20;
+ d_info[DUNGEON_GOD].rules[1].mode = 3;
+ d_info[DUNGEON_GOD].rules[1].percent = 20;
+ d_info[DUNGEON_GOD].rules[2].mode = 3;
+ d_info[DUNGEON_GOD].rules[2].percent = 20;
+ d_info[DUNGEON_GOD].rules[3].mode = 3;
+ d_info[DUNGEON_GOD].rules[3].percent = 20;
+ d_info[DUNGEON_GOD].rules[4].mode = 3;
+ d_info[DUNGEON_GOD].rules[4].percent = 20;
+
+ /* M: We want air(poison-type) or flying characters. Orcs too. */
+ d_info[DUNGEON_GOD].rules[0].mflags2 = RF2_INVISIBLE;
+ d_info[DUNGEON_GOD].rules[1].mflags3 = RF3_ORC | RF3_IM_POIS;
+ d_info[DUNGEON_GOD].rules[2].mflags4 = RF4_BR_POIS | RF4_BR_GRAV;
+ d_info[DUNGEON_GOD].rules[3].mflags5 = RF5_BA_POIS;
+ d_info[DUNGEON_GOD].rules[4].mflags7 = RF7_CAN_FLY;
+}
+
+static void quest_god_set_god_dungeon_attributes_ulmo()
+{
+ /* Ulmo dungeon is basically Tulkas, except with acquatic creatures. */
+
+ /* W: but with lots of monsters */
+ d_info[DUNGEON_GOD].min_m_alloc_level = 20;
+ d_info[DUNGEON_GOD].max_m_alloc_chance = 120;
+
+ /* L: floor is dirt */
+ d_info[DUNGEON_GOD].floor1 = 88;
+ d_info[DUNGEON_GOD].floor_percent1[0] = 100;
+
+ /* A: Cheat: walls are water. */
+ d_info[DUNGEON_GOD].fill_type1 = 187;
+ d_info[DUNGEON_GOD].fill_percent1[0] = 100;
+ d_info[DUNGEON_GOD].outer_wall = 238;
+ d_info[DUNGEON_GOD].inner_wall = 84;
+ d_info[DUNGEON_GOD].fill_method = 0;
+
+ /* O: Lots of treasure, not much else. */
+ d_info[DUNGEON_GOD].objs.treasure = 90;
+ d_info[DUNGEON_GOD].objs.combat = 0;
+ d_info[DUNGEON_GOD].objs.magic = 5;
+ d_info[DUNGEON_GOD].objs.tools = 5;
+
+ /* F: fairly standard */
+ d_info[DUNGEON_GOD].flags1 = DF1_NO_DESTROY | DF1_ADJUST_LEVEL_2;
+ d_info[DUNGEON_GOD].flags2 = DF2_ADJUST_LEVEL_PLAYER;
+
+ /* R: */
+ d_info[DUNGEON_GOD].rules[0].mode = 3;
+ d_info[DUNGEON_GOD].rules[0].percent = 35;
+ d_info[DUNGEON_GOD].rules[1].mode = 3;
+ d_info[DUNGEON_GOD].rules[1].percent = 30;
+ d_info[DUNGEON_GOD].rules[2].mode = 3;
+ d_info[DUNGEON_GOD].rules[2].percent = 30;
+
+ /* M: Aquatic creatures only. */
+ d_info[DUNGEON_GOD].rules[0].mflags3 = RF7_CAN_FLY;
+ d_info[DUNGEON_GOD].rules[1].mflags3 = RF7_AQUATIC;
+ d_info[DUNGEON_GOD].rules[2].mflags3 = RF3_RES_WATE;
+}
+
+static void quest_god_set_god_dungeon_attributes_mandos()
+{
+ /* Mandos dungeon is basically Tulkas, except with undead. */
+
+ /* W: but with lots of monsters */
+ d_info[DUNGEON_GOD].min_m_alloc_level = 20;
+ d_info[DUNGEON_GOD].max_m_alloc_chance = 120;
+
+ /* L: floor is normal */
+ d_info[DUNGEON_GOD].floor1 = 1;
+ d_info[DUNGEON_GOD].floor_percent1[0] = 100;
+
+ /* A: Granite walls */
+ d_info[DUNGEON_GOD].fill_type1 = 56;
+ d_info[DUNGEON_GOD].fill_percent1[0] = 100;
+ d_info[DUNGEON_GOD].outer_wall = 58;
+ d_info[DUNGEON_GOD].inner_wall = 57;
+ d_info[DUNGEON_GOD].fill_method = 0;
+
+ /* O: Loads of combat drops */
+ d_info[DUNGEON_GOD].objs.treasure = 10;
+ d_info[DUNGEON_GOD].objs.combat = 70;
+ d_info[DUNGEON_GOD].objs.magic = 5;
+ d_info[DUNGEON_GOD].objs.tools = 15;
+
+ /* F: fairly standard */
+ d_info[DUNGEON_GOD].flags1 = DF1_NO_DESTROY | DF1_ADJUST_LEVEL_2;
+ d_info[DUNGEON_GOD].flags2 = DF2_ADJUST_LEVEL_PLAYER;
+
+ /* R: */
+ d_info[DUNGEON_GOD].rules[0].mode = 3;
+ d_info[DUNGEON_GOD].rules[0].percent = 100;
+
+ /* M: vampires! */
+ d_info[DUNGEON_GOD].rules[0].r_char[0] = 'V';
+ d_info[DUNGEON_GOD].rules[0].r_char[1] = '\0';
+ d_info[DUNGEON_GOD].rules[0].r_char[2] = '\0';
+ d_info[DUNGEON_GOD].rules[0].r_char[3] = '\0';
+ d_info[DUNGEON_GOD].rules[0].r_char[4] = '\0';
+ d_info[DUNGEON_GOD].rules[0].mflags3 = RF3_UNDEAD | RF3_EVIL;
+}
+
+static bool_ quest_god_level_end_gen_hook(void *, void *, void *)
+{
+ /* Check for dungeon */
+ if ((dungeon_type != DUNGEON_GOD) ||
+ (cquest.status == QUEST_STATUS_UNTAKEN))
+ {
+ return FALSE;
+ }
+
+ /* 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.*/
+
+ else if ((cquest_relic_generated == TRUE) &&
+ (cquest.status != QUEST_STATUS_FAILED))
+ {
+ /* fail the quest, don't give another one, don't give
+ * this message again */
+ cquest.status = QUEST_STATUS_FAILED;
+
+ /* God issues instructions */
+ cmsg_format(TERM_L_BLUE, "The voice of %s booms in your head:", deity_info[p_ptr->pgod].name);
+
+ 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!'");
+ }
+
+ /* Force relic generation on 5th attempt if others have been
+ * unsuccessful. */
+
+ else if ((cquest_relic_gen_tries == 4) &&
+ (cquest_relic_generated == FALSE))
+ {
+ quest_god_generate_relic();
+ }
+
+ else
+ {
+ /* 1/5 chance of generation */
+ if (magik(20))
+ {
+ quest_god_generate_relic();
+ }
+ else
+ {
+ cquest_relic_gen_tries = cquest_relic_gen_tries + 1;
+ }
+ }
+
+ return FALSE;
+}
+
+static bool_ quest_god_player_level_hook(void *, void *in_, void *)
+{
+ struct hook_player_level_in *in = static_cast<struct hook_player_level_in *>(in_);
+ s32b gained = in->gained_levels;
+
+ if (gained <= 0)
+ {
+ return FALSE;
+ }
+
+ /* check player is worshipping a god, not already on a god quest. */
+ if ((p_ptr->astral) ||
+ (p_ptr->pgod <= 0) ||
+ (cquest.status == QUEST_STATUS_TAKEN) ||
+ (cquest.status == QUEST_STATUS_FAILED) ||
+ (cquest_quests_given >= MAX_NUM_GOD_QUESTS()) ||
+ (magik(CHANCE_OF_GOD_QUEST) == FALSE) ||
+ ((dungeon_type == DUNGEON_GOD) &&
+ (dun_level > 0)) ||
+ (p_ptr->lev <= cquest_dun_minplev))
+ {
+ /* Don't let a player get quests with trickery */
+ if (p_ptr->lev > cquest_dun_minplev)
+ {
+ cquest_dun_minplev = p_ptr->lev;
+ }
+ return FALSE;
+ }
+ else
+ {
+ /* This var will need resetting */
+ cquest.status = QUEST_STATUS_TAKEN;
+ cquest_relic_generated = FALSE;
+ cquest_quests_given = cquest_quests_given + 1;
+
+ /* actually place the dungeon in a random place */
+ quest_god_place_rand_dung();
+
+ /* God issues instructions */
+ cmsg_format(TERM_L_BLUE, "The voice of %s booms in your head:", deity_info[p_ptr->pgod].name);
+
+ 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!");
+
+ print_directions(TRUE, print_using_cmsg, NULL);
+
+ /* 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! */
+ cquest_dun_mindepth = p_ptr->lev*2/3;
+ cquest_dun_maxdepth = cquest_dun_mindepth + 4;
+ }
+
+ return FALSE;
+}
+
+static bool_ quest_god_get_hook(void *, void *in_, void *)
+{
+ hook_get_in *in = static_cast<hook_get_in *>(in_);
+
+ s32b item = -in->o_idx; /* Note the negation */
+
+ object_type *o_ptr = get_object(item);
+
+ /* -- Is it the relic, and check to make sure the relic hasn't already been identified */
+ if ((cquest.status == QUEST_STATUS_TAKEN) &&
+ (o_ptr->tval == TV_JUNK) &&
+ (o_ptr->sval == get_relic_num()) &&
+ (o_ptr->pval != TRUE) &&
+ (cquest_relics_found < cquest_quests_given))
+ {
+ cmsg_format(TERM_L_BLUE, "%s speaks to you:", deity_info[p_ptr->pgod].name);
+
+ /* Is it the last piece of the relic? */
+ if (cquest_quests_given == MAX_NUM_GOD_QUESTS())
+ {
+ 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!'");
+ s_info[SKILL_PRAY].value += (10 * s_info[SKILL_PRAY].mod);
+ }
+ 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'");
+
+ /* reward player by increasing prayer skill */
+ cmsg_print(TERM_YELLOW, "'As a reward, I shall teach thee how to pray better'");
+ s_info[SKILL_PRAY].value += (5 * s_info[SKILL_PRAY].mod);
+ }
+
+ /* Take the relic piece */
+ inc_stack_size_ex(item, -1, OPTIMIZE, NO_DESCRIBE);
+
+ /* relic piece has been identified */
+ o_ptr->pval = TRUE;
+ cquest_relics_found = cquest_relics_found + 1;
+
+ /* Make sure quests can be given again if neccesary */
+ cquest.status = QUEST_STATUS_UNTAKEN;
+
+ /* Prevent further processing of 'take' action; we've
+ destroyed the item. */
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static bool_ quest_god_char_dump_hook(void *, void *in_, void *)
+{
+ struct hook_chardump_in *in = static_cast<struct hook_chardump_in *>(in_);
+ FILE *f = in->file;
+
+ if (cquest_quests_given > 0)
+ {
+ int relics = cquest_relics_found;
+ char relics_text[128];
+ cptr append_text = "";
+
+ snprintf(relics_text, sizeof(relics_text), "%d", relics);
+
+ if (relics == MAX_NUM_GOD_QUESTS())
+ {
+ strcpy(relics_text, "all");
+ append_text = " and pleased your god";
+ }
+ else
+ {
+ if (relics == 0)
+ {
+ strcpy(relics_text, "none");
+ }
+ if (cquest.status == QUEST_STATUS_FAILED)
+ {
+ append_text = " and failed in your quest";
+ }
+ }
+
+ fprintf(f, "\n You found %s of the relic pieces%s.", relics_text, append_text);
+ }
+
+ return FALSE;
+}
+
+static void set_god_dungeon_attributes()
+{
+ /* dungeon properties altered according to which god player is worshipping, */
+ if (p_ptr->pgod == GOD_ERU)
+ {
+ quest_god_set_god_dungeon_attributes_eru();
+ }
+ else if (p_ptr->pgod == GOD_MANWE)
+ {
+ quest_god_set_god_dungeon_attributes_manwe();
+ }
+ else if (p_ptr->pgod == GOD_TULKAS)
+ {
+ quest_god_set_god_dungeon_attributes_tulkas();
+ }
+ else if (p_ptr->pgod == GOD_MELKOR)
+ {
+ quest_god_set_god_dungeon_attributes_melkor();
+ }
+ else if (p_ptr->pgod == GOD_YAVANNA)
+ {
+ quest_god_set_god_dungeon_attributes_yavanna();
+ }
+ else if (p_ptr->pgod == GOD_AULE)
+ {
+ quest_god_set_god_dungeon_attributes_aule();
+ }
+ else if (p_ptr->pgod == GOD_VARDA)
+ {
+ quest_god_set_god_dungeon_attributes_varda();
+ }
+ else if (p_ptr->pgod == GOD_ULMO)
+ {
+ quest_god_set_god_dungeon_attributes_ulmo();
+ }
+ else if (p_ptr->pgod == GOD_MANDOS)
+ {
+ quest_god_set_god_dungeon_attributes_mandos();
+ }
+ else
+ {
+ assert(FALSE); /* Uh, oh! */
+ }
+
+ /* W: All dungeons are 5 levels deep, and created at 2/3 of
+ * the player clvl when the quest is given */
+ {
+ dungeon_info_type *d_ptr = &d_info[DUNGEON_GOD];
+ d_ptr->mindepth = cquest_dun_mindepth;
+ d_ptr->maxdepth = cquest_dun_maxdepth;
+ d_ptr->min_plev = cquest_dun_minplev;
+ }
+}
+
+static void quest_god_dungeon_setup(int d_idx)
+{
+ /* call the function to set the dungeon variables (dependant
+ * on pgod) the first time we enter the dungeon */
+ if (d_idx != DUNGEON_GOD)
+ {
+ return;
+ }
+
+ set_god_dungeon_attributes();
+}
+
+static bool_ quest_god_enter_dungeon_hook(void *, void *in_, void *)
+{
+ struct hook_enter_dungeon_in *in = static_cast<struct hook_enter_dungeon_in *>(in_);
+ quest_god_dungeon_setup(in->d_idx);
+ return FALSE;
+}
+
+static bool_ quest_god_gen_level_begin_hook(void *, void *, void *)
+{
+ quest_god_dungeon_setup(dungeon_type);
+ return FALSE;
+}
+
+static bool_ quest_god_stair_hook(void *, void *, void *)
+{
+ quest_god_dungeon_setup(dungeon_type);
+ return FALSE;
+}
+
+static bool_ quest_god_birth_objects_hook(void *, void *, void *)
+{
+ cquest_quests_given = 0;
+ cquest_relics_found = 0;
+ cquest_dun_mindepth = 1;
+ cquest_dun_maxdepth = 4;
+ cquest_dun_minplev = 0;
+ cquest_relic_gen_tries = 0;
+ cquest_relic_generated = FALSE;
+
+ return FALSE;
+}
+
+bool_ quest_god_init_hook(int q)
+{
+ /* Only need hooks if the quest is unfinished. */
+ if ((cquest.status >= QUEST_STATUS_UNTAKEN) &&
+ (cquest.status < QUEST_STATUS_FINISHED))
+ {
+ add_hook_new(HOOK_LEVEL_END_GEN, quest_god_level_end_gen_hook, "q_god_level_end_gen", NULL);
+ add_hook_new(HOOK_ENTER_DUNGEON, quest_god_enter_dungeon_hook, "q_god_enter_dungeon", NULL);
+ add_hook_new(HOOK_GEN_LEVEL_BEGIN, quest_god_gen_level_begin_hook, "q_god_gen_level_begin", NULL);
+ add_hook_new(HOOK_STAIR, quest_god_stair_hook, "q_god_hook_stair", NULL);
+ add_hook_new(HOOK_GET, quest_god_get_hook, "q_god_get", NULL);
+ add_hook_new(HOOK_CHAR_DUMP, quest_god_char_dump_hook, "q_god_char_dump", NULL);
+ add_hook_new(HOOK_PLAYER_LEVEL, quest_god_player_level_hook, "q_god_player_level", NULL);
+ }
+
+ /* Need this to re-initialize at birth; the quest data is
+ * zeroed which isn't quite right. */
+ add_hook_new(HOOK_BIRTH_OBJECTS, quest_god_birth_objects_hook, "q_god_birth_objects", NULL);
+
+ return FALSE;
+}
diff --git a/src/q_god.hpp b/src/q_god.hpp
new file mode 100644
index 00000000..d9513bdb
--- /dev/null
+++ b/src/q_god.hpp
@@ -0,0 +1,6 @@
+#pragma once
+
+#include "h-basic.h"
+
+bool_ quest_god_describe(FILE *);
+bool_ quest_god_init_hook(int q);
diff --git a/src/q_haunted.c b/src/q_haunted.c
deleted file mode 100644
index db8992bc..00000000
--- a/src/q_haunted.c
+++ /dev/null
@@ -1,147 +0,0 @@
-#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_haunted.cc b/src/q_haunted.cc
new file mode 100644
index 00000000..57daa40e
--- /dev/null
+++ b/src/q_haunted.cc
@@ -0,0 +1,163 @@
+#include "q_haunted.hpp"
+
+#include "cave.hpp"
+#include "cave_type.hpp"
+#include "feature_type.hpp"
+#include "hook_quest_finish_in.hpp"
+#include "hooks.hpp"
+#include "init1.hpp"
+#include "monster2.hpp"
+#include "monster_type.hpp"
+#include "player_type.hpp"
+#include "traps.hpp"
+#include "tables.hpp"
+#include "util.hpp"
+#include "variable.hpp"
+#include "z-rand.hpp"
+
+#define cquest (quest[QUEST_HAUNTED])
+
+static bool_ quest_haunted_gen_hook(void *, void *, void *)
+{
+ 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;
+}
+
+static bool_ quest_haunted_death_hook(void *, void *, void *)
+{
+ 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_new(HOOK_MONSTER_DEATH, quest_haunted_death_hook);
+ del_hook_new(HOOK_GEN_QUEST, quest_haunted_gen_hook);
+ process_hooks_restart = TRUE;
+
+ cmsg_print(TERM_YELLOW, "Minas Anor is safer now.");
+ return (FALSE);
+ }
+ return FALSE;
+}
+
+static bool_ quest_haunted_finish_hook(void *, void *in_, void *)
+{
+ struct hook_quest_finish_in *in = static_cast<struct hook_quest_finish_in *>(in_);
+ s32b q_idx = in->q_idx;
+
+ 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_new(HOOK_MONSTER_DEATH, quest_haunted_death_hook, "haunted_monster_death", NULL);
+ add_hook_new(HOOK_QUEST_FINISH, quest_haunted_finish_hook, "haunted_finish", NULL);
+ add_hook_new(HOOK_GEN_QUEST, quest_haunted_gen_hook, "haunted_geb", NULL);
+ }
+ return (FALSE);
+}
diff --git a/src/q_haunted.hpp b/src/q_haunted.hpp
new file mode 100644
index 00000000..4f51bce3
--- /dev/null
+++ b/src/q_haunted.hpp
@@ -0,0 +1,5 @@
+#pragma once
+
+#include "h-basic.h"
+
+bool_ quest_haunted_init_hook(int q_idx);
diff --git a/src/q_hobbit.c b/src/q_hobbit.c
deleted file mode 100644
index f3b7d856..00000000
--- a/src/q_hobbit.c
+++ /dev/null
@@ -1,195 +0,0 @@
-#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_hobbit.cc b/src/q_hobbit.cc
new file mode 100644
index 00000000..5a71711e
--- /dev/null
+++ b/src/q_hobbit.cc
@@ -0,0 +1,230 @@
+#include "q_hobbit.hpp"
+
+#include "cave.hpp"
+#include "hook_chardump_in.hpp"
+#include "hook_chat_in.hpp"
+#include "hook_give_in.hpp"
+#include "hook_mon_speak_in.hpp"
+#include "hook_wild_gen_in.hpp"
+#include "hooks.hpp"
+#include "messages.hpp"
+#include "monster2.hpp"
+#include "monster_type.hpp"
+#include "object2.hpp"
+#include "object_type.hpp"
+#include "player_type.hpp"
+#include "tables.hpp"
+#include "util.hpp"
+#include "variable.hpp"
+#include "z-rand.hpp"
+
+#include <cassert>
+
+#define cquest (quest[QUEST_HOBBIT])
+
+GENERATE_MONSTER_LOOKUP_FN(get_melinda_proudfoot, "Melinda Proudfoot")
+GENERATE_MONSTER_LOOKUP_FN(get_merton_proudfoot, "Merton Proudfoot, the lost hobbit")
+
+static bool_ quest_hobbit_town_gen_hook(void *, void *in_, void *)
+{
+ struct hook_wild_gen_in *in = static_cast<struct hook_wild_gen_in *>(in_);
+ int x = 1, y = 1, tries = 10000;
+ bool_ small = in->small;
+
+ 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 */
+ int r_idx = get_melinda_proudfoot();
+ m_allow_special[r_idx] = TRUE;
+ place_monster_one(y, x, r_idx, 0, FALSE, MSTATUS_ENEMY);
+ m_allow_special[r_idx] = FALSE;
+
+ return FALSE;
+}
+
+static bool_ quest_hobbit_gen_hook(void *, void *, void *)
+{
+ 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 */
+ int r_idx = get_merton_proudfoot();
+ m_allow_special[r_idx] = TRUE;
+ place_monster_one(y, x, r_idx, 0, FALSE, MSTATUS_FRIEND);
+ m_allow_special[r_idx] = FALSE;
+
+ return FALSE;
+}
+
+static bool_ quest_hobbit_give_hook(void *, void *in_, void *)
+{
+ struct hook_give_in *in = static_cast<struct hook_give_in *>(in_);
+ object_type *o_ptr;
+ monster_type *m_ptr;
+ s32b m_idx = in->m_idx;
+ s32b item = in->item;
+
+ o_ptr = &p_ptr->inventory[item];
+ m_ptr = &m_list[m_idx];
+
+ if (m_ptr->r_idx != get_merton_proudfoot()) 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_new(HOOK_GIVE, quest_hobbit_give_hook);
+ process_hooks_restart = TRUE;
+
+ return TRUE;
+}
+
+static bool_ quest_hobbit_speak_hook(void *, void *in_, void *)
+{
+ struct hook_mon_speak_in *in = static_cast<struct hook_mon_speak_in *>(in_);
+ s32b m_idx = in->m_idx;
+
+ if (m_list[m_idx].r_idx != get_melinda_proudfoot())
+ {
+ return (FALSE);
+ }
+
+ if (cquest.status < QUEST_STATUS_COMPLETED)
+ {
+ msg_format("%^s begs for your help.", in->m_name);
+ }
+ return (TRUE);
+}
+
+static bool_ quest_hobbit_chat_hook(void *, void *in_, void *)
+{
+ struct hook_chat_in *in = static_cast<struct hook_chat_in *>(in_);
+ s32b m_idx = in->m_idx;
+ monster_type *m_ptr;
+
+ m_ptr = &m_list[m_idx];
+
+ if (m_ptr->r_idx != get_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_new(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;
+}
+
+static bool_ quest_hobbit_dump_hook(void *, void *in_, void *)
+{
+ struct hook_chardump_in *in = static_cast<struct hook_chardump_in *>(in_);
+ FILE *f = in->file;
+
+ if (cquest.status >= QUEST_STATUS_COMPLETED)
+ {
+ fprintf(f, "\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(format("Hobbit level %d", cquest.data[0]), TERM_BLUE);
+ }
+ }
+
+ if ((cquest.status >= QUEST_STATUS_TAKEN) && (cquest.status < QUEST_STATUS_FINISHED))
+ {
+ add_hook_new(HOOK_GIVE, quest_hobbit_give_hook, "hobbit_give", NULL);
+ add_hook_new(HOOK_GEN_LEVEL, quest_hobbit_gen_hook, "hobbit_gen", NULL);
+ add_hook_new(HOOK_WILD_GEN, quest_hobbit_town_gen_hook, "hobbit_town_gen", NULL);
+ add_hook_new(HOOK_CHAT, quest_hobbit_chat_hook, "hobbit_chat", NULL);
+ add_hook_new(HOOK_MON_SPEAK, quest_hobbit_speak_hook, "hobbit_speak", NULL);
+ }
+ if (cquest.status == QUEST_STATUS_UNTAKEN)
+ {
+ add_hook_new(HOOK_MON_SPEAK, quest_hobbit_speak_hook, "hobbit_speak", NULL);
+ add_hook_new(HOOK_WILD_GEN, quest_hobbit_town_gen_hook, "hobbit_town_gen", NULL);
+ add_hook_new(HOOK_CHAT, quest_hobbit_chat_hook, "hobbit_chat", NULL);
+ }
+ add_hook_new(HOOK_CHAR_DUMP, quest_hobbit_dump_hook, "hobbit_dump", NULL);
+ return (FALSE);
+}
diff --git a/src/q_hobbit.hpp b/src/q_hobbit.hpp
new file mode 100644
index 00000000..b1878748
--- /dev/null
+++ b/src/q_hobbit.hpp
@@ -0,0 +1,5 @@
+#pragma once
+
+#include "h-basic.h"
+
+bool_ quest_hobbit_init_hook(int q_idx);
diff --git a/src/q_invas.c b/src/q_invas.c
deleted file mode 100644
index 59c71d62..00000000
--- a/src/q_invas.c
+++ /dev/null
@@ -1,201 +0,0 @@
-#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_invas.cc b/src/q_invas.cc
new file mode 100644
index 00000000..64483d28
--- /dev/null
+++ b/src/q_invas.cc
@@ -0,0 +1,222 @@
+#include "q_invas.hpp"
+
+#include "cave.hpp"
+#include "cave_type.hpp"
+#include "hook_chardump_in.hpp"
+#include "hook_monster_death_in.hpp"
+#include "hook_monster_ai_in.hpp"
+#include "hook_monster_ai_out.hpp"
+#include "hook_stair_in.hpp"
+#include "hooks.hpp"
+#include "init1.hpp"
+#include "monster2.hpp"
+#include "monster_type.hpp"
+#include "player_type.hpp"
+#include "tables.hpp"
+#include "town_type.hpp"
+#include "util.hpp"
+#include "variable.hpp"
+
+#define cquest (quest[QUEST_INVASION])
+
+static bool_ quest_invasion_gen_hook(void *, void *, void *)
+{
+ 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;
+}
+
+static bool_ quest_invasion_ai_hook(void *, void *in_, void *out_)
+{
+ struct hook_monster_ai_in *in = static_cast<struct hook_monster_ai_in *>(in_);
+ struct hook_monster_ai_out *out = static_cast<struct hook_monster_ai_out *>(out_);
+ monster_type *m_ptr = in->m_ptr;
+ s32b m_idx = in->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
+ {
+ out->y = cquest.data[0];
+ out->x = cquest.data[1];
+ return (TRUE);
+ }
+ }
+
+ return (FALSE);
+}
+
+static bool_ quest_invasion_turn_hook(void *, void *, void *)
+{
+ 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 */
+ 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;
+
+ quest_invasion_init_hook(QUEST_INVASION);
+ del_hook_new(HOOK_END_TURN, quest_invasion_turn_hook);
+ process_hooks_restart = TRUE;
+
+ return (FALSE);
+}
+
+static bool_ quest_invasion_dump_hook(void *, void *in_, void *)
+{
+ struct hook_chardump_in *in = static_cast<struct hook_chardump_in *>(in_);
+ FILE *f = in->file;
+
+ if (cquest.status == QUEST_STATUS_FAILED)
+ {
+ fprintf(f, "\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(f, "\n You saved Gondolin from destruction.");
+ }
+ return (FALSE);
+}
+
+static bool_ quest_invasion_death_hook(void *, void *in_, void *)
+{
+ struct hook_monster_death_in *in = static_cast<struct hook_monster_death_in *>(in_);
+ s32b m_idx = in->m_idx;
+ s32b 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_new(HOOK_MONSTER_DEATH, quest_invasion_death_hook);
+ process_hooks_restart = TRUE;
+
+ return (FALSE);
+ }
+
+ return FALSE;
+}
+
+static bool_ quest_invasion_stair_hook(void *, void *in_, void *)
+{
+ struct hook_stair_in *in = static_cast<struct hook_stair_in *>(in_);
+
+ if (p_ptr->inside_quest != QUEST_INVASION) return FALSE;
+
+ if (cave[p_ptr->py][p_ptr->px].feat != FEAT_LESS) return TRUE;
+
+ if (in->direction == STAIRS_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_new(HOOK_STAIR, quest_invasion_stair_hook);
+ process_hooks_restart = TRUE;
+ return (FALSE);
+ }
+
+ return TRUE;
+}
+
+bool_ quest_invasion_init_hook(int q_idx)
+{
+ add_hook_new(HOOK_END_TURN, quest_invasion_turn_hook, "invasion_turn", NULL);
+ add_hook_new(HOOK_CHAR_DUMP, quest_invasion_dump_hook, "invasion_dump", NULL);
+ if ((cquest.status >= QUEST_STATUS_TAKEN) && (cquest.status < QUEST_STATUS_FINISHED))
+ {
+ add_hook_new(HOOK_MONSTER_AI, quest_invasion_ai_hook, "invasion_ai", NULL);
+ add_hook_new(HOOK_GEN_QUEST, quest_invasion_gen_hook, "invasion_gen", NULL);
+ add_hook_new(HOOK_MONSTER_DEATH, quest_invasion_death_hook, "invasion_death", NULL);
+ add_hook_new(HOOK_STAIR, quest_invasion_stair_hook, "invasion_stair", NULL);
+ }
+ return (FALSE);
+}
diff --git a/src/q_invas.hpp b/src/q_invas.hpp
new file mode 100644
index 00000000..87b8fc77
--- /dev/null
+++ b/src/q_invas.hpp
@@ -0,0 +1,5 @@
+#pragma once
+
+#include "h-basic.h"
+
+bool_ quest_invasion_init_hook(int q_idx);
diff --git a/src/q_library.cc b/src/q_library.cc
new file mode 100644
index 00000000..52a67291
--- /dev/null
+++ b/src/q_library.cc
@@ -0,0 +1,526 @@
+#include "q_library.hpp"
+
+#include "cave_type.hpp"
+#include "hooks.hpp"
+#include "lua_bind.hpp"
+#include "monster2.hpp"
+#include "monster_type.hpp"
+#include "object2.hpp"
+#include "player_type.hpp"
+#include "quark.hpp"
+#include "spells3.hpp"
+#include "spells4.hpp"
+#include "tables.hpp"
+#include "util.hpp"
+#include "util.h"
+#include "variable.h"
+#include "variable.hpp"
+#include "z-rand.hpp"
+
+#include <cassert>
+
+#define cquest (quest[QUEST_LIBRARY])
+
+#define print_hook(fmt,...) do { fprintf(hook_file, fmt, ##__VA_ARGS__); } while (0)
+
+#define MONSTER_LICH 518
+#define MONSTER_MONASTIC_LICH 611
+#define MONSTER_FLESH_GOLEM 256
+#define MONSTER_CLAY_GOLEM 261
+#define MONSTER_IRON_GOLEM 367
+#define MONSTER_MITHRIL_GOLEM 464
+
+#define MAX_BOOKABLE_SPELLS 128
+
+static s16b bookable_spells[MAX_BOOKABLE_SPELLS];
+static s16b bookable_spells_size = 0;
+
+static void push_spell(s16b spell_idx)
+{
+ assert(bookable_spells_size < MAX_BOOKABLE_SPELLS);
+ bookable_spells[bookable_spells_size++] = spell_idx;
+}
+
+void initialize_bookable_spells()
+{
+ push_spell(MANATHRUST);
+ push_spell(DELCURSES);
+ push_spell(GLOBELIGHT);
+ push_spell(FIREGOLEM);
+ push_spell(FIREFLASH);
+ push_spell(FIREWALL);
+ push_spell(GEYSER);
+ push_spell(VAPOR);
+ push_spell(ENTPOTION);
+ push_spell(NOXIOUSCLOUD);
+ push_spell(POISONBLOOD);
+ push_spell(STONESKIN);
+ push_spell(DIG);
+ push_spell(RECHARGE);
+ push_spell(DISPERSEMAGIC);
+ push_spell(BLINK);
+ push_spell(DISARM);
+ push_spell(TELEPORT);
+ push_spell(SENSEMONSTERS);
+ push_spell(SENSEHIDDEN);
+ push_spell(REVEALWAYS);
+ push_spell(IDENTIFY);
+ push_spell(VISION);
+ push_spell(MAGELOCK);
+ push_spell(SLOWMONSTER);
+ push_spell(ESSENCESPEED);
+ push_spell(CHARM);
+ push_spell(CONFUSE);
+ push_spell(ARMOROFFEAR);
+ push_spell(STUN);
+ push_spell(GROWTREE);
+ push_spell(HEALING);
+ push_spell(RECOVERY);
+ push_spell(ERU_SEE);
+ push_spell(ERU_LISTEN);
+ push_spell(MANWE_BLESS);
+ push_spell(MANWE_SHIELD);
+ push_spell(YAVANNA_CHARM_ANIMAL);
+ push_spell(YAVANNA_GROW_GRASS);
+ push_spell(YAVANNA_TREE_ROOTS);
+ push_spell(TULKAS_AIM);
+ push_spell(TULKAS_SPIN);
+ push_spell(MELKOR_CURSE);
+ push_spell(MELKOR_CORPSE_EXPLOSION);
+ push_spell(DRAIN);
+
+ if (game_module_idx == MODULE_THEME)
+ {
+ push_spell(AULE_FIREBRAND);
+ push_spell(AULE_CHILD);
+ push_spell(VARDA_LIGHT_VALINOR);
+ push_spell(VARDA_EVENSTAR);
+ push_spell(ULMO_BELEGAER);
+ push_spell(ULMO_WRATH);
+ push_spell(MANDOS_TEARS_LUTHIEN);
+ push_spell(MANDOS_TALE_DOOM);
+ }
+}
+
+static s16b library_quest_place_random(int minY, int minX, int maxY, int maxX, int r_idx)
+{
+ int y = randint(maxY - minY + 1) + minY;
+ int x = randint(maxX - minX + 1) + minX;
+ return place_monster_one(y, x, r_idx, 0, TRUE, MSTATUS_ENEMY);
+}
+
+static void library_quest_place_nrandom(int minY, int minX, int maxY, int maxX, int r_idx, int n)
+{
+ while(n > 0)
+ {
+ if (0 < library_quest_place_random(minY, minX, maxY, maxX, r_idx))
+ {
+ n--;
+ }
+ }
+}
+
+static s32b library_quest_book_get_slot(int slot)
+{
+ return cquest.data[slot-1];
+}
+
+static void library_quest_book_set_slot(int slot, s32b spell)
+{
+ cquest.data[slot-1] = spell;
+}
+
+static int library_quest_book_slots_left()
+{
+ if (library_quest_book_get_slot(1) == -1) {
+ return 3;
+ } else if (library_quest_book_get_slot(2) == -1) {
+ return 2;
+ } else if (library_quest_book_get_slot(3) == -1) {
+ return 1;
+ } else {
+ return 0;
+ }
+}
+
+static bool_ library_quest_book_contains_spell(int spell)
+{
+ int i;
+ for (i = 1; i <= 3; i++)
+ {
+ if (library_quest_book_get_slot(i) == spell)
+ {
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+static void quest_library_finalize_book()
+{
+ int i = 0;
+ for (i = 1; i <= 3; i++)
+ {
+ school_book *school_book = school_books_at(BOOK_PLAYER);
+ school_book_add_spell(school_book, library_quest_book_get_slot(i));
+ }
+}
+
+static void library_quest_add_spell(int spell) {
+ if (library_quest_book_get_slot(1) == -1) {
+ library_quest_book_set_slot(1, spell);
+ } else if (library_quest_book_get_slot(2) == -1) {
+ library_quest_book_set_slot(2, spell);
+ } else if (library_quest_book_get_slot(3) == -1) {
+ library_quest_book_set_slot(3, spell);
+ }
+}
+
+static void library_quest_remove_spell(int spell) {
+ if (library_quest_book_get_slot(1) == spell) {
+ library_quest_book_set_slot(1, library_quest_book_get_slot(2));
+ library_quest_book_set_slot(2, library_quest_book_get_slot(3));
+ library_quest_book_set_slot(3, -1);
+ } else if (library_quest_book_get_slot(2) == spell) {
+ library_quest_book_set_slot(2, library_quest_book_get_slot(3));
+ library_quest_book_set_slot(3, -1);
+ } else if (library_quest_book_get_slot(3) == spell) {
+ library_quest_book_set_slot(3, -1);
+ }
+}
+
+/* spell selection routines inspired by skills.c */
+static void library_quest_print_spells(int first, int current)
+{
+ int width, height;
+ int slots, row;
+ int index;
+
+ Term_clear();
+ Term_get_size(&width, &height);
+
+ 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) {
+ c_prt(TERM_L_RED, "The book can hold no more spells.", 2, 0);
+ } else if (slots == 1) {
+ c_prt(TERM_L_BLUE, "The book can hold 1 more spell.", 2, 0);
+ } else {
+ c_prt(TERM_L_BLUE, format("The book can hold %d more spells.", slots), 2, 0);
+ }
+
+ row = 3;
+
+ for (index = 0; index < bookable_spells_size; index++) {
+ int spell = bookable_spells[index];
+ if (index >= first) {
+ int color;
+ if (index == current) {
+ color = TERM_GREEN;
+ } else if (library_quest_book_contains_spell(spell)) {
+ color = TERM_WHITE;
+ } else {
+ color = TERM_ORANGE;
+ }
+
+ print_spell(NULL, color, row, spell);
+
+ if (row == height - 1) {
+ return;
+ }
+ row = row + 1;
+ }
+ }
+}
+
+static void library_quest_fill_book()
+{
+ int width, height, margin, first, current;
+ bool_ done;
+
+ /* Always start with a cleared book */
+ library_quest_book_set_slot(1, -1);
+ library_quest_book_set_slot(2, -1);
+ library_quest_book_set_slot(3, -1);
+
+ screen_save();
+ Term_get_size(&width, &height);
+
+ /* room for legend */
+ margin = 3;
+
+ first = 0;
+ current = 0;
+ done = FALSE;
+
+ while (done == FALSE)
+ {
+ char ch;
+ int dir, spell_idx;
+
+ library_quest_print_spells(first, current);
+
+ ch = inkey();
+ dir = get_keymap_dir(ch);
+
+ spell_idx = bookable_spells[current];
+
+ if (ch == ESCAPE) {
+ if (library_quest_book_slots_left() == 0) {
+ flush();
+ done = get_check("Really create the book?");
+ } else {
+ done = TRUE;
+ }
+ } else if (ch == '\r') {
+ /* TODO: make tree of schools */
+ } else if (ch == 'n') {
+ current = current + height;
+ } else if (ch == 'p') {
+ current = current - height;
+ } else if (ch == 'I') {
+ print_spell_desc(spell_idx, 0);
+ inkey();
+ } else if (dir == 2) {
+ current = current + 1;
+ } else if (dir == 8) {
+ current = current - 1;
+ } else if (dir == 6) {
+ if (library_quest_book_contains_spell(spell_idx) == FALSE)
+ {
+ library_quest_add_spell(spell_idx);
+ }
+ } else if (dir == 4) {
+ library_quest_remove_spell(spell_idx);
+ }
+
+ if (current >= bookable_spells_size) {
+ current = bookable_spells_size - 1;
+ } else if (current < 0) {
+ current = 0;
+ }
+
+ if (current > (first + height - margin - 1)) {
+ first = current - height + margin + 1;
+ } else if (first > current) {
+ first = current;
+ }
+ }
+
+ screen_load();
+}
+
+static bool_ quest_library_gen_hook(void *, void *, void *)
+{
+ /* Only if player doing this quest */
+ if (p_ptr->inside_quest != QUEST_LIBRARY)
+ {
+ return FALSE;
+ }
+
+ {
+ int y = 2;
+ int x = 2;
+ load_map("library.map", &y, &x);
+ dungeon_flags2 = DF2_NO_GENO;
+ }
+
+ /* Generate monsters */
+ library_quest_place_nrandom(
+ 4, 4, 14, 37, MONSTER_LICH, damroll(4,2));
+
+ library_quest_place_nrandom(
+ 14, 34, 37, 67, MONSTER_MONASTIC_LICH, damroll(1, 2));
+
+ library_quest_place_nrandom(
+ 4, 34, 14, 67, MONSTER_MONASTIC_LICH, damroll(1, 2) - 1);
+
+ library_quest_place_nrandom(
+ 14, 4, 37, 34, MONSTER_MONASTIC_LICH, damroll(1, 2) - 1);
+
+ library_quest_place_nrandom(
+ 10, 10, 37, 67, MONSTER_FLESH_GOLEM, 2);
+
+ library_quest_place_nrandom(
+ 10, 10, 37, 67, MONSTER_CLAY_GOLEM, 2);
+
+ library_quest_place_nrandom(
+ 10, 10, 37, 67, MONSTER_IRON_GOLEM, 2);
+
+ library_quest_place_nrandom(
+ 10, 10, 37, 67, MONSTER_MITHRIL_GOLEM, 1);
+
+ return TRUE;
+}
+
+static bool_ quest_library_stair_hook(void *, void *, void *)
+{
+ bool_ ret;
+
+ /* only ask this if player about to go up stairs of quest and hasn't won yet */
+ if ((p_ptr->inside_quest != QUEST_LIBRARY) ||
+ (cquest.status == QUEST_STATUS_COMPLETED))
+ {
+ return FALSE;
+ }
+
+ if (cave[p_ptr->py][p_ptr->px].feat != FEAT_LESS)
+ {
+ return FALSE;
+ }
+
+ /* flush all pending input */
+ flush();
+
+ /* confirm */
+ ret = get_check("Really abandon the quest?");
+
+ /* if yes, then */
+ if (ret == TRUE)
+ {
+ /* fail the quest */
+ cquest.status = QUEST_STATUS_FAILED;
+ return FALSE;
+ }
+ else
+ {
+ /* if no, they stay in the quest */
+ return TRUE;
+ }
+}
+
+static bool_ quest_library_monster_death_hook(void *, void *, void *)
+{
+ int i, count = -1;
+
+ /* if they're in the quest and haven't won, continue */
+ if ((p_ptr->inside_quest != QUEST_LIBRARY) ||
+ (cquest.status == QUEST_STATUS_COMPLETED))
+ {
+ return FALSE;
+ }
+
+ /* Count all the enemies left alive */
+ for (i = 0; i < m_max; i++)
+ {
+ monster_type *m_ptr = &m_list[i];
+ if ((m_ptr->r_idx > 0) &&
+ (m_ptr->status <= MSTATUS_ENEMY))
+ {
+ count = count + 1;
+ }
+ }
+
+ /* We've just killed the last monster */
+ if (count == 0)
+ {
+ cquest.status = QUEST_STATUS_COMPLETED;
+ cmsg_print(TERM_YELLOW, "The library is safe now.");
+ }
+
+ /* Normal processing */
+ return FALSE;
+}
+
+void quest_library_building(bool_ *paid, bool_ *recreate)
+{
+ int status = cquest.status;
+
+ /* the quest hasn't been requested already, right? */
+ if (status == QUEST_STATUS_UNTAKEN)
+ {
+ /* quest has been taken now */
+ cquest.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.");
+
+ *paid = FALSE;
+ *recreate = TRUE;
+ }
+
+ /* if quest completed */
+ else if (status == QUEST_STATUS_COMPLETED)
+ {
+ 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)
+ {
+ cquest.status = QUEST_STATUS_REWARDED;
+
+ {
+ object_type forge;
+ object_type *q_ptr = &forge;
+ object_prep(q_ptr, lookup_kind(TV_BOOK, 61));
+ q_ptr->art_name = quark_add(player_name);
+ q_ptr->found = OBJ_FOUND_REWARD;
+ object_aware(q_ptr);
+ object_known(q_ptr);
+ inven_carry(q_ptr, FALSE);
+ }
+
+ quest_library_finalize_book();
+ }
+ }
+
+ /* if the player asks for a quest when they already have it,
+ * but haven't failed it, give them some extra instructions */
+ else if (status == QUEST_STATUS_TAKEN)
+ {
+ msg_print("Please use the side entrance and vanquish the intruders for me.");
+ }
+
+ /* quest failed or completed, then give no more quests */
+ else if ((status == QUEST_STATUS_FAILED) || (status == QUEST_STATUS_REWARDED))
+ {
+ msg_print("I have no more quests for you.");
+ }
+}
+
+bool_ quest_library_describe(FILE *hook_file)
+{
+ if (cquest.status == QUEST_STATUS_TAKEN)
+ {
+ 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");
+ }
+ else if (cquest.status == QUEST_STATUS_COMPLETED)
+ {
+ /* Quest done, book not gotten yet */
+ 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");
+ }
+
+ /* Normal processing */
+ return TRUE;
+}
+
+bool_ quest_library_init_hook(int q)
+{
+ /* Only need hooks if the quest is unfinished. */
+ if ((cquest.status >= QUEST_STATUS_UNTAKEN) &&
+ (cquest.status < QUEST_STATUS_FINISHED))
+ {
+ add_hook_new(HOOK_GEN_QUEST , quest_library_gen_hook , "library_gen_hook", NULL);
+ add_hook_new(HOOK_STAIR , quest_library_stair_hook , "library_stair_hook", NULL);
+ add_hook_new(HOOK_MONSTER_DEATH, quest_library_monster_death_hook, "library_monster_death_hook", NULL);
+ }
+
+ /* If quest was rewarded we need to initialize the real player's spellbook. */
+ if (cquest.status == QUEST_STATUS_REWARDED)
+ {
+ quest_library_finalize_book();
+ }
+
+ return FALSE;
+}
+
+#undef print_hook
diff --git a/src/q_library.hpp b/src/q_library.hpp
new file mode 100644
index 00000000..8150893e
--- /dev/null
+++ b/src/q_library.hpp
@@ -0,0 +1,8 @@
+#pragma once
+
+#include "h-basic.h"
+
+bool_ quest_library_init_hook(int q);
+bool_ quest_library_describe(FILE *fff);
+void quest_library_building(bool_ *paid, bool_ *recreate);
+void initialize_bookable_spells();
diff --git a/src/q_main.c b/src/q_main.c
deleted file mode 100644
index a13b0790..00000000
--- a/src/q_main.c
+++ /dev/null
@@ -1,176 +0,0 @@
-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_main.cc b/src/q_main.cc
new file mode 100644
index 00000000..ed11b9dc
--- /dev/null
+++ b/src/q_main.cc
@@ -0,0 +1,210 @@
+#include "q_main.hpp"
+
+#include "hook_chardump_in.hpp"
+#include "hook_monster_death_in.hpp"
+#include "hook_new_monster_in.hpp"
+#include "hooks.hpp"
+#include "monster_race.hpp"
+#include "monster_type.hpp"
+#include "player_type.hpp"
+#include "tables.hpp"
+#include "util.hpp"
+#include "variable.hpp"
+
+#include <cassert>
+
+GENERATE_MONSTER_LOOKUP_FN(get_necromancer, "The Necromancer of Dol Guldur")
+GENERATE_MONSTER_LOOKUP_FN(get_sauron, "Sauron, the Sorcerer")
+GENERATE_MONSTER_LOOKUP_FN(get_morgoth, "Morgoth, Lord of Darkness")
+
+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++]);
+ }
+}
+
+static bool_ quest_main_monsters_hook(void *, void *in_, void *)
+{
+ struct hook_new_monster_in *in = static_cast<struct hook_new_monster_in *>(in_);
+ s32b r_idx = in->r_idx;
+
+ /* Sauron */
+ if (r_idx == get_sauron())
+ {
+ /* No Sauron until Necromancer dies */
+ if (r_info[get_necromancer()].max_num) return TRUE;
+ }
+ /* Morgoth */
+ else if (r_idx == get_morgoth())
+ {
+ /* No Morgoth until Sauron dies */
+ if (r_info[get_sauron()].max_num) return TRUE;
+ }
+ return FALSE;
+}
+
+static bool_ quest_morgoth_hook(void *, void *, void *)
+{
+ monster_race *r_ptr = &r_info[get_morgoth()];
+
+ /* 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_FRAME);
+
+ /* 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_new(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);
+}
+
+static bool_ quest_morgoth_dump_hook(void *, void *in_, void *)
+{
+ struct hook_chardump_in *in = static_cast<struct hook_chardump_in *>(in_);
+ FILE *f = in->file;
+
+ if (quest[QUEST_MORGOTH].status >= QUEST_STATUS_COMPLETED)
+ {
+ if (quest[QUEST_ONE].status == QUEST_STATUS_FINISHED)
+ fprintf(f, "\n You saved Arda and became a famed %s.", sp_ptr->winner);
+ else
+ fprintf(f, "\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_new(HOOK_MONSTER_DEATH, quest_morgoth_hook, "morgoth_death", NULL);
+ }
+ add_hook_new(HOOK_CHAR_DUMP, quest_morgoth_dump_hook, "morgoth_dump", NULL);
+ add_hook_new(HOOK_NEW_MONSTER, quest_main_monsters_hook, "main_new_monster", NULL);
+ return (FALSE);
+}
+
+static bool_ quest_sauron_hook(void *, void *, void *)
+{
+ monster_race *r_ptr = &r_info[get_sauron()];
+
+ /* 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_new(HOOK_MONSTER_DEATH, quest_sauron_hook);
+ add_hook_new(HOOK_MONSTER_DEATH, quest_morgoth_hook, "morgort_death", NULL);
+ *(quest[QUEST_SAURON].plot) = QUEST_MORGOTH;
+ quest_morgoth_init_hook(QUEST_MORGOTH);
+
+ process_hooks_restart = TRUE;
+ }
+ return (FALSE);
+}
+
+static bool_ quest_sauron_resurect_hook(void *, void *in_, void *)
+{
+ struct hook_monster_death_in *in = static_cast<struct hook_monster_death_in *>(in_);
+ s32b m_idx = in->m_idx;
+ 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[get_sauron()].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 == get_sauron()) && (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_new(HOOK_MONSTER_DEATH, quest_sauron_hook, "sauron_death", NULL);
+ }
+ add_hook_new(HOOK_NEW_MONSTER, quest_main_monsters_hook, "main_new_monster", NULL);
+ add_hook_new(HOOK_MONSTER_DEATH, quest_sauron_resurect_hook, "sauron_resurect_death", NULL);
+ return (FALSE);
+}
+
+static bool_ quest_necro_hook(void *, void *, void *)
+{
+ monster_race *r_ptr = &r_info[get_necromancer()];
+
+ /* 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_new(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_new(HOOK_MONSTER_DEATH, quest_necro_hook, "necro_death", NULL);
+ }
+ add_hook_new(HOOK_NEW_MONSTER, quest_main_monsters_hook, "main_new_monster", NULL);
+ return (FALSE);
+}
diff --git a/src/q_main.hpp b/src/q_main.hpp
new file mode 100644
index 00000000..a88530fc
--- /dev/null
+++ b/src/q_main.hpp
@@ -0,0 +1,7 @@
+#pragma once
+
+#include "h-basic.h"
+
+bool_ quest_necro_init_hook(int q_idx);
+bool_ quest_sauron_init_hook(int q_idx);
+bool_ quest_morgoth_init_hook(int q_idx);
diff --git a/src/q_narsil.c b/src/q_narsil.c
deleted file mode 100644
index 27ec218e..00000000
--- a/src/q_narsil.c
+++ /dev/null
@@ -1,108 +0,0 @@
-#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_narsil.cc b/src/q_narsil.cc
new file mode 100644
index 00000000..a6c0eed3
--- /dev/null
+++ b/src/q_narsil.cc
@@ -0,0 +1,122 @@
+#include "q_narsil.hpp"
+
+#include "cave_type.hpp"
+#include "hook_chardump_in.hpp"
+#include "hook_identify_in.hpp"
+#include "hook_move_in.hpp"
+#include "hooks.hpp"
+#include "object2.hpp"
+#include "object_type.hpp"
+#include "player_type.hpp"
+#include "tables.hpp"
+#include "util.hpp"
+#include "variable.hpp"
+
+#define cquest (quest[QUEST_NARSIL])
+
+static bool_ quest_narsil_move_hook(void *, void *in_, void *)
+{
+ struct hook_move_in *in = static_cast<struct hook_move_in *>(in_);
+ s32b y = in->y;
+ s32b x = in->x;
+ cave_type *c_ptr = &cave[y][x];
+ int i;
+ object_type *o_ptr;
+
+ 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_new(HOOK_MOVE, quest_narsil_move_hook);
+ process_hooks_restart = TRUE;
+
+ return TRUE;
+}
+
+static bool_ quest_narsil_dump_hook(void *, void *in_, void *)
+{
+ struct hook_chardump_in *in = static_cast<struct hook_chardump_in *>(in_);
+ FILE *f = in->file;
+
+ if (cquest.status >= QUEST_STATUS_COMPLETED)
+ {
+ fprintf(f, "\n The sword that was broken is now reforged.");
+ }
+ return (FALSE);
+}
+
+static bool_ quest_narsil_identify_hook(void *, void *in_, void *)
+{
+ struct hook_identify_in *in = static_cast<struct hook_identify_in *>(in_);
+
+ if (cquest.status == QUEST_STATUS_UNTAKEN)
+ {
+ if (in->o_ptr->name1 == ART_NARSIL)
+ {
+ cquest.status = QUEST_STATUS_TAKEN;
+
+ for (int i = 0; i < 5; i++)
+ {
+ if (quest[QUEST_NARSIL].desc[i][0] != '\0')
+ {
+ cmsg_print(TERM_YELLOW, quest[QUEST_NARSIL].desc[i]);
+ }
+ }
+
+ add_hook_new(HOOK_MOVE, quest_narsil_move_hook, "narsil_move", NULL);
+ del_hook_new(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_new(HOOK_MOVE, quest_narsil_move_hook, "narsil_move", NULL);
+ }
+ if (cquest.status == QUEST_STATUS_UNTAKEN)
+ {
+ add_hook_new(HOOK_IDENTIFY, quest_narsil_identify_hook, "narsil_id", NULL);
+ }
+ add_hook_new(HOOK_CHAR_DUMP, quest_narsil_dump_hook, "narsil_dump", NULL);
+ return (FALSE);
+}
diff --git a/src/q_narsil.hpp b/src/q_narsil.hpp
new file mode 100644
index 00000000..b83e63cf
--- /dev/null
+++ b/src/q_narsil.hpp
@@ -0,0 +1,5 @@
+#pragma once
+
+#include "h-basic.h"
+
+bool_ quest_narsil_init_hook(int q_idx);
diff --git a/src/q_nazgul.c b/src/q_nazgul.c
deleted file mode 100644
index 66d3dc98..00000000
--- a/src/q_nazgul.c
+++ /dev/null
@@ -1,116 +0,0 @@
-#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_nazgul.cc b/src/q_nazgul.cc
new file mode 100644
index 00000000..15a6a843
--- /dev/null
+++ b/src/q_nazgul.cc
@@ -0,0 +1,145 @@
+#include "q_nazgul.hpp"
+
+#include "cave.hpp"
+#include "hook_chardump_in.hpp"
+#include "hook_init_quest_in.hpp"
+#include "hook_monster_death_in.hpp"
+#include "hook_quest_finish_in.hpp"
+#include "hook_wild_gen_in.hpp"
+#include "hooks.hpp"
+#include "monster2.hpp"
+#include "monster_type.hpp"
+#include "object2.hpp"
+#include "player_type.hpp"
+#include "tables.hpp"
+#include "util.hpp"
+#include "variable.hpp"
+#include "z-rand.hpp"
+
+#include <cassert>
+
+#define cquest (quest[QUEST_NAZGUL])
+
+GENERATE_MONSTER_LOOKUP_FN(get_uvatha, "Uvatha the Horseman")
+
+static bool_ quest_nazgul_gen_hook(void *, void *in_, void *)
+{
+ struct hook_wild_gen_in *in = static_cast<struct hook_wild_gen_in *>(in_);
+ int m_idx, x = 1, y = 1, tries = 10000;
+ bool_ small = in->small;
+
+ 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 */
+ int r_idx = get_uvatha();
+
+ m_allow_special[r_idx] = TRUE;
+ m_idx = place_monster_one(y, x, r_idx, 0, FALSE, MSTATUS_ENEMY);
+ m_allow_special[r_idx] = FALSE;
+
+ if (m_idx) m_list[m_idx].mflag |= MFLAG_QUEST;
+
+ return FALSE;
+}
+
+static bool_ quest_nazgul_finish_hook(void *, void *in_, void *)
+{
+ struct hook_quest_finish_in *in = static_cast<struct hook_quest_finish_in *>(in_);
+ s32b q_idx = in->q_idx;
+ object_type forge, *q_ptr;
+
+ 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_new(HOOK_QUEST_FINISH, quest_nazgul_finish_hook);
+ process_hooks_restart = TRUE;
+
+ return TRUE;
+}
+
+static bool_ quest_nazgul_dump_hook(void *, void *in_, void *)
+{
+ struct hook_chardump_in *in = static_cast<struct hook_chardump_in *>(in_);
+ FILE *f = in->file;
+
+ if (cquest.status >= QUEST_STATUS_COMPLETED)
+ {
+ fprintf(f, "\n You saved Bree from a dreadful Nazgul.");
+ }
+ return (FALSE);
+}
+
+static bool_ quest_nazgul_forbid_hook(void *, void *in_, void *)
+{
+ struct hook_init_quest_in *in = static_cast<struct hook_init_quest_in *>(in_);
+ s32b q_idx = in->q_idx;
+
+ 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);
+}
+
+static bool_ quest_nazgul_death_hook(void *, void *in_, void *)
+{
+ struct hook_monster_death_in *in = static_cast<struct hook_monster_death_in *>(in_);
+ s32b m_idx = in->m_idx;
+ s32b r_idx = m_list[m_idx].r_idx;
+
+ if (cquest.status != QUEST_STATUS_TAKEN) return (FALSE);
+ if (r_idx != get_uvatha()) return (FALSE);
+
+ cquest.status = QUEST_STATUS_COMPLETED;
+
+ del_hook_new(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_new(HOOK_MONSTER_DEATH, quest_nazgul_death_hook, "nazgul_death", NULL);
+ add_hook_new(HOOK_WILD_GEN, quest_nazgul_gen_hook, "nazgul_gen", NULL);
+ add_hook_new(HOOK_QUEST_FINISH, quest_nazgul_finish_hook, "nazgul_finish", NULL);
+ }
+ add_hook_new(HOOK_CHAR_DUMP, quest_nazgul_dump_hook, "nazgul_dump", NULL);
+ add_hook_new(HOOK_INIT_QUEST, quest_nazgul_forbid_hook, "nazgul_forbid", NULL);
+ return (FALSE);
+}
diff --git a/src/q_nazgul.hpp b/src/q_nazgul.hpp
new file mode 100644
index 00000000..32e3237c
--- /dev/null
+++ b/src/q_nazgul.hpp
@@ -0,0 +1,5 @@
+#pragma once
+
+#include "h-basic.h"
+
+bool_ quest_nazgul_init_hook(int q_idx);
diff --git a/src/q_nirna.c b/src/q_nirna.c
deleted file mode 100644
index be856d31..00000000
--- a/src/q_nirna.c
+++ /dev/null
@@ -1,109 +0,0 @@
-#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_nirna.cc b/src/q_nirna.cc
new file mode 100644
index 00000000..a92ba6e4
--- /dev/null
+++ b/src/q_nirna.cc
@@ -0,0 +1,125 @@
+#include "q_nirna.hpp"
+
+#include "cave.hpp"
+#include "cave_type.hpp"
+#include "hook_quest_finish_in.hpp"
+#include "hooks.hpp"
+#include "init1.hpp"
+#include "monster2.hpp"
+#include "player_type.hpp"
+#include "tables.hpp"
+#include "util.hpp"
+#include "variable.hpp"
+
+#define cquest (quest[QUEST_NIRNAETH])
+
+static bool_ quest_nirnaeth_gen_hook(void *, void *, void *)
+{
+ 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;
+}
+
+static bool_ quest_nirnaeth_finish_hook(void *, void *in_, void *)
+{
+ struct hook_quest_finish_in *in = static_cast<struct hook_quest_finish_in *>(in_);
+ s32b q_idx = in->q_idx;
+
+ 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_FRAME);
+
+ /* 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_new(HOOK_QUEST_FINISH, quest_nirnaeth_finish_hook);
+ process_hooks_restart = TRUE;
+
+ return TRUE;
+}
+
+static bool_ quest_nirnaeth_death_hook(void *, void *, void *)
+{
+ if (p_ptr->inside_quest != QUEST_NIRNAETH) return FALSE;
+
+ cquest.data[1]++;
+
+ return FALSE;
+}
+
+static bool_ quest_nirnaeth_stair_hook(void *, void *, void *)
+{
+ 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_new(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_new(HOOK_MONSTER_DEATH, quest_nirnaeth_death_hook, "nirnaeth_death", NULL);
+ add_hook_new(HOOK_GEN_QUEST, quest_nirnaeth_gen_hook, "nirnaeth_gen", NULL);
+ add_hook_new(HOOK_STAIR, quest_nirnaeth_stair_hook, "nirnaeth_stair", NULL);
+ add_hook_new(HOOK_QUEST_FINISH, quest_nirnaeth_finish_hook, "nirnaeth_finish", NULL);
+ }
+ return (FALSE);
+}
diff --git a/src/q_nirna.hpp b/src/q_nirna.hpp
new file mode 100644
index 00000000..24a8759f
--- /dev/null
+++ b/src/q_nirna.hpp
@@ -0,0 +1,5 @@
+#pragma once
+
+#include "h-basic.h"
+
+bool_ quest_nirnaeth_init_hook(int q_idx);
diff --git a/src/q_one.c b/src/q_one.c
deleted file mode 100644
index 4bfeaf3e..00000000
--- a/src/q_one.c
+++ /dev/null
@@ -1,354 +0,0 @@
-#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_one.cc b/src/q_one.cc
new file mode 100644
index 00000000..3741e009
--- /dev/null
+++ b/src/q_one.cc
@@ -0,0 +1,378 @@
+#include "q_one.hpp"
+
+#include "artifact_type.hpp"
+#include "cave.hpp"
+#include "cave_type.hpp"
+#include "gods.hpp"
+#include "hook_calculate_hp_in.hpp"
+#include "hook_calculate_hp_out.hpp"
+#include "hook_chardump_in.hpp"
+#include "hook_drop_in.hpp"
+#include "hook_identify_in.hpp"
+#include "hook_monster_death_in.hpp"
+#include "hook_move_in.hpp"
+#include "hook_wield_in.hpp"
+#include "hooks.hpp"
+#include "monster2.hpp"
+#include "monster_type.hpp"
+#include "object1.hpp"
+#include "object2.hpp"
+#include "player_type.hpp"
+#include "tables.hpp"
+#include "town_type.hpp"
+#include "util.hpp"
+#include "variable.hpp"
+#include "z-rand.hpp"
+
+#define cquest (quest[QUEST_ONE])
+
+static bool_ quest_one_move_hook(void *, void *in_, void *)
+{
+ struct hook_move_in *in = static_cast<struct hook_move_in *>(in_);
+ s32b y = in->y;
+ s32b x = in->x;
+ cave_type *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.'");
+
+ if (p_ptr->pgod == GOD_ERU)
+ {
+ cmsg_print(TERM_YELLOW, "'Also, Eru will abandon you if you wear it.'");
+ }
+
+ if (p_ptr->pgod == GOD_MANWE)
+ {
+ cmsg_print(TERM_YELLOW, "'Also, Manwe will abandon you if you wear it.'");
+ }
+
+ if (p_ptr->pgod == GOD_TULKAS)
+ {
+ cmsg_print(TERM_YELLOW, "'Also, Tulkas will abandon you if you wear it.'");
+ }
+
+ if (p_ptr->pgod == 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!'");
+
+ if (p_ptr->pgod == 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;
+}
+
+static bool_ quest_one_drop_hook(void *, void *in_, void *)
+{
+ struct hook_drop_in *in = static_cast<struct hook_drop_in *>(in_);
+ s32b o_idx = in->o_idx;
+ object_type *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;
+}
+
+static bool_ quest_one_wield_hook(void *, void *in_, void *)
+{
+ struct hook_wield_in *in = static_cast<struct hook_wield_in *>(in_);
+ object_type *o_ptr = in->o_ptr;
+
+ 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;
+}
+
+static bool_ quest_one_hp_hook(void *, void *in_, void *out_)
+{
+ struct hook_calculate_hp_in *in = static_cast<struct hook_calculate_hp_in *>(in_);
+ struct hook_calculate_hp_out *out = static_cast<struct hook_calculate_hp_out *>(out_);
+
+ if (cquest.status == QUEST_STATUS_FAILED_DONE)
+ {
+ s32b mhp = in->mhp;
+
+ for (int i = 0; i < p_ptr->lives + 1; i++)
+ mhp = (mhp * 2) / 3;
+
+ out->mhp = mhp;
+ return (TRUE);
+ }
+ return (FALSE);
+}
+
+static bool_ quest_one_die_hook(void *, void *, void *)
+{
+ 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);
+}
+
+static bool_ quest_one_identify_hook(void *, void *in_, void *)
+{
+ struct hook_identify_in *in = static_cast<struct hook_identify_in *>(in_);
+ object_type *o_ptr = in->o_ptr;
+
+ if (cquest.status == QUEST_STATUS_TAKEN)
+ {
+ 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);
+}
+
+static bool_ quest_one_death_hook(void *, void *in_, void *)
+{
+ struct hook_monster_death_in *in = static_cast<struct hook_monster_death_in *>(in_);
+ s32b m_idx = in->m_idx;
+ s32b r_idx = m_list[m_idx].r_idx;
+ bool_ ok = FALSE;
+
+ 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);
+}
+
+static bool_ quest_one_dump_hook(void *, void *in_, void *)
+{
+ struct hook_chardump_in *in = static_cast<struct hook_chardump_in *>(in_);
+ FILE *f = in->file;
+
+ if (cquest.status == QUEST_STATUS_FINISHED)
+ {
+ fprintf(f, "\n You destroyed the One Ring, thus weakening Sauron.");
+ }
+ if (cquest.status == QUEST_STATUS_FAILED_DONE)
+ {
+ fprintf(f, "\n You fell under the evil influence of the One Ring and decided to wear it.");
+ }
+ return (FALSE);
+}
+
+static bool_ quest_one_gen_hook(void *, void *, void *)
+{
+ 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_new(HOOK_LEVEL_END_GEN, quest_one_gen_hook, "one_gen", NULL);
+ add_hook_new(HOOK_MONSTER_DEATH, quest_one_death_hook, "one_death", NULL);
+ add_hook_new(HOOK_DROP, quest_one_drop_hook, "one_drop", NULL);
+ add_hook_new(HOOK_WIELD, quest_one_wield_hook, "one_wield", NULL);
+ add_hook_new(HOOK_IDENTIFY, quest_one_identify_hook, "one_id", NULL);
+ }
+ if (cquest.status == QUEST_STATUS_UNTAKEN)
+ {
+ add_hook_new(HOOK_MOVE, quest_one_move_hook, "one_move", NULL);
+ }
+ add_hook_new(HOOK_CHAR_DUMP, quest_one_dump_hook, "one_dump", NULL);
+ add_hook_new(HOOK_CALC_HP, quest_one_hp_hook, "one_hp", NULL);
+ add_hook_new(HOOK_DIE, quest_one_die_hook, "one_die", NULL);
+ return (FALSE);
+}
diff --git a/src/q_one.hpp b/src/q_one.hpp
new file mode 100644
index 00000000..a85a5733
--- /dev/null
+++ b/src/q_one.hpp
@@ -0,0 +1,5 @@
+#pragma once
+
+#include "h-basic.h"
+
+bool_ quest_one_init_hook(int q_idx);
diff --git a/src/q_poison.c b/src/q_poison.c
deleted file mode 100644
index e6fed3a1..00000000
--- a/src/q_poison.c
+++ /dev/null
@@ -1,238 +0,0 @@
-#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_poison.cc b/src/q_poison.cc
new file mode 100644
index 00000000..a5b274b0
--- /dev/null
+++ b/src/q_poison.cc
@@ -0,0 +1,263 @@
+#include "q_poison.hpp"
+
+#include "cave.hpp"
+#include "cave_type.hpp"
+#include "hook_chardump_in.hpp"
+#include "hook_drop_in.hpp"
+#include "hook_init_quest_in.hpp"
+#include "hook_quest_finish_in.hpp"
+#include "hooks.hpp"
+#include "messages.hpp"
+#include "monster2.hpp"
+#include "monster_race.hpp"
+#include "monster_type.hpp"
+#include "object2.hpp"
+#include "player_type.hpp"
+#include "quark.hpp"
+#include "tables.hpp"
+#include "util.hpp"
+#include "variable.hpp"
+#include "z-rand.hpp"
+
+#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;
+}
+
+static bool_ quest_poison_gen_hook(void *, void *, void *)
+{
+ 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;
+}
+
+static bool_ quest_poison_finish_hook(void *, void *in_, void *)
+{
+ struct hook_quest_finish_in *in = static_cast<struct hook_quest_finish_in *>(in_);
+ s32b q_idx = in->q_idx;
+ object_type forge, *q_ptr;
+
+ 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_new(HOOK_QUEST_FINISH, quest_poison_finish_hook);
+ process_hooks_restart = TRUE;
+
+ return TRUE;
+}
+
+static bool_ quest_poison_dump_hook(void *, void *in_, void *)
+{
+ hook_chardump_in *in = static_cast<struct hook_chardump_in *>(in_);
+ FILE *f = in->file;
+
+ if (cquest.status >= QUEST_STATUS_COMPLETED)
+ {
+ fprintf(f, "\n You saved the beautiful Mallorns of Lothlorien.");
+ }
+ return (FALSE);
+}
+
+static bool_ quest_poison_quest_hook(void *, void *in_, void *)
+{
+ struct hook_init_quest_in *in = static_cast<struct hook_init_quest_in *>(in_);
+ s32b q_idx = in->q_idx;
+ object_type forge, *q_ptr;
+
+ 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_new(HOOK_INIT_QUEST, quest_poison_quest_hook);
+ process_hooks_restart = TRUE;
+
+ return FALSE;
+}
+
+static bool_ quest_poison_drop_hook(void *, void *in_, void *)
+{
+ struct hook_drop_in *in = static_cast<struct hook_drop_in *>(in_);
+ s32b mcnt = 0, i, x, y;
+ s32b o_idx = in->o_idx;
+ object_type *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_new(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(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_new(HOOK_DROP, quest_poison_drop_hook, "poison_drop", NULL);
+ add_hook_new(HOOK_WILD_GEN, quest_poison_gen_hook, "poison_gen", NULL);
+ add_hook_new(HOOK_QUEST_FINISH, quest_poison_finish_hook, "poison_finish", NULL);
+ }
+ if (cquest.status < QUEST_STATUS_COMPLETED)
+ {
+ add_hook_new(HOOK_INIT_QUEST, quest_poison_quest_hook, "poison_iquest", NULL);
+ }
+ add_hook_new(HOOK_CHAR_DUMP, quest_poison_dump_hook, "poison_dump", NULL);
+ return (FALSE);
+}
diff --git a/src/q_poison.hpp b/src/q_poison.hpp
new file mode 100644
index 00000000..f8d97ace
--- /dev/null
+++ b/src/q_poison.hpp
@@ -0,0 +1,5 @@
+#pragma once
+
+#include "h-basic.h"
+
+bool_ quest_poison_init_hook(int q_idx);
diff --git a/src/q_rand.c b/src/q_rand.c
deleted file mode 100644
index 5a3b3ab2..00000000
--- a/src/q_rand.c
+++ /dev/null
@@ -1,465 +0,0 @@
-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_rand.cc b/src/q_rand.cc
new file mode 100644
index 00000000..4ef79928
--- /dev/null
+++ b/src/q_rand.cc
@@ -0,0 +1,655 @@
+#include "q_rand.hpp"
+
+#include "artifact_type.hpp"
+#include "cave.hpp"
+#include "cave_type.hpp"
+#include "dungeon_info_type.hpp"
+#include "generate.hpp"
+#include "hook_build_room1_in.hpp"
+#include "hook_chardump_in.hpp"
+#include "hook_monster_death_in.hpp"
+#include "hooks.hpp"
+#include "init1.hpp"
+#include "lua_bind.hpp"
+#include "messages.hpp"
+#include "monster2.hpp"
+#include "monster3.hpp"
+#include "monster_type.hpp"
+#include "monster_race.hpp"
+#include "object1.hpp"
+#include "object2.hpp"
+#include "object_kind.hpp"
+#include "object_type.hpp"
+#include "player_type.hpp"
+#include "skills.hpp"
+#include "tables.hpp"
+#include "util.hpp"
+#include "variable.hpp"
+#include "z-rand.hpp"
+
+#include <cassert>
+
+static int randquest_hero[] = { 20, 13, 15, 16, 9, 17, 18, 8, -1 };
+
+/* Possible number(and layout) or random quests */
+#define MAX_RANDOM_QUESTS_TYPES ((8 * 3) + (8 * 1))
+static 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
+
+// Generate lookup function
+GENERATE_MONSTER_LOOKUP_FN(get_adventurer, "Adventurer")
+
+void initialize_random_quests(int n)
+{
+ int step, lvl, i, k;
+ int old_type = dungeon_type;
+
+ /* Zero out everything first */
+ for (i = 0; i < MAX_RANDOM_QUEST; i++) random_quests[i].type = 0;
+
+ if (n == 0) return;
+
+ /* 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 = nullptr;
+
+ 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;
+
+ /* If module says a monster race is friendly, then skip */
+ if (modules[game_module_idx].race_status != NULL)
+ {
+ s16b *status = (*modules[game_module_idx].race_status)(q_ptr->r_idx);
+ if ((status != NULL) && (*status >= 0))
+ {
+ 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(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(format("Quest for %d on lvl %d",
+ q_ptr->r_idx, rl), TERM_RED);
+ }
+ }
+
+ lvl += step;
+ }
+
+ dungeon_type = old_type;
+}
+
+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;
+}
+
+static void do_get_new_obj(int y, int x)
+{
+ obj_theme theme;
+ object_type *q_ptr[3], forge[3];
+ int res, i;
+
+ /* Create objects */
+ std::vector<std::string> items;
+ for (i = 0; i < 3; i++)
+ {
+ /* Get local object */
+ q_ptr[i] = &forge[i];
+
+ /* Wipe the object */
+ object_wipe(q_ptr[i]);
+
+ /* No themes */
+ theme.treasure = 100;
+ theme.combat = 100;
+ theme.magic = 100;
+ theme.tools = 100;
+
+ /* Make a great object */
+ make_object(q_ptr[i], TRUE, TRUE, theme);
+ q_ptr[i]->found = OBJ_FOUND_REWARD;
+
+ char buf[100];
+ object_desc(buf, q_ptr[i], 0, 0);
+ items.push_back(buf);
+ }
+
+
+ while (TRUE)
+ {
+ res = ask_menu("Choose a reward to get(a-c to choose, ESC to cancel)?", items);
+
+ /* 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;
+ }
+ }
+ }
+}
+
+static 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;
+ }
+ }
+}
+
+static 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 r_idx = get_adventurer();
+
+ m_allow_special[r_idx] = TRUE;
+ int m_idx = place_monster_one(y, x, r_idx, 0, FALSE, MSTATUS_COMPANION);
+ m_allow_special[r_idx] = 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();
+ }
+}
+
+static bool_ quest_random_death_hook(void *, void *in_, void *)
+{
+ struct hook_monster_death_in *in = static_cast<struct hook_monster_death_in *>(in_);
+ s32b m_idx = in->m_idx;
+ int 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);
+}
+
+static bool_ quest_random_turn_hook(void *, void *, void *)
+{
+ quest[QUEST_RANDOM].data[0] = 0;
+ quest[QUEST_RANDOM].data[1] = 0;
+ return (FALSE);
+}
+
+static bool_ quest_random_feeling_hook(void *, void *, void *)
+{
+ 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);
+ }
+ else
+ cmsg_format(TERM_YELLOW, "You hear someone shouting: 'Leave me alone, stupid %s'", r_info[random_quests[dun_level].r_idx].name);
+ return (FALSE);
+}
+
+static bool_ quest_random_gen_hero_hook(void *, void *, void *)
+{
+ 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);
+}
+
+static bool_ quest_random_gen_hook(void *, void *in_, void *)
+{
+ struct hook_build_room1_in *in = static_cast<struct hook_build_room1_in *>(in_);
+ s32b bx0 = in->x;
+ s32b by0 = in->y;
+ s32b x, y;
+ 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);
+
+ /* 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);
+}
+
+static bool_ quest_random_dump_hook(void *, void *in_, void *)
+{
+ static const char *number[] = { "two", "three", "four", "five", "six", "seven", "eight", "nine", "ten" };
+ struct hook_chardump_in *in = static_cast<struct hook_chardump_in *>(in_);
+ FILE *f = in->file;
+ 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(f, "\n You have completed %d princess quests.", pcnt);
+ else if (pcnt > 1)
+ fprintf(f, "\n You have completed %s princess quests.", number[pcnt-2]);
+ else if (pcnt == 1)
+ fprintf(f, "\n You have completed one princess quest.");
+ else
+ fprintf(f, "\n You haven't completed a single princess quest.");
+
+ if (lscnt > 10)
+ fprintf(f, "\n You have completed %d lost sword quests.", lscnt);
+ else if (lscnt > 1)
+ fprintf(f, "\n You have completed %s lost sword quests.", number[lscnt-2]);
+ else if (lscnt == 1)
+ fprintf(f, "\n You have completed one lost sword quest.");
+ else
+ fprintf(f, "\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);
+ }
+ 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);
+ 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_new(HOOK_MONSTER_DEATH, quest_random_death_hook, "rand_death", NULL);
+ add_hook_new(HOOK_NEW_LEVEL, quest_random_turn_hook, "rand_new_lvl", NULL);
+ add_hook_new(HOOK_LEVEL_REGEN, quest_random_turn_hook, "rand_regen_lvl", NULL);
+ add_hook_new(HOOK_LEVEL_END_GEN, quest_random_gen_hero_hook, "rand_gen_hero", NULL);
+ add_hook_new(HOOK_BUILD_ROOM1, quest_random_gen_hook, "rand_gen", NULL);
+ add_hook_new(HOOK_FEELING, quest_random_feeling_hook, "rand_feel", NULL);
+ add_hook_new(HOOK_CHAR_DUMP, quest_random_dump_hook, "rand_dump", NULL);
+ return (FALSE);
+}
diff --git a/src/q_rand.hpp b/src/q_rand.hpp
new file mode 100644
index 00000000..fe87289b
--- /dev/null
+++ b/src/q_rand.hpp
@@ -0,0 +1,8 @@
+#pragma once
+
+#include "h-basic.h"
+
+void initialize_random_quests(int n);
+bool_ is_randhero(int level);
+bool_ quest_random_init_hook(int q_idx);
+bool_ quest_random_describe(FILE *fff);
diff --git a/src/q_shroom.c b/src/q_shroom.c
deleted file mode 100644
index b6e26cdf..00000000
--- a/src/q_shroom.c
+++ /dev/null
@@ -1,293 +0,0 @@
-#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_shroom.cc b/src/q_shroom.cc
new file mode 100644
index 00000000..89b576d8
--- /dev/null
+++ b/src/q_shroom.cc
@@ -0,0 +1,311 @@
+#include "q_shroom.hpp"
+
+#include "cave.hpp"
+#include "hook_chat_in.hpp"
+#include "hook_give_in.hpp"
+#include "hook_monster_death_in.hpp"
+#include "hook_mon_speak_in.hpp"
+#include "hook_wild_gen_in.hpp"
+#include "hooks.hpp"
+#include "messages.hpp"
+#include "monster2.hpp"
+#include "monster_race.hpp"
+#include "monster_type.hpp"
+#include "object2.hpp"
+#include "player_type.hpp"
+#include "tables.hpp"
+#include "util.hpp"
+#include "variable.hpp"
+#include "z-rand.hpp"
+
+#include <cassert>
+
+#define cquest (quest[QUEST_SHROOM])
+
+static bool_ quest_shroom_speak_hook(void *, void *, void *);
+static bool_ quest_shroom_chat_hook(void *, void *, void *);
+
+GENERATE_MONSTER_LOOKUP_FN(get_grip, "Grip, Farmer Maggot's dog")
+GENERATE_MONSTER_LOOKUP_FN(get_wolf, "Wolf, Farmer Maggot's dog")
+GENERATE_MONSTER_LOOKUP_FN(get_fang, "Fang, Farmer Maggot's dog")
+GENERATE_MONSTER_LOOKUP_FN(get_farmer_maggot, "Farmer Maggot")
+
+static bool_ quest_shroom_town_gen_hook(void *, void *in_, void *)
+{
+ struct hook_wild_gen_in *in = static_cast<struct hook_wild_gen_in *>(in_);
+ int m_idx, x = 1, y = 1, tries = 10000;
+ bool_ small = in->small;
+
+ /* 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[get_grip()] = TRUE;
+ m_idx = place_monster_one(y, x, get_grip(), 0, FALSE, MSTATUS_ENEMY);
+ if (m_idx) m_list[m_idx].mflag |= MFLAG_QUEST;
+ m_allow_special[get_grip()] = 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[get_wolf()] = TRUE;
+ m_idx = place_monster_one(y, x, get_wolf(), 0, FALSE, MSTATUS_ENEMY);
+ if (m_idx) m_list[m_idx].mflag |= MFLAG_QUEST;
+ m_allow_special[get_wolf()] = 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[get_fang()] = TRUE;
+ m_idx = place_monster_one(y, x, get_fang(), 0, FALSE, MSTATUS_ENEMY);
+ if (m_idx) m_list[m_idx].mflag |= MFLAG_QUEST;
+ m_allow_special[get_fang()] = 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[get_farmer_maggot()] = TRUE;
+ place_monster_one(y, x, get_farmer_maggot(), 0, FALSE, MSTATUS_ENEMY);
+ m_allow_special[get_farmer_maggot()] = FALSE;
+
+ return FALSE;
+}
+
+static bool_ quest_shroom_death_hook(void *, void *in_, void *)
+{
+ struct hook_monster_death_in *in = static_cast<struct hook_monster_death_in *>(in_);
+ s32b m_idx = in->m_idx;
+ s32b r_idx = m_list[m_idx].r_idx;
+
+ if (cquest.status > QUEST_STATUS_COMPLETED) return FALSE;
+
+ if ((r_idx == get_wolf()) ||
+ (r_idx == get_grip()) ||
+ (r_idx == get_fang()))
+ {
+ msg_print("The dog yells a last time and drops dead on the grass.");
+ }
+
+ return FALSE;
+}
+
+static bool_ quest_shroom_give_hook(void *, void *in_, void *)
+{
+ struct hook_give_in *in = static_cast<struct hook_give_in *>(in_);
+ object_type *o_ptr;
+ monster_type *m_ptr;
+
+ s32b m_idx = in->m_idx;
+ s32b item = in->item;
+
+ o_ptr = &p_ptr->inventory[item];
+ m_ptr = &m_list[m_idx];
+
+ if (m_ptr->r_idx != get_farmer_maggot()) return (FALSE);
+
+ /* If one is dead .. its bad */
+ if ((r_info[get_grip()].max_num == 0) ||
+ (r_info[get_wolf()].max_num == 0) ||
+ (r_info[get_fang()].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_new(HOOK_GIVE, quest_shroom_give_hook);
+ del_hook_new(HOOK_CHAT, quest_shroom_speak_hook);
+ del_hook_new(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_new(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;
+}
+
+static void check_dogs_alive(s32b m_idx)
+{
+ if ((r_info[get_grip()].max_num == 0) ||
+ (r_info[get_wolf()].max_num == 0) ||
+ (r_info[get_fang()].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_new(HOOK_GIVE, quest_shroom_give_hook);
+ del_hook_new(HOOK_MON_SPEAK, quest_shroom_speak_hook);
+ del_hook_new(HOOK_CHAT, quest_shroom_chat_hook);
+ del_hook_new(HOOK_WILD_GEN, quest_shroom_town_gen_hook);
+ process_hooks_restart = TRUE;
+ }
+ else
+ {
+ msg_format("You still have %d mushrooms to bring back!", cquest.data[1] - cquest.data[0]);
+ }
+}
+
+static bool_ quest_shroom_speak_hook(void *, void *in_, void *)
+{
+ struct hook_mon_speak_in *in = static_cast<struct hook_mon_speak_in *>(in_);
+ s32b m_idx = in->m_idx;
+
+ if (m_list[m_idx].r_idx != get_farmer_maggot()) return (FALSE);
+
+ if (cquest.status == QUEST_STATUS_UNTAKEN)
+ {
+ msg_format("%^s asks your help.", in->m_name);
+ process_hooks_new(HOOK_MON_ASK_HELP, NULL, NULL);
+ }
+ else
+ {
+ check_dogs_alive(m_idx);
+ }
+ return (TRUE);
+}
+
+static bool_ quest_shroom_chat_hook(void *, void *in_, void *)
+{
+ struct hook_chat_in *in = static_cast<struct hook_chat_in *>(in_);
+ s32b m_idx = in->m_idx;
+ monster_type *m_ptr = &m_list[m_idx];
+
+ if (m_ptr->r_idx != get_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
+ {
+ check_dogs_alive(m_idx);
+ }
+
+ 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(format("Shrooms number %d", cquest.data[1]), TERM_BLUE);
+ }
+ }
+
+ if ((cquest.status >= QUEST_STATUS_TAKEN) && (cquest.status < QUEST_STATUS_FINISHED))
+ {
+ add_hook_new(HOOK_MONSTER_DEATH, quest_shroom_death_hook, "shroom_death", NULL);
+ add_hook_new(HOOK_GIVE, quest_shroom_give_hook, "shroom_give", NULL);
+ add_hook_new(HOOK_WILD_GEN, quest_shroom_town_gen_hook, "shroom_town_gen", NULL);
+ add_hook_new(HOOK_CHAT, quest_shroom_chat_hook, "shroom_chat", NULL);
+ add_hook_new(HOOK_MON_SPEAK, quest_shroom_speak_hook, "shroom_speak", NULL);
+ }
+ if (cquest.status == QUEST_STATUS_UNTAKEN)
+ {
+ add_hook_new(HOOK_MON_SPEAK, quest_shroom_speak_hook, "shroom_speak", NULL);
+ add_hook_new(HOOK_WILD_GEN, quest_shroom_town_gen_hook, "shroom_town_gen", NULL);
+ add_hook_new(HOOK_CHAT, quest_shroom_chat_hook, "shroom_chat", NULL);
+ }
+ return (FALSE);
+}
diff --git a/src/q_shroom.hpp b/src/q_shroom.hpp
new file mode 100644
index 00000000..6124775b
--- /dev/null
+++ b/src/q_shroom.hpp
@@ -0,0 +1,5 @@
+#pragma once
+
+#include "h-basic.h"
+
+bool_ quest_shroom_init_hook(int q_idx);
diff --git a/src/q_spider.c b/src/q_spider.c
deleted file mode 100644
index a739535b..00000000
--- a/src/q_spider.c
+++ /dev/null
@@ -1,108 +0,0 @@
-#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_spider.cc b/src/q_spider.cc
new file mode 100644
index 00000000..07531b96
--- /dev/null
+++ b/src/q_spider.cc
@@ -0,0 +1,127 @@
+#include "q_spider.hpp"
+
+#include "cave.hpp"
+#include "gods.hpp"
+#include "hook_quest_finish_in.hpp"
+#include "hooks.hpp"
+#include "init1.hpp"
+#include "monster2.hpp"
+#include "monster_type.hpp"
+#include "object2.hpp"
+#include "object_type.hpp"
+#include "player_type.hpp"
+#include "tables.hpp"
+#include "util.hpp"
+#include "variable.hpp"
+
+#define cquest (quest[QUEST_SPIDER])
+
+static bool_ quest_spider_gen_hook(void *, void *, void *)
+{
+ 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;
+}
+
+static bool_ quest_spider_death_hook(void *, void *, void *)
+{
+ 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 */
+ if (p_ptr->pgod == 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_new(HOOK_MONSTER_DEATH, quest_spider_death_hook);
+ process_hooks_restart = TRUE;
+
+ return (FALSE);
+ }
+
+ return (FALSE);
+}
+
+static bool_ quest_spider_finish_hook(void *, void *in_, void *)
+{
+ struct hook_quest_finish_in *in = static_cast<struct hook_quest_finish_in *>(in_);
+ object_type forge, *q_ptr;
+ s32b q_idx = in->q_idx;
+
+ 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_new(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_new(HOOK_MONSTER_DEATH, quest_spider_death_hook, "spider_death", NULL);
+ add_hook_new(HOOK_GEN_QUEST, quest_spider_gen_hook, "spider_gen", NULL);
+ add_hook_new(HOOK_QUEST_FINISH, quest_spider_finish_hook, "spider_finish", NULL);
+ }
+ return (FALSE);
+}
diff --git a/src/q_spider.hpp b/src/q_spider.hpp
new file mode 100644
index 00000000..e17cb523
--- /dev/null
+++ b/src/q_spider.hpp
@@ -0,0 +1,5 @@
+#pragma once
+
+#include "h-basic.h"
+
+bool_ quest_spider_init_hook(int q_idx);
diff --git a/src/q_thief.c b/src/q_thief.c
deleted file mode 100644
index 6b033f8c..00000000
--- a/src/q_thief.c
+++ /dev/null
@@ -1,172 +0,0 @@
-#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_thief.cc b/src/q_thief.cc
new file mode 100644
index 00000000..0f6543cc
--- /dev/null
+++ b/src/q_thief.cc
@@ -0,0 +1,193 @@
+#include "q_thief.hpp"
+
+#include "cave.hpp"
+#include "cave_type.hpp"
+#include "hook_quest_finish_in.hpp"
+#include "hooks.hpp"
+#include "init1.hpp"
+#include "monster2.hpp"
+#include "monster_type.hpp"
+#include "object1.hpp"
+#include "object2.hpp"
+#include "object_type.hpp"
+#include "player_type.hpp"
+#include "skill_type.hpp"
+#include "spells2.hpp"
+#include "tables.hpp"
+#include "util.hpp"
+#include "variable.hpp"
+#include "z-rand.hpp"
+
+#define cquest (quest[QUEST_THIEVES])
+
+static bool_ quest_thieves_gen_hook(void *, void *, void *)
+{
+ 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_new(HOOK_GEN_QUEST, quest_thieves_gen_hook);
+ process_hooks_restart = TRUE;
+
+ return TRUE;
+}
+
+static bool_ quest_thieves_hook(void *, void *, void *)
+{
+ 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_new(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;
+}
+
+static bool_ quest_thieves_finish_hook(void *, void *in_, void *)
+{
+ struct hook_quest_finish_in *in = static_cast<struct hook_quest_finish_in *>(in_);
+ s32b q_idx = in->q_idx;
+
+ 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_new(HOOK_QUEST_FINISH, quest_thieves_finish_hook);
+ process_hooks_restart = TRUE;
+
+ return TRUE;
+}
+
+static bool_ quest_thieves_feeling_hook(void *, void *, void *)
+{
+ 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_new(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_new(HOOK_END_TURN, quest_thieves_hook, "thieves_end_turn", NULL);
+ add_hook_new(HOOK_QUEST_FINISH, quest_thieves_finish_hook, "thieves_finish", NULL);
+ add_hook_new(HOOK_GEN_QUEST, quest_thieves_gen_hook, "thieves_geb", NULL);
+ add_hook_new(HOOK_FEELING, quest_thieves_feeling_hook, "thieves_feel", NULL);
+ }
+ return (FALSE);
+}
diff --git a/src/q_thief.hpp b/src/q_thief.hpp
new file mode 100644
index 00000000..48e5dc8d
--- /dev/null
+++ b/src/q_thief.hpp
@@ -0,0 +1,5 @@
+#pragma once
+
+#include "h-basic.h"
+
+bool_ quest_thieves_init_hook(int q_idx);
diff --git a/src/q_thrain.c b/src/q_thrain.c
deleted file mode 100644
index b2b1be9f..00000000
--- a/src/q_thrain.c
+++ /dev/null
@@ -1,230 +0,0 @@
-#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_thrain.cc b/src/q_thrain.cc
new file mode 100644
index 00000000..05def27a
--- /dev/null
+++ b/src/q_thrain.cc
@@ -0,0 +1,261 @@
+#include "q_thrain.hpp"
+
+#include "cave.hpp"
+#include "cave_type.hpp"
+#include "dungeon_info_type.hpp"
+#include "generate.hpp"
+#include "hook_build_room1_in.hpp"
+#include "hook_move_in.hpp"
+#include "hook_monster_death_in.hpp"
+#include "hooks.hpp"
+#include "init1.hpp"
+#include "lua_bind.hpp"
+#include "object_type.hpp"
+#include "quark.hpp"
+#include "randart.hpp"
+#include "messages.hpp"
+#include "monster2.hpp"
+#include "monster_type.hpp"
+#include "object2.hpp"
+#include "tables.hpp"
+#include "util.hpp"
+#include "variable.hpp"
+#include "z-rand.hpp"
+
+#include <cassert>
+
+#define cquest (quest[QUEST_THRAIN])
+
+GENERATE_MONSTER_LOOKUP_FN(get_thrain, "Thrain, the King Under the Mountain")
+GENERATE_MONSTER_LOOKUP_FN(get_dwar, "Dwar, Dog Lord of Waw")
+GENERATE_MONSTER_LOOKUP_FN(get_hoarmurath, "Hoarmurath of Dir")
+
+static bool_ quest_thrain_death_hook(void *, void *in_, void *)
+{
+ struct hook_monster_death_in *in = static_cast<struct hook_monster_death_in *>(in_);
+ s32b m_idx = in->m_idx;
+ int r, x, y;
+ monster_type *m_ptr;
+
+ 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 != get_dwar()) && (m_ptr->r_idx != get_hoarmurath())) 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 == get_thrain())
+ {
+ 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_new(HOOK_MONSTER_DEATH, quest_thrain_death_hook);
+ process_hooks_restart = TRUE;
+
+ return (FALSE);
+}
+
+static bool_ quest_thrain_gen_hook(void *, void *in_, void *)
+{
+ struct hook_build_room1_in *in = static_cast<struct hook_build_room1_in *>(in_);
+ s32b bx0 = in->x;
+ s32b by0 = in->y;
+ s32b x, y;
+ 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);
+
+ /* 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)
+ {
+ m_allow_special[get_thrain()] = TRUE;
+ int i = place_monster_one(y, x, get_thrain(), 0, FALSE, MSTATUS_NEUTRAL);
+ m_allow_special[get_thrain()] = FALSE;
+
+ if (i) m_list[i].mflag |= MFLAG_QUEST;
+ }
+ }
+
+ /* Don't try another one for this generation */
+ cquest.data[1] = 1;
+
+ return (TRUE);
+}
+
+static bool_ quest_thrain_feeling_hook(void *, void *, void *)
+{
+ 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);
+}
+
+static bool_ quest_thrain_move_hook(void *, void *in_, void *)
+{
+ struct hook_move_in *in = static_cast<struct hook_move_in *>(in_);
+ s32b y = in->y;
+ s32b x = in->x;
+ cave_type *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);
+}
+
+static bool_ quest_thrain_turn_hook(void *, void *, void *)
+{
+ 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(format("Thrain lvl %d", cquest.data[0]), TERM_BLUE);
+ }
+ }
+ if ((cquest.status >= QUEST_STATUS_TAKEN) && (cquest.status < QUEST_STATUS_FINISHED))
+ {
+ add_hook_new(HOOK_MOVE, quest_thrain_move_hook, "thrain_move", NULL);
+ }
+ if ((cquest.status >= QUEST_STATUS_UNTAKEN) && (cquest.status < QUEST_STATUS_FINISHED))
+ {
+ add_hook_new(HOOK_LEVEL_REGEN, quest_thrain_turn_hook, "thrain_regen_lvl", NULL);
+ add_hook_new(HOOK_NEW_LEVEL, quest_thrain_turn_hook, "thrain_new_lvl", NULL);
+ add_hook_new(HOOK_BUILD_ROOM1, quest_thrain_gen_hook, "thrain_gen", NULL);
+ add_hook_new(HOOK_FEELING, quest_thrain_feeling_hook, "thrain_feel", NULL);
+ add_hook_new(HOOK_MONSTER_DEATH, quest_thrain_death_hook, "thrain_death", NULL);
+ }
+ return (FALSE);
+}
diff --git a/src/q_thrain.hpp b/src/q_thrain.hpp
new file mode 100644
index 00000000..830da016
--- /dev/null
+++ b/src/q_thrain.hpp
@@ -0,0 +1,5 @@
+#pragma once
+
+#include "h-basic.h"
+
+extern bool_ quest_thrain_init_hook(int q_idx);
diff --git a/src/q_troll.c b/src/q_troll.c
deleted file mode 100644
index c314d2a7..00000000
--- a/src/q_troll.c
+++ /dev/null
@@ -1,178 +0,0 @@
-#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_troll.cc b/src/q_troll.cc
new file mode 100644
index 00000000..fce3ad49
--- /dev/null
+++ b/src/q_troll.cc
@@ -0,0 +1,194 @@
+#include "q_troll.hpp"
+
+#include "artifact_type.hpp"
+#include "cave.hpp"
+#include "cave_type.hpp"
+#include "hook_monster_death_in.hpp"
+#include "hook_quest_finish_in.hpp"
+#include "hooks.hpp"
+#include "init1.hpp"
+#include "monster2.hpp"
+#include "monster_type.hpp"
+#include "object2.hpp"
+#include "object_type.hpp"
+#include "player_type.hpp"
+#include "tables.hpp"
+#include "util.hpp"
+#include "variable.hpp"
+#include "z-rand.hpp"
+
+#include <cassert>
+
+#define cquest (quest[QUEST_TROLL])
+
+GENERATE_MONSTER_LOOKUP_FN(get_tom, "Tom the Stone Troll")
+GENERATE_MONSTER_LOOKUP_FN(get_stone_troll, "Stone troll")
+GENERATE_MONSTER_LOOKUP_FN(get_forest_troll, "Forest troll")
+
+static bool_ quest_troll_gen_hook(void *, void *, void *)
+{
+ 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)
+ {
+ m_allow_special[get_tom()] = TRUE;
+ int m_idx = place_monster_one(y, x, get_tom(), 0, FALSE, MSTATUS_ENEMY);
+ m_allow_special[get_tom()] = 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);
+
+ /* Add to monster's inventory */
+ o_ptr->held_m_idx = m_idx;
+ o_ptr->ix = 0;
+ o_ptr->iy = 0;
+ m_list[m_idx].hold_o_idxs.push_back(o_idx);
+ }
+ else
+ {
+ a_info[q_ptr->name1].cur_num = 0;
+ }
+ }
+ }
+ }
+
+ /* Reinitialize the ambush ... hehehe */
+ cquest.data[0] = FALSE;
+ return TRUE;
+}
+
+static bool_ quest_troll_finish_hook(void *, void *in_, void *)
+{
+ struct hook_quest_finish_in *in = static_cast<struct hook_quest_finish_in *>(in_);
+ s32b q_idx = in->q_idx;
+
+ 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_new(HOOK_QUEST_FINISH, quest_troll_finish_hook);
+ process_hooks_restart = TRUE;
+
+ return TRUE;
+}
+
+static bool_ quest_troll_death_hook(void *, void *in_, void *)
+{
+ struct hook_monster_death_in *in = static_cast<struct hook_monster_death_in *>(in_);
+ s32b m_idx = in->m_idx;
+ s32b r_idx = m_list[m_idx].r_idx;
+ int x, y, xstart = 2, ystart = 2;
+
+ if (p_ptr->inside_quest != QUEST_TROLL) return FALSE;
+
+ if (r_idx == get_tom())
+ {
+ 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_new(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)
+ {
+ cave_set_feat(y, x, FEAT_GRASS);
+ c_ptr->info &= ~CAVE_SPEC;
+
+ int r_idx = (rand_int(2) == 0) ? get_forest_troll() : get_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_new(HOOK_MONSTER_DEATH, quest_troll_death_hook, "troll_death", NULL);
+ add_hook_new(HOOK_GEN_QUEST, quest_troll_gen_hook, "troll_gen", NULL);
+ add_hook_new(HOOK_QUEST_FINISH, quest_troll_finish_hook, "troll_finish", NULL);
+ }
+ return (FALSE);
+}
diff --git a/src/q_troll.hpp b/src/q_troll.hpp
new file mode 100644
index 00000000..140fe0b2
--- /dev/null
+++ b/src/q_troll.hpp
@@ -0,0 +1,5 @@
+#pragma once
+
+#include "h-basic.h"
+
+bool_ quest_troll_init_hook(int q_idx);
diff --git a/src/q_ultrae.c b/src/q_ultrae.c
deleted file mode 100644
index 78471df5..00000000
--- a/src/q_ultrae.c
+++ /dev/null
@@ -1,11 +0,0 @@
-/*
- * 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_ultrae.cc b/src/q_ultrae.cc
new file mode 100644
index 00000000..d42b9c6f
--- /dev/null
+++ b/src/q_ultrae.cc
@@ -0,0 +1,8 @@
+#include "q_ultrae.hpp"
+
+#define cquest (quest[QUEST_ULTRA_EVIL])
+
+bool_ quest_ultra_evil_init_hook(int q)
+{
+ return (FALSE);
+}
diff --git a/src/q_ultrae.hpp b/src/q_ultrae.hpp
new file mode 100644
index 00000000..5b08127b
--- /dev/null
+++ b/src/q_ultrae.hpp
@@ -0,0 +1,5 @@
+#pragma once
+
+#include "h-basic.h"
+
+bool_ quest_ultra_evil_init_hook(int q_idx);
diff --git a/src/q_ultrag.c b/src/q_ultrag.c
deleted file mode 100644
index a5a09f2d..00000000
--- a/src/q_ultrag.c
+++ /dev/null
@@ -1,276 +0,0 @@
-/*
- * 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_ultrag.cc b/src/q_ultrag.cc
new file mode 100644
index 00000000..c7c0312b
--- /dev/null
+++ b/src/q_ultrag.cc
@@ -0,0 +1,292 @@
+#include "q_ultrag.hpp"
+
+#include "cave.hpp"
+#include "cave_type.hpp"
+#include "hook_chardump_in.hpp"
+#include "hook_move_in.hpp"
+#include "hook_stair_in.hpp"
+#include "hook_monster_death_in.hpp"
+#include "hooks.hpp"
+#include "monster_type.hpp"
+#include "object1.hpp"
+#include "object2.hpp"
+#include "object_type.hpp"
+#include "options.hpp"
+#include "player_type.hpp"
+#include "tables.hpp"
+#include "util.hpp"
+#include "variable.hpp"
+
+#define cquest (quest[QUEST_ULTRA_GOOD])
+
+static bool_ quest_ultra_good_move_hook(void *, void *in_, void *)
+{
+ struct hook_move_in *in = static_cast<struct hook_move_in *>(in_);
+ s32b y = in->y;
+ s32b x = in->x;
+ cave_type *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;
+}
+
+static bool_ quest_ultra_good_stair_hook(void *, void *in_, void *)
+{
+ struct hook_stair_in *in = static_cast<struct hook_stair_in *>(in_);
+ stairs_direction dir = in->direction;
+
+ if (dungeon_type != DUNGEON_VOID)
+ return FALSE;
+
+ /* Cant leave */
+ if ((dir == STAIRS_UP) && (dun_level == 128))
+ {
+ cmsg_print(TERM_YELLOW, "The portal to Arda is now closed.");
+ return TRUE;
+ }
+ /* there is no coming back */
+ if ((dir == STAIRS_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 ((dir == STAIRS_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;
+}
+
+static bool_ quest_ultra_good_recall_hook(void *, void *, void *)
+{
+ 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;
+}
+
+static bool_ quest_ultra_good_death_hook(void *, void *in_, void *)
+{
+ struct hook_monster_death_in *in = static_cast<struct hook_monster_death_in *>(in_);
+ s32b m_idx = in->m_idx;
+
+ 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_FRAME);
+
+ /* 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_new(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);
+}
+
+static bool_ quest_ultra_good_dump_hook(void *, void *in_, void *)
+{
+ struct hook_chardump_in *in = static_cast<struct hook_chardump_in *>(in_);
+ FILE *f = in->file;
+
+ if (quest[QUEST_ULTRA_GOOD].status >= QUEST_STATUS_TAKEN)
+ {
+ /* Ultra winner ! */
+ if (total_winner == WINNER_ULTRA)
+ {
+ fprintf(f, "\n You destroyed Melkor forever and have been elevated to the status of Vala by Eru Iluvatar.");
+ fprintf(f, "\n Arda will forever be free.");
+ }
+ else
+ {
+ /* Tried and failed */
+ if (death)
+ {
+ fprintf(f, "\n You tried to destroy Melkor forever, but died in the attempt.");
+ fprintf(f, "\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_new(HOOK_STAIR, quest_ultra_good_stair_hook, "ultrag_stair", NULL);
+ add_hook_new(HOOK_RECALL, quest_ultra_good_recall_hook, "ultrag_recall", NULL);
+ add_hook_new(HOOK_MONSTER_DEATH, quest_ultra_good_death_hook, "ultrag_death", NULL);
+ }
+ if (cquest.status == QUEST_STATUS_UNTAKEN)
+ {
+ add_hook_new(HOOK_MOVE, quest_ultra_good_move_hook, "ultrag_move", NULL);
+ }
+ add_hook_new(HOOK_CHAR_DUMP, quest_ultra_good_dump_hook, "ultrag_dump", NULL);
+ return (FALSE);
+}
diff --git a/src/q_ultrag.hpp b/src/q_ultrag.hpp
new file mode 100644
index 00000000..0064b878
--- /dev/null
+++ b/src/q_ultrag.hpp
@@ -0,0 +1,5 @@
+#pragma once
+
+#include "h-basic.h"
+
+bool_ quest_ultra_good_init_hook(int q_idx);
diff --git a/src/q_wight.c b/src/q_wight.c
deleted file mode 100644
index 3f6b2c34..00000000
--- a/src/q_wight.c
+++ /dev/null
@@ -1,156 +0,0 @@
-#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_wight.cc b/src/q_wight.cc
new file mode 100644
index 00000000..f2cc630c
--- /dev/null
+++ b/src/q_wight.cc
@@ -0,0 +1,179 @@
+#include "q_wight.hpp"
+
+#include "cave.hpp"
+#include "cave_type.hpp"
+#include "hook_monster_death_in.hpp"
+#include "hook_quest_finish_in.hpp"
+#include "hooks.hpp"
+#include "init1.hpp"
+#include "monster2.hpp"
+#include "monster_type.hpp"
+#include "object2.hpp"
+#include "player_type.hpp"
+#include "quark.hpp"
+#include "tables.hpp"
+#include "util.hpp"
+#include "variable.hpp"
+#include "z-rand.hpp"
+
+#include <cassert>
+
+#define cquest (quest[QUEST_WIGHT])
+
+GENERATE_MONSTER_LOOKUP_FN(get_wight_king, "The Wight-King of the Barrow-downs")
+
+static bool_ quest_wight_gen_hook(void *, void *, void *)
+{
+ 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[get_wight_king()] = TRUE;
+ m_idx = place_monster_one(y, x, get_wight_king(), 0, FALSE, MSTATUS_ENEMY);
+ m_allow_special[get_wight_king()] = 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->held_m_idx = m_idx;
+ o_ptr->ix = 0;
+ o_ptr->iy = 0;
+
+ m_list[m_idx].hold_o_idxs.push_back(o_idx);
+ }
+ }
+ }
+ }
+
+ return TRUE;
+}
+
+static bool_ quest_wight_death_hook(void *, void *in_, void *)
+{
+ struct hook_monster_death_in *in = static_cast<struct hook_monster_death_in *>(in_);
+ s32b m_idx = in->m_idx;
+ s32b r_idx = m_list[m_idx].r_idx;
+
+ if (p_ptr->inside_quest != QUEST_WIGHT) return FALSE;
+
+ if (r_idx == get_wight_king())
+ {
+ 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_new(HOOK_MONSTER_DEATH, quest_wight_death_hook);
+ process_hooks_restart = TRUE;
+
+ return (FALSE);
+ }
+
+ return (FALSE);
+}
+
+static bool_ quest_wight_finish_hook(void *, void *in_, void *)
+{
+ struct hook_quest_finish_in *in = static_cast<struct hook_quest_finish_in *>(in_);
+ s32b q_idx = in->q_idx;
+
+ 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_new(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_new(HOOK_MONSTER_DEATH, quest_wight_death_hook, "wight_death", NULL);
+ add_hook_new(HOOK_GEN_QUEST, quest_wight_gen_hook, "wight_gen", NULL);
+ add_hook_new(HOOK_QUEST_FINISH, quest_wight_finish_hook, "wight_finish", NULL);
+ }
+ return (FALSE);
+}
diff --git a/src/q_wight.hpp b/src/q_wight.hpp
new file mode 100644
index 00000000..1252e4fa
--- /dev/null
+++ b/src/q_wight.hpp
@@ -0,0 +1,5 @@
+#pragma once
+
+#include "h-basic.h"
+
+bool_ quest_wight_init_hook(int q_idx);
diff --git a/src/q_wolves.c b/src/q_wolves.c
deleted file mode 100644
index 2ec14cc2..00000000
--- a/src/q_wolves.c
+++ /dev/null
@@ -1,130 +0,0 @@
-#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/q_wolves.cc b/src/q_wolves.cc
new file mode 100644
index 00000000..c5863b59
--- /dev/null
+++ b/src/q_wolves.cc
@@ -0,0 +1,146 @@
+#include "q_wolves.hpp"
+
+#include "cave.hpp"
+#include "cave_type.hpp"
+#include "feature_type.hpp"
+#include "hook_quest_finish_in.hpp"
+#include "hooks.hpp"
+#include "init1.hpp"
+#include "monster2.hpp"
+#include "monster_type.hpp"
+#include "player_type.hpp"
+#include "quest_type.hpp"
+#include "tables.hpp"
+#include "util.hpp"
+#include "variable.hpp"
+#include "z-rand.hpp"
+
+#define cquest (quest[QUEST_WOLVES])
+
+static bool_ quest_wolves_gen_hook(void *, void *, void *)
+{
+ 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;
+}
+
+static bool_ quest_wolves_death_hook(void *, void *, void *)
+{
+ 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_new(HOOK_MONSTER_DEATH, quest_wolves_death_hook);
+ del_hook_new(HOOK_GEN_QUEST, quest_wolves_gen_hook);
+ process_hooks_restart = TRUE;
+
+ cmsg_print(TERM_YELLOW, "Lothlorien is safer now.");
+ return (FALSE);
+ }
+ return FALSE;
+}
+
+static bool_ quest_wolves_finish_hook(void *, void *in_, void *)
+{
+ struct hook_quest_finish_in *in = static_cast<struct hook_quest_finish_in *>(in_);
+ s32b q_idx = in->q_idx;
+
+ 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_new(HOOK_MONSTER_DEATH, quest_wolves_death_hook, "wolves_monster_death", NULL);
+ add_hook_new(HOOK_QUEST_FINISH, quest_wolves_finish_hook, "wolves_finish", NULL);
+ add_hook_new(HOOK_GEN_QUEST, quest_wolves_gen_hook, "wolves_geb", NULL);
+ }
+ return (FALSE);
+}
diff --git a/src/q_wolves.hpp b/src/q_wolves.hpp
new file mode 100644
index 00000000..59a83c56
--- /dev/null
+++ b/src/q_wolves.hpp
@@ -0,0 +1,5 @@
+#pragma once
+
+#include "h-basic.h"
+
+bool_ quest_wolves_init_hook(int q_idx);
diff --git a/src/quark.cc b/src/quark.cc
new file mode 100644
index 00000000..45072ded
--- /dev/null
+++ b/src/quark.cc
@@ -0,0 +1,96 @@
+#include "quark.hpp"
+
+#include "z-util.h"
+
+#include <cassert>
+
+/*
+ * The number of quarks
+ */
+static s16b quark__num = 0;
+
+
+/*
+ * The pointers to the quarks [QUARK_MAX]
+ */
+static cptr *quark__str = NULL;
+
+
+/*
+ * Initialize the quark subsystem
+ */
+void quark_init()
+{
+ quark__num = 0;
+ quark__str = new cptr[QUARK_MAX];
+
+ for (int i = 0; i < QUARK_MAX; i++) {
+ quark__str[i] = nullptr;
+ }
+}
+
+
+/*
+* 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)
+{
+ assert(str != nullptr);
+
+ 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] = strdup(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);
+}
+
+
diff --git a/src/quark.hpp b/src/quark.hpp
new file mode 100644
index 00000000..0fce3932
--- /dev/null
+++ b/src/quark.hpp
@@ -0,0 +1,12 @@
+#pragma once
+
+#include "h-basic.h"
+
+/**
+ * Maximum number of quarks.
+ */
+constexpr int QUARK_MAX = 768;
+
+void quark_init();
+cptr quark_str(s16b num);
+s16b quark_add(cptr str);
diff --git a/src/quest.cc b/src/quest.cc
new file mode 100644
index 00000000..a1aee67f
--- /dev/null
+++ b/src/quest.cc
@@ -0,0 +1,17 @@
+#include "quest.hpp"
+
+#include "tables.hpp"
+
+#include <cstddef>
+
+void init_hooks_quests()
+{
+ for (std::size_t i = 0; i < MAX_Q_IDX; i++)
+ {
+ if (quest[i].init != NULL)
+ {
+ quest[i].init(i);
+ }
+ }
+}
+
diff --git a/src/quest.hpp b/src/quest.hpp
new file mode 100644
index 00000000..7ff3cd3c
--- /dev/null
+++ b/src/quest.hpp
@@ -0,0 +1,3 @@
+#pragma once
+
+extern void init_hooks_quests();
diff --git a/src/quest.pkg b/src/quest.pkg
deleted file mode 100755
index 4ba93b7a..00000000
--- a/src/quest.pkg
+++ /dev/null
@@ -1,170 +0,0 @@
-/* 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/quest_type.hpp b/src/quest_type.hpp
new file mode 100644
index 00000000..aa99f40a
--- /dev/null
+++ b/src/quest_type.hpp
@@ -0,0 +1,27 @@
+#pragma once
+
+#include "h-basic.h"
+
+/**
+ * Quest descriptor and runtime data.
+ */
+struct quest_type
+{
+ bool_ silent;
+
+ 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? */
+
+ bool_ (*init)(int q); /* Function that takes care of generating hardcoded quests */
+
+ s32b data[9]; /* Various datas used by the quests */
+
+ bool_ (*gen_desc)(FILE *fff); /* Function for generating description. */
+};
diff --git a/src/randart.c b/src/randart.c
deleted file mode 100644
index 298ee83a..00000000
--- a/src/randart.c
+++ /dev/null
@@ -1,476 +0,0 @@
-/* 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/randart.cc b/src/randart.cc
new file mode 100644
index 00000000..5135438a
--- /dev/null
+++ b/src/randart.cc
@@ -0,0 +1,481 @@
+/*
+ * 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 "randart.hpp"
+#include "mimic.hpp"
+#include "object1.hpp"
+#include "object2.hpp"
+#include "object_type.hpp"
+#include "options.hpp"
+#include "player_type.hpp"
+#include "quark.hpp"
+#include "randart_gen_type.hpp"
+#include "randart_part_type.hpp"
+#include "spells2.hpp"
+#include "util.hpp"
+#include "variable.h"
+#include "variable.hpp"
+#include "z-rand.hpp"
+
+#include <memory>
+#include <vector>
+
+/* 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)
+{
+ bool_ ret = FALSE;
+ u32b f1, f2, f3, f4, f5, esp;
+
+ std::vector<size_t> ok_ra;
+
+ /* Grab the ok randart */
+ for (size_t i = 0; i < max_ra_idx; i++)
+ {
+ randart_part_type *ra_ptr = &ra_info[i];
+ bool_ ok = FALSE;
+
+ /* Must have the correct fields */
+ for (size_t 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.push_back(i);
+ }
+
+ /* Now test them a few times */
+ for (size_t count = 0; count < ok_ra.size() * 10; count++)
+ {
+ size_t i = ok_ra[rand_int(ok_ra.size())];
+ randart_part_type *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;
+ }
+
+ /* 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 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;
+
+ std::unique_ptr<s16b[]> max_times(new s16b[max_ra_idx]);
+ for (int i = 0; i < max_ra_idx; i++) {
+ max_times[i] = 0;
+ }
+
+ /* Main loop */
+ while (powers)
+ {
+ int ra_idx;
+ randart_part_type *ra_ptr;
+
+ powers--;
+
+ if (!grab_one_power(&ra_idx, o_ptr, TRUE, max_times.get())) 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;
+ };
+
+ 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 = find_random_mimic_shape(127, TRUE);
+ o_ptr->pval2 = mimic;
+ }
+ else if (f5 & TR5_SPELL_CONTAIN)
+ {
+ o_ptr->pval2 = -1;
+ }
+
+ return TRUE;
+}
+
+
+bool_ artifact_scroll(void)
+{
+ bool_ okay = FALSE;
+
+ /* Get an item */
+ int item;
+ if (!get_item(&item,
+ "Enchant which item? ",
+ "You have nothing to enchant.",
+ (USE_EQUIP | USE_INVEN | USE_FLOOR),
+ item_tester_hook_artifactable()))
+ {
+ return (FALSE);
+ }
+
+ /* Get the item */
+ object_type *o_ptr = get_object(item);
+
+ /* Description */
+ char o_name[80];
+ 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/randart.hpp b/src/randart.hpp
new file mode 100644
index 00000000..31b70f08
--- /dev/null
+++ b/src/randart.hpp
@@ -0,0 +1,9 @@
+#pragma once
+
+#include "h-basic.h"
+#include "object_type_fwd.hpp"
+
+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);
diff --git a/src/randart_gen_type.hpp b/src/randart_gen_type.hpp
new file mode 100644
index 00000000..09aedcd9
--- /dev/null
+++ b/src/randart_gen_type.hpp
@@ -0,0 +1,9 @@
+#pragma once
+
+struct randart_gen_type
+{
+ int chance; /* Chance to have that number of powers */
+ int dd;
+ int ds;
+ int plus; /* xdy+plus power */
+};
diff --git a/src/randart_gen_type_fwd.hpp b/src/randart_gen_type_fwd.hpp
new file mode 100644
index 00000000..eba3e84e
--- /dev/null
+++ b/src/randart_gen_type_fwd.hpp
@@ -0,0 +1,3 @@
+#pragma once
+
+struct randart_gen_type;
diff --git a/src/randart_part_type.hpp b/src/randart_part_type.hpp
new file mode 100644
index 00000000..c2fa5386
--- /dev/null
+++ b/src/randart_part_type.hpp
@@ -0,0 +1,43 @@
+#pragma once
+
+#include "h-basic.h"
+
+/**
+ * Random artifact part descriptor.
+ */
+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) */
+};
diff --git a/src/randart_part_type_fwd.hpp b/src/randart_part_type_fwd.hpp
new file mode 100644
index 00000000..979fd72c
--- /dev/null
+++ b/src/randart_part_type_fwd.hpp
@@ -0,0 +1,3 @@
+#pragma once
+
+struct randart_part_type;
diff --git a/src/random_artifact.hpp b/src/random_artifact.hpp
new file mode 100644
index 00000000..a3fc1c66
--- /dev/null
+++ b/src/random_artifact.hpp
@@ -0,0 +1,18 @@
+#pragma once
+
+#include "h-basic.h"
+
+/**
+ * Random artifact descriptor.
+ */
+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? */
+};
diff --git a/src/random_quest.hpp b/src/random_quest.hpp
new file mode 100644
index 00000000..11ebe797
--- /dev/null
+++ b/src/random_quest.hpp
@@ -0,0 +1,10 @@
+#pragma once
+
+#include "h-basic.h"
+
+struct random_quest
+{
+ byte type; /* Type/number of monsters to kill(0 = no quest) */
+ s16b r_idx; /* Monsters to crush */
+ bool_ done; /* Done ? */
+};
diff --git a/src/random_spell.hpp b/src/random_spell.hpp
new file mode 100644
index 00000000..01b5ba5e
--- /dev/null
+++ b/src/random_spell.hpp
@@ -0,0 +1,21 @@
+#pragma once
+
+#include "h-basic.h"
+
+/**
+ * A structure to describe the random spells of the Power Mages
+ */
+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? */
+};
diff --git a/src/range.cc b/src/range.cc
new file mode 100644
index 00000000..7bd407c7
--- /dev/null
+++ b/src/range.cc
@@ -0,0 +1,11 @@
+#include "range.hpp"
+
+#include <cassert>
+
+void range_init(range_type *range, s32b min, s32b max)
+{
+ assert(range != NULL);
+
+ range->min = min;
+ range->max = max;
+}
diff --git a/src/range.hpp b/src/range.hpp
new file mode 100644
index 00000000..3c185ba6
--- /dev/null
+++ b/src/range.hpp
@@ -0,0 +1,15 @@
+#pragma once
+
+#include "range_fwd.hpp"
+#include "h-basic.h"
+
+/*
+ * Range
+ */
+struct range_type
+{
+ s32b min;
+ s32b max;
+};
+
+void range_init(range_type *range, s32b min, s32b max);
diff --git a/src/range_fwd.hpp b/src/range_fwd.hpp
new file mode 100644
index 00000000..b5eef3fa
--- /dev/null
+++ b/src/range_fwd.hpp
@@ -0,0 +1,4 @@
+#pragma once
+
+typedef struct range_type range_type;
+struct range_type;
diff --git a/src/readdib.c b/src/readdib.c
deleted file mode 100644
index 294c2702..00000000
--- a/src/readdib.c
+++ /dev/null
@@ -1,342 +0,0 @@
-/* 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
deleted file mode 100644
index c6402b50..00000000
--- a/src/readdib.h
+++ /dev/null
@@ -1,21 +0,0 @@
-/* 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/rule_type.hpp b/src/rule_type.hpp
new file mode 100644
index 00000000..a8b35ffa
--- /dev/null
+++ b/src/rule_type.hpp
@@ -0,0 +1,22 @@
+#pragma once
+
+#include "h-basic.h"
+
+/* Define monster generation rules */
+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 */
+};
diff --git a/src/rune_spell.hpp b/src/rune_spell.hpp
new file mode 100644
index 00000000..d04a8dc4
--- /dev/null
+++ b/src/rune_spell.hpp
@@ -0,0 +1,15 @@
+#pragma once
+
+#include "h-basic.h"
+
+/**
+ * Runecrafter prefered spells
+ */
+struct rune_spell
+{
+ char name[30]; /* name */
+
+ s16b type; /* Type of the spell(GF) */
+ s16b rune2; /* Modifiers */
+ s16b mana; /* Mana involved */
+};
diff --git a/src/rune_spell_fwd.hpp b/src/rune_spell_fwd.hpp
new file mode 100644
index 00000000..eb540a2a
--- /dev/null
+++ b/src/rune_spell_fwd.hpp
@@ -0,0 +1,3 @@
+#pragma once
+
+struct rune_spell;
diff --git a/src/school_book.hpp b/src/school_book.hpp
new file mode 100644
index 00000000..51d3e6a7
--- /dev/null
+++ b/src/school_book.hpp
@@ -0,0 +1,15 @@
+#pragma once
+
+#include "h-basic.h"
+
+#include <vector>
+
+/**
+ * School book.
+ */
+struct school_book {
+ /**
+ * Indexes of all the spells in the book.
+ */
+ std::vector<s32b> spell_idxs;
+};
diff --git a/src/school_book_fwd.hpp b/src/school_book_fwd.hpp
new file mode 100644
index 00000000..46363da6
--- /dev/null
+++ b/src/school_book_fwd.hpp
@@ -0,0 +1,3 @@
+#pragma once
+
+struct school_book;
diff --git a/src/school_type.hpp b/src/school_type.hpp
new file mode 100644
index 00000000..7a5702b4
--- /dev/null
+++ b/src/school_type.hpp
@@ -0,0 +1,21 @@
+#pragma once
+
+#include "h-basic.h"
+#include "deity_type_fwd.hpp"
+
+struct school_type
+{
+ cptr name; /* Name */
+ s16b skill; /* Skill used for that school */
+ bool_ spell_power; /* Does spell power affect spells in this school? */
+ bool_ sorcery; /* Does Sorcery affect this school? */
+
+ int deity_idx; /* Deity; if <=0, no deity required */
+ deity_type *deity; /* Direct pointer to deity */
+
+ int (*bonus_levels)(); /* Calculate number of bonus levels */
+
+ bool_ (*depends_satisfied)(); /* Are dependendies satisfied? */
+
+ struct school_provider_list *providers; /* List of secondary providers of this school */
+};
diff --git a/src/school_type_fwd.hpp b/src/school_type_fwd.hpp
new file mode 100644
index 00000000..dea0d3b4
--- /dev/null
+++ b/src/school_type_fwd.hpp
@@ -0,0 +1,3 @@
+#pragma once
+
+struct school_type;
diff --git a/src/script.c b/src/script.c
deleted file mode 100644
index 89c9ff3b..00000000
--- a/src/script.c
+++ /dev/null
@@ -1,535 +0,0 @@
-/* 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/script.cc b/src/script.cc
new file mode 100644
index 00000000..84f7c3e4
--- /dev/null
+++ b/src/script.cc
@@ -0,0 +1,30 @@
+/*
+ * 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 "script.h"
+
+#include "init2.hpp"
+#include "q_library.hpp"
+#include "spells4.hpp"
+#include "spells5.hpp"
+#include "spells6.hpp"
+
+
+void init_lua_init()
+{
+ /* Initialize schooled spells */
+ schools_init();
+ school_spells_init();
+ init_school_books();
+
+ /* Post-spell creation initialization */
+ initialize_bookable_spells();
+
+ /* Finish up the corruptions */
+ init_corruptions();
+}
diff --git a/src/script.h b/src/script.h
new file mode 100644
index 00000000..3d1a0840
--- /dev/null
+++ b/src/script.h
@@ -0,0 +1,12 @@
+#pragma once
+
+// C linkage required for these functions since main-* code uses them.
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern void init_lua_init(void);
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
diff --git a/src/set_type.hpp b/src/set_type.hpp
new file mode 100644
index 00000000..827c23ac
--- /dev/null
+++ b/src/set_type.hpp
@@ -0,0 +1,28 @@
+#pragma once
+
+#include "h-basic.h"
+
+/**
+ * Item set descriptor and runtime information.
+ */
+struct set_type
+{
+ const char *name; /* Name */
+ char *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];
+};
diff --git a/src/set_type_fwd.hpp b/src/set_type_fwd.hpp
new file mode 100644
index 00000000..3b311808
--- /dev/null
+++ b/src/set_type_fwd.hpp
@@ -0,0 +1,3 @@
+#pragma once
+
+struct set_type;
diff --git a/src/skill_type.hpp b/src/skill_type.hpp
new file mode 100644
index 00000000..c6de1dc1
--- /dev/null
+++ b/src/skill_type.hpp
@@ -0,0 +1,37 @@
+#pragma once
+
+#include "h-basic.h"
+#include "skills_defs.hpp"
+
+/**
+ * Skill descriptors and runtime data.
+ */
+struct skill_type
+{
+ const char *name; /* Name */
+ char *desc; /* Description */
+
+ const char *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 */
+};
diff --git a/src/skill_type_fwd.hpp b/src/skill_type_fwd.hpp
new file mode 100644
index 00000000..0a06dadb
--- /dev/null
+++ b/src/skill_type_fwd.hpp
@@ -0,0 +1,3 @@
+#pragma once
+
+struct skill_type;
diff --git a/src/skills.c b/src/skills.c
deleted file mode 100644
index 36b4f585..00000000
--- a/src/skills.c
+++ /dev/null
@@ -1,1661 +0,0 @@
-/* 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/skills.cc b/src/skills.cc
new file mode 100644
index 00000000..3a14a6ce
--- /dev/null
+++ b/src/skills.cc
@@ -0,0 +1,1829 @@
+/*
+ * 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 "skills.hpp"
+
+#include "ability_type.hpp"
+#include "birth.hpp"
+#include "cmd2.hpp"
+#include "cmd3.hpp"
+#include "cmd5.hpp"
+#include "cmd7.hpp"
+#include "gods.hpp"
+#include "help.hpp"
+#include "hooks.hpp"
+#include "lua_bind.hpp"
+#include "monster2.hpp"
+#include "monster3.hpp"
+#include "object1.hpp"
+#include "object2.hpp"
+#include "player_class.hpp"
+#include "player_race.hpp"
+#include "player_race_mod.hpp"
+#include "player_spec.hpp"
+#include "player_type.hpp"
+#include "skill_type.hpp"
+#include "spells1.hpp"
+#include "spells4.hpp"
+#include "tables.hpp"
+#include "traps.hpp"
+#include "util.hpp"
+#include "util.h"
+#include "variable.h"
+#include "variable.hpp"
+#include "xtra2.hpp"
+#include "z-rand.hpp"
+
+#include <algorithm>
+#include <boost/algorithm/string/predicate.hpp>
+#include <cassert>
+#include <cmath>
+#include <memory>
+#include <vector>
+#include <tuple>
+
+using boost::algorithm::iequals;
+
+/*
+ * Advance the skill point of the skill specified by i and
+ * modify related skills
+ */
+static 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 */
+ max_skill_overage = modules[game_module_idx].skills.max_skill_overage;
+ if (((s_info[i].value + s_info[i].mod) / SKILL_STEP) >= (p_ptr->lev + max_skill_overage + 1))
+ {
+ int hgt, wid;
+ char buf[256];
+
+ sprintf(buf,
+ "Cannot raise a skill value above " FMTs32b " + player level.",
+ max_skill_overage);
+
+ Term_get_size(&wid, &hgt);
+ msg_box(buf, hgt / 2, 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
+ */
+static 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++)
+ {
+ if (s_info[i].name && streq(s_info[i].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 (s_info[i].name && iequals(s_info[i].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);
+}
+
+static int get_idx(int i)
+{
+ for (int 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;
+}
+
+static void init_table_aux(int table[MAX_SKILLS][2], int *idx, int father, int lev, bool_ full)
+{
+ for (int j = 1; j < max_s_idx; j++)
+ {
+ int 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);
+ }
+}
+
+static void init_table(int table[MAX_SKILLS][2], int *max, bool_ full)
+{
+ *max = 0;
+ init_table_aux(table, max, -1, 0, full);
+}
+
+static 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));
+ }
+ else
+ {
+ strcat(buf, format(" - %s", s_info[i].name));
+ }
+
+ fprintf(fff, "%-49s%s%06.3f [%05.3f]",
+ buf, s_info[i].value < 0 ? "-" : " ",
+ static_cast<double>(ABS(s_info[i].value)) / SKILL_STEP,
+ static_cast<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, 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),
+ 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),
+ j + 7 - start, table[j][1] * 4);
+ }
+ else
+ {
+ c_prt(color, format("%c+%c%s", deb, end, s_info[i].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);
+ }
+
+ /* Antimagic means you don't believe in gods. */
+ if ((p_ptr->pgod != GOD_NONE) &&
+ (s_info[SKILL_ANTIMAGIC].value > 0))
+ {
+ msg_print("You no longer believe.");
+ abandon_god(GOD_ALL);
+ }
+
+ process_hooks_new(HOOK_RECALC_SKILLS, NULL, NULL);
+
+ /* 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_FRAME | PR_MAP);
+ }
+}
+
+/*
+ * Recalc the skill value
+ */
+static 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;
+
+ recalc_skills(TRUE);
+
+ /* Save the screen */
+ screen_save();
+
+ /* Allocate arrays to save skill values */
+ std::unique_ptr<s32b[]> skill_values_save(new s32b[MAX_SKILLS]);
+ std::unique_ptr<s32b[]> skill_mods_save(new s32b[MAX_SKILLS]);
+ std::unique_ptr<s16b[]> skill_rates_save(new s16b[MAX_SKILLS]);
+ std::unique_ptr<s16b[]> skill_invest(new s16b[MAX_SKILLS]);
+ std::unique_ptr<s32b[]> skill_bonus(new s32b[MAX_SKILLS]);
+
+ /* 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;
+ skill_bonus[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.get(), skill_values_save.get(), skill_mods_save.get(), skill_bonus.get());
+ 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 ((sel >= 0) && (sel < max) && table[sel][0] == SKILL_MISC) continue;
+
+ /* Increase the current skill */
+ if (dir == 6) increase_skill(table[sel][0], skill_invest.get());
+
+ /* Decrease the current skill */
+ if (dir == 4) decrease_skill(table[sel][0], skill_invest.get());
+
+ /* 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 == '?')
+ {
+ help_skill(s_info[table[sel][0]].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)", hgt / 2, 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];
+ }
+ }
+ }
+
+ /* Load the screen */
+ screen_load();
+
+ recalc_skills(FALSE);
+}
+
+
+
+/*
+ * List of melee skills
+ */
+static s16b melee_skills[MAX_MELEE] =
+{
+ SKILL_MASTERY,
+ SKILL_HAND,
+ SKILL_BEAR,
+};
+static const 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);
+}
+
+cptr get_melee_name()
+{
+ return melee_names[get_melee_skill()];
+}
+
+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_FRAME);
+
+ 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(const std::vector<std::tuple<cptr, int>> &p, int start)
+{
+ char buff[80];
+ int j = 0;
+
+ prt(format(" %-31s", "Name"), 1, 20);
+
+ for (int i = start; i < (start + 20); i++)
+ {
+ if (static_cast<size_t>(i) >= p.size())
+ {
+ break;
+ }
+
+ sprintf(buff, " %c - %d) %-30s", I2A(j),
+ std::get<1>(p[i]),
+ std::get<0>(p[i]));
+
+ prt(buff, 2 + j, 20);
+ j++;
+ }
+ prt("", 2 + j, 20);
+ prt(format("Select a skill (a-%c), @ to select by name, +/- to scroll:", I2A(j - 1)), 0, 0);
+}
+
+static int do_cmd_activate_skill_aux()
+{
+ char which;
+ int start = 0;
+ int ret;
+
+ std::vector<std::tuple<cptr,int>> p;
+
+ /* More than 1 melee skill ? */
+ if (get_melee_skills() > 1)
+ {
+ p.push_back(std::make_tuple("Change melee mode", 0));
+ }
+
+ for (size_t i = 1; i < max_s_idx; i++)
+ {
+ if (s_info[i].action_mkey && s_info[i].value && ((!s_info[i].hidden) || (i == SKILL_LEARN)))
+ {
+ bool_ next = FALSE;
+
+ /* Already got it ? */
+ for (size_t j = 0; j < p.size(); j++)
+ {
+ if (s_info[i].action_mkey == std::get<1>(p[j]))
+ {
+ next = TRUE;
+ break;
+ }
+ }
+ if (next) continue;
+
+ p.push_back(std::make_tuple(s_info[i].action_desc,
+ s_info[i].action_mkey));
+ }
+ }
+
+ for (size_t i = 0; i < max_ab_idx; i++)
+ {
+ if (ab_info[i].action_mkey && ab_info[i].acquired)
+ {
+ bool_ next = FALSE;
+
+ /* Already got it ? */
+ for (size_t j = 0; j < p.size(); j++)
+ {
+ if (ab_info[i].action_mkey == std::get<1>(p[j]))
+ {
+ next = TRUE;
+ break;
+ }
+ }
+ if (next) continue;
+
+ p.push_back(std::make_tuple(ab_info[i].action_desc,
+ ab_info[i].action_mkey));
+ }
+ }
+
+ if (p.empty())
+ {
+ msg_print("You don't have any activable skills or abilities.");
+ return -1;
+ }
+
+ character_icky = TRUE;
+ Term_save();
+
+ while (1)
+ {
+ print_skill_batch(p, start);
+ which = inkey();
+
+ if (which == ESCAPE)
+ {
+ ret = -1;
+ break;
+ }
+ else if (which == '+')
+ {
+ start += 20;
+ if (static_cast<size_t>(start) >= p.size())
+ {
+ 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 */
+ size_t i = 0;
+ for (; i < p.size(); i++)
+ {
+ if (!strcmp(buf, std::get<0>(p[i])))
+ break;
+ }
+
+ if (i < p.size())
+ {
+ ret = std::get<1>(p[i]);
+ break;
+ }
+ }
+ else
+ {
+ which = tolower(which);
+ if (start + A2I(which) >= static_cast<int>(p.size()))
+ {
+ bell();
+ continue;
+ }
+ if (start + A2I(which) < 0)
+ {
+ bell();
+ continue;
+ }
+
+ ret = std::get<1>(p[start + A2I(which)]);
+ break;
+ }
+ }
+ Term_load();
+ character_icky = FALSE;
+
+ 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_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_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;
+ case MKEY_DEATH_TOUCH:
+ {
+ if (p_ptr->csp > 40)
+ {
+ increase_mana(-40);
+ set_project(randint(30) + 10,
+ GF_INSTA_DEATH,
+ 1,
+ 0,
+ PROJECT_STOP | PROJECT_KILL);
+ energy_use = 100;
+ }
+ else
+ {
+ msg_print("You need at least 40 mana.");
+ }
+ break;
+ }
+ case MKEY_GEOMANCY:
+ {
+ s32b s = -1;
+ object_type *o_ptr = NULL;
+
+ /* No magic */
+ if (p_ptr->antimagic > 0)
+ {
+ msg_print("Your anti-magic field disrupts any magic attempts.");
+ break;
+ }
+
+ o_ptr = get_object(INVEN_WIELD);
+ if ((o_ptr->k_idx <= 0) ||
+ (o_ptr->tval != TV_MSTAFF))
+ {
+ msg_print("You must wield a magestaff to use Geomancy.");
+ break;
+ }
+
+ s = get_school_spell("cast", BOOK_GEOMANCY);
+ if (s >= 0)
+ {
+ lua_cast_school_spell(s, FALSE);
+ }
+
+ break;
+ }
+ case MKEY_REACH_ATTACK:
+ {
+ object_type *o_ptr = NULL;
+ int dir, dy, dx, targetx, targety, max_blows, flags;
+
+ o_ptr = get_object(INVEN_WIELD);
+ if (o_ptr->tval == TV_POLEARM)
+ {
+ msg_print("You will need a long polearm for this!");
+ return;
+ }
+
+ if (!get_rep_dir(&dir))
+ {
+ return;
+ }
+
+ dy = ddy[dir];
+ dx = ddx[dir];
+ dy = dy * 2;
+ dx = dx * 2;
+ targety = p_ptr->py + dy;
+ targetx = p_ptr->px + dx;
+
+ max_blows = get_skill_scale(SKILL_POLEARM, p_ptr->num_blow / 2);
+ if (max_blows == 0)
+ {
+ max_blows = 1;
+ }
+
+ energy_use = energy_use + 200;
+
+ flags = PROJECT_BEAM | PROJECT_KILL;
+ if (get_skill(SKILL_POLEARM) < 40)
+ {
+ flags |= PROJECT_STOP;
+ }
+
+ project(0, 0, targety, targetx,
+ max_blows, GF_ATTACK, flags);
+
+ break;
+ }
+ default:
+ 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()
+{
+ if (p_ptr->pgod == 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;
+}
+
+/*
+ * Perform weighted random shuffle according to the algorithm given in
+ * "Weighted Random Sampling" (2005, Efraimidis, Spirakis).
+ *
+ * @param weights is the vector of weights.
+ * @return an output vector of the same size as the input weights vector containing,
+ * in order of selection, the indices to select. For example, if you
+ * need to choose two items, you would use v[0], v[1] as the indices
+ * to pick.
+ */
+static std::vector<size_t> wrs(const std::vector<s32b> &unscaled_weights)
+{
+ const size_t n = unscaled_weights.size();
+
+ /* Rescale weights into unit interval for numerical stability */
+ std::vector<double> weights(unscaled_weights.size());
+ {
+ s32b scale = 0;
+ for (s32b weight: unscaled_weights)
+ {
+ scale += weight;
+ }
+
+ for (size_t i = 0; i < n; i++) {
+ weights[i] =
+ ((double) unscaled_weights[i]) /
+ ((double) scale);
+ }
+ }
+
+ /* Generate the keys and indexes to use for selection. This
+ is the only randomized portion of the algorithm. */
+ std::vector<std::tuple<double,size_t>> keys_and_indexes(unscaled_weights.size());
+ for (size_t i = 0; i < n; i++) {
+ /* Randomized keys according to the algorithm. */
+ double u = static_cast<double>(rand_int(100000)) / 100000;
+ double k = std::pow(u, 1/weights[i]);
+ /* Set up the key and index. We negate the k value
+ here so that keys will be sorted in descending
+ order rather than ascending order. */
+ keys_and_indexes[i] = std::make_tuple(-k, i);
+ }
+
+ /* Sort indexes according to keys. Since the keys have been
+ negated and we're using a lexicographical sort, we're
+ effectively sorting in descending order of key. */
+ std::sort(std::begin(keys_and_indexes),
+ std::end(keys_and_indexes));
+
+ /* Produce the output vector consisting of indexes only. */
+ std::vector<size_t> indexes;
+ for (auto const &key_and_index: keys_and_indexes) {
+ indexes.push_back(std::get<1>(key_and_index));
+ }
+ return indexes;
+}
+
+void do_get_new_skill()
+{
+ std::vector<std::string> items;
+ int skl[LOST_SWORD_NSKILLS];
+ s32b val[LOST_SWORD_NSKILLS], mod[LOST_SWORD_NSKILLS];
+ int available_skills[MAX_SKILLS];
+ int max_a = 0, res, i;
+
+ /* Check if some skills didn't influence other stuff */
+ recalc_skills(TRUE);
+
+ /* Grab the ones we can gain */
+ max_a = 0;
+ for (i = 0; i < max_s_idx; i++)
+ {
+ if (s_info[i].flags1 & SKF1_RANDOM_GAIN) {
+ available_skills[max_a] = i;
+ max_a++;
+ }
+ }
+
+ /* Perform the selection */
+ std::vector<s32b> weights;
+ for (i = 0; i < max_a; i++) {
+ weights.push_back(s_info[available_skills[i]].random_gain_chance);
+ }
+
+ std::vector<size_t> indexes = wrs(weights);
+ assert(indexes.size() >= LOST_SWORD_NSKILLS);
+
+ /* Extract the information needed from the skills */
+ for (i = 0; i < LOST_SWORD_NSKILLS; i++)
+ {
+ s32b s_idx = available_skills[indexes[i]];
+ skill_type *s_ptr = &s_info[s_idx];
+
+ if (s_ptr->mod)
+ {
+ if (s_ptr->mod < 300)
+ {
+ val[i] = 1000;
+ mod[i] = 300 - s_ptr->mod;
+ }
+ else if (s_ptr->mod < 500)
+ {
+ val[i] = s_ptr->mod * 1;
+ mod[i] = 100;
+ if (mod[i] + s_ptr->mod > 500)
+ mod[i] = 500 - s_ptr->mod;
+ }
+ else
+ {
+ val[i] = s_ptr->mod * 3;
+ mod[i] = 0;
+ }
+ }
+ else
+ {
+ mod[i] = 300;
+ val[i] = 1000;
+ }
+
+ if (s_ptr->value + val[i] > SKILL_MAX) {
+ val[i] = SKILL_MAX - s_ptr->value;
+ }
+
+ skl[i] = s_idx;
+ items.push_back(format("%-40s: +%02ld.%03ld value, +%01d.%03d modifier",
+ s_ptr->name,
+ val[i] / SKILL_STEP,
+ val[i] % SKILL_STEP,
+ mod[i] / SKILL_STEP,
+ mod[i] % 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, items);
+
+ /* 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);
+
+ /* 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);
+ }
+ else
+ {
+ msg_format("Your knowledge of the %s skill increases.",
+ s_ptr->name);
+ }
+ break;
+ }
+ }
+
+ /* 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++)
+ {
+ if (ab_info[i].name && streq(ab_info[i].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 */
+static 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;
+ }
+ }
+
+ return TRUE;
+}
+
+/* Learn an ability */
+static 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.", hgt / 2, 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)", hgt / 2, wid / 2) != 'y')
+ {
+ return;
+ }
+
+ ab_info[ab].acquired = TRUE;
+ p_ptr->skill_points -= ab_info[ab].cost;
+}
+
+static bool compare_abilities(const int ab_idx1, const int ab_idx2)
+{
+ return strcmp(ab_info[ab_idx1].name, ab_info[ab_idx2].name) < 0;
+}
+
+/*
+ * Print the abilities list
+ */
+void dump_abilities(FILE *fff)
+{
+ int i;
+
+ // Find all abilities that the player has.
+ std::vector<int> table;
+ for (i = 0; i < max_ab_idx; i++)
+ {
+ if (ab_info[i].name && has_ability(i))
+ {
+ table.push_back(i);
+ }
+ }
+
+ // Sort
+ std::sort(std::begin(table),
+ std::end(table),
+ compare_abilities);
+
+ // Show
+ if (!table.empty())
+ {
+ fprintf(fff, "\nAbilities");
+
+ for (int i : table)
+ {
+ fprintf(fff, "\n * %s", ab_info[i].name);
+ }
+
+ fprintf(fff, "\n");
+ }
+}
+
+/*
+ * Draw the abilities list
+ */
+static void print_abilities(const std::vector<int> &table, 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, 3, 0);
+
+ for (j = start; j < start + (hgt - 7); j++)
+ {
+ byte color = TERM_WHITE;
+ char deb = ' ', end = ' ';
+
+ assert(j >= 0);
+ if (static_cast<size_t>(j) >= table.size())
+ {
+ 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),
+ 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;
+ char c;
+ int i;
+ int wid, hgt;
+
+ /* Save the screen */
+ screen_save();
+
+ /* Clear the screen */
+ Term_clear();
+
+ /* Initialise the abilities list */
+ std::vector<int> table;
+ for (i = 0; i < max_ab_idx; i++)
+ {
+ if (ab_info[i].name)
+ {
+ table.push_back(i);
+ }
+ }
+
+ std::sort(std::begin(table),
+ std::end(table),
+ compare_abilities);
+
+ while (TRUE)
+ {
+ Term_get_size(&wid, &hgt);
+
+ /* Display list of skills */
+ print_abilities(table, 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);
+ assert(sel >= 0);
+ if (static_cast<size_t>(sel) >= table.size())
+ {
+ sel = table.size() - 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 == '?')
+ {
+ help_ability(ab_info[table[sel]].name);
+ }
+
+ /* Handle boundaries and scrolling */
+ if (sel < 0)
+ {
+ sel = table.size() - 1;
+ }
+ if (static_cast<size_t>(sel) >= table.size())
+ {
+ sel = 0;
+ }
+ if (sel < start)
+ {
+ start = sel;
+ }
+ if (sel >= start + (hgt - 7))
+ {
+ start = sel - (hgt - 7) + 1;
+ }
+ }
+ }
+
+ /* Load the screen */
+ screen_load();
+
+ /* 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_FRAME | 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_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_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_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_info[rmp_ptr->abilities[i].ability].name);
+ }
+ ab_info[rmp_ptr->abilities[i].ability].acquired = TRUE;
+ }
+ }
+}
diff --git a/src/skills.hpp b/src/skills.hpp
new file mode 100644
index 00000000..6c1880a6
--- /dev/null
+++ b/src/skills.hpp
@@ -0,0 +1,27 @@
+#pragma once
+
+#include "h-basic.h"
+
+/* Skill functions */
+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 cptr get_melee_name();
+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);
diff --git a/src/skills_defs.hpp b/src/skills_defs.hpp
new file mode 100644
index 00000000..1dbdee9f
--- /dev/null
+++ b/src/skills_defs.hpp
@@ -0,0 +1,63 @@
+#pragma once
+
+/*
+ * Skill constants
+ */
+#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
+#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
+#define MAX_SKILLS 200
diff --git a/src/spell_type.cc b/src/spell_type.cc
new file mode 100644
index 00000000..6cf6e35b
--- /dev/null
+++ b/src/spell_type.cc
@@ -0,0 +1,433 @@
+#include "spell_type.hpp"
+
+#include "range.hpp"
+#include "device_allocation.hpp"
+#include "dice.hpp"
+#include "skills_defs.hpp"
+#include "spells4.hpp"
+#include "stats.hpp"
+
+#include <cassert>
+#include <vector>
+#include <string>
+#include <type_traits>
+
+#define SCHOOL_IDXS_MAX 3
+
+/**
+ * Spell type definition.
+ */
+struct spell_type
+{
+ cptr name; /* Name */
+ byte skill_level; /* Required level (to learn) */
+ std::vector<std::string> m_description; /* List of strings */
+
+ casting_result (*effect_func)(); /* Spell effect function */
+ const char* (*info_func)(); /* Information function */
+ int (*lasting_func)(); /* Lasting effect function */
+ bool_ (*depend_func)(); /* Check dependencies */
+
+ s16b minimum_pval; /* Minimum required pval for item-based spells */
+
+ enum casting_type casting_type; /* Type of casting required */
+ s16b casting_stat; /* Stat used for casting */
+
+ bool_ castable_while_blind;
+ bool_ castable_while_confused;
+
+ dice_type device_charges; /* Number of charges for devices */
+ std::vector<device_allocation *> m_device_allocation; /* Allocation table for devices */
+
+ s16b random_type; /* Type of random items in which skill may appear */
+
+ s32b failure_rate; /* Failure rate */
+
+ s32b inertia_difficulty; /* Mana cost when used in Inertia Control */
+ s32b inertia_delay; /* Delay between castings */
+
+ range_type mana_range;
+
+ size_t school_idxs_count;
+ s32b school_idxs[3];
+
+public:
+
+ spell_type(cptr _name)
+ : name(_name)
+ , skill_level(0)
+ , m_description()
+ , effect_func(nullptr)
+ , info_func(nullptr)
+ , lasting_func(nullptr)
+ , depend_func(nullptr)
+ , minimum_pval(0)
+ , casting_type(USE_SPELL_POINTS)
+ , casting_stat(0)
+ , castable_while_blind(FALSE)
+ , castable_while_confused(FALSE)
+ , device_charges({ 0, 0, 0 })
+ , m_device_allocation()
+ , random_type(-1)
+ , failure_rate(0)
+ , inertia_difficulty(-1)
+ , inertia_delay(-1)
+ , mana_range({ -1, -1 })
+ , school_idxs_count(0)
+ , school_idxs{ -1, -1, -1 }
+ {
+ }
+
+};
+
+static void school_idx_add_new(spell_type *spell, s32b i)
+{
+ assert(spell != NULL);
+ assert(spell->school_idxs_count < SCHOOL_IDXS_MAX);
+
+ spell->school_idxs[spell->school_idxs_count] = i;
+ spell->school_idxs_count++;
+}
+
+void spell_type_set_inertia(spell_type *spell, s32b difficulty, s32b delay)
+{
+ assert(spell != NULL);
+ spell->inertia_difficulty = difficulty;
+ spell->inertia_delay = delay;
+}
+
+void spell_type_init_music(spell_type *spell,
+ s16b minimum_pval,
+ const char* (*info_func)(),
+ casting_result (*effect_func)())
+{
+ assert(spell != NULL);
+
+ /* Set up callbacks */
+ spell->info_func = info_func;
+ spell->effect_func = effect_func;
+
+ /* Use spell points, but CHR for success/failure calculations */
+ spell->casting_type = USE_SPELL_POINTS;
+ spell->casting_stat = A_CHR;
+ spell->random_type = SKILL_MUSIC;
+ spell->minimum_pval = minimum_pval;
+ /* Add school */
+ school_idx_add_new(spell, SCHOOL_MUSIC);
+}
+
+void spell_type_init_music_lasting(spell_type *spell,
+ s16b minimum_pval,
+ const char* (*info_func)(),
+ casting_result (*effect_func)(),
+ int (*lasting_func)())
+{
+ spell_type_init_music(
+ spell,
+ minimum_pval,
+ info_func,
+ effect_func);
+
+ spell->lasting_func = lasting_func;
+}
+
+void spell_type_init_mage(spell_type *spell,
+ random_type random_type,
+ s32b school_idx,
+ const char* (*info_func)(),
+ casting_result (*effect_func)())
+{
+ assert(spell != NULL);
+
+ spell->info_func = info_func;
+ spell->effect_func = effect_func;
+
+ spell->casting_type = USE_SPELL_POINTS;
+ spell->casting_stat = A_INT;
+
+ switch (random_type)
+ {
+ case RANDOM:
+ spell->random_type = SKILL_MAGIC;
+ break;
+ case NO_RANDOM:
+ spell->random_type = -1;
+ break;
+ default:
+ /* Cannot happen */
+ assert(FALSE);
+ }
+
+ /* Add first school */
+ spell_type_add_school(spell, school_idx);
+}
+
+void spell_type_init_priest(spell_type *spell,
+ s32b school_idx,
+ const char* (*info_func)(),
+ casting_result (*effect_func)())
+{
+ assert(spell != NULL);
+
+ spell->info_func = info_func;
+ spell->effect_func = effect_func;
+
+ spell->random_type = SKILL_SPIRITUALITY;
+ spell->casting_type = USE_PIETY;
+ spell->casting_stat = A_WIS;
+
+ school_idx_add_new(spell, school_idx);
+}
+
+void spell_type_init_device(spell_type *spell,
+ const char* (*info_func)(),
+ casting_result (*effect_func)())
+{
+ assert(spell != NULL);
+
+ spell_type_init_mage(spell,
+ NO_RANDOM,
+ SCHOOL_DEVICE,
+ info_func,
+ effect_func);
+}
+
+void spell_type_init_demonology(spell_type *spell,
+ const char* (*info_func)(),
+ casting_result (*effect_func)())
+{
+ spell_type_init_mage(spell,
+ NO_RANDOM,
+ SCHOOL_DEMON,
+ info_func,
+ effect_func);
+}
+
+void spell_type_init_geomancy(spell_type *spell,
+ const char* (*info_func)(),
+ casting_result (*effect_func)(),
+ bool_ (*depend_func)())
+{
+ spell_type_init_mage(spell,
+ NO_RANDOM,
+ SCHOOL_GEOMANCY,
+ info_func,
+ effect_func);
+
+ spell->depend_func = depend_func;
+}
+
+void spell_type_set_difficulty(spell_type *spell, byte skill_level, s32b failure_rate)
+{
+ assert(spell != NULL);
+
+ spell->skill_level = skill_level;
+ spell->failure_rate = failure_rate;
+}
+
+void spell_type_set_mana(spell_type *spell, s32b min, s32b max)
+{
+ assert(spell != NULL);
+
+ range_init(&spell->mana_range, min, max);
+}
+
+void spell_type_set_castable_while_blind(spell_type *spell, bool_ value)
+{
+ assert(spell != NULL);
+
+ spell->castable_while_blind = value;
+}
+
+void spell_type_set_castable_while_confused(spell_type *spell, bool_ value)
+{
+ assert(spell != NULL);
+
+ spell->castable_while_confused = value;
+}
+
+void spell_type_describe(spell_type *spell, cptr line)
+{
+ assert(spell != NULL);
+
+ spell->m_description.push_back(std::string(line));
+}
+
+void spell_type_add_school(spell_type *spell, s32b school_idx)
+{
+ school_idx_add_new(spell, school_idx);
+}
+
+void spell_type_set_device_charges(spell_type *spell, cptr charges_s)
+{
+ assert(spell != NULL);
+
+ dice_parse_checked(&spell->device_charges, charges_s);
+}
+
+void spell_type_add_device_allocation(spell_type *spell, struct device_allocation *a)
+{
+ assert(spell != NULL);
+ assert(a != NULL);
+ spell->m_device_allocation.push_back(a);
+}
+
+spell_type *spell_type_new(cptr name)
+{
+ spell_type *spell = new spell_type(name);
+ assert(spell != NULL);
+ return spell;
+}
+
+int spell_type_produce_effect_lasting(spell_type *spell)
+{
+ assert(spell->lasting_func != NULL);
+ return spell->lasting_func();
+}
+
+casting_result spell_type_produce_effect(spell_type *spell)
+{
+ assert(spell->effect_func != NULL);
+ return spell->effect_func();
+}
+
+cptr spell_type_name(spell_type *spell)
+{
+ assert(spell != NULL);
+
+ return spell->name;
+}
+
+int spell_type_skill_level(spell_type *spell)
+{
+ assert(spell != NULL);
+
+ return spell->skill_level;
+}
+
+void spell_type_description_foreach(spell_type *spell, std::function<void (std::string const &text)> callback)
+{
+ for (auto line: spell->m_description)
+ {
+ callback(line);
+ }
+}
+
+long spell_type_roll_charges(spell_type *spell)
+{
+ return dice_roll(&spell->device_charges);
+}
+
+device_allocation *spell_type_device_allocation(spell_type *spell, byte tval)
+{
+ for (auto device_allocation_ptr: spell->m_device_allocation)
+ {
+ if (device_allocation_ptr->tval == tval)
+ {
+ return device_allocation_ptr;
+ }
+ }
+
+ return NULL;
+}
+
+bool_ spell_type_uses_piety_to_cast(spell_type *spell)
+{
+ assert(spell != NULL);
+ return spell->casting_type == USE_PIETY;
+}
+
+bool_ spell_type_castable_while_blind(spell_type *spell)
+{
+ assert(spell != NULL);
+ return spell->castable_while_blind;
+}
+
+bool_ spell_type_castable_while_confused(spell_type *spell)
+{
+ assert(spell != NULL);
+ return spell->castable_while_confused;
+}
+
+s16b spell_type_minimum_pval(spell_type *spell)
+{
+ return spell->minimum_pval;
+}
+
+s16b spell_type_random_type(spell_type *spell)
+{
+ return spell->random_type;
+}
+
+std::vector<s32b> const spell_type_get_schools(spell_type *spell)
+{
+ std::vector<s32b> school_idxs;
+ for (size_t i = 0; i < spell->school_idxs_count; i++)
+ {
+ school_idxs.push_back(spell->school_idxs[i]);
+ }
+ return school_idxs;
+}
+
+bool_ spell_type_inertia(spell_type *spell, s32b *difficulty, s32b *delay)
+{
+ if ((spell->inertia_difficulty < 0) ||
+ (spell->inertia_delay < 0))
+ {
+ return FALSE;
+ }
+
+ if (difficulty != NULL)
+ {
+ *difficulty = spell->inertia_difficulty;
+ }
+
+ if (delay != NULL)
+ {
+ *delay = spell->inertia_delay;
+ }
+
+ return TRUE;
+}
+
+cptr spell_type_info(spell_type *spell)
+{
+ assert(spell != NULL);
+
+ return spell->info_func();
+}
+
+s32b spell_type_failure_rate(spell_type *spell)
+{
+ assert(spell != NULL);
+
+ return spell->failure_rate;
+}
+
+s16b spell_type_casting_stat(spell_type *spell)
+{
+ assert(spell != NULL);
+
+ return spell->casting_stat;
+}
+
+void spell_type_mana_range(spell_type *spell, range_type *range)
+{
+ assert(spell != NULL);
+
+ if (range != NULL)
+ {
+ *range = spell->mana_range;
+ }
+}
+
+bool_ spell_type_dependencies_satisfied(spell_type *spell)
+{
+ assert(spell != NULL);
+
+ if (spell->depend_func != NULL) {
+ return spell->depend_func();
+ } else {
+ return TRUE;
+ }
+}
diff --git a/src/spell_type.hpp b/src/spell_type.hpp
new file mode 100644
index 00000000..43758103
--- /dev/null
+++ b/src/spell_type.hpp
@@ -0,0 +1,86 @@
+#pragma once
+
+#include "spell_type_fwd.hpp"
+#include <vector>
+#include <string>
+#include <functional>
+#include "h-basic.h"
+#include "device_allocation_fwd.hpp"
+#include "range_fwd.hpp"
+
+/*
+ * Casting type
+ */
+enum casting_type { USE_SPELL_POINTS, USE_PIETY };
+
+/*
+ * Does the spell appear on spell random books?
+ */
+enum random_type { RANDOM, NO_RANDOM };
+
+/*
+ * Spell functions
+ */
+
+void spell_type_init_music(spell_type *spell,
+ s16b minimum_pval,
+ const char* (*info_func)(),
+ casting_result (*effect_func)());
+void spell_type_init_music_lasting(spell_type *spell,
+ s16b minimum_pval,
+ const char* (*info_func)(),
+ casting_result (*effect_func)(),
+ int (*lasting_func)());
+void spell_type_init_mage(spell_type *spell,
+ random_type random_type,
+ s32b school_idx,
+ const char* (*info_func)(),
+ casting_result (*effect_func)());
+void spell_type_init_priest(spell_type *spell,
+ s32b school_idx,
+ const char* (*info_func)(),
+ casting_result (*effect_func)());
+void spell_type_init_device(spell_type *spell,
+ const char* (*info_func)(),
+ casting_result (*effect_func)());
+void spell_type_init_demonology(spell_type *spell,
+ const char* (*info_func)(),
+ casting_result (*effect_func)());
+void spell_type_init_geomancy(spell_type *spell,
+ const char* (*info_func)(),
+ casting_result (*effect_func)(),
+ bool_ (*depend_func)());
+
+void spell_type_set_inertia(spell_type *spell, s32b difficulty, s32b delay);
+void spell_type_set_difficulty(spell_type *spell, byte skill_level, s32b failure_rate);
+void spell_type_set_mana(spell_type *spell, s32b min, s32b max);
+void spell_type_set_castable_while_blind(spell_type *spell, bool_ value);
+void spell_type_set_castable_while_confused(spell_type *spell, bool_ value);
+void spell_type_describe(spell_type *spell, cptr line);
+
+void spell_type_add_school(spell_type *spell, s32b school_idx);
+
+void spell_type_set_device_charges(spell_type *spell, cptr charges_s);
+void spell_type_add_device_allocation(spell_type *spell, device_allocation *a);
+
+spell_type *spell_type_new(cptr name);
+
+int spell_type_produce_effect_lasting(spell_type *spell);
+casting_result spell_type_produce_effect(spell_type *spell);
+cptr spell_type_name(spell_type *spell);
+int spell_type_skill_level(spell_type *spell);
+long spell_type_roll_charges(spell_type *spell);
+struct device_allocation *spell_type_device_allocation(spell_type *spell, byte tval);
+bool_ spell_type_uses_piety_to_cast(spell_type *spell);
+bool_ spell_type_castable_while_blind(spell_type *spell);
+bool_ spell_type_castable_while_confused(spell_type *spell);
+s16b spell_type_minimum_pval(spell_type *spell);
+s16b spell_type_random_type(spell_type *spell);
+std::vector<s32b> const spell_type_get_schools(spell_type *spell);
+bool_ spell_type_inertia(spell_type *spell, s32b *difficulty, s32b *delay);
+s32b spell_type_failure_rate(spell_type *spell);
+s16b spell_type_casting_stat(spell_type *spell);
+cptr spell_type_info(spell_type *spell);
+void spell_type_mana_range(spell_type *spell, struct range_type *range);
+bool_ spell_type_dependencies_satisfied(spell_type *spell);
+void spell_type_description_foreach(spell_type *spell, std::function<void (std::string const &text)>);
diff --git a/src/spell_type_fwd.hpp b/src/spell_type_fwd.hpp
new file mode 100644
index 00000000..a3b27d27
--- /dev/null
+++ b/src/spell_type_fwd.hpp
@@ -0,0 +1,16 @@
+#pragma once
+
+/*
+ * Spell effect function result
+ */
+typedef enum {
+ NO_CAST, /* Spell not cast; user aborted */
+ CAST_OBVIOUS, /* Cast; caster discovers effect (devices) */
+ CAST_HIDDEN /* Cast; caster does NOT discover effect (devices) */
+} casting_result;
+
+/*
+ * Forward declaration of the spell_type
+ */
+typedef struct spell_type spell_type;
+struct spell_type;
diff --git a/src/spells.pkg b/src/spells.pkg
deleted file mode 100644
index e785de0d..00000000
--- a/src/spells.pkg
+++ /dev/null
@@ -1,2448 +0,0 @@
-/* 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
deleted file mode 100644
index 9bfc6fe2..00000000
--- a/src/spells1.c
+++ /dev/null
@@ -1,9327 +0,0 @@
-/* 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/spells1.cc b/src/spells1.cc
new file mode 100644
index 00000000..5d6722af
--- /dev/null
+++ b/src/spells1.cc
@@ -0,0 +1,9275 @@
+/*
+ * 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 "spells1.hpp"
+
+#include "cave.hpp"
+#include "cave_type.hpp"
+#include "cmd1.hpp"
+#include "cmd3.hpp"
+#include "cmd5.hpp"
+#include "dungeon_info_type.hpp"
+#include "files.hpp"
+#include "feature_type.hpp"
+#include "gods.hpp"
+#include "melee2.hpp"
+#include "monster2.hpp"
+#include "monster3.hpp"
+#include "monster_type.hpp"
+#include "monster_race.hpp"
+#include "object1.hpp"
+#include "object2.hpp"
+#include "object_kind.hpp"
+#include "options.hpp"
+#include "player_type.hpp"
+#include "skills.hpp"
+#include "spell_type.hpp"
+#include "spells2.hpp"
+#include "spells4.hpp"
+#include "spells5.hpp"
+#include "squeltch.hpp"
+#include "stats.hpp"
+#include "tables.hpp"
+#include "traps.hpp"
+#include "trap_type.hpp"
+#include "util.hpp"
+#include "util.h"
+#include "variable.hpp"
+#include "wizard2.hpp"
+#include "xtra1.hpp"
+#include "xtra2.hpp"
+#include "z-rand.hpp"
+
+#include <chrono>
+#include <thread>
+
+using std::this_thread::sleep_for;
+using std::chrono::milliseconds;
+
+/* 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
+
+/*
+ * 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)))
+
+
+/*
+ * 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);
+
+ /* 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)
+{
+ bool_ look = TRUE;
+
+ monster_type *m_ptr = &m_list[m_idx];
+
+ 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 */
+ const int oy = m_ptr->fy;
+ const int ox = m_ptr->fx;
+
+ /* Minimum distance */
+ int min = dis / 2;
+
+ /* Look until done */
+ int tries = 0;
+ int ny = 0;
+ int nx = 0;
+ while (look)
+ {
+ tries++;
+
+ /* Verify max distance */
+ if (dis > 200) dis = 200;
+
+ /* Try several locations */
+ for (int i = 0; i < 500; i++)
+ {
+ /* Pick a (possibly illegal) location */
+ while (1)
+ {
+ ny = rand_spread(oy, dis);
+ nx = rand_spread(ox, dis);
+ int 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))
+ 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 */
+ auto const r_ptr = m_ptr->race();
+ if (r_ptr->flags9 & RF9_HAS_LITE)
+ {
+ p_ptr->update |= (PU_MON_LITE);
+ }
+}
+
+
+/*
+ * Teleport monster next to the player
+ */
+static void teleport_to_player(int m_idx)
+{
+ monster_type *m_ptr = &m_list[m_idx];
+ auto const r_ptr = m_ptr->race();
+
+ 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 */
+ const int oy = m_ptr->fy;
+ const int ox = m_ptr->fx;
+
+ /* Minimum distance */
+ int dis = 2;
+ int min = dis / 2;
+
+ /* End destination */
+ int ny = 0;
+ int nx = 0;
+
+ /* Look until done */
+ bool_ look = TRUE;
+ while (look && --attempts)
+ {
+ /* Verify max distance */
+ if (dis > 200) dis = 200;
+
+ /* Try several locations */
+ for (int 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);
+ const int 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)
+ {
+ auto const r_ptr = m_list[cave[oy + yy][ox + xx].m_idx].race();
+
+ 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_FRAME);
+
+ /* 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_FRAME);
+
+ /* 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_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_FRAME);
+}
+
+
+/*
+ * Check the gods
+ */
+static void project_check_gods(int typ)
+{
+ if (p_ptr->pgod == GOD_VARDA)
+ {
+ if ((typ == GF_LITE) || (typ == GF_LITE_WEAK))
+ {
+ /* Raise piety for using lite */
+ set_grace(p_ptr->grace + 1);
+ }
+ }
+
+ if (p_ptr->pgod == GOD_ULMO)
+ {
+ if ((typ == GF_FIRE) ||
+ (typ == GF_HELL_FIRE) ||
+ (typ == GF_HOLY_FIRE) ||
+ (typ == GF_LAVA_FLOW) ||
+ (typ == GF_METEOR) ||
+ (typ == GF_NUKE) ||
+ (typ == GF_PLASMA))
+ {
+ /* Reduce piety for using any kind of fire magic */
+ set_grace(p_ptr->grace - 5);
+ }
+ }
+}
+
+
+/*
+ * 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)
+{
+ {
+ /* 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);
+ case GF_INSTA_DEATH:
+ return TERM_DARK;
+ case GF_ELEMENTAL_WALL:
+ case GF_ELEMENTAL_GROWTH:
+ return TERM_GREEN;
+ }
+ }
+
+ /* 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.", spell_type_name(spell_at(p_ptr->spellbinder[i])));
+ lua_cast_school_spell(p_ptr->spellbinder[i], TRUE);
+ }
+ 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);
+
+ /* 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_FRAME);
+ }
+
+ /* 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_FRAME;
+ }
+ 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_FRAME);
+ }
+
+ /* Hurt the player */
+ if (!monster_take) p_ptr->chp -= damage;
+
+ /* Display the hitpoints */
+ p_ptr->redraw |= (PR_FRAME);
+
+ /* 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_FRAME);
+
+ /* 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)
+ {
+ if (praying_to(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);
+
+
+ /* Hurt the player */
+ p_ptr->csane -= damage;
+
+ /* Display the hitpoints */
+ p_ptr->redraw |= (PR_FRAME);
+
+ /* 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);
+}
+
+
+
+/*
+ * 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".
+ *
+ * This function returns the coordinates of all the grids on the path.
+ * The returned vector will be empty if and only if (y1,x1) and (y2,x2) are
+ * equal. 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 size of the result of this function should never be
+ * compared directly to "range". Note that the initial grid (y1,x1) is
+ * never saved into the returned grid array, not even if the initial grid
+ * is also the final grid.
+ *
+ * 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 algorithm is similar to, but slightly different from, the one used
+ * by "update_view_los()", and very different from the one used by "los()".
+ */
+static std::vector<std::tuple<int, int>> project_path(unsigned int range, int y1, int x1, int y2, int x2, int flg)
+{
+ int y, x, mana = 0, dir = 0;
+
+ /* Output grids */
+ std::vector<std::tuple<int, int>> gp;
+ gp.reserve(range + 10);
+
+ /* 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 gp;
+ }
+
+ /* 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.push_back(std::make_tuple(y, x));
+
+ /* Hack -- Check maximum range */
+ if (gp.size() >= range + 10)
+ {
+ return gp;
+ }
+
+ /* Always stop at non-initial wall grids */
+ if ((!cave_sight_bold(y, x) || !cave_floor_bold(y, x)))
+ {
+ return gp;
+ }
+
+ /* Sometimes stop at non-initial monsters/players */
+ if ((flg & (PROJECT_STOP)) && (cave[y][x].m_idx != 0))
+ {
+ return gp;
+ }
+
+ /* Get the new direction */
+ dir = get_mana_path_dir(y, x, oy, ox, pdir, mana);
+ if (dir == 5)
+ {
+ return gp;
+ }
+
+ 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;
+
+ /* Counter for distance calculation */
+ int k = 0;
+
+ /* Create the projection path */
+ while (1)
+ {
+ /* Save grid */
+ gp.push_back(std::make_tuple(y, x));
+
+ /* Hack -- Check maximum range */
+ if ((gp.size() + (k >> 1)) >= range)
+ {
+ break;
+ }
+
+ /* Sometimes stop at destination grid */
+ if (!(flg & (PROJECT_THRU)) && (x == x2) && (y == y2))
+ {
+ break;
+ }
+
+ /* Always stop at non-initial wall grids */
+ if ((!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)) && (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;
+
+ /* Counter for distance calculation */
+ int k = 0;
+
+ /* Create the projection path */
+ while (1)
+ {
+ /* Save grid */
+ gp.push_back(std::make_tuple(y, x));
+
+ /* Hack -- Check maximum range */
+ if ((gp.size() + (k >> 1)) >= range)
+ {
+ break;
+ }
+
+ /* Sometimes stop at destination grid */
+ if (!(flg & (PROJECT_THRU)) && (x == x2) && (y == y2))
+ {
+ break;
+ }
+
+ /* Always stop at non-initial wall grids */
+ if ((!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)) && (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.push_back(std::make_tuple(y, x));
+
+ /* Hack -- Check maximum range */
+ if ((gp.size() + (gp.size() >> 1)) >= range)
+ {
+ break;
+ }
+
+ /* Sometimes stop at destination grid */
+ if (!(flg & (PROJECT_THRU)) && (x == x2) && (y == y2))
+ {
+ break;
+ }
+
+ /* Always stop at non-initial wall grids */
+ if ((!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)) && (cave[y][x].m_idx != 0))
+ {
+ break;
+ }
+
+ /* Advance (Y) */
+ y += sy;
+
+ /* Advance (X) */
+ x += sx;
+ }
+ }
+
+ /* Done */
+ return gp;
+}
+
+
+
+/*
+ * 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);
+
+ /* Check gods */
+ project_check_gods(typ);
+
+ /* 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;
+ }
+
+ case GF_ELEMENTAL_WALL:
+ {
+ if ((p_ptr->py != y) || (p_ptr->px != x)) {
+ geomancy_random_wall(y, x);
+ }
+ break;
+ }
+
+ case GF_ELEMENTAL_GROWTH:
+ {
+ geomancy_random_floor(y, x, FALSE);
+ 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];
+
+ 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);
+
+ /* Check new gods. */
+ project_check_gods(typ);
+
+ /* Copy list of objects since we may destroy during iteration */
+ auto const object_idxs(c_ptr->o_idxs);
+
+ /* Scan all objects in the grid */
+ for (auto const this_o_idx: object_idxs)
+ {
+ bool_ is_art = FALSE;
+ bool_ ignore = FALSE;
+ bool_ plural = FALSE;
+ bool_ do_kill = FALSE;
+
+ cptr note_kill = NULL;
+
+ /* Acquire object */
+ object_type * o_ptr = &o_list[this_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 */
+ identify_hooks(0 - this_o_idx, o_ptr, IDENT_FULL);
+
+ /* Squelch ! */
+ squeltch_grid();
+
+ break;
+ }
+ case GF_IDENTIFY:
+ {
+ object_aware(o_ptr);
+ object_known(o_ptr);
+
+ /* Process the appropriate hooks */
+ identify_hooks(0 - this_o_idx, o_ptr, IDENT_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:
+ 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];
+
+ char killer [80];
+
+ /* 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);
+
+
+ /* Check gods */
+ project_check_gods(typ);
+
+ /* Get the monster name (BEFORE polymorphing) */
+ monster_desc(m_name, m_ptr, 0);
+
+ /* Get race information */
+ auto r_ptr = m_ptr->race();
+
+ /* 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;
+ case GF_INSTA_DEATH:
+ get_angry = TRUE;
+ break;
+ case GF_ELEMENTAL_GROWTH:
+ case GF_ELEMENTAL_WALL:
+ get_angry = FALSE;
+ break;
+ }
+
+ /* 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(r_ptr->name, "W") ||
+ (strstr(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(r_ptr->name, "W") ||
+ (strstr(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(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_FRAME;
+ 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_FRAME;
+ }
+
+ 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_FRAME);
+
+ /* 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_FRAME);
+
+ /* 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;
+ }
+
+ case GF_INSTA_DEATH:
+ {
+ if (magik(95) && !(r_ptr->flags1 & RF1_UNIQUE) && !(r_ptr->flags3 & RF3_UNDEAD) && !(r_ptr->flags3 & RF3_NONLIVING)) {
+ /* Kill outright, but reduce exp. */
+ m_ptr->level = m_ptr->level / 3;
+ dam = 32535; /* Should be enough */
+ note = " faints.";
+ note_dies = " is sucked out of life.";
+ } else {
+ /* No effect */
+ skipped = TRUE;
+ }
+
+ break;
+ }
+
+ default:
+ skipped = TRUE;
+ 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 = m_ptr->race();
+ }
+ }
+
+ /* 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);
+ 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_info[dungeon_type].name);
+ }
+ if (who == -101)
+ {
+ sprintf(killer, "%s", 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_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(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(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:
+ {
+ /* 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);
+
+
+ /* 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 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);
+
+ /* Actual grids in the "path" */
+ std::vector<std::tuple<int, int>> path_g;
+
+ /* 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))
+ {
+ /* Leave path empty */
+ }
+ else
+ {
+ path_g = project_path(MAX_RANGE, y1, x1, y2, x2, flg);
+ }
+
+
+ /* Hack -- Handle stuff */
+ handle_stuff();
+
+ /* Project along the path */
+ for (auto const &grid_yx: path_g)
+ {
+ int oy = y;
+ int ox = x;
+
+ int ny = std::get<0>(grid_yx);
+ int nx = std::get<1>(grid_yx);
+
+ /* 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();
+ sleep_for(milliseconds(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 */
+ sleep_for(milliseconds(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 (int 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)
+ {
+ sleep_for(milliseconds(msec));
+ }
+ }
+
+ /* Flush the erasing */
+ if (drawn)
+ {
+ /* Erase the explosion drawn above */
+ for (int 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 (int 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 (int 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 (int 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
+ {
+ auto ref_ptr = m_list[cave[y][x].m_idx].race();
+
+ 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 (int 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));
+
+ // Silence warning. We may want to introuce an actual implementation
+ // and I want to preserve the original "ident" values if we do so.
+ (void) ident;
+
+ /* 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.
+ */
+
+static 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/spells1.hpp b/src/spells1.hpp
new file mode 100644
index 00000000..5512063f
--- /dev/null
+++ b/src/spells1.hpp
@@ -0,0 +1,32 @@
+#pragma once
+
+#include "h-basic.h"
+
+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_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_ 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 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 s16b do_poly_monster(int y, int x);
diff --git a/src/spells2.c b/src/spells2.c
deleted file mode 100644
index 5467499c..00000000
--- a/src/spells2.c
+++ /dev/null
@@ -1,8076 +0,0 @@
-/* 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/spells2.cc b/src/spells2.cc
new file mode 100644
index 00000000..08a643c9
--- /dev/null
+++ b/src/spells2.cc
@@ -0,0 +1,6837 @@
+/*
+ * 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 "spells2.hpp"
+
+#include "cave.hpp"
+#include "cave_type.hpp"
+#include "cmd1.hpp"
+#include "cmd7.hpp"
+#include "dungeon_info_type.hpp"
+#include "feature_type.hpp"
+#include "files.hpp"
+#include "hook_identify_in.hpp"
+#include "hooks.hpp"
+#include "melee2.hpp"
+#include "monster2.hpp"
+#include "monster3.hpp"
+#include "monster_race.hpp"
+#include "monster_type.hpp"
+#include "notes.hpp"
+#include "object1.hpp"
+#include "object2.hpp"
+#include "object_kind.hpp"
+#include "object_type.hpp"
+#include "options.hpp"
+#include "player_type.hpp"
+#include "skills.hpp"
+#include "spells1.hpp"
+#include "spells3.hpp"
+#include "stats.hpp"
+#include "tables.hpp"
+#include "util.hpp"
+#include "util.h"
+#include "variable.h"
+#include "variable.hpp"
+#include "xtra1.hpp"
+#include "xtra2.hpp"
+#include "z-rand.hpp"
+
+#include <boost/algorithm/string/predicate.hpp>
+#include <cassert>
+#include <chrono>
+#include <sstream>
+#include <thread>
+#include <vector>
+
+using boost::algorithm::iequals;
+using std::this_thread::sleep_for;
+using std::chrono::milliseconds;
+
+#define WEIRD_LUCK 12
+#define BIAS_LUCK 20
+/*
+ * Bias luck needs to be higher than weird luck,
+ * since it is usually tested several times...
+ */
+
+static 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_FRAME);
+
+ /* 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);
+}
+
+
+/*
+ * Increases a stat by one randomized level -RAK-
+ *
+ * Note that this function (used by stat potions) now restores
+ * the stat BEFORE increasing it.
+ */
+static 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);
+}
+
+
+/*
+ * 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);
+}
+
+
+/*
+ * Process all identify hooks
+ */
+void identify_hooks(int i, object_type *o_ptr, identify_mode mode)
+{
+ /* Process the appropriate hooks */
+ hook_identify_in in = { o_ptr, mode };
+ process_hooks_new(HOOK_IDENTIFY, &in, NULL);
+}
+
+
+/*
+ * Identify everything being carried.
+ * Done by a potion of "self knowledge".
+ */
+bool_ 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 */
+ identify_hooks(i, o_ptr, IDENT_NORMAL);
+ }
+
+ p_ptr->notice |= (PN_COMBINE | PN_REORDER);
+ p_ptr->window |= (PW_INVEN | PW_EQUIP | PW_PLAYER);
+ return TRUE;
+}
+
+/*
+ * 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);
+}
+
+/*
+ * 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 */
+ identify_hooks(i, o_ptr, IDENT_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
+};
+
+static 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;
+ char o_name[80];
+ char out_val[160];
+
+ /* Hack -- force destruction */
+ if (command_arg > 0) force = TRUE;
+
+ /* Get an item */
+ if (!get_item(&item,
+ "Turn which item to gold? ",
+ "You have nothing to turn to gold.",
+ (USE_INVEN | USE_FLOOR),
+ object_filter::True()))
+ {
+ return (FALSE);
+ }
+
+ /* Get the item */
+ object_type *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)
+ {
+ /* 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_FRAME);
+
+ /* 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->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_FRAME);
+
+ /* 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 monsters on current panel using a
+ * predicate function P and an update function U.
+ * The "update function" is called exactly once if
+ * the predicate succeeds. The
+ */
+template<typename P, typename U> static bool detect_monsters_fn(int radius, P p, U u) {
+ bool flag = false;
+ /* Scan monsters */
+ for (int i = 1; i < m_max; i++)
+ {
+ monster_type *m_ptr = &m_list[i];
+
+ /* Skip dead monsters */
+ if (!m_ptr->r_idx)
+ {
+ continue;
+ }
+
+ /* Location */
+ int const y = m_ptr->fy;
+ int const x = m_ptr->fx;
+
+ /* Only detect nearby monsters */
+ if (m_ptr->cdis > radius)
+ {
+ continue;
+ }
+ /* Detect monsters which fulfill the predicate */
+ auto r_ptr = m_ptr->race();
+ if (p(r_ptr.get()))
+ {
+ /* Update */
+ u(r_ptr.get());
+
+ /* We're assuming the update function does
+ * *something*, so we'll need to update
+ * the recall window if we're currently looking
+ * at it.
+ */
+ if (monster_race_idx == m_ptr->r_idx)
+ {
+ 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;
+ }
+ }
+ /* Result */
+ return flag;
+}
+
+/*
+ * Detect all (string) monsters on current panel
+ */
+static bool_ detect_monsters_string(cptr chars, int rad)
+{
+ auto predicate = [chars](monster_race *r_ptr) -> bool {
+ return strchr(chars, r_ptr->d_char);
+ };
+ auto update = [](monster_race *) -> void {
+ };
+
+ /* Describe */
+ if (detect_monsters_fn(rad, predicate, update))
+ {
+ /* Describe result */
+ msg_print("You sense the presence of monsters!");
+ return TRUE;
+ }
+ else
+ {
+ return FALSE;
+ }
+}
+
+
+/**
+ * Detect objects on the current panel.
+ */
+template <typename P> bool detect_objects_fn(int radius, const char *object_message, const char *monsters, P p)
+{
+ bool detect = false;
+
+ /* Scan objects */
+ for (int i = 1; i < o_max; i++)
+ {
+ object_type *o_ptr = &o_list[i];
+
+ /* Skip dead objects */
+ if (!o_ptr->k_idx) continue;
+
+ /* Location */
+ int y, x;
+
+ /* Skip held objects */
+ if (o_ptr->held_m_idx)
+ {
+ /* Access the monster */
+ monster_type *m_ptr = &m_list[o_ptr->held_m_idx];
+ auto const r_ptr = m_ptr->race();
+
+ if (!(r_ptr->flags9 & RF9_MIMIC))
+ {
+ continue; /* Skip mimics completely */
+ }
+ 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) > radius)
+ {
+ continue;
+ }
+
+ /* Detect objects that satisfy predicate */
+ if (p(o_ptr))
+ {
+ /* Hack -- memorize it */
+ o_ptr->marked = TRUE;
+
+ /* Redraw */
+ if (panel_contains(y, x)) lite_spot(y, x);
+
+ /* Detect */
+ detect = TRUE;
+ }
+ }
+
+ /* Describe */
+ if (detect)
+ {
+ msg_print(object_message);
+ }
+
+ if (detect_monsters_string(monsters, radius))
+ {
+ detect = true;
+ }
+
+ /* Result */
+ return detect;
+}
+
+
+/*
+ * Detect all "gold" objects on the current panel
+ */
+bool detect_objects_gold(int rad)
+{
+ auto predicate = [](object_type const *o_ptr) -> bool {
+ return o_ptr->tval == TV_GOLD;
+ };
+
+ return detect_objects_fn(
+ rad,
+ "You sense the presence of treasure!",
+ "$",
+ predicate);
+}
+
+
+/*
+ * Detect all "normal" objects on the current panel
+ */
+bool detect_objects_normal(int rad)
+{
+ auto predicate = [](object_type const *o_ptr) -> bool {
+ return o_ptr->tval != TV_GOLD;
+ };
+ const char *object_message = "You sense the presence of objects!";
+ const char *monsters = "!=?|";
+
+ return detect_objects_fn(
+ rad,
+ object_message,
+ monsters,
+ predicate);
+}
+
+
+/*
+ * Detect all "normal" monsters on the current panel
+ */
+bool_ detect_monsters_normal(int rad)
+{
+ auto predicate = [](monster_race *r_ptr) -> bool {
+ return (!(r_ptr->flags2 & (RF2_INVISIBLE))) ||
+ p_ptr->see_inv || p_ptr->tim_invis;
+ };
+ auto update = [](monster_race *) -> void {
+ };
+
+ if (detect_monsters_fn(rad, predicate, update))
+ {
+ /* Describe result */
+ msg_print("You sense the presence of monsters!");
+ return TRUE;
+ }
+ else
+ {
+ return FALSE;
+ }
+}
+
+
+/*
+ * Detect all "invisible" monsters on current panel
+ */
+bool_ detect_monsters_invis(int rad)
+{
+ auto predicate = [](monster_race *r_ptr) -> bool {
+ return (r_ptr->flags2 & (RF2_INVISIBLE));
+ };
+ auto update = [](monster_race *r_ptr) -> void {
+ r_ptr->r_flags2 |= (RF2_INVISIBLE);
+ };
+
+ if (detect_monsters_fn(rad, predicate, update))
+ {
+ /* Describe result */
+ msg_print("You sense the presence of invisible creatures!");
+ return TRUE;
+ }
+ else
+ {
+ return FALSE;
+ }
+}
+
+
+
+/*
+ * A "generic" detect monsters routine, tagged to flags3
+ */
+bool_ detect_monsters_xxx(u32b match_flag, int rad)
+{
+ auto predicate = [match_flag](monster_race *r_ptr) -> bool {
+ return (r_ptr->flags3 & match_flag);
+ };
+ auto update = [match_flag](monster_race *r_ptr) -> void {
+ r_ptr->r_flags3 |= (match_flag);
+ };
+
+ if (detect_monsters_fn(rad, predicate, update))
+ {
+ cptr desc_monsters = "weird monsters";
+ 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;
+ case RF3_ORC:
+ desc_monsters = "orcs";
+ break;
+ }
+
+ /* Describe result */
+ msg_format("You sense the presence of %s!", desc_monsters);
+ msg_print(NULL);
+ return TRUE;
+ }
+ else
+ {
+ return FALSE;
+ }
+}
+
+
+
+/*
+ * 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_quest)
+ {
+ /* 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 object_filter_t const &item_tester_hook_weapon()
+{
+ using namespace object_filter;
+ static auto instance =
+ Or(
+ TVal(TV_MSTAFF),
+ TVal(TV_BOOMERANG),
+ TVal(TV_SWORD),
+ TVal(TV_AXE),
+ TVal(TV_HAFTED),
+ TVal(TV_POLEARM),
+ TVal(TV_BOW),
+ TVal(TV_BOLT),
+ TVal(TV_ARROW),
+ TVal(TV_SHOT),
+ And(
+ TVal(TV_DAEMON_BOOK),
+ SVal(SV_DEMONBLADE)));
+ return instance;
+}
+
+
+/*
+ * Hook to specify "armour"
+ */
+static object_filter_t const &item_tester_hook_armour()
+{
+ using namespace object_filter;
+ static auto instance =
+ Or(
+ TVal(TV_DRAG_ARMOR),
+ TVal(TV_HARD_ARMOR),
+ TVal(TV_SOFT_ARMOR),
+ TVal(TV_SHIELD),
+ TVal(TV_CLOAK),
+ TVal(TV_CROWN),
+ TVal(TV_HELM),
+ TVal(TV_BOOTS),
+ TVal(TV_GLOVES),
+ And(
+ TVal(TV_DAEMON_BOOK),
+ Or(
+ SVal(SV_DEMONHORN),
+ SVal(SV_DEMONSHIELD))));
+ return instance;
+}
+
+
+/*
+ * Check if an object is artifactable
+ */
+object_filter_t const &item_tester_hook_artifactable()
+{
+ using namespace object_filter;
+ static auto instance = And(
+ // Check base item family
+ Or(
+ item_tester_hook_weapon(),
+ item_tester_hook_armour(),
+ TVal(TV_DIGGING),
+ TVal(TV_RING),
+ TVal(TV_AMULET)),
+ // Only unenchanted items
+ Not(IsArtifactP()),
+ Not(IsEgo()));
+ return instance;
+}
+
+
+/*
+ * 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;
+ char o_name[80];
+ cptr q, s;
+
+
+ /* Assume enchant weapon */
+ object_filter_t object_filter = item_tester_hook_weapon();
+
+ /* Enchant armor if requested */
+ if (num_ac)
+ {
+ object_filter = 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), object_filter)) return (FALSE);
+
+ /* Get the item */
+ object_type *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;
+}
+
+
+
+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;
+ }
+}
+
+
+
+/*
+ * Make note of found artifacts.
+ */
+static void note_found_object(object_type *o_ptr)
+{
+ char note[150];
+ char item_name[80];
+
+ if (artifact_p(o_ptr) || o_ptr->name1)
+ {
+ object_desc(item_name, o_ptr, FALSE, 0);
+
+ /* Build note and write */
+ sprintf(note, "Found The %s", item_name);
+ add_note(note, 'A');
+ }
+}
+
+
+
+
+/*
+ * 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)
+{
+ /* Get an item */
+ int item;
+ if (!get_item(&item,
+ "Identify which item? ",
+ "You have nothing to identify.",
+ (USE_EQUIP | USE_INVEN | USE_FLOOR),
+ object_filter::Not(object_known_p))) return (FALSE);
+
+ /* Get the item */
+ object_type *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 */
+ char o_name[80];
+ 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);
+ }
+
+ /* Make note of found artifacts */
+ note_found_object(o_ptr);
+
+ /* Process the appropriate hooks */
+ identify_hooks(item, o_ptr, IDENT_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);
+
+ /* Make note of found artifacts */
+ note_found_object(o_ptr);
+
+ /* Process the appropriate hooks */
+ identify_hooks(-i, o_ptr, IDENT_NORMAL);
+ }
+
+ /* Something happened */
+ return (TRUE);
+}
+
+
+
+/*
+ * Determine if an object is not fully identified
+ */
+static bool item_tester_hook_no_mental(object_type const *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)
+{
+ /* Get an item */
+ int item;
+ if (!get_item(&item,
+ "Identify which item? ",
+ "You have nothing to identify.",
+ (USE_EQUIP | USE_INVEN | USE_FLOOR),
+ item_tester_hook_no_mental))
+ {
+ return (FALSE);
+ }
+
+ /* Get the item */
+ object_type *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 */
+ char o_name[80];
+ 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);
+ }
+
+ /* Make note of found artifacts */
+ note_found_object(o_ptr);
+
+ /* Describe it fully */
+ object_out_desc(o_ptr, NULL, FALSE, TRUE);
+
+ /* Process the appropriate hooks */
+ identify_hooks(item, o_ptr, IDENT_FULL);
+
+ /* Success */
+ return (TRUE);
+}
+
+
+
+
+/*
+ * Hook for "get_item()". Determine if something is rechargable.
+ */
+object_filter_t const &item_tester_hook_recharge()
+{
+ using namespace object_filter;
+ static auto instance =
+ And(
+ // Must NOT have NO_RECHARGE flag.
+ Not(HasFlag4(TR4_NO_RECHARGE)),
+ // ... and must be a device.
+ Or(
+ TVal(TV_STAFF),
+ TVal(TV_WAND),
+ TVal(TV_ROD_MAIN)));
+ return instance;
+}
+
+
+/*
+ * 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 lev;
+ bool_ fail = FALSE;
+ byte fail_type = 1;
+
+ char o_name[80];
+
+ /* Get an item */
+ int item;
+ if (!get_item(&item,
+ "Recharge which item? ",
+ "You have nothing to recharge.",
+ (USE_INVEN | USE_FLOOR),
+ item_tester_hook_recharge()))
+ {
+ return (FALSE);
+ }
+
+ /* Get the item */
+ object_type *o_ptr = get_object(item);
+
+ /* Extract the flags */
+ u32b f1, f2, f3, f4, f5, esp;
+ 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 */
+ 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);
+ }
+}
+
+
+/*
+ * Banish evil monsters
+ */
+bool_ banish_evil(int dist)
+{
+ return (project_hack(GF_AWAY_EVIL, dist));
+}
+
+
+
+/*
+ * 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));
+}
+
+
+/*
+ * 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];
+
+ /* 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))
+ {
+ auto const r_ptr = m_ptr->race();
+
+ /* 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
+ */
+static 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];
+ auto const r_ptr = m_ptr->race();
+
+ *typ = r_ptr->d_char;
+ return true;
+ }
+
+ msg_print("You must select a monster.");
+ return false;
+}
+
+
+/*
+ * 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];
+ auto const r_ptr = m_ptr->race();
+
+ /* 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;
+ char buf[256];
+
+ monster_race_desc(buf, 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.", buf);
+ }
+
+ 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 */
+ sleep_for(milliseconds(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_FRAME);
+
+ /* 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];
+ auto const r_ptr = m_ptr->race();
+
+ /* 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;
+ char buf[256];
+
+ monster_race_desc(buf, 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.", buf);
+ }
+
+ 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 */
+ sleep_for(milliseconds(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_FRAME);
+
+ /* 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);
+
+ {
+ std::ostringstream buf;
+ buf << " has " << m_ptr->exp
+ << " exp and needs " << monster_exp(m_ptr->level + 1) << ".";
+ msg_format("%^s%s", m_name, buf.str().c_str());
+ }
+ }
+
+ /* 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);
+}
+
+
+/*
+ * 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)
+{
+ int y, x, k, t;
+
+ 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);
+
+ /* 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 (race_flags1_p(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];
+ auto const r_ptr = m_ptr->race();
+
+ /* 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_FRAME);
+
+ /* 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];
+ auto const r_ptr = m_ptr->race();
+
+ /* 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));
+}
+
+
+
+void teleport_swap(int dir)
+{
+ if (p_ptr->resist_continuum)
+ {
+ msg_print("The space-time continuum can't be disrupted.");
+ return;
+ }
+
+ int tx, ty;
+ if ((dir == 5) && target_okay())
+ {
+ tx = target_col;
+ ty = target_row;
+ }
+ else
+ {
+ tx = p_ptr->px + ddx[dir];
+ ty = p_ptr->py + ddy[dir];
+ }
+
+ cave_type *c_ptr = &cave[ty][tx];
+
+ if (!c_ptr->m_idx)
+ {
+ msg_print("You can't trade places with that!");
+ }
+ else
+ {
+ monster_type *m_ptr = &m_list[c_ptr->m_idx];
+ auto const r_ptr = m_ptr->race();
+
+ 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_FRAME);
+
+ /* 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_FRAME);
+
+ /* 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_FRAME);
+
+ /* 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 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));
+ }
+}
+
+
+/*
+ * 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_ disarm_trap(int dir)
+{
+ int flg = PROJECT_BEAM | PROJECT_GRID | PROJECT_ITEM;
+ return (project_hook(GF_KILL_TRAP, dir, 0, 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_ confuse_monster(int dir, int plev)
+{
+ int flg = PROJECT_STOP | PROJECT_KILL;
+ return (project_hook(GF_OLD_CONF, 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_ fear_monster(int dir, int plev)
+{
+ int flg = PROJECT_STOP | PROJECT_KILL;
+ return (project_hook(GF_TURN_ALL, 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));
+}
+
+
+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_ 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));
+ }
+}
+
+
+static 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);
+ }
+ }
+}
+
+
+/*
+ * 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(randint(3));
+ else
+ set_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(randint(3));
+ else
+ set_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 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);
+ }
+}
+
+static 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);
+ }
+}
+
+
+
+/*
+ * 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));
+}
+
+
+/*
+ * Stun monsters
+ */
+bool_ stun_monsters(int dam)
+{
+ return (project_hack(GF_STUN, 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 everyone
+ */
+bool_ turn_monsters(int dam)
+{
+ return (project_hack(GF_TURN_ALL, dam));
+}
+
+
+bool_ charm_monster(int dir, int plev)
+{
+ int flg = PROJECT_STOP | PROJECT_KILL;
+ return (project_hook(GF_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_FRAME);
+ 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_FRAME);
+
+ /* 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(std::vector<int> const &dungeon_idxs,
+ int start,
+ 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 < static_cast<int>(dungeon_idxs.size()); i++, j++)
+ {
+ dungeon_info_type *d_ptr = &d_info[dungeon_idxs[j]];
+
+ strnfmt(buf, 80, " %c) %-30s", I2A(i), 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);
+}
+
+static int find_dungeon_by_name(char const *name)
+{
+ /* Find the index corresponding to the name */
+ for (int i = 1; i < max_d_idx; i++)
+ {
+ /* Skip non-initialized entries. */
+ if (d_info[i].name == nullptr) {
+ continue;
+ }
+ if (iequals(name, d_info[i].name))
+ {
+ return i;
+ }
+ }
+ /* Not found */
+ return -1;
+}
+
+static int reset_recall_aux()
+{
+ char which;
+ int start = 0;
+ int ret;
+ bool_ mode = FALSE;
+
+ // Dungeons available for recall
+ std::vector<int> dungeons;
+ for (size_t i = 1; i < max_d_idx; i++)
+ {
+ /* skip "blocked" dungeons */
+ if (d_info[i].flags1 & DF1_NO_RECALL) continue;
+
+ if (max_dlv[i])
+ {
+ dungeons.push_back(i);
+ }
+ }
+
+ character_icky = TRUE;
+ Term_save();
+
+ while (1)
+ {
+ print_dungeon_batch(dungeons, start, 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;
+ assert(start > 0);
+ if (static_cast<size_t>(start) >= dungeons.size())
+ {
+ 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, d_info[p_ptr->recall_dungeon].name);
+ if (!get_string("Which dungeon? ", buf, 79)) continue;
+
+ /* Find the index corresponding to the name */
+ int i = find_dungeon_by_name(buf);
+
+ if (i < 0)
+ {
+ 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);
+ int i = start + A2I(which);
+
+ if (i < 0)
+ {
+ bell();
+ continue;
+ }
+ else if (static_cast<size_t>(i) >= dungeons.size()) // Cast to avoid compilation warning
+ {
+ bell();
+ continue;
+ }
+ else
+ {
+ ret = dungeons[i];
+ break;
+ }
+ }
+ }
+
+ Term_load();
+ character_icky = FALSE;
+
+ 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_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;
+}
+
+/*
+ * 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);
+ }
+}
+
+/**
+ * Geomancy
+ */
+typedef struct geomancy_entry {
+ int skill;
+ int feat;
+ int min_skill_level;
+} geomancy_entry;
+
+static int choose_geomancy_feature(int n, geomancy_entry *table)
+{
+ int feat = -1;
+ /* choose feature */
+ while (feat < 0) {
+ geomancy_entry *t = &table[rand_int(n)];
+
+ /* Do we meet the requirements ?
+ And then select the features based on skill proportions */
+ if ((get_skill(t->skill) >= t->min_skill_level) && magik(get_skill_scale(t->skill, 100)))
+ {
+ feat = t->feat;
+ }
+ }
+ /* return */
+ return feat;
+}
+
+static int rotate_dir(int dir, int mov)
+{
+ if (mov > 0)
+ {
+ switch (dir) {
+ case 7: return 8;
+ case 8: return 9;
+ case 9: return 6;
+ case 6: return 3;
+ case 3: return 2;
+ case 2: return 1;
+ case 1: return 4;
+ case 4: return 7;
+ }
+ }
+ else if (mov < 0)
+ {
+ switch (dir) {
+ case 7: return 4;
+ case 4: return 1;
+ case 1: return 2;
+ case 2: return 3;
+ case 3: return 6;
+ case 6: return 9;
+ case 9: return 8;
+ case 8: return 7;
+ }
+ }
+
+ return dir;
+}
+
+void geomancy_random_wall(int y, int x)
+{
+#define TABLE_SIZE 4
+ cave_type *c_ptr = &cave[y][x];
+ int feat = -1;
+ geomancy_entry table[TABLE_SIZE] = {
+ /* Fire element */
+ { SKILL_FIRE, FEAT_SANDWALL, 1},
+ /* Water element */
+ { SKILL_WATER, FEAT_TREES, 1},
+ { SKILL_WATER, FEAT_ICE_WALL, 12},
+ /* Earth element */
+ { SKILL_EARTH, FEAT_WALL_EXTRA, 1}
+ };
+
+ /* Do not destroy permanent things */
+ if (f_info[c_ptr->feat].flags1 & FF1_PERMANENT) {
+ return;
+ }
+
+ /* Choose feature */
+ feat = choose_geomancy_feature(TABLE_SIZE, table);
+ if (feat >= 0)
+ {
+ cave_set_feat(y, x, feat);
+ }
+#undef TABLE_SIZE
+}
+
+void geomancy_random_floor(int y, int x, bool_ kill_wall)
+{
+#define TABLE_SIZE 9
+ cave_type *c_ptr = &cave[y][x];
+ int feat = -1;
+ geomancy_entry table[TABLE_SIZE] = {
+ /* Fire element */
+ { SKILL_FIRE, FEAT_SAND, 1},
+ { SKILL_FIRE, FEAT_SHAL_LAVA, 8},
+ { SKILL_FIRE, FEAT_DEEP_LAVA, 18},
+ /* Water element */
+ { SKILL_WATER, FEAT_SHAL_WATER, 1},
+ { SKILL_WATER, FEAT_DEEP_WATER, 8},
+ { SKILL_WATER, FEAT_ICE, 18},
+ /* Earth element */
+ { SKILL_EARTH, FEAT_GRASS, 1},
+ { SKILL_EARTH, FEAT_FLOWER, 8},
+ { SKILL_EARTH, FEAT_DARK_PIT, 18}
+ };
+
+ /* Do not destroy permanent things */
+ if (f_info[c_ptr->feat].flags1 & FF1_PERMANENT) {
+ return;
+ }
+ if (!(kill_wall || (f_info[c_ptr->feat].flags1 & FF1_FLOOR))) {
+ return;
+ }
+
+ /* Choose feature */
+ feat = choose_geomancy_feature(TABLE_SIZE, table);
+ if (feat >= 0)
+ {
+ cave_set_feat(y, x, feat);
+ }
+#undef TABLE_SIZE
+}
+
+static bool_ geomancy_can_tunnel(int y, int x)
+{
+ switch (cave[y][x].feat)
+ {
+ case FEAT_WALL_EXTRA:
+ case FEAT_WALL_OUTER:
+ case FEAT_WALL_INNER:
+ case FEAT_WALL_SOLID:
+ case FEAT_MAGMA:
+ case FEAT_QUARTZ:
+ case FEAT_MAGMA_H:
+ case FEAT_QUARTZ_H:
+ case FEAT_MAGMA_K:
+ case FEAT_QUARTZ_K:
+ case FEAT_TREES:
+ case FEAT_DEAD_TREE:
+ case FEAT_SANDWALL:
+ case FEAT_SANDWALL_H:
+ case FEAT_SANDWALL_K:
+ case FEAT_ICE_WALL:
+ return TRUE;
+ default:
+ return FALSE;
+ }
+}
+
+void geomancy_dig(int oy, int ox, int dir, int length)
+{
+ int dy = ddy[dir];
+ int dx = ddx[dir];
+ int y = dy + oy;
+ int x = dx + ox;
+ int i;
+
+ for (i=0; i<length; i++)
+ {
+ /* stop at the end of tunnelable things */
+ if (!geomancy_can_tunnel(y, x)) {
+ break;
+ }
+
+ if (geomancy_can_tunnel(y - 1, x - 1)) { geomancy_random_wall(y - 1, x - 1); }
+ if (geomancy_can_tunnel(y - 1, x )) { geomancy_random_wall(y - 1, x ); }
+ if (geomancy_can_tunnel(y - 1, x + 1)) { geomancy_random_wall(y - 1, x + 1); }
+
+ if (geomancy_can_tunnel(y , x - 1)) { geomancy_random_wall(y , x - 1); }
+ if (geomancy_can_tunnel(y , x + 1)) { geomancy_random_wall(y , x + 1); }
+
+ if (geomancy_can_tunnel(y + 1, x - 1)) { geomancy_random_wall(y + 1, x - 1); }
+ if (geomancy_can_tunnel(y + 1, x )) { geomancy_random_wall(y + 1, x ); }
+ if (geomancy_can_tunnel(y + 1, x + 1)) { geomancy_random_wall(y + 1, x + 1); }
+
+ y = y + dy;
+ x = x + dx;
+ }
+
+ /* Step back towards origin */
+ y = y - dy;
+ x = x - dx;
+ while ((y != oy) || (x != ox))
+ {
+ geomancy_random_floor(y, x, TRUE);
+
+ /* Should we branch ? */
+ if (magik(20))
+ {
+ int rot = magik(50) ? -1 : 1;
+ geomancy_dig(y, x, rotate_dir(dir, rot), length / 3);
+ }
+
+ y = y - dy;
+ x = x - dx;
+ }
+}
+
+void channel_the_elements(int y, int x, int level)
+{
+ // Type of water to use (if any)
+ auto water_type = []() -> int {
+ return (get_skill(SKILL_WATER) >= 18) ? GF_WAVE : GF_WATER;
+ };
+ // Do we use hellfire?
+ auto use_hellfire = []() -> bool {
+ return get_skill(SKILL_FIRE) >= 15;
+ };
+ // Type of fire to use (if any)
+ auto fire_type = [&use_hellfire]() -> int {
+ return use_hellfire() ? GF_HELL_FIRE : GF_FIRE;
+ };
+
+ switch (cave[y][x].feat)
+ {
+ case FEAT_GRASS:
+ hp_player(p_ptr->mhp * (5 + get_skill_scale(SKILL_EARTH, 20)) / 100);
+ break;
+
+ case FEAT_FLOWER:
+ hp_player(p_ptr->mhp * (5 + get_skill_scale(SKILL_EARTH, 30)) / 100);
+ break;
+
+ case FEAT_DARK_PIT:
+ {
+ int dir, type;
+ if (!get_aim_dir(&dir)) break;
+
+ type = (get_skill(SKILL_EARTH) >= 18) ? GF_NETHER : GF_DARK;
+
+ fire_bolt(type, dir, damroll(10, get_skill(SKILL_EARTH)));
+
+ break;
+ }
+
+ case FEAT_SHAL_WATER:
+ {
+ int dir;
+ if (!get_aim_dir(&dir)) break;
+
+ if (get_skill(SKILL_WATER) >= 8)
+ {
+ fire_beam(water_type(), dir, damroll(3, get_skill(SKILL_WATER)));
+ }
+ else
+ {
+ fire_bolt(water_type(), dir, damroll(3, get_skill(SKILL_WATER)));
+ }
+
+ break;
+ }
+
+ case FEAT_DEEP_WATER:
+ {
+ int dir;
+ if (!get_aim_dir(&dir)) break;
+
+ if (get_skill(SKILL_WATER) >= 8)
+ {
+ fire_beam(water_type(), dir, damroll(5, get_skill(SKILL_WATER)));
+ }
+ else
+ {
+ fire_bolt(water_type(), dir, damroll(5, get_skill(SKILL_WATER)));
+ }
+
+ break;
+ }
+
+ case FEAT_ICE:
+ {
+ int dir;
+ if (!get_aim_dir(&dir)) break;
+
+ if (get_skill(SKILL_WATER) >= 12)
+ {
+ fire_ball(GF_ICE, dir, get_skill_scale(SKILL_WATER, 340), 3);
+ }
+ else
+ {
+ fire_bolt(GF_ICE, dir, damroll(3, get_skill(SKILL_WATER)));
+ }
+
+ break;
+ }
+
+ case FEAT_SAND:
+ {
+ int type, dur;
+
+ type = use_hellfire() ? SHIELD_GREAT_FIRE : SHIELD_FIRE;
+
+ 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);
+
+ break;
+ }
+
+ case FEAT_SHAL_LAVA:
+ {
+ int dir;
+ if (!get_aim_dir(&dir)) break;
+
+ fire_bolt(fire_type(), dir, damroll(get_skill_scale(SKILL_FIRE, 30), 15));
+ break;
+ }
+
+ case FEAT_DEEP_LAVA:
+ {
+ int dir;
+ if (!get_aim_dir(&dir)) break;
+
+ fire_ball(fire_type(), dir, damroll(get_skill_scale(SKILL_FIRE, 30), 15), 3);
+ break;
+ }
+
+ default:
+ msg_print("You cannot channel this area.");
+ return;
+ }
+
+ /* Drain area? */
+ if (magik(100 - level))
+ {
+ if (cave[y][x].feat == FEAT_FLOWER)
+ {
+ cave_set_feat(y, x, FEAT_GRASS);
+ }
+ else
+ {
+ cave_set_feat(y, x, FEAT_FLOOR);
+ }
+ msg_print("The area is drained.");
+ }
+}
diff --git a/src/spells2.hpp b/src/spells2.hpp
new file mode 100644
index 00000000..bffc4a2c
--- /dev/null
+++ b/src/spells2.hpp
@@ -0,0 +1,115 @@
+#pragma once
+
+#include "h-basic.h"
+#include "identify_mode.hpp"
+#include "object_filter.hpp"
+#include "object_type_fwd.hpp"
+
+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_hooks(int i, object_type *o_ptr, identify_mode type);
+extern bool_ 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 detect_objects_gold(int rad);
+extern bool detect_objects_normal(int rad);
+extern bool_ detect_monsters_normal(int rad);
+extern bool_ detect_monsters_invis(int rad);
+extern bool_ detect_monsters_xxx(u32b match_flag, 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 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 void destroy_area(int y1, int x1, int r);
+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_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 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_ wall_to_mud(int dir);
+extern bool_ disarm_trap(int dir);
+extern bool_ wizard_lock(int dir);
+extern bool_ slow_monster(int dir);
+extern bool_ sleep_monster(int dir);
+extern bool_ confuse_monster(int dir, int plev);
+extern bool_ fear_monster(int dir, int plev);
+extern bool_ poly_monster(int dir);
+extern bool_ teleport_monster(int dir);
+extern bool_ trap_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 summon_cyber(void);
+extern bool_ confuse_monsters(int dam);
+extern bool_ charm_monsters(int dam);
+extern bool_ charm_animals(int dam);
+extern bool_ stun_monsters(int dam);
+extern bool_ banish_monsters(int dist);
+extern bool_ turn_monsters(int dam);
+extern bool_ 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 object_filter_t const &item_tester_hook_recharge();
+extern bool_ project_hack(int typ, int dam);
+extern void project_meteor(int radius, int typ, int dam, u32b flg);
+extern object_filter_t const &item_tester_hook_artifactable();
+extern bool_ passwall(int dir, bool_ safe);
+extern bool_ project_hook(int typ, int dir, int dam, int flg);
+extern bool_ reset_recall(bool_ no_trepas_max_depth);
+extern void geomancy_random_wall(int y, int x);
+extern void geomancy_random_floor(int y, int x, bool_ kill_wall);
+extern void geomancy_dig(int oy, int ox, int dir, int length);
+extern void channel_the_elements(int y, int x, int level);
+extern void random_resistance (object_type * o_ptr, bool_ is_scroll, int specific);
diff --git a/src/spells3.cc b/src/spells3.cc
new file mode 100644
index 00000000..35604f7d
--- /dev/null
+++ b/src/spells3.cc
@@ -0,0 +1,4606 @@
+#include "spells3.hpp"
+
+#include "cave.hpp"
+#include "cave_type.hpp"
+#include "cmd5.hpp"
+#include "feature_type.hpp"
+#include "lua_bind.hpp"
+#include "mimic.hpp"
+#include "monster2.hpp"
+#include "monster3.hpp"
+#include "monster_race.hpp"
+#include "monster_type.hpp"
+#include "object1.hpp"
+#include "object2.hpp"
+#include "object_kind.hpp"
+#include "player_type.hpp"
+#include "school_book.hpp"
+#include "skills.hpp"
+#include "spell_type.hpp"
+#include "spells1.hpp"
+#include "spells2.hpp"
+#include "spells4.hpp"
+#include "spells5.hpp"
+#include "stats.hpp"
+#include "tables.hpp"
+#include "timer_type.hpp"
+#include "util.hpp"
+#include "variable.hpp"
+#include "xtra2.hpp"
+#include "z-rand.hpp"
+
+#include <algorithm>
+#include <cassert>
+#include <vector>
+
+s32b NOXIOUSCLOUD = -1; /* Identifier */
+s32b AIRWINGS = -1; /* Identifier */
+s32b INVISIBILITY;
+s32b POISONBLOOD;
+s32b THUNDERSTORM;
+s32b STERILIZE;
+
+s32b BLINK;
+s32b DISARM;
+s32b TELEPORT;
+s32b TELEAWAY;
+s32b RECALL;
+s32b PROBABILITY_TRAVEL;
+
+s32b DEMON_BLADE;
+s32b DEMON_MADNESS;
+s32b DEMON_FIELD;
+s32b DOOM_SHIELD;
+s32b UNHOLY_WORD;
+s32b DEMON_CLOAK;
+s32b DEMON_SUMMON;
+s32b DISCHARGE_MINION;
+s32b CONTROL_DEMON;
+
+s32b STARIDENTIFY;
+s32b IDENTIFY;
+s32b VISION;
+s32b SENSEHIDDEN;
+s32b REVEALWAYS;
+s32b SENSEMONSTERS;
+
+s32b STONESKIN;
+s32b DIG;
+s32b STONEPRISON;
+s32b STRIKE;
+s32b SHAKE;
+
+s32b ERU_SEE;
+s32b ERU_LISTEN;
+s32b ERU_UNDERSTAND;
+s32b ERU_PROT;
+
+s32b GLOBELIGHT;
+s32b FIREFLASH;
+s32b FIERYAURA;
+s32b FIREWALL;
+s32b FIREGOLEM;
+
+s32b CALL_THE_ELEMENTS;
+s32b CHANNEL_ELEMENTS;
+s32b ELEMENTAL_WAVE;
+s32b VAPORIZE;
+s32b GEOLYSIS;
+s32b DRIPPING_TREAD;
+s32b GROW_BARRIER;
+s32b ELEMENTAL_MINION;
+
+s32b MANATHRUST;
+s32b DELCURSES;
+s32b RESISTS;
+s32b MANASHIELD;
+
+s32b MANWE_SHIELD;
+s32b MANWE_AVATAR;
+s32b MANWE_BLESS;
+s32b MANWE_CALL;
+
+s32b MELKOR_CURSE;
+s32b MELKOR_CORPSE_EXPLOSION;
+s32b MELKOR_MIND_STEAL;
+
+s32b RECHARGE;
+s32b SPELLBINDER;
+s32b DISPERSEMAGIC;
+s32b TRACKER;
+s32b INERTIA_CONTROL;
+timer_type *TIMER_INERTIA_CONTROL = 0;
+
+s32b CHARM;
+s32b CONFUSE;
+s32b ARMOROFFEAR;
+s32b STUN;
+
+s32b MAGELOCK;
+s32b SLOWMONSTER;
+s32b ESSENCESPEED;
+s32b BANISHMENT;
+
+s32b TULKAS_AIM;
+s32b TULKAS_WAVE;
+s32b TULKAS_SPIN;
+
+s32b DRAIN;
+s32b GENOCIDE;
+s32b WRAITHFORM;
+s32b FLAMEOFUDUN;
+
+s32b TIDALWAVE;
+s32b ICESTORM;
+s32b ENTPOTION;
+s32b VAPOR;
+s32b GEYSER;
+
+s32b YAVANNA_CHARM_ANIMAL;
+s32b YAVANNA_GROW_GRASS;
+s32b YAVANNA_TREE_ROOTS;
+s32b YAVANNA_WATER_BITE;
+s32b YAVANNA_UPROOT;
+
+s32b GROWTREE;
+s32b HEALING;
+s32b RECOVERY;
+s32b REGENERATION;
+s32b SUMMONANNIMAL;
+s32b GROW_ATHELAS = -1;
+
+s32b DEVICE_HEAL_MONSTER;
+s32b DEVICE_SPEED_MONSTER;
+s32b DEVICE_WISH;
+s32b DEVICE_SUMMON;
+s32b DEVICE_MANA;
+s32b DEVICE_NOTHING;
+s32b DEVICE_HOLY_FIRE;
+s32b DEVICE_THUNDERLORDS;
+
+s32b MUSIC_STOP;
+s32b MUSIC_HOLD;
+s32b MUSIC_CONF;
+s32b MUSIC_STUN;
+s32b MUSIC_LITE;
+s32b MUSIC_HEAL;
+s32b MUSIC_HERO;
+s32b MUSIC_TIME;
+s32b MUSIC_MIND;
+s32b MUSIC_BLOW;
+s32b MUSIC_WIND;
+s32b MUSIC_YLMIR;
+s32b MUSIC_AMBARKANTA;
+
+s32b AULE_FIREBRAND;
+s32b AULE_ENCHANT_WEAPON;
+s32b AULE_ENCHANT_ARMOUR;
+s32b AULE_CHILD;
+
+s32b MANDOS_TEARS_LUTHIEN = -1;
+s32b MANDOS_SPIRIT_FEANTURI = -1;
+s32b MANDOS_TALE_DOOM = -1;
+s32b MANDOS_CALL_HALLS = -1;
+
+s32b ULMO_BELEGAER;
+s32b ULMO_DRAUGHT_ULMONAN;
+s32b ULMO_CALL_ULUMURI;
+s32b ULMO_WRATH;
+
+s32b VARDA_LIGHT_VALINOR;
+s32b VARDA_CALL_ALMAREN;
+s32b VARDA_EVENSTAR;
+s32b VARDA_STARKINDLER;
+
+static s32b get_level_s(int sp, int max)
+{
+ return get_level(sp, max, 1);
+}
+
+static 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 casting_result cast(bool_ effect)
+{
+ return effect ? CAST_OBVIOUS : CAST_HIDDEN;
+}
+
+static casting_result cplus(casting_result old, bool_ effect)
+{
+ if (old == NO_CAST)
+ {
+ return cast(effect);
+ }
+ else
+ {
+ if ((old == CAST_OBVIOUS) || (effect == TRUE)) {
+ return CAST_OBVIOUS;
+ }
+ else
+ {
+ return CAST_HIDDEN;
+ }
+ }
+}
+
+GENERATE_MONSTER_LOOKUP_FN(get_fire_golem, "Fire golem")
+
+// -------------------------------------------------------------
+
+casting_result air_noxious_cloud()
+{
+ int dir, type;
+
+ if (!get_aim_dir(&dir))
+ {
+ return NO_CAST;
+ }
+
+ if (get_level_s(NOXIOUSCLOUD, 50) >= 30)
+ {
+ type = GF_UNBREATH;
+ }
+ else
+ {
+ type = GF_POIS;
+ }
+
+ fire_cloud(type, dir, 7 + get_level_s(NOXIOUSCLOUD, 150), 3, 5 + get_level_s(NOXIOUSCLOUD, 40));
+ return CAST_OBVIOUS;
+}
+
+const char *air_noxious_cloud_info()
+{
+ static char buf[128];
+ sprintf(buf,
+ "dam " FMTs32b " rad 3 dur " FMTs32b,
+ (7 + get_level_s(NOXIOUSCLOUD, 150)),
+ (5 + get_level_s(NOXIOUSCLOUD, 40)));
+ return buf;
+}
+
+casting_result air_wings_of_winds()
+{
+ if (get_level_s(AIRWINGS, 50) >= 16)
+ {
+ if (p_ptr->tim_fly == 0)
+ {
+ return cast(set_tim_fly(randint(10) + 5 + get_level_s(AIRWINGS, 25)));
+ }
+ }
+ else
+ {
+ if (p_ptr->tim_ffall == 0)
+ {
+ return cast(set_tim_ffall(randint(10) + 5 + get_level_s(AIRWINGS, 25)));
+ }
+ }
+
+ return CAST_HIDDEN;
+}
+
+const char *air_wings_of_winds_info()
+{
+ static char buf[128];
+ sprintf(buf, "dur " FMTs32b "+d10", (5 + get_level_s(AIRWINGS, 25)));
+ return buf;
+}
+
+casting_result air_invisibility()
+{
+ if (p_ptr->tim_invisible == 0)
+ {
+ return cast(set_invis(randint(20) + 15 + get_level_s(INVISIBILITY, 50), 20 + get_level_s(INVISIBILITY, 50)));
+ }
+
+ return CAST_HIDDEN;
+}
+
+const char *air_invisibility_info()
+{
+ static char buf[128];
+ sprintf(buf, "dur " FMTs32b "+d20 power " FMTs32b,
+ (15 + get_level_s(INVISIBILITY, 50)),
+ (20 + get_level_s(INVISIBILITY, 50)));
+ return buf;
+}
+
+casting_result air_poison_blood()
+{
+ casting_result result = NO_CAST;
+
+ if (p_ptr->oppose_pois == 0)
+ {
+ result = cplus(result, set_oppose_pois(randint(30) + 25 + get_level_s(POISONBLOOD, 25)));
+ }
+
+ if ((p_ptr->tim_poison == 0) &&
+ (get_level_s(POISONBLOOD, 50) >= 15))
+ {
+ result = cplus(result, set_poison(randint(30) + 25 + get_level_s(POISONBLOOD, 25)));
+ }
+
+ return result;
+}
+
+const char *air_poison_blood_info()
+{
+ static char buf[128];
+ sprintf(buf,
+ "dur " FMTs32b "+d30",
+ (25 + get_level_s(POISONBLOOD, 25)));
+ return buf;
+}
+
+casting_result air_thunderstorm()
+{
+ if (p_ptr->tim_thunder == 0)
+ {
+ return cast(set_tim_thunder(randint(10) + 10 + get_level_s(THUNDERSTORM, 25), 5 + get_level_s(THUNDERSTORM, 10), 10 + get_level_s(THUNDERSTORM, 25)));
+ }
+
+ return CAST_HIDDEN;
+}
+
+const char *air_thunderstorm_info()
+{
+ static char buf[128];
+ sprintf(buf,
+ "dam " FMTs32b "d" FMTs32b " dur " FMTs32b "+d10",
+ (5 + get_level_s(THUNDERSTORM, 10)),
+ (10 + get_level_s(THUNDERSTORM, 25)),
+ (10 + get_level_s(THUNDERSTORM, 25)));
+ return buf;
+}
+
+casting_result air_sterilize()
+{
+ set_no_breeders((30) + 20 + get_level_s(STERILIZE, 70));
+ return CAST_OBVIOUS;
+}
+
+const char *air_sterilize_info()
+{
+ static char buf[128];
+ sprintf(buf,
+ "dur " FMTs32b "+d30",
+ (20 + get_level_s(STERILIZE, 70)));
+ return buf;
+}
+
+casting_result convey_blink()
+{
+ if (get_level_s(BLINK, 50) >= 30)
+ {
+ int oy = p_ptr->py;
+ int ox = p_ptr->px;
+
+ teleport_player(10 + get_level_s(BLINK, 8));
+ create_between_gate(0, oy, ox);
+ return CAST_OBVIOUS;
+ }
+ else
+ {
+ teleport_player(10 + get_level_s(BLINK, 8));
+ return CAST_OBVIOUS;
+ }
+}
+
+const char *convey_blink_info()
+{
+ static char buf[128];
+ sprintf(buf,
+ "distance " FMTs32b,
+ (10 + get_level_s(BLINK, 8)));
+ return buf;
+}
+
+casting_result convey_disarm()
+{
+ casting_result result = NO_CAST;
+
+ result = cplus(result, destroy_doors_touch());
+ if (get_level_s(DISARM, 50) >= 10)
+ {
+ result = cplus(result, destroy_traps_touch());
+ }
+
+ return result;
+}
+
+casting_result convey_teleport()
+{
+ p_ptr->energy -= (25 - get_level_s(TELEPORT, 50));
+ teleport_player(100 + get_level_s(TELEPORT, 100));
+ return CAST_OBVIOUS;
+}
+
+const char *convey_teleport_info()
+{
+ static char buf[128];
+ sprintf(buf,
+ "distance " FMTs32b,
+ (100 + get_level_s(TELEPORT, 100)));
+ return buf;
+}
+
+casting_result convey_teleport_away()
+{
+ if (get_level_s(TELEAWAY, 50) >= 20)
+ {
+ return cast(project_hack(GF_AWAY_ALL, 100));
+ }
+ else if (get_level_s(TELEAWAY, 50) >= 10)
+ {
+ int dir;
+ if (!get_aim_dir(&dir))
+ {
+ return NO_CAST;
+ }
+
+ return cast(fire_ball(GF_AWAY_ALL, dir, 100, 3 + get_level_s(TELEAWAY, 4)));
+ }
+ else
+ {
+ int dir;
+ if (!get_aim_dir(&dir))
+ {
+ return NO_CAST;
+ }
+ return cast(teleport_monster(dir));
+ }
+}
+
+static int recall_get_d()
+{
+ int d = 21 - get_level_s(RECALL, 15);
+ if (d < 0)
+ {
+ d = 0;
+ }
+ return d;
+}
+
+static int recall_get_f()
+{
+ int f = 15 - get_level_s(RECALL, 10);
+ if (f < 1)
+ {
+ f = 1;
+ }
+ return f;
+}
+
+casting_result convey_recall()
+{
+ int x,y;
+ cave_type *c_ptr;
+
+ if (!tgt_pt(&x, &y))
+ {
+ return NO_CAST;
+ }
+
+ c_ptr = &cave[y][x];
+
+ if ((y == p_ptr->py) &&
+ (x == p_ptr->px))
+ {
+ int d = recall_get_d();
+ int f = recall_get_f();
+ recall_player(d, f);
+ return CAST_OBVIOUS;
+ }
+ else if (c_ptr->m_idx > 0)
+ {
+ swap_position(y, x);
+ return CAST_OBVIOUS;
+ }
+ else if (!c_ptr->o_idxs.empty())
+ {
+ // Set the target
+ target_who = -1;
+ target_col = x;
+ target_row = y;
+ // Fetch item
+ if (get_level_s(RECALL, 50) >= 15)
+ {
+ fetch(5, 10 + get_level_s(RECALL, 150), FALSE);
+ }
+ else
+ {
+ fetch(5, 10 + get_level_s(RECALL, 150), TRUE);
+ }
+ return CAST_OBVIOUS;
+ }
+ else
+ {
+ return NO_CAST;
+ }
+}
+
+const char *convey_recall_info()
+{
+ static char buf[128];
+ int d = recall_get_d();
+ int f = recall_get_f();
+
+ sprintf(buf,
+ "dur %d+d%d weight " FMTs32b "lb",
+ f, d, (1 + get_level_s(RECALL, 15)));
+ return buf;
+}
+
+casting_result convey_probability_travel()
+{
+ return cast(set_prob_travel(randint(20) + get_level_s(PROBABILITY_TRAVEL, 60)));
+}
+
+const char *convey_probability_travel_info()
+{
+ static char buf[128];
+ sprintf(buf,
+ "dur " FMTs32b "+d20",
+ get_level_s(PROBABILITY_TRAVEL, 60));
+ return buf;
+}
+
+casting_result demonology_demon_blade()
+{
+ int rad, type;
+
+ type = GF_FIRE;
+ if (get_level_s(DEMON_BLADE, 50) >= 30)
+ {
+ type = GF_HELL_FIRE;
+ }
+
+ rad = 0;
+ if (get_level_s(DEMON_BLADE, 50) >= 45)
+ {
+ rad = 1;
+ }
+
+ return cast(set_project(randint(20) + get_level_s(DEMON_BLADE, 80),
+ type,
+ 4 + get_level_s(DEMON_BLADE, 40),
+ rad,
+ PROJECT_STOP | PROJECT_KILL));
+}
+
+const char *demonology_demon_blade_info()
+{
+ static char buf[128];
+ sprintf(buf,
+ "dur " FMTs32b "+d20 dam " FMTs32b "/blow",
+ (get_level_s(DEMON_BLADE, 80)),
+ (4 + get_level_s(DEMON_BLADE, 40)));
+ return buf;
+}
+
+casting_result demonology_demon_madness()
+{
+ casting_result result = NO_CAST;
+ int dir, type, y1, x1, y2, x2;
+
+ if (!get_aim_dir(&dir))
+ {
+ return NO_CAST;
+ }
+
+ type = GF_CHAOS;
+ if (magik(33))
+ {
+ type = GF_CONFUSION;
+ }
+ if (magik(33))
+ {
+ type = GF_CHARM;
+ }
+
+ // Calculate the coordinates of arrival
+ {
+ // Use the given direction
+ int tx = p_ptr->px + (ddx[dir] * 100);
+ int ty = p_ptr->py + (ddy[dir] * 100);
+
+ // Hack -- Use an actual "target"
+ if ((dir == 5) && target_okay())
+ {
+ tx = target_col;
+ ty = target_row;
+ }
+
+ y1 = ty;
+ x1 = tx;
+ }
+
+ // Calculate the appropriate place
+ y2 = p_ptr->py - (y1 - p_ptr->py);
+ x2 = p_ptr->px - (x1 - p_ptr->px);
+
+ result = cplus(result,
+ project(0, 1 + get_level(DEMON_MADNESS, 4, 0),
+ y1, x1,
+ 20 + get_level_s(DEMON_MADNESS, 200),
+ type,
+ PROJECT_STOP | PROJECT_GRID | PROJECT_ITEM | PROJECT_KILL));
+ result = cplus(result,
+ project(0, 1 + get_level(DEMON_MADNESS, 4, 0),
+ y2, x2,
+ 20 + get_level_s(DEMON_MADNESS, 200),
+ type,
+ PROJECT_STOP | PROJECT_GRID | PROJECT_ITEM | PROJECT_KILL));
+
+ return result;
+}
+
+const char *demonology_demon_madness_info()
+{
+ static char buf[128];
+ sprintf(buf,
+ "dam " FMTs32b " rad " FMTs32b,
+ (20 + get_level_s(DEMON_MADNESS, 200)),
+ (1 + get_level(DEMON_MADNESS, 4, 0)));
+ return buf;
+}
+
+casting_result demonology_demon_field()
+{
+ int dir;
+
+ if (!get_aim_dir(&dir))
+ {
+ return NO_CAST;
+ }
+
+ return cast(fire_cloud(GF_NEXUS,
+ dir,
+ 20 + get_level_s(DEMON_FIELD, 70),
+ 7,
+ 30 + get_level_s(DEMON_FIELD, 100)));
+}
+
+const char *demonology_demon_field_info()
+{
+ static char buf[128];
+ sprintf(buf,
+ "dam " FMTs32b " dur " FMTs32b,
+ (20 + get_level_s(DEMON_FIELD, 70)),
+ (30 + get_level_s(DEMON_FIELD, 100)));
+ return buf;
+}
+
+casting_result demonology_doom_shield()
+{
+ return cast(set_shield(randint(10) + 20 + get_level_s(DOOM_SHIELD, 100),
+ -300 + get_level_s(DOOM_SHIELD, 100),
+ SHIELD_COUNTER,
+ 1 + get_level_s(DOOM_SHIELD, 14),
+ 10 + get_level_s(DOOM_SHIELD, 15)));
+}
+
+const char *demonology_doom_shield_info()
+{
+ static char buf[128];
+ sprintf(buf,
+ "dur " FMTs32b "+d10 dam " FMTs32b "d" FMTs32b,
+ (20 + get_level_s(DOOM_SHIELD, 100)),
+ (1 + get_level_s(DOOM_SHIELD, 14)),
+ (10 + get_level_s(DOOM_SHIELD, 15)));
+ return buf;
+}
+
+casting_result demonology_unholy_word()
+{
+ int x, y;
+ cave_type *c_ptr = NULL;
+
+ if (!tgt_pt(&x, &y))
+ {
+ return NO_CAST;
+ }
+
+ c_ptr = &cave[y][x];
+ if (c_ptr->m_idx > 0)
+ {
+ monster_type *m_ptr = &m_list[c_ptr->m_idx];
+
+ if (m_ptr->status != MSTATUS_PET)
+ {
+ msg_print("You can only target a pet.");
+ return NO_CAST;
+ }
+
+ /* Oops he is angry now */
+ if (magik(30 - get_level(UNHOLY_WORD, 25, 0)))
+ {
+ char buf[128];
+ monster_desc(buf, m_ptr, 0);
+ if (buf[0] != '\0')
+ {
+ buf[0] = toupper(buf[0]);
+ }
+
+ msg_format("%s turns against you.", buf);
+ }
+ else
+ {
+ char buf[128];
+ s32b heal;
+
+ monster_desc(buf, m_ptr, 0);
+ msg_format("You consume %s.", buf);
+
+ 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);
+ }
+
+ return CAST_OBVIOUS;
+ }
+ else
+ {
+ return NO_CAST;
+ }
+}
+
+const char *demonology_unholy_word_info()
+{
+ static char buf[128];
+ sprintf(buf,
+ "heal mhp%% of " FMTs32b "%%",
+ (30 + get_level(UNHOLY_WORD, 50, 0)));
+ return buf;
+}
+
+casting_result demonology_demon_cloak()
+{
+ return cast(set_tim_reflect(randint(5) + 5 + get_level(DEMON_CLOAK, 15, 0)));
+}
+
+const char *demonology_demon_cloak_info()
+{
+ static char buf[128];
+ sprintf(buf,
+ "dur " FMTs32b "+d5",
+ (5 + get_level(DEMON_CLOAK, 15, 0)));
+ return buf;
+}
+
+casting_result demonology_summon_demon()
+{
+ int type, level, minlevel;
+
+ level = dun_level;
+
+ minlevel = 4;
+ if (level < minlevel)
+ {
+ level = minlevel;
+ }
+
+ summon_specific_level = 5 + get_level_s(DEMON_SUMMON, 100);
+
+ type = SUMMON_DEMON;
+ if (get_level_s(DEMON_SUMMON, 50) >= 35)
+ {
+ type = SUMMON_HI_DEMON;
+ }
+
+ if (summon_specific_friendly(p_ptr->py, p_ptr->px, level, type, TRUE))
+ {
+ return CAST_OBVIOUS;
+ }
+ else
+ {
+ msg_print("Something blocks your summoning!");
+ return CAST_HIDDEN;
+ }
+}
+
+const char *demonology_summon_demon_info()
+{
+ static char buf[128];
+ sprintf(buf,
+ "level " FMTs32b,
+ (5 + get_level_s(DEMON_SUMMON, 100)));
+ return buf;
+}
+
+casting_result demonology_discharge_minion()
+{
+ cave_type *c_ptr;
+ int x, y;
+
+ if (!tgt_pt(&x, &y))
+ {
+ return NO_CAST;
+ }
+
+ c_ptr = &cave[y][x];
+ if (c_ptr->m_idx > 0)
+ {
+ s32b dam;
+ monster_type *m_ptr = &m_list[c_ptr->m_idx];
+
+ if (m_ptr->status != MSTATUS_PET)
+ {
+ msg_print("You can only target a pet.");
+ return NO_CAST;
+ }
+
+ delete_monster_idx(c_ptr->m_idx);
+
+ dam = m_ptr->hp;
+ dam = (dam * (20 + get_level(DISCHARGE_MINION, 60, 0))) / 100;
+ if (dam > 100 + get_level(DISCHARGE_MINION, 500, 0))
+ {
+ dam = 100 + get_level(DISCHARGE_MINION, 500, 0);
+ }
+
+ /* We use project instead of fire_ball because we must tell it exactly where to land */
+ return cast(project(0, 2, y, x, dam,
+ GF_GRAVITY,
+ PROJECT_STOP | PROJECT_GRID | PROJECT_ITEM | PROJECT_KILL));
+ }
+ else
+ {
+ return NO_CAST;
+ }
+}
+
+const char *demonology_discharge_minion_info()
+{
+ static char buf[128];
+ sprintf(buf,
+ "dam " FMTs32b "%% max " FMTs32b,
+ (20 + get_level(DISCHARGE_MINION, 60, 0)),
+ (100 + get_level(DISCHARGE_MINION, 500, 0)));
+ return buf;
+}
+
+casting_result demonology_control_demon()
+{
+ int dir;
+ if (!get_aim_dir(&dir))
+ {
+ return NO_CAST;
+ }
+
+ return cast(fire_ball(GF_CONTROL_DEMON, dir, 50 + get_level_s(CONTROL_DEMON, 250), 0));
+}
+
+const char *demonology_control_demon_info()
+{
+ static char buf[128];
+ sprintf(buf,
+ "power " FMTs32b,
+ (50 + get_level_s(CONTROL_DEMON, 250)));
+ return buf;
+}
+
+casting_result divination_greater_identify()
+{
+ if (get_check("Cast on yourself?"))
+ {
+ self_knowledge(NULL);
+ }
+ else
+ {
+ identify_fully();
+ }
+ return CAST_OBVIOUS;
+}
+
+casting_result divination_identify()
+{
+ if (get_level_s(IDENTIFY, 50) >= 27)
+ {
+ casting_result result = NO_CAST;
+ result = cplus(result, identify_pack());
+ result = cplus(result, fire_ball(GF_IDENTIFY, 0, 1, get_level_s(IDENTIFY, 3)));
+ return result;
+ }
+ else if (get_level_s(IDENTIFY, 50) >= 17)
+ {
+ casting_result result = NO_CAST;
+ result = cplus(result, identify_pack());
+ result = cplus(result, fire_ball(GF_IDENTIFY, 0, 1, 0));
+ return result;
+ }
+ else if (ident_spell())
+ {
+ return CAST_OBVIOUS;
+ }
+ else
+ {
+ return NO_CAST;
+ }
+}
+
+const char *divination_identify_info()
+{
+ static char buf[128];
+
+ if (get_level_s(IDENTIFY, 50) >= 27)
+ {
+ sprintf(buf, "rad " FMTs32b, get_level_s(IDENTIFY, 3));
+ return buf;
+ }
+ else
+ {
+ return "";
+ }
+}
+
+casting_result divination_vision()
+{
+ if (get_level_s(VISION, 50) >= 25)
+ {
+ wiz_lite_extra();
+ }
+ else
+ {
+ map_area();
+ }
+ return CAST_OBVIOUS;
+
+}
+
+casting_result divination_sense_hidden()
+{
+ casting_result result = NO_CAST;
+
+ result = cplus(result, detect_traps(15 + get_level(SENSEHIDDEN, 40, 0)));
+ if (get_level_s(SENSEHIDDEN, 50) >= 15)
+ {
+ result = cplus(result, set_tim_invis(10 + randint(20) + get_level_s(SENSEHIDDEN, 40)));
+ }
+
+ return result;
+}
+
+const char *divination_sense_hidden_info()
+{
+ static char buf[128];
+
+ if (get_level_s(SENSEHIDDEN, 50) >= 15)
+ {
+ sprintf(buf,
+ "rad " FMTs32b " dur " FMTs32b "+d20",
+ (15 + get_level_s(SENSEHIDDEN, 40)),
+ (10 + get_level_s(SENSEHIDDEN, 40)));
+ }
+ else
+ {
+ sprintf(buf,
+ "rad " FMTs32b,
+ (15 + get_level_s(SENSEHIDDEN, 40)));
+ }
+
+ return buf;
+}
+
+casting_result divination_reveal_ways()
+{
+ casting_result result = NO_CAST;
+ result = cplus(result, detect_doors(10 + get_level(REVEALWAYS, 40, 0)));
+ result = cplus(result, detect_stairs(10 + get_level(REVEALWAYS, 40, 0)));
+ return result;
+}
+
+const char *divination_reveal_ways_info()
+{
+ static char buf[128];
+ sprintf(buf,
+ "rad " FMTs32b,
+ (10 + get_level_s(REVEALWAYS, 40)));
+ return buf;
+}
+
+casting_result divination_sense_monsters()
+{
+ casting_result result = NO_CAST;
+
+ result = cplus(result, detect_monsters_normal(10 + get_level(SENSEMONSTERS, 40, 0)));
+ if (get_level_s(SENSEMONSTERS, 50) >= 30)
+ {
+ result = cplus(result, set_tim_esp(10 + randint(10) + get_level_s(SENSEMONSTERS, 20)));
+ }
+ return result;
+}
+
+const char *divination_sense_monsters_info()
+{
+ static char buf[128];
+
+ if (get_level_s(SENSEMONSTERS, 50) >= 30)
+ {
+ sprintf(buf,
+ "rad " FMTs32b " dur " FMTs32b "+d10",
+ (10 + get_level_s(SENSEMONSTERS, 40)),
+ (10 + get_level_s(SENSEMONSTERS, 20)));
+ }
+ else
+ {
+ sprintf(buf,
+ "rad " FMTs32b,
+ (10 + get_level_s(SENSEMONSTERS, 40)));
+ }
+
+ return buf;
+}
+
+casting_result earth_stone_skin()
+{
+ int type;
+
+ type = 0;
+ if (get_level_s(STONESKIN, 50) >= 25)
+ {
+ type = SHIELD_COUNTER;
+ }
+
+ return cast(set_shield(randint(10) + 10 + get_level_s(STONESKIN, 100),
+ 10 + get_level_s(STONESKIN, 50),
+ type,
+ 2 + get_level_s(STONESKIN, 5),
+ 3 + get_level_s(STONESKIN, 5)));
+}
+
+const char *earth_stone_skin_info()
+{
+ static char buf[128];
+
+ if (get_level_s(STONESKIN, 50) >= 25)
+ {
+ sprintf(buf,
+ "dam " FMTs32b "d" FMTs32b " dur " FMTs32b "+d10 AC " FMTs32b,
+ (2 + get_level_s(STONESKIN, 5)),
+ (3 + get_level_s(STONESKIN, 5)),
+ (10 + get_level_s(STONESKIN, 100)),
+ (10 + get_level_s(STONESKIN, 50)));
+ }
+ else
+ {
+ sprintf(buf,
+ "dur " FMTs32b "+d10 AC " FMTs32b,
+ (10 + get_level_s(STONESKIN, 100)),
+ (10 + get_level_s(STONESKIN, 50)));
+ }
+
+ return buf;
+}
+
+casting_result earth_dig()
+{
+ int dir;
+ if (!get_aim_dir(&dir))
+ {
+ return NO_CAST;
+ }
+
+ return cast(wall_to_mud(dir));
+}
+
+casting_result earth_stone_prison()
+{
+ int x,y;
+
+ if (get_level_s(STONEPRISON, 50) >= 10)
+ {
+ if (!tgt_pt(&x, &y))
+ {
+ return NO_CAST;
+ }
+ }
+ else
+ {
+ y = p_ptr->py;
+ x = p_ptr->px;
+ }
+
+ wall_stone(y, x);
+ return CAST_OBVIOUS;
+}
+
+casting_result earth_strike()
+{
+ int dir, dmg;
+
+ if (!get_aim_dir(&dir))
+ {
+ return NO_CAST;
+ }
+
+ dmg = 50 + get_level_s(STRIKE, 50);
+ if (get_level_s(STRIKE, 50) >= 12)
+ {
+ return cast(fire_ball(GF_FORCE, dir, dmg, 1));
+ }
+ else
+ {
+ return cast(fire_ball(GF_FORCE, dir, dmg, 0));
+ }
+}
+
+const char *earth_strike_info()
+{
+ static char buf[128];
+ int dmg = 50 + get_level_s(STRIKE, 50);
+
+ if (get_level_s(STRIKE, 50) >= 12)
+ {
+ sprintf(buf, "dam %d rad 1", dmg);
+ }
+ else
+ {
+ sprintf(buf, "dam %d", dmg);
+ }
+
+ return buf;
+}
+
+casting_result earth_shake()
+{
+ int x,y;
+
+ if (get_level_s(SHAKE, 50) >= 10)
+ {
+ if (!tgt_pt(&x, &y))
+ {
+ return NO_CAST;
+ }
+ }
+ else
+ {
+ x = p_ptr->px;
+ y = p_ptr->py;
+ }
+ earthquake(y, x, 4 + get_level_s(SHAKE, 10));
+ return CAST_OBVIOUS;
+}
+
+const char *earth_shake_info()
+{
+ static char buf[128];
+ sprintf(buf, "rad " FMTs32b, (4 + get_level_s(SHAKE, 10)));
+ return buf;
+}
+
+casting_result eru_see_the_music()
+{
+ casting_result result = NO_CAST;
+
+ result = cplus(result, set_tim_invis(randint(20) + 10 + get_level_s(ERU_SEE, 100)));
+
+ if (get_level_s(ERU_SEE, 50) >= 30)
+ {
+ wiz_lite_extra();
+ result = CAST_OBVIOUS;
+ }
+ else if (get_level_s(ERU_SEE, 50) >= 10)
+ {
+ map_area();
+ result = CAST_OBVIOUS;
+ }
+
+ if (get_level_s(ERU_SEE, 50) >= 20)
+ {
+ result = cplus(result, set_blind(0));
+ }
+
+ return result;
+}
+
+const char *eru_see_the_music_info()
+{
+ static char buf[128];
+ sprintf(buf,
+ "dur " FMTs32b "+d20",
+ (10 + get_level_s(ERU_SEE, 100)));
+ return buf;
+}
+
+casting_result eru_listen_to_the_music()
+{
+ casting_result result = NO_CAST;
+
+ if (get_level_s(ERU_LISTEN, 50) >= 30)
+ {
+ result = cplus(result, ident_all());
+ result = cplus(result, identify_pack());
+ }
+ else if (get_level_s(ERU_LISTEN, 50) >= 14)
+ {
+ result = cplus(result, identify_pack());
+ }
+ else
+ {
+ result = cplus(result, ident_spell());
+ }
+
+ return result;
+}
+
+casting_result eru_know_the_music()
+{
+ if (get_level_s(ERU_UNDERSTAND, 50) >= 10)
+ {
+ identify_pack_fully();
+ return CAST_OBVIOUS;
+ }
+ else
+ {
+ return cast(identify_fully());
+ }
+}
+
+casting_result eru_lay_of_protection()
+{
+ return cast(fire_ball(GF_MAKE_GLYPH, 0, 1, 1 + get_level(ERU_PROT, 2, 0)));
+}
+
+const char *eru_lay_of_protection_info()
+{
+ static char buf[128];
+ sprintf(buf,
+ "rad " FMTs32b,
+ (1 + get_level(ERU_PROT, 2, 0)));
+ return buf;
+}
+
+casting_result fire_globe_of_light()
+{
+ casting_result result = NO_CAST;
+
+ if (get_level_s(GLOBELIGHT, 50) >= 3)
+ {
+ result = cplus(result, lite_area(10, 4));
+ }
+ else
+ {
+ lite_room(p_ptr->py, p_ptr->px);
+ result = CAST_OBVIOUS;
+ }
+
+ if (get_level_s(GLOBELIGHT, 50) >= 15)
+ {
+ result = cplus(result,
+ fire_ball(GF_LITE,
+ 0,
+ 10 + get_level_s(GLOBELIGHT, 100),
+ 5 + get_level_s(GLOBELIGHT, 6)));
+ p_ptr->update |= PU_VIEW;
+ }
+
+ return result;
+}
+
+const char *fire_globe_of_light_info()
+{
+ static char buf[128];
+
+ if (get_level_s(GLOBELIGHT, 50) >= 15)
+ {
+ sprintf(buf, "dam " FMTs32b " rad " FMTs32b,
+ (10 + get_level_s(GLOBELIGHT, 100)),
+ (5 + get_level_s(GLOBELIGHT, 6)));
+ }
+ else
+ {
+ buf[0] = '\0';
+ }
+
+ return buf;
+}
+
+casting_result fire_fireflash()
+{
+ int dir;
+ int type = GF_FIRE;
+
+ if (get_level_s(FIREFLASH, 50) >= 20)
+ {
+ type = GF_HOLY_FIRE;
+ }
+
+ if (!get_aim_dir(&dir))
+ {
+ return NO_CAST;
+ }
+
+ return cast(fire_ball(type, dir,
+ 20 + get_level_s(FIREFLASH, 500),
+ 2 + get_level_s(FIREFLASH, 5)));
+}
+
+const char *fire_fireflash_info()
+{
+ static char buf[128];
+ sprintf(buf,
+ "dam " FMTs32b " rad " FMTs32b,
+ (20 + get_level_s(FIREFLASH, 500)),
+ (2 + get_level_s(FIREFLASH, 5)));
+ return buf;
+}
+
+casting_result fire_fiery_shield()
+{
+ int type = SHIELD_FIRE;
+ if (get_level_s(FIERYAURA, 50) >= 8)
+ {
+ type = SHIELD_GREAT_FIRE;
+ }
+
+ return cast(set_shield(randint(20) + 10 + get_level_s(FIERYAURA, 70),
+ 10,
+ type,
+ 5 + get_level_s(FIERYAURA, 10),
+ 5 + get_level_s(FIERYAURA, 7)));
+}
+
+const char *fire_fiery_shield_info()
+{
+ static char buf[128];
+ sprintf(buf,
+ "dam " FMTs32b "d" FMTs32b " dur " FMTs32b "+d20",
+ (5 + get_level_s(FIERYAURA, 15)),
+ (5 + get_level_s(FIERYAURA, 7)),
+ (10 + get_level_s(FIERYAURA, 70)));
+ return buf;
+}
+
+casting_result fire_firewall()
+{
+ int dir;
+ int type = GF_FIRE;
+ if (get_level_s(FIREWALL, 50) >= 6)
+ {
+ type = GF_HELL_FIRE;
+ }
+
+ if (!get_aim_dir(&dir))
+ {
+ return NO_CAST;
+ }
+
+ fire_wall(type, dir,
+ 40 + get_level_s(FIREWALL, 150),
+ 10 + get_level_s(FIREWALL, 14));
+ return CAST_OBVIOUS;
+}
+
+const char *fire_firewall_info()
+{
+ static char buf[128];
+ sprintf(buf,
+ "dam " FMTs32b " dur " FMTs32b,
+ (40 + get_level_s(FIREWALL, 150)),
+ (10 + get_level_s(FIREWALL, 14)));
+ return buf;
+}
+
+object_filter_t const &item_tester_hook_fire_golem()
+{
+ using namespace object_filter;
+ static auto instance = And(
+ TVal(TV_LITE),
+ Or(
+ SVal(SV_LITE_TORCH),
+ SVal(SV_LITE_LANTERN)));
+ return instance;
+}
+
+casting_result fire_golem()
+{
+ /* Can we reconnect ? */
+ if (do_control_reconnect())
+ {
+ msg_print("Control re-established.");
+ return NO_CAST;
+ }
+
+ int item;
+ if (!get_item(&item,
+ "Which light source do you want to use to create the golem?",
+ "You have no light source for the golem",
+ USE_INVEN | USE_EQUIP,
+ item_tester_hook_fire_golem()))
+ {
+ return NO_CAST;
+ }
+
+ /* Destroy the source object */
+ inc_stack_size(item, -1);
+
+ /* Find a place for it */
+ int x, y;
+ find_position(p_ptr->py, p_ptr->px, &y, &x);
+
+ /* Summon it */
+ int r_idx = get_fire_golem();
+ m_allow_special[r_idx] = TRUE;
+ int m_idx = place_monster_one(y, x, r_idx, 0, FALSE, MSTATUS_FRIEND);
+ m_allow_special[r_idx] = FALSE;
+
+ /* level it */
+ if (m_idx != 0)
+ {
+ monster_set_level(m_idx, 7 + get_level_s(FIREGOLEM, 70));
+ p_ptr->control = m_idx;
+ m_list[m_idx].mflag |= MFLAG_CONTROL;
+ }
+
+ return CAST_OBVIOUS;
+}
+
+const char *fire_golem_info()
+{
+ static char buf[128];
+ sprintf(buf,
+ "golem level " FMTs32b,
+ (7 + get_level_s(FIREGOLEM, 70)));
+ return buf;
+}
+
+casting_result geomancy_call_the_elements()
+{
+ int dir = 0;
+
+ if (get_level_s(CALL_THE_ELEMENTS, 50) >= 17)
+ {
+ if (!get_aim_dir(&dir))
+ {
+ return NO_CAST;
+ }
+ }
+
+ fire_ball(GF_ELEMENTAL_GROWTH,
+ dir,
+ 1,
+ 1 + get_level(CALL_THE_ELEMENTS, 5, 0));
+
+ return CAST_OBVIOUS;
+}
+
+const char *geomancy_call_the_elements_info()
+{
+ static char buf[128];
+ sprintf(buf,
+ "rad " FMTs32b,
+ (1 + get_level(CALL_THE_ELEMENTS, 5, 0)));
+ return buf;
+}
+
+casting_result geomancy_channel_elements()
+{
+ channel_the_elements(p_ptr->py, p_ptr->px, get_level_s(CHANNEL_ELEMENTS, 50));
+ return CAST_OBVIOUS;
+}
+
+typedef struct eff_type eff_type;
+struct eff_type {
+ s16b feat;
+ s16b low_effect;
+ s16b high_effect;
+ int damage;
+};
+
+static eff_type *geomancy_find_effect(eff_type effs[], int feat)
+{
+ int i;
+ for (i = 0; effs[i].feat >= 0; i++)
+ {
+ eff_type *p = &effs[i];
+ if (p->feat == feat)
+ {
+ return p;
+ }
+ }
+ return NULL;
+}
+
+static u32b dir_to_eff_flags(int dir)
+{
+ assert(dir >= 1);
+ assert(dir <= 9);
+
+ switch (dir)
+ {
+ case 1: return EFF_DIR1;
+ case 2: return EFF_DIR2;
+ case 3: return EFF_DIR3;
+ case 4: return EFF_DIR4;
+ case 5: return 0;
+ case 6: return EFF_DIR6;
+ case 7: return EFF_DIR7;
+ case 8: return EFF_DIR8;
+ case 9: return EFF_DIR9;
+ default:
+ assert(FALSE);
+ }
+ /* Default */
+ return 0;
+}
+
+casting_result geomancy_elemental_wave()
+{
+ int dir = 0, y = 0, x = 0;
+ eff_type *eff_ptr = NULL;
+ eff_type t[] =
+ {
+ /* Earth */
+ { 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) },
+
+ /* Water */
+ { 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 */
+ { 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) },
+ { -1, -1, -1, -1 },
+ };
+
+ if (!get_rep_dir(&dir))
+ {
+ return NO_CAST;
+ }
+
+ y = ddy[dir] + p_ptr->py;
+ x = ddx[dir] + p_ptr->px;
+
+ eff_ptr = geomancy_find_effect(t, cave[y][x].feat);
+
+ if (!eff_ptr)
+ {
+ msg_print("You cannot channel this area.");
+ return NO_CAST;
+ }
+ else
+ {
+ s16b typ = eff_ptr->low_effect;
+ u32b dir_flag = dir_to_eff_flags(dir);
+
+ if (get_level_s(ELEMENTAL_WAVE, 50) >= 20)
+ {
+ typ = eff_ptr->high_effect;
+ }
+
+ cave_set_feat(y, x, FEAT_FLOOR);
+
+ fire_wave(typ,
+ 0,
+ eff_ptr->damage,
+ 0,
+ 6 + get_level_s(ELEMENTAL_WAVE, 20),
+ EFF_WAVE + EFF_LAST + dir_flag);
+
+ return CAST_OBVIOUS;
+ }
+}
+
+casting_result geomancy_vaporize()
+{
+ eff_type *eff_ptr = NULL;
+ eff_type 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) },
+ { -1, -1, -1, -1 },
+ };
+
+ eff_ptr = geomancy_find_effect(t, cave[p_ptr->py][p_ptr->px].feat);
+
+ if (!eff_ptr)
+ {
+ msg_print("You cannot channel this area.");
+ return NO_CAST;
+ }
+ else
+ {
+ s16b typ = eff_ptr->low_effect;
+ if (get_level_s(VAPORIZE, 50) >= 20)
+ {
+ typ = eff_ptr->high_effect;
+ }
+
+ cave_set_feat(p_ptr->py, p_ptr->px, FEAT_FLOOR);
+
+ fire_cloud(typ,
+ 0,
+ eff_ptr->damage,
+ 1 + get_level_s(VAPORIZE, 4),
+ 10 + get_level_s(VAPORIZE, 20));
+
+ return CAST_OBVIOUS;
+ }
+}
+
+const char *geomancy_vaporize_info()
+{
+ static char buf[128];
+ sprintf(buf,
+ "rad " FMTs32b " dur " FMTs32b,
+ (1 + get_level_s(VAPORIZE, 4)),
+ (10 + get_level_s(VAPORIZE, 20)));
+ return buf;
+}
+
+bool_ geomancy_vaporize_depends()
+{
+ return get_skill(SKILL_AIR) >= 4;
+}
+
+casting_result geomancy_geolysis()
+{
+ int dir = 0;
+
+ if (!get_rep_dir(&dir))
+ {
+ return NO_CAST;
+ }
+
+ msg_print("Elements recombine before you, laying down an open path.");
+ geomancy_dig(p_ptr->py, p_ptr->px, dir, 5 + get_level_s(GEOLYSIS, 12));
+
+ return CAST_OBVIOUS;
+}
+
+const char *geomancy_geolysis_info()
+{
+ static char buf[128];
+ sprintf(buf,
+ "length " FMTs32b,
+ (5 + get_level_s(GEOLYSIS, 12)));
+ return buf;
+}
+
+bool_ geomancy_geolysis_depends()
+{
+ return get_skill(SKILL_EARTH) >= 7;
+}
+
+casting_result geomancy_dripping_tread()
+{
+ if (p_ptr->dripping_tread == 0)
+ {
+ p_ptr->dripping_tread = randint(15) + 10 + get_level_s(DRIPPING_TREAD, 50);
+ msg_print("You start dripping raw elemental energies.");
+ }
+ else
+ {
+ p_ptr->dripping_tread = 0;
+ msg_print("You stop dripping raw elemental energies.");
+ }
+
+ return CAST_OBVIOUS;
+}
+
+const char *geomancy_dripping_tread_info()
+{
+ static char buf[128];
+ sprintf(buf,
+ "dur " FMTs32b "+d15 movs",
+ (10 + get_level_s(DRIPPING_TREAD, 50)));
+ return buf;
+}
+
+bool_ geomancy_dripping_tread_depends()
+{
+ return get_skill(SKILL_WATER) >= 10;
+}
+
+casting_result geomancy_grow_barrier()
+{
+ int dir = 0;
+
+ if (get_level_s(GROW_BARRIER, 50) >= 20)
+ {
+ if (!get_aim_dir(&dir))
+ {
+ return NO_CAST;
+ }
+ }
+
+ fire_ball(GF_ELEMENTAL_WALL, dir, 1, 1);
+ return CAST_OBVIOUS;
+}
+
+bool_ geomancy_grow_barrier_depends()
+{
+ return get_skill(SKILL_EARTH) >= 12;
+}
+
+typedef struct geo_summon geo_summon;
+struct geo_summon {
+ s16b feat;
+ s16b skill_idx;
+ cptr *summon_names;
+};
+
+geo_summon *geomancy_find_summon(geo_summon summons[], int feat)
+{
+ int i;
+ for (i = 0; summons[i].feat >= 0; i++)
+ {
+ geo_summon *summon = &summons[i];
+ if (summon->feat == feat)
+ {
+ return summon;
+ }
+ }
+ return NULL;
+}
+
+int geomancy_count_elements(cptr *elements)
+{
+ int i;
+ for (i = 0; elements[i] != NULL; i++)
+ {
+ }
+ return i;
+}
+
+casting_result geomancy_elemental_minion()
+{
+ int dir = 0;
+ int x = 0, y = 0;
+ geo_summon *summon_ptr = NULL;
+ cptr earth_summons[] = {
+ "Earth elemental",
+ "Xorn",
+ "Xaren",
+ NULL
+ };
+ cptr air_summons[] = {
+ "Air elemental",
+ "Ancient blue dragon",
+ "Great Storm Wyrm",
+ "Sky Drake",
+ NULL
+ };
+ cptr fire_summons[] = {
+ "Fire elemental",
+ "Ancient red dragon",
+ NULL
+ };
+ cptr water_summons[] = {
+ "Water elemental",
+ "Water troll",
+ "Water demon",
+ NULL
+ };
+ geo_summon summons[] = {
+ { FEAT_WALL_EXTRA, SKILL_EARTH, earth_summons },
+ { FEAT_WALL_OUTER, SKILL_EARTH, earth_summons },
+ { FEAT_WALL_INNER, SKILL_EARTH, earth_summons },
+ { FEAT_WALL_SOLID, SKILL_EARTH, earth_summons },
+ { FEAT_MAGMA, SKILL_EARTH, earth_summons },
+ { FEAT_QUARTZ, SKILL_EARTH, earth_summons },
+ { FEAT_MAGMA_H, SKILL_EARTH, earth_summons },
+ { FEAT_QUARTZ_H, SKILL_EARTH, earth_summons },
+ { FEAT_MAGMA_K, SKILL_EARTH, earth_summons },
+ { FEAT_QUARTZ_K, SKILL_EARTH, earth_summons },
+
+ { FEAT_DARK_PIT, SKILL_AIR, air_summons },
+
+ { FEAT_SANDWALL, SKILL_FIRE, fire_summons },
+ { FEAT_SANDWALL_H, SKILL_FIRE, fire_summons },
+ { FEAT_SANDWALL_K, SKILL_FIRE, fire_summons },
+ { FEAT_SHAL_LAVA, SKILL_FIRE, fire_summons },
+ { FEAT_DEEP_LAVA, SKILL_FIRE, fire_summons },
+
+ { FEAT_ICE_WALL, SKILL_WATER, water_summons },
+ { FEAT_SHAL_WATER, SKILL_WATER, water_summons },
+ { FEAT_DEEP_WATER, SKILL_WATER, water_summons },
+
+ { -1, -1, NULL },
+ };
+
+ if (!get_rep_dir(&dir))
+ {
+ return NO_CAST;
+ }
+
+ y = ddy[dir] + p_ptr->py;
+ x = ddx[dir] + p_ptr->px;
+
+ summon_ptr = geomancy_find_summon(summons, cave[y][x].feat);
+
+ if (!summon_ptr)
+ {
+ msg_print("You cannot summon from this area.");
+ return NO_CAST;
+ }
+ else
+ {
+ cptr *names = summon_ptr->summon_names;
+ int max = get_skill_scale(summon_ptr->skill_idx,
+ geomancy_count_elements(names));
+ int r_idx = test_monster_name(names[rand_int(max)]);
+ int mx, my, m_idx;
+
+ /* Summon it */
+ find_position(y, x, &my, &mx);
+ m_idx = place_monster_one(my, mx, r_idx, 0, FALSE, MSTATUS_FRIEND);
+
+ /* Level it */
+ if (m_idx)
+ {
+ monster_set_level(m_idx, 10 + get_level_s(ELEMENTAL_MINION, 120));
+ }
+
+ cave_set_feat(y, x, FEAT_FLOOR);
+
+ return CAST_OBVIOUS;
+ }
+}
+
+const char *geomancy_elemental_minion_info()
+{
+ static char buf[128];
+ sprintf(buf,
+ "min level " FMTs32b,
+ (10 + get_level_s(ELEMENTAL_MINION, 120)));
+ return buf;
+}
+
+static void get_manathrust_dam(s16b *num, s16b *sides)
+{
+ *num = 3 + get_level_s(MANATHRUST, 50);
+ *sides = 1 + get_level_s(MANATHRUST, 20);
+}
+
+casting_result mana_manathrust()
+{
+ int dir;
+ s16b num = 0;
+ s16b sides = 0;
+
+ if (!get_aim_dir(&dir))
+ {
+ return NO_CAST;
+ }
+
+ get_manathrust_dam(&num, &sides);
+ return cast(fire_bolt(GF_MANA, dir, damroll(num, sides)));
+}
+
+const char *mana_manathrust_info()
+{
+ s16b num = 0;
+ s16b sides = 0;
+ static char buf[128];
+
+ get_manathrust_dam(&num, &sides);
+ sprintf(buf,
+ "dam " FMTs16b "d" FMTs16b,
+ num,
+ sides);
+ return buf;
+}
+
+casting_result mana_remove_curses()
+{
+ casting_result result = NO_CAST;
+
+ if (get_level_s(DELCURSES, 50) >= 20)
+ {
+ result = cplus(result, remove_all_curse());
+ }
+ else
+ {
+ result = cplus(result, remove_curse());
+ }
+
+ if (result == CAST_OBVIOUS)
+ {
+ msg_print("The curse is broken!");
+ }
+
+ return result;
+}
+
+casting_result mana_elemental_shield()
+{
+ casting_result res = NO_CAST;
+
+ if (p_ptr->oppose_fire == 0)
+ {
+ res = cplus(res, set_oppose_fire(randint(10) + 15 + get_level_s(RESISTS, 50)));
+ }
+
+ if (p_ptr->oppose_cold == 0)
+ {
+ res = cplus(res, set_oppose_cold(randint(10) + 15 + get_level_s(RESISTS, 50)));
+ }
+
+ if (p_ptr->oppose_elec == 0)
+ {
+ res = cplus(res, set_oppose_elec(randint(10) + 15 + get_level_s(RESISTS, 50)));
+ }
+
+ if (p_ptr->oppose_acid == 0)
+ {
+ res = cplus(res, set_oppose_acid(randint(10) + 15 + get_level_s(RESISTS, 50)));
+ }
+
+ return res;
+}
+
+const char *mana_elemental_shield_info()
+{
+ static char buf[128];
+ sprintf(buf,
+ "dur " FMTs32b "+d10",
+ (15 + get_level_s(RESISTS, 50)));
+ return buf;
+}
+
+casting_result mana_disruption_shield()
+{
+ if (get_level_s(MANASHIELD, 50) >= 5)
+ {
+ if (p_ptr->invuln == 0)
+ {
+ return cast(set_invuln(randint(5) + 3 + get_level_s(MANASHIELD, 10)));
+ }
+ }
+ else if (p_ptr->disrupt_shield == 0)
+ {
+ return cast(set_disrupt_shield(randint(5) + 3 + get_level_s(MANASHIELD, 10)));
+ }
+
+ return NO_CAST;
+}
+
+const char *mana_disruption_shield_info()
+{
+ static char buf[128];
+ sprintf(buf,
+ "dur " FMTs32b "+d5",
+ (3 + get_level_s(MANASHIELD, 10)));
+ return buf;
+}
+
+casting_result manwe_wind_shield()
+{
+ casting_result res = NO_CAST;
+ s32b dur = get_level_s(MANWE_SHIELD, 50) + 10 + randint(20);
+
+ res = cplus(res, set_protevil(dur));
+
+ if (get_level_s(MANWE_SHIELD, 50) >= 10)
+ {
+ int type = 0;
+ if (get_level_s(MANWE_SHIELD, 50) >= 20)
+ {
+ type = SHIELD_COUNTER;
+ }
+
+ res = cplus(res,
+ set_shield(dur,
+ get_level_s(MANWE_SHIELD, 30),
+ type,
+ 1 + get_level_s(MANWE_SHIELD, 2),
+ 1 + get_level_s(MANWE_SHIELD, 6)));
+ }
+
+ return res;
+}
+
+const char *manwe_wind_shield_info()
+{
+ static char buf[128];
+
+ sprintf(buf,
+ "dur " FMTs32b "+d20",
+ (get_level_s(MANWE_SHIELD, 50) + 10));
+
+ if (get_level_s(MANWE_SHIELD, 50) >= 10)
+ {
+ char tmp[128];
+ sprintf(tmp, " AC " FMTs32b, get_level_s(MANWE_SHIELD, 30));
+ strcat(buf, tmp);
+ }
+
+ if (get_level_s(MANWE_SHIELD, 50) >= 20)
+ {
+ char tmp[128];
+ sprintf(tmp, " dam " FMTs32b "d" FMTs32b,
+ (1 + get_level_s(MANWE_SHIELD, 2)),
+ (1 + get_level_s(MANWE_SHIELD, 6)));
+ strcat(buf, tmp);
+ }
+
+ return buf;
+}
+
+casting_result manwe_avatar()
+{
+ s16b mimic_idx = resolve_mimic_name("Maia");
+ assert(mimic_idx >= 0);
+
+ return cast(set_mimic(get_level_s(MANWE_AVATAR, 20) + randint(10),
+ mimic_idx,
+ p_ptr->lev));
+}
+
+const char *manwe_avatar_info()
+{
+ static char buf[128];
+ sprintf(buf,
+ "dur " FMTs32b "+d10",
+ get_level_s(MANWE_AVATAR, 20));
+ return buf;
+}
+
+casting_result manwe_blessing()
+{
+ casting_result res = NO_CAST;
+ s32b dur = get_level_s(MANWE_BLESS, 70) + 30 + randint(40);
+
+ res = cplus(res, set_blessed(dur));
+ res = cplus(res, set_afraid(0));
+ res = cplus(res, set_lite(0));
+
+ if (get_level_s(MANWE_BLESS, 50) >= 10)
+ {
+ res = cplus(res, set_hero(dur));
+ }
+ if (get_level_s(MANWE_BLESS, 50) >= 20)
+ {
+ res = cplus(res, set_shero(dur));
+ }
+ if (get_level_s(MANWE_BLESS, 50) >= 30)
+ {
+ res = cplus(res, set_holy(dur));
+ }
+
+ return res;
+}
+
+const char *manwe_blessing_info()
+{
+ static char buf[128];
+ sprintf(buf,
+ "dur " FMTs32b "+d40",
+ get_level_s(MANWE_BLESS, 70) + 30);
+ return buf;
+}
+
+casting_result manwe_call()
+{
+ int y = 0, x = 0, m_idx = -1, r_idx = -1;
+
+ find_position(p_ptr->py, p_ptr->px, &y, &x);
+
+ r_idx = test_monster_name("Great eagle");
+ assert(r_idx >= 1);
+
+ m_idx = place_monster_one(y, x, r_idx, 0, FALSE, MSTATUS_FRIEND);
+
+ if (m_idx > 0)
+ {
+ monster_set_level(m_idx, 20 + get_level(MANWE_CALL, 70, 0));
+ return CAST_OBVIOUS;
+ }
+
+ return NO_CAST;
+}
+
+const char *manwe_call_info()
+{
+ static char buf[128];
+ sprintf(buf,
+ "level " FMTs32b,
+ get_level_s(MANWE_CALL, 70) + 20);
+ return buf;
+}
+
+void do_melkor_curse(int m_idx)
+{
+ assert(m_idx >= 0);
+
+ monster_type *m_ptr = &m_list[m_idx];
+
+ if (get_level_s(MELKOR_CURSE, 50) >= 35)
+ {
+ auto const r_ptr = m_ptr->race();
+
+ m_ptr->maxhp = m_ptr->maxhp - r_ptr->hside;
+ if (m_ptr->maxhp < 1)
+ {
+ m_ptr->maxhp = 1;
+ }
+ if (m_ptr->hp > m_ptr->maxhp)
+ {
+ m_ptr->hp = m_ptr->maxhp;
+ }
+
+ p_ptr->redraw |= PR_FRAME;
+ }
+
+ if (get_level_s(MELKOR_CURSE, 50) >= 25)
+ {
+ m_ptr->speed = m_ptr->speed - get_level_s(MELKOR_CURSE, 7);
+ m_ptr->mspeed = m_ptr->mspeed - get_level_s(MELKOR_CURSE, 7);
+
+ if (m_ptr->speed < 70)
+ {
+ m_ptr->speed = 70;
+ }
+
+ if (m_ptr->mspeed < 70)
+ {
+ m_ptr->mspeed = 70;
+ }
+ }
+
+ if (get_level_s(MELKOR_CURSE, 50) >= 15)
+ {
+ m_ptr->ac = m_ptr->ac - get_level_s(MELKOR_CURSE, 50);
+
+ if (m_ptr->ac < -70)
+ {
+ m_ptr->ac = -70;
+ }
+ }
+
+ /* Reduce melee too */
+ {
+ int i;
+ int pow = get_level_s(MELKOR_CURSE, 2);
+
+ for (i = 0; i < 4; i++)
+ {
+ if (m_ptr->blow[i].d_dice <= 0)
+ {
+ break;
+ }
+
+ if (m_ptr->blow[i].d_dice < pow)
+ {
+ pow = m_ptr->blow[i].d_dice;
+ }
+ if (m_ptr->blow[i].d_side < pow)
+ {
+ pow = m_ptr->blow[i].d_side;
+ }
+
+ m_ptr->blow[i].d_dice = m_ptr->blow[i].d_dice - pow;
+ }
+ }
+
+ /* Describe what happened */
+ {
+ char buf[128];
+
+ monster_desc(buf, m_ptr, 0);
+ buf[0] = toupper(buf[0]);
+
+ strcat(buf, " looks weaker.");
+ msg_print(buf);
+ }
+
+ /* wake it */
+ m_ptr->csleep = 0;
+}
+
+casting_result melkor_curse()
+{
+ int dir = 0;
+
+ if (!get_aim_dir(&dir))
+ {
+ return NO_CAST;
+ }
+
+ if (target_who < 0)
+ {
+ msg_print("You must target a monster.");
+ return NO_CAST;
+ }
+ else
+ {
+ do_melkor_curse(target_who);
+ return CAST_OBVIOUS;
+ }
+}
+
+casting_result melkor_corpse_explosion()
+{
+ return cast(fire_ball(GF_CORPSE_EXPL,
+ 0,
+ 20 + get_level_s(MELKOR_CORPSE_EXPLOSION, 70),
+ 2 + get_level_s(MELKOR_CORPSE_EXPLOSION, 5)));
+}
+
+const char *melkor_corpse_explosion_info()
+{
+ static char buf[128];
+ sprintf(buf,
+ "dam " FMTs32b "%%",
+ 20 + get_level_s(MELKOR_CORPSE_EXPLOSION, 70));
+ return buf;
+}
+
+casting_result melkor_mind_steal()
+{
+ int dir = 0;
+
+ if (!get_aim_dir(&dir))
+ {
+ return NO_CAST;
+ }
+
+ if (target_who < 0)
+ {
+ msg_print("You must target a monster.");
+ return NO_CAST;
+ }
+ else
+ {
+ monster_type *m_ptr = &m_list[target_who];
+ int chance = get_level_s(MELKOR_MIND_STEAL, 50);
+
+ char buf[128];
+ monster_desc(buf, m_ptr, 0);
+ buf[0] = toupper(buf[0]);
+
+ auto const r_ptr = m_ptr->race();
+ if ((randint(m_ptr->level) < chance) &&
+ ((r_ptr->flags1 & RF1_UNIQUE) == 0))
+ {
+ p_ptr->control = target_who;
+ m_ptr->mflag |= MFLAG_CONTROL;
+ strcat(buf, " falls under your control.");
+ }
+ else
+ {
+ strcat(buf, " resists.");
+ }
+
+ msg_print(buf);
+ return CAST_OBVIOUS;
+ }
+}
+
+const char *melkor_mind_steal_info()
+{
+ static char buf[128];
+ sprintf(buf,
+ "chance 1d(mlvl)<" FMTs32b,
+ get_level_s(MELKOR_MIND_STEAL, 50));
+ return buf;
+}
+
+casting_result meta_recharge()
+{
+ return cast(recharge(60 + get_level_s(RECHARGE, 140)));
+}
+
+const char *meta_recharge_info()
+{
+ static char buf[128];
+ sprintf(buf,
+ "power " FMTs32b,
+ 60 + get_level_s(RECHARGE, 140));
+ return buf;
+}
+
+static int get_spellbinder_max()
+{
+ int i = get_level_s(SPELLBINDER, 4);
+ if (i > 4)
+ {
+ i = 4;
+ }
+ return i;
+}
+
+casting_result meta_spellbinder()
+{
+ if (p_ptr->spellbinder_num != 0)
+ {
+ struct trigger {
+ int idx;
+ cptr desc;
+ };
+ struct trigger triggers[] = {
+ { SPELLBINDER_HP75, "75% HP", },
+ { SPELLBINDER_HP50, "50% HP", },
+ { SPELLBINDER_HP25, "25% HP", },
+ { -1, NULL, },
+ };
+ int trigger_idx = -1;
+ int i;
+
+ assert(p_ptr->spellbinder_trigger >= 0);
+
+ for (trigger_idx = 0; triggers[trigger_idx].idx >= 0; trigger_idx++)
+ {
+ if (triggers[trigger_idx].idx == p_ptr->spellbinder_trigger)
+ {
+ break;
+ }
+ }
+
+ msg_print("The spellbinder is already active.");
+ msg_format("It will trigger at %s.", triggers[trigger_idx].desc);
+ msg_print("With the spells: ");
+ for (i = 0; i < p_ptr->spellbinder_num; i++)
+ {
+ msg_print(spell_type_name(spell_at(p_ptr->spellbinder[i])));
+ }
+
+ /* Doesn't cost anything */
+ return NO_CAST;
+ }
+ else
+ {
+ char c;
+ int i;
+
+ if (!get_com("Trigger at [a]75% hp [b]50% hp [c]25% hp?", &c))
+ {
+ return NO_CAST;
+ }
+
+ switch (c)
+ {
+ case 'a':
+ p_ptr->spellbinder_trigger = SPELLBINDER_HP75;
+ break;
+ case 'b':
+ p_ptr->spellbinder_trigger = SPELLBINDER_HP50;
+ break;
+ case 'c':
+ p_ptr->spellbinder_trigger = SPELLBINDER_HP25;
+ break;
+ default:
+ return NO_CAST;
+
+ }
+
+ p_ptr->spellbinder_num = get_spellbinder_max();
+ i = p_ptr->spellbinder_num;
+ while (i > 0)
+ {
+ s32b s = get_school_spell("bind", 0);
+ if (s == -1)
+ {
+ p_ptr->spellbinder_trigger = 0;
+ p_ptr->spellbinder_num = 0;
+ return CAST_OBVIOUS;
+ } else {
+ if (spell_type_skill_level(spell_at(s)) > 7 + get_level_s(SPELLBINDER, 35))
+ {
+ msg_format("You are only allowed spells with a base level of " FMTs32b ".", (7 + get_level_s(SPELLBINDER, 35)));
+ return CAST_OBVIOUS;
+ }
+ }
+
+ p_ptr->spellbinder[i] = s;
+ i = i - 1;
+ }
+
+ p_ptr->energy = p_ptr->energy - 3100;
+ msg_print("Spellbinder ready.");
+ return CAST_OBVIOUS;
+ }
+}
+
+const char *meta_spellbinder_info()
+{
+ static char buf[128];
+ sprintf(buf,
+ "number %d max level " FMTs32b,
+ get_spellbinder_max(),
+ (7 + get_level_s(SPELLBINDER, 35)));
+ return buf;
+}
+
+casting_result meta_disperse_magic()
+{
+ casting_result res = NO_CAST;
+
+ res = cplus(res, set_blind(0));
+ res = cplus(res, set_lite(0));
+ if (get_level_s(DISPERSEMAGIC, 50) >= 5)
+ {
+ res = cplus(res, set_confused(0));
+ res = cplus(res, set_image(0));
+ }
+ if (get_level_s(DISPERSEMAGIC, 50) >= 10)
+ {
+ res = cplus(res, set_slow(0));
+ res = cplus(res, set_fast(0, 0));
+ res = cplus(res, set_light_speed(0));
+ }
+ if (get_level_s(DISPERSEMAGIC, 50) >= 15)
+ {
+ res = cplus(res, set_stun(0));
+ res = cplus(res, set_cut(0));
+ }
+ if (get_level_s(DISPERSEMAGIC, 50) >= 20)
+ {
+ res = cplus(res, set_hero(0));
+ res = cplus(res, set_shero(0));
+ res = cplus(res, set_blessed(0));
+ res = cplus(res, set_shield(0, 0, 0, 0, 0));
+ res = cplus(res, set_afraid(0));
+ res = cplus(res, set_parasite(0, 0));
+ res = cplus(res, set_mimic(0, 0, 0));
+ }
+ return res;
+}
+
+casting_result meta_tracker()
+{
+ if ((last_teleportation_y < 0) ||
+ (last_teleportation_x < 0))
+ {
+ msg_print("There has not been any teleporatation here.");
+ }
+ else
+ {
+ teleport_player_to(last_teleportation_y, last_teleportation_x);
+ }
+ return CAST_OBVIOUS;
+}
+
+static void stop_inertia_controlled_spell()
+{
+ assert(TIMER_INERTIA_CONTROL != NULL);
+
+ p_ptr->inertia_controlled_spell = -1;
+ TIMER_INERTIA_CONTROL->enabled = FALSE;
+ p_ptr->update = p_ptr->update | PU_MANA;
+}
+
+void meta_inertia_control_hook_birth_objects()
+{
+ stop_inertia_controlled_spell();
+}
+
+casting_result meta_inertia_control()
+{
+ s32b s, difficulty, delay;
+ spell_type *spell;
+
+ if (p_ptr->inertia_controlled_spell != -1)
+ {
+ msg_print("You cancel your inertia flow control.");
+ stop_inertia_controlled_spell();
+ return NO_CAST;
+ }
+
+ s = get_school_spell("control", 0);
+ if (s == -1)
+ {
+ stop_inertia_controlled_spell();
+ return NO_CAST;
+ }
+
+ spell = spell_at(s);
+
+ if (!spell_type_inertia(spell, &difficulty, &delay))
+ {
+ msg_print("This spell inertia flow can not be controlled.");
+ stop_inertia_controlled_spell();
+ return NO_CAST;
+ }
+
+ if (difficulty > get_level_s(INERTIA_CONTROL, 10))
+ {
+ msg_format("This spell inertia flow(" FMTs32b ") is too strong to be controlled by your current spell.", difficulty);
+ stop_inertia_controlled_spell();
+ return NO_CAST;
+ }
+
+ p_ptr->inertia_controlled_spell = s;
+ TIMER_INERTIA_CONTROL->enabled = TRUE;
+ TIMER_INERTIA_CONTROL->delay = delay;
+ TIMER_INERTIA_CONTROL->countdown = delay;
+ p_ptr->update |= PU_MANA;
+ msg_format("Inertia flow controlling spell %s.", spell_type_name(spell_at(s)));
+ return CAST_OBVIOUS;
+}
+
+const char *meta_inertia_control_info()
+{
+ static char buf[128];
+ sprintf(buf,
+ "level " FMTs32b,
+ get_level_s(INERTIA_CONTROL, 10));
+ return buf;
+}
+
+void meta_inertia_control_timer_callback()
+{
+ /* Don't cast a controlled spell in wilderness mode */
+ if (p_ptr->antimagic)
+ {
+ msg_print("Your anti-magic field disrupts any magic attempts.");
+ }
+ else if (p_ptr->anti_magic)
+ {
+ msg_print("Your anti-magic shell disrupts any magic attempts.");
+ }
+ else if ((p_ptr->inertia_controlled_spell != -1) &&
+ (!p_ptr->wild_mode))
+ {
+ lua_cast_school_spell(p_ptr->inertia_controlled_spell, TRUE);
+ }
+}
+
+void meta_inertia_control_calc_mana(int *msp)
+{
+ if (p_ptr->inertia_controlled_spell != -1)
+ {
+ *msp = *msp - (get_mana(p_ptr->inertia_controlled_spell) * 4);
+ if (*msp < 0)
+ {
+ *msp = 0;
+ }
+ }
+}
+
+static int mind_charm_power()
+{
+ return 10 + get_level_s(CHARM, 150);
+}
+
+casting_result mind_charm()
+{
+ int pwr = mind_charm_power();
+ int level = get_level_s(CHARM, 50);
+
+ if (level >= 35)
+ {
+ return cast(project_hack(GF_CHARM, pwr));
+ }
+ else
+ {
+ int dir;
+ if (!get_aim_dir(&dir))
+ {
+ return NO_CAST;
+ }
+
+ if (level >= 15)
+ {
+ return cast(fire_ball(GF_CHARM, dir, pwr, 3));
+ }
+ else
+ {
+ return cast(fire_bolt(GF_CHARM, dir, pwr));
+ }
+ }
+}
+
+const char *mind_charm_info()
+{
+ static char buf[128];
+ sprintf(buf,
+ "power %d",
+ mind_charm_power());
+ return buf;
+}
+
+static int mind_confuse_power()
+{
+ return 10 + get_level_s(CONFUSE, 150);
+}
+
+casting_result mind_confuse()
+{
+ int pwr = mind_confuse_power();
+ int level = get_level_s(CONFUSE, 50);
+
+ if (level >= 35)
+ {
+ return cast(project_hack(GF_OLD_CONF, pwr));
+ }
+ else
+ {
+ int dir;
+ if (!get_aim_dir(&dir))
+ {
+ return NO_CAST;
+ }
+
+ if (level >= 15)
+ {
+ return cast(fire_ball(GF_OLD_CONF, dir, pwr, 3));
+ }
+ else
+ {
+ return cast(fire_bolt(GF_OLD_CONF, dir, pwr));
+ }
+ }
+}
+
+const char *mind_confuse_info()
+{
+ static char buf[128];
+ sprintf(buf,
+ "power %d",
+ mind_confuse_power());
+ return buf;
+}
+
+static int mind_armor_of_fear_base_duration()
+{
+ return 10 + get_level_s(ARMOROFFEAR, 100);
+}
+
+static int mind_armor_of_fear_power_sides()
+{
+ return 1 + get_level_s(ARMOROFFEAR, 7);
+}
+
+static int mind_armor_of_fear_power_dice()
+{
+ return 5 + get_level_s(ARMOROFFEAR, 20);
+}
+
+casting_result mind_armor_of_fear()
+{
+ return cast(set_shield(randint(10) + mind_armor_of_fear_base_duration(),
+ 10,
+ SHIELD_FEAR,
+ mind_armor_of_fear_power_sides(),
+ mind_armor_of_fear_power_dice()));
+}
+
+const char *mind_armor_of_fear_info()
+{
+ static char buf[128];
+ sprintf(buf,
+ "dur %d+d10 power %dd%d",
+ mind_armor_of_fear_base_duration(),
+ mind_armor_of_fear_power_sides(),
+ mind_armor_of_fear_power_dice());
+ return buf;
+}
+
+static int mind_stun_power()
+{
+ return 10 + get_level_s(STUN, 150);
+}
+
+casting_result mind_stun()
+{
+ int dir;
+
+ if (!get_aim_dir(&dir))
+ {
+ return NO_CAST;
+ }
+
+ if (get_level_s(STUN, 50) >= 20)
+ {
+ return cast(fire_ball(GF_STUN, dir, mind_stun_power(), 3));
+ }
+ else
+ {
+ return cast(fire_bolt(GF_STUN, dir, mind_stun_power()));
+ }
+}
+
+const char *mind_stun_info()
+{
+ static char buf[128];
+ sprintf(buf,
+ "power %d",
+ mind_stun_power());
+ return buf;
+}
+
+casting_result tempo_magelock()
+{
+ if (get_level_s(MAGELOCK, 50) >= 30)
+ {
+ int x,y;
+
+ if (get_level_s(MAGELOCK, 50) >= 40)
+ {
+ cave_type *c_ptr = NULL;
+
+ if (!tgt_pt(&x, &y))
+ {
+ return NO_CAST;
+ }
+
+ c_ptr = &cave[y][x];
+
+ if ((!(f_info[c_ptr->feat].flags1 | FF1_FLOOR)) ||
+ (f_info[c_ptr->feat].flags1 | FF1_PERMANENT) ||
+ (!los(p_ptr->py, p_ptr->px, y, x)))
+ {
+ msg_print("You cannot place it there.");
+ return NO_CAST;
+ }
+ } else {
+ y = p_ptr->py;
+ x = p_ptr->px;
+ }
+ cave_set_feat(y, x, 3);
+ return CAST_OBVIOUS;
+ } else {
+ int dir;
+ if (!get_aim_dir(&dir))
+ {
+ return NO_CAST;
+ }
+ return cast(wizard_lock(dir));
+ }
+}
+
+static s32b tempo_slow_monster_power()
+{
+ return 40 + get_level_s(SLOWMONSTER, 160);
+}
+
+casting_result tempo_slow_monster()
+{
+ int dir;
+ s32b pwr;
+
+ if (!get_aim_dir(&dir))
+ {
+ return NO_CAST;
+ }
+
+ pwr = tempo_slow_monster_power();
+ if (get_level_s(SLOWMONSTER, 50) >= 20)
+ {
+ return cast(fire_ball(GF_OLD_SLOW, dir, pwr, 1));
+ }
+ else
+ {
+ return cast(fire_bolt(GF_OLD_SLOW, dir, pwr));
+ }
+}
+
+const char *tempo_slow_monster_info()
+{
+ static char buf[128];
+ s32b pwr = tempo_slow_monster_power();
+
+ if (get_level_s(SLOWMONSTER, 50) >= 20)
+ {
+ sprintf(buf, "power " FMTs32b " rad 1", pwr);
+ }
+ else
+ {
+ sprintf(buf, "power " FMTs32b, pwr);
+ }
+ return buf;
+}
+
+static s32b tempo_essence_of_speed_base_duration()
+{
+ return 10 + get_level_s(ESSENCESPEED, 50);
+}
+
+static s32b tempo_essence_of_speed_bonus()
+{
+ return 5 + get_level_s(ESSENCESPEED, 20);
+}
+
+casting_result tempo_essence_of_speed()
+{
+ if (p_ptr->fast == 0)
+ {
+ return cast(set_fast(randint(10) + tempo_essence_of_speed_base_duration(),
+ tempo_essence_of_speed_bonus()));
+ }
+ return NO_CAST;
+}
+
+const char *tempo_essence_of_speed_info()
+{
+ static char buf[128];
+ sprintf(buf,
+ "dur " FMTs32b "+d10 speed " FMTs32b,
+ tempo_essence_of_speed_base_duration(),
+ tempo_essence_of_speed_bonus());
+ return buf;
+}
+
+static s32b tempo_banishment_power()
+{
+ return 40 + get_level_s(BANISHMENT, 160);
+}
+
+casting_result tempo_banishment()
+{
+ casting_result result = NO_CAST;
+ s32b pwr = tempo_banishment_power();
+
+ result = cplus(result, project_hack(GF_AWAY_ALL, pwr));
+
+ if (get_level_s(BANISHMENT, 50) >= 15)
+ {
+ result = cplus(result,
+ project_hack(GF_STASIS, 20 + get_level_s(BANISHMENT, 120)));
+ }
+
+ return result;
+}
+
+const char *tempo_banishment_info()
+{
+ static char buf[128];
+ sprintf(buf,
+ "power " FMTs32b,
+ tempo_banishment_power());
+ return buf;
+}
+
+casting_result tulkas_divine_aim()
+{
+ casting_result result = NO_CAST;
+ s32b dur = get_level_s(TULKAS_AIM, 50) + randint(10);
+
+ result = cplus(result, set_strike(dur));
+ if (get_level_s(TULKAS_AIM, 50) >= 20)
+ {
+ result = cplus(result, set_tim_deadly(dur));
+ }
+
+ return result;
+}
+
+const char *tulkas_divine_aim_info()
+{
+ static char buf[128];
+ sprintf(buf,
+ "dur " FMTs32b "+d10",
+ get_level_s(TULKAS_AIM, 50));
+ return buf;
+}
+
+casting_result tulkas_wave_of_power()
+{
+ int dir;
+
+ if (!get_aim_dir(&dir))
+ {
+ return NO_CAST;
+ }
+
+ return cast(fire_bolt(GF_ATTACK, dir, get_level_s(TULKAS_WAVE, p_ptr->num_blow)));
+}
+
+const char *tulkas_wave_of_power_info()
+{
+ static char buf[128];
+ sprintf(buf,
+ "blows " FMTs32b,
+ get_level_s(TULKAS_WAVE, p_ptr->num_blow));
+ return buf;
+}
+
+casting_result tulkas_whirlwind()
+{
+ return cast(fire_ball(GF_ATTACK, 0, 1, 1));
+}
+
+/* Return the number of Udun/Melkor spells in a given book */
+int udun_in_book(s32b sval, s32b pval)
+{
+ int count = 0;
+
+ random_book_setup(sval, pval);
+
+ /* Get the school book */
+ school_book *school_book = school_books_at(sval);
+
+ /* Go through spells */
+ for (auto spell_idx : school_book->spell_idxs) {
+ spell_type *spell = spell_at(spell_idx);
+ for (auto school_idx : spell_type_get_schools(spell))
+ {
+ if ((school_idx == SCHOOL_UDUN) ||
+ (school_idx == SCHOOL_MELKOR))
+ {
+ count++;
+ }
+ }
+ }
+
+ return count;
+}
+
+int levels_in_book(s32b sval, s32b pval)
+{
+ int levels = 0;
+
+ random_book_setup(sval, pval);
+
+ /* Get the school book */
+ school_book *school_book = school_books_at(sval);
+
+ /* Parse all spells */
+ for (auto spell_idx : school_book->spell_idxs)
+ {
+ spell_type *spell = spell_at(spell_idx);
+ levels += spell_type_skill_level(spell);
+ }
+
+ return levels;
+}
+
+static object_filter_t const &udun_object_is_drainable()
+{
+ using namespace object_filter;
+ static auto instance = Or(
+ TVal(TV_WAND),
+ TVal(TV_ROD_MAIN),
+ TVal(TV_STAFF));
+ return instance;
+}
+
+casting_result udun_drain()
+{
+ /* Ask for an item */
+ int item;
+ if (!get_item(&item,
+ "What item to drain?",
+ "You have nothing you can drain",
+ USE_INVEN,
+ udun_object_is_drainable()))
+ {
+ return NO_CAST;
+ }
+
+ /* Drain */
+ object_type *o_ptr = get_object(item);
+
+ switch (o_ptr->tval)
+ {
+ case TV_STAFF:
+ case TV_WAND:
+ {
+ object_kind *k_ptr = &k_info[o_ptr->k_idx];
+
+ /* Generate mana */
+ increase_mana(o_ptr->pval * k_ptr->level * o_ptr->number);
+
+ /* Destroy it */
+ inc_stack_size(item, -99);
+
+ break;
+ }
+
+ case TV_ROD_MAIN:
+ {
+ /* Generate mana */
+ increase_mana(o_ptr->timeout);
+
+ /* Drain it */
+ o_ptr->timeout = 0;
+
+ /* Combine / Reorder the pack (later) */
+ p_ptr->notice |= PN_COMBINE | PN_REORDER;
+ p_ptr->window |= PW_INVEN | PW_EQUIP | PW_PLAYER;
+ break;
+ }
+
+ default:
+ assert(FALSE);
+ }
+
+ return CAST_OBVIOUS;
+}
+
+casting_result udun_genocide()
+{
+ if (get_level_s(GENOCIDE, 50) < 10)
+ {
+ genocide(TRUE);
+ }
+ else
+ {
+ if (get_check("Genocide all monsters near you? "))
+ {
+ mass_genocide(TRUE);
+ }
+ else
+ {
+ genocide(TRUE);
+ }
+ }
+
+ return CAST_OBVIOUS;
+}
+
+static int udun_wraithform_base_duration()
+{
+ return 20 + get_level_s(WRAITHFORM, 40);
+}
+
+casting_result udun_wraithform()
+{
+ return cast(set_shadow(randint(30) + udun_wraithform_base_duration()));
+}
+
+const char *udun_wraithform_info()
+{
+ static char buf[128];
+ sprintf(buf,
+ "dur %d+d30",
+ udun_wraithform_base_duration());
+ return buf;
+}
+
+static int udun_flame_of_udun_base_duration()
+{
+ return 5 + get_level_s(FLAMEOFUDUN, 30);
+}
+
+casting_result udun_flame_of_udun()
+{
+ return cast(set_mimic(randint(15) + udun_flame_of_udun_base_duration(),
+ resolve_mimic_name("Balrog"),
+ get_level_s(FLAMEOFUDUN, 50)));
+}
+
+const char *udun_flame_of_udun_info()
+{
+ static char buf[128];
+ sprintf(buf,
+ "dur %d+d15",
+ udun_flame_of_udun_base_duration());
+ return buf;
+}
+
+static int tidal_wave_damage()
+{
+ return 40 + get_level_s(TIDALWAVE, 200);
+}
+
+static int tidal_wave_duration()
+{
+ return 6 + get_level_s(TIDALWAVE, 10);
+}
+
+casting_result water_tidal_wave()
+{
+ fire_wave(GF_WAVE,
+ 0,
+ tidal_wave_damage(),
+ 0,
+ tidal_wave_duration(),
+ EFF_WAVE);
+ return CAST_OBVIOUS;
+}
+
+const char *water_tidal_wave_info()
+{
+ static char buf[128];
+ sprintf(buf,
+ "dam %d dur %d",
+ tidal_wave_damage(),
+ tidal_wave_duration());
+ return buf;
+}
+
+static int water_ice_storm_damage()
+{
+ return 80 + get_level_s(ICESTORM, 200);
+}
+
+static int water_ice_storm_radius()
+{
+ return 1 + get_level(ICESTORM, 3, 0);
+}
+
+static int water_ice_storm_duration()
+{
+ return 20 + get_level_s(ICESTORM, 70);
+}
+
+casting_result water_ice_storm()
+{
+ int type = GF_COLD;
+
+ if (get_level_s(ICESTORM, 50) >= 10)
+ {
+ type = GF_ICE;
+ }
+
+ fire_wave(type,
+ 0,
+ water_ice_storm_damage(),
+ water_ice_storm_radius(),
+ water_ice_storm_duration(),
+ EFF_STORM);
+
+ return CAST_OBVIOUS;
+}
+
+const char *water_ice_storm_info()
+{
+ static char buf[128];
+ sprintf(buf,
+ "dam %d rad %d dur %d",
+ water_ice_storm_damage(),
+ water_ice_storm_radius(),
+ water_ice_storm_duration());
+ return buf;
+}
+
+static int water_ent_potion_base_duration()
+{
+ return 25 + get_level_s(ENTPOTION, 40);;
+}
+
+casting_result water_ent_potion()
+{
+ set_food(PY_FOOD_MAX - 1);
+ msg_print("The Ent's Potion fills your stomach.");
+
+ if (get_level_s(ENTPOTION, 50) >= 5)
+ {
+ set_afraid(0);
+ }
+ if (get_level_s(ENTPOTION, 50) >= 12)
+ {
+ set_hero(p_ptr->hero + randint(25) + water_ent_potion_base_duration());
+ }
+
+ return CAST_OBVIOUS;
+}
+
+const char *water_ent_potion_info()
+{
+ if (get_level_s(ENTPOTION, 50) >= 12)
+ {
+ static char buf[128];
+ sprintf(buf,
+ "dur %d+d25",
+ water_ent_potion_base_duration());
+ return buf;
+ }
+ else
+ {
+ return "";
+ }
+}
+
+static int water_vapor_damage()
+{
+ return 3 + get_level_s(VAPOR, 20);
+}
+
+static int water_vapor_radius()
+{
+ return 3 + get_level(VAPOR, 9, 0);
+}
+
+static int water_vapor_duration()
+{
+ return 5;
+}
+
+casting_result water_vapor()
+{
+ fire_cloud(GF_WATER,
+ 0,
+ water_vapor_damage(),
+ water_vapor_radius(),
+ water_vapor_duration());
+ return CAST_OBVIOUS;
+}
+
+const char *water_vapor_info()
+{
+ static char buf[128];
+ sprintf(buf,
+ "dam %d rad %d dur %d",
+ water_vapor_damage(),
+ water_vapor_radius(),
+ water_vapor_duration());
+ return buf;
+}
+
+static void get_geyser_damage(int *dice, int *sides)
+{
+ assert(dice != NULL);
+ assert(sides != NULL);
+
+ *dice = get_level_s(GEYSER, 10);
+ *sides = 3 + get_level_s(GEYSER, 35);
+}
+
+casting_result water_geyser()
+{
+ int dir, dice, sides;
+
+ if (!get_aim_dir(&dir))
+ {
+ return NO_CAST;
+ }
+
+ get_geyser_damage(&dice, &sides);
+ return cast(fire_bolt_or_beam(2 * get_level_s(GEYSER, 85),
+ GF_WATER,
+ dir,
+ damroll(dice, sides)));
+}
+
+const char *water_geyser_info()
+{
+ static char buf[128];
+ int dice, sides;
+
+ get_geyser_damage(&dice, &sides);
+
+ sprintf(buf,
+ "dam %dd%d",
+ dice,
+ sides);
+ return buf;
+}
+
+static int charm_animal_power()
+{
+ return 10 + get_level_s(YAVANNA_CHARM_ANIMAL, 170);
+}
+
+static int charm_animal_radius()
+{
+ return get_level_s(YAVANNA_CHARM_ANIMAL, 2);
+}
+
+casting_result yavanna_charm_animal()
+{
+ int dir;
+
+ if (!get_aim_dir(&dir))
+ {
+ return NO_CAST;
+ }
+
+ return cast(fire_ball(GF_CONTROL_ANIMAL,
+ dir,
+ charm_animal_power(),
+ charm_animal_radius()));
+}
+
+const char *yavanna_charm_animal_info()
+{
+ static char buf[128];
+ sprintf(buf,
+ "power %d rad %d",
+ charm_animal_power(),
+ charm_animal_radius());
+ return buf;
+}
+
+static int yavanna_grow_grass_radius()
+{
+ return get_level_s(YAVANNA_GROW_GRASS, 4);
+}
+
+casting_result yavanna_grow_grass()
+{
+ grow_grass(yavanna_grow_grass_radius());
+ return CAST_OBVIOUS;
+}
+
+const char *yavanna_grow_grass_info()
+{
+ static char buf[128];
+ sprintf(buf,
+ "rad %d",
+ yavanna_grow_grass_radius());
+ return buf;
+}
+
+static int tree_roots_duration()
+{
+ return 10 + get_level_s(YAVANNA_TREE_ROOTS, 30);
+}
+
+static int tree_roots_ac()
+{
+ return 10 + get_level_s(YAVANNA_TREE_ROOTS, 60);
+}
+
+static int tree_roots_damage()
+{
+ return 10 + get_level_s(YAVANNA_TREE_ROOTS, 20);
+}
+
+casting_result yavanna_tree_roots()
+{
+ return cast(set_roots(tree_roots_duration(),
+ tree_roots_ac(),
+ tree_roots_damage()));
+}
+
+const char *yavanna_tree_roots_info()
+{
+ static char buf[128];
+ sprintf(buf,
+ "dur %d AC %d dam %d",
+ tree_roots_duration(),
+ tree_roots_ac(),
+ tree_roots_damage());
+ return buf;
+}
+
+static int water_bite_base_duration()
+{
+ return 30 + get_level_s(YAVANNA_WATER_BITE, 150);
+}
+
+static int water_bite_damage()
+{
+ return 10 + get_level_s(YAVANNA_WATER_BITE, 50);
+}
+
+casting_result yavanna_water_bite()
+{
+ int rad = 0;
+
+ if (get_level_s(YAVANNA_WATER_BITE, 50) >= 25)
+ {
+ rad = 1;
+ }
+
+ return cast(set_project(randint(30) + water_bite_base_duration(),
+ GF_WATER,
+ water_bite_damage(),
+ rad,
+ PROJECT_STOP | PROJECT_KILL));
+}
+
+const char *yavanna_water_bite_info()
+{
+ static char buf[128];
+ sprintf(buf,
+ "dur %d+d30 dam %d/blow",
+ water_bite_base_duration(),
+ water_bite_damage());
+ return buf;
+}
+
+static int uproot_mlevel()
+{
+ return 30 + get_level_s(YAVANNA_UPROOT, 70);
+}
+
+casting_result yavanna_uproot()
+{
+ int dir, x, y;
+ cave_type *c_ptr;
+
+ if (!get_rep_dir(&dir))
+ {
+ return NO_CAST;
+ }
+
+ y = ddy[dir];
+ x = ddx[dir];
+
+ y += p_ptr->py;
+ x += p_ptr->px;
+
+ c_ptr = &cave[y][x];
+
+ if (c_ptr->feat == FEAT_TREES)
+ {
+ s16b m_idx;
+
+ cave_set_feat(y, x, FEAT_GRASS);
+
+ /* Summon it */
+ find_position(y, x, &y, &x);
+ m_idx = place_monster_one(y, x, test_monster_name("Ent"), 0, FALSE, MSTATUS_FRIEND);
+
+ /* level it */
+ if (m_idx != 0)
+ {
+ monster_set_level(m_idx, uproot_mlevel());
+ }
+
+ msg_print("The tree awakes!");
+ return CAST_OBVIOUS;
+ }
+ else
+ {
+ msg_print("There is no tree there.");
+ return NO_CAST;
+ }
+}
+
+const char *yavanna_uproot_info()
+{
+ static char buf[128];
+ sprintf(buf,
+ "lev %d",
+ uproot_mlevel());
+ return buf;
+}
+
+static int nature_grow_trees_radius()
+{
+ return 2 + get_level_s(GROWTREE, 7);
+}
+
+casting_result nature_grow_trees()
+{
+ grow_trees(nature_grow_trees_radius());
+ return CAST_OBVIOUS;
+}
+
+const char *nature_grow_trees_info()
+{
+ static char buf[128];
+ sprintf(buf,
+ "rad %d",
+ nature_grow_trees_radius());
+ return buf;
+}
+
+static int nature_healing_percentage()
+{
+ return 15 + get_level_s(HEALING, 35);
+}
+
+static int nature_healing_hp()
+{
+ return p_ptr->mhp * nature_healing_percentage() / 100;
+}
+
+casting_result nature_healing()
+{
+ return cast(hp_player(nature_healing_hp()));
+}
+
+const char *nature_healing_info()
+{
+ static char buf[128];
+ sprintf(buf,
+ "heal %d%% = %dhp",
+ nature_healing_percentage(),
+ nature_healing_hp());
+ return buf;
+}
+
+casting_result nature_recovery()
+{
+ casting_result result = NO_CAST;
+
+ result = cplus(result, set_poisoned(p_ptr->poisoned / 2));
+ if (get_level_s(RECOVERY, 50) >= 5)
+ {
+ result = cplus(result, set_poisoned(0));
+ result = cplus(result, set_cut(0));
+ }
+ if (get_level_s(RECOVERY, 50) >= 10)
+ {
+ result = cplus(result, do_res_stat(A_STR, TRUE));
+ result = cplus(result, do_res_stat(A_CON, TRUE));
+ result = cplus(result, do_res_stat(A_DEX, TRUE));
+ result = cplus(result, do_res_stat(A_WIS, TRUE));
+ result = cplus(result, do_res_stat(A_INT, TRUE));
+ result = cplus(result, do_res_stat(A_CHR, TRUE));
+ }
+ if (get_level_s(RECOVERY, 50) >= 15)
+ {
+ result = cplus(result, restore_level());
+ }
+
+ return result;
+}
+
+static int regeneration_base_duration()
+{
+ return 5 + get_level_s(REGENERATION, 50);
+}
+
+static int regeneration_power()
+{
+ return 300 + get_level_s(REGENERATION, 700);
+}
+
+casting_result nature_regeneration()
+{
+ if (p_ptr->tim_regen == 0)
+ {
+ return cast(set_tim_regen(randint(10) + regeneration_base_duration(),
+ regeneration_power()));
+ }
+ return NO_CAST;
+}
+
+const char *nature_regeneration_info()
+{
+ static char buf[128];
+ sprintf(buf,
+ "dur %d+d10 power %d",
+ regeneration_base_duration(),
+ regeneration_power());
+ return buf;
+}
+
+static int summon_animal_level()
+{
+ return 25 + get_level_s(SUMMONANNIMAL, 50);
+}
+
+casting_result nature_summon_animal()
+{
+ summon_specific_level = summon_animal_level();
+ return cast(summon_specific_friendly(p_ptr->py,
+ p_ptr->px,
+ dun_level,
+ SUMMON_ANIMAL,
+ TRUE));
+}
+
+const char *nature_summon_animal_info()
+{
+ static char buf[128];
+ sprintf(buf,
+ "level %d",
+ summon_animal_level());
+ return buf;
+}
+
+casting_result nature_grow_athelas()
+{
+ if (p_ptr->black_breath)
+ {
+ msg_print("The hold of the Black Breath on you is broken!");
+ p_ptr->black_breath = FALSE;
+ return CAST_OBVIOUS;
+ }
+
+ return CAST_HIDDEN;
+}
+
+static int device_heal_monster_hp()
+{
+ return 20 + get_level_s(DEVICE_HEAL_MONSTER, 380);
+}
+
+casting_result device_heal_monster()
+{
+ int dir;
+
+ if (!get_aim_dir(&dir))
+ {
+ return NO_CAST;
+ }
+
+ return cast(fire_ball(GF_OLD_HEAL, dir, device_heal_monster_hp(), 0));
+}
+
+const char *device_heal_monster_info()
+{
+ static char buf[128];
+ sprintf(buf,
+ "heal %d",
+ device_heal_monster_hp());
+ return buf;
+}
+
+casting_result device_haste_monster()
+{
+ int dir;
+
+ if (!get_aim_dir(&dir))
+ {
+ return NO_CAST;
+ }
+
+ return cast(fire_ball(GF_OLD_SPEED, dir, 1, 0));
+}
+
+const char *device_haste_monster_info()
+{
+ return "speed +10";
+}
+
+casting_result device_wish()
+{
+ make_wish();
+ return CAST_OBVIOUS;
+}
+
+casting_result device_summon_monster()
+{
+ casting_result result = NO_CAST;
+ int i;
+
+ for (i = 0; i < 4 + get_level_s(DEVICE_SUMMON, 30); i++)
+ {
+ result = cplus(result, summon_specific(p_ptr->py, p_ptr->px, dun_level, 0));
+ }
+
+ return result;
+}
+
+static int device_mana_pct()
+{
+ return 20 + get_level_s(DEVICE_MANA, 50);
+}
+
+casting_result device_mana()
+{
+ increase_mana((p_ptr->msp * device_mana_pct()) / 100);
+ return CAST_OBVIOUS;
+}
+
+const char *device_mana_info()
+{
+ static char buf[128];
+ sprintf(buf,
+ "restore %d%%",
+ device_mana_pct());
+ return buf;
+}
+
+casting_result device_nothing()
+{
+ return CAST_HIDDEN;
+}
+
+static int holy_fire_damage()
+{
+ return 50 + get_level_s(DEVICE_HOLY_FIRE, 300);
+}
+
+casting_result device_holy_fire()
+{
+ return cast(project_hack(GF_HOLY_FIRE, holy_fire_damage()));
+}
+
+const char *device_holy_fire_info()
+{
+ static char buf[128];
+ sprintf(buf,
+ "dam %d",
+ holy_fire_damage());
+ return buf;
+}
+
+casting_result device_thunderlords()
+{
+ switch (game_module_idx)
+ {
+ case MODULE_TOME:
+ {
+ if (dun_level > 0)
+ {
+ 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.");
+ }
+ return CAST_OBVIOUS;
+ }
+
+ case MODULE_THEME:
+ {
+ if (dun_level > 0)
+ {
+ 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.");
+ }
+ return CAST_OBVIOUS;
+ }
+
+ default:
+ assert(FALSE);
+ return NO_CAST;
+ }
+}
+
+void static start_lasting_spell(int spl)
+{
+ p_ptr->music_extra = -spl;
+}
+
+casting_result music_stop_singing_spell()
+{
+ start_lasting_spell(0);
+ return CAST_OBVIOUS;
+}
+
+static int holding_pattern_power()
+{
+ return 10 + get_level_s(MUSIC_HOLD, 100);
+}
+
+int music_holding_pattern_lasting()
+{
+ project_hack(GF_OLD_SLOW, holding_pattern_power());
+ return get_mana(MUSIC_HOLD);
+}
+
+casting_result music_holding_pattern_spell()
+{
+ start_lasting_spell(MUSIC_HOLD);
+ return CAST_OBVIOUS;
+}
+
+const char *music_holding_pattern_info()
+{
+ static char buf[128];
+ sprintf(buf,
+ "power %d",
+ holding_pattern_power());
+ return buf;
+}
+
+static int illusion_pattern_power()
+{
+ return 10 + get_level_s(MUSIC_CONF, 100);
+}
+
+int music_illusion_pattern_lasting()
+{
+ project_hack(GF_OLD_CONF, illusion_pattern_power());
+ return get_mana(MUSIC_CONF);
+}
+
+casting_result music_illusion_pattern_spell()
+{
+ start_lasting_spell(MUSIC_CONF);
+ return CAST_OBVIOUS;
+}
+
+const char *music_illusion_pattern_info()
+{
+ static char buf[128];
+ sprintf(buf,
+ "power %d",
+ illusion_pattern_power());
+ return buf;
+}
+
+static int stun_pattern_power()
+{
+ return 10 + get_level_s(MUSIC_STUN, 90);
+}
+
+int music_stun_pattern_lasting()
+{
+ project_hack(GF_STUN, stun_pattern_power());
+ return get_mana(MUSIC_STUN);
+}
+
+casting_result music_stun_pattern_spell()
+{
+ start_lasting_spell(MUSIC_STUN);
+ return CAST_OBVIOUS;
+}
+
+const char *music_stun_pattern_info()
+{
+ static char buf[128];
+ sprintf(buf,
+ "power %d",
+ stun_pattern_power());
+ return buf;
+}
+
+int music_song_of_the_sun_lasting()
+{
+ set_lite(5);
+ return 1;
+}
+
+casting_result music_song_of_the_sun_spell()
+{
+ start_lasting_spell(MUSIC_LITE);
+ return CAST_OBVIOUS;
+}
+
+int flow_of_life_hp()
+{
+ return 7 + get_level_s(MUSIC_HEAL, 100);
+}
+
+int music_flow_of_life_lasting()
+{
+ hp_player(flow_of_life_hp());
+ return get_mana(MUSIC_HEAL);
+}
+
+casting_result music_flow_of_life_spell()
+{
+ start_lasting_spell(MUSIC_HEAL);
+ return CAST_OBVIOUS;
+}
+
+const char *music_flow_of_life_info()
+{
+ static char buf[128];
+ sprintf(buf,
+ "heal %d/turn",
+ flow_of_life_hp());
+ return buf;
+}
+
+int music_heroic_ballad_lasting()
+{
+ set_hero(5);
+ if (get_level_s(MUSIC_HERO, 50) >= 10)
+ {
+ set_shero(5);
+ }
+ if (get_level_s(MUSIC_HERO, 50) >= 20)
+ {
+ set_strike(5);
+ }
+ if (get_level_s(MUSIC_HERO, 50) >= 25)
+ {
+ set_oppose_cc(5);
+ }
+ return get_mana(MUSIC_HERO);
+}
+
+casting_result music_heroic_ballad_spell()
+{
+ start_lasting_spell(MUSIC_HERO);
+ return CAST_OBVIOUS;
+}
+
+int music_hobbit_melodies_lasting()
+{
+ set_shield(5, 10 + get_level_s(MUSIC_TIME, 50), 0, 0, 0);
+ if (get_level_s(MUSIC_TIME, 50) >= 15)
+ {
+ set_fast(5, 7 + get_level_s(MUSIC_TIME, 10));
+ }
+ return get_mana(MUSIC_TIME);
+}
+
+casting_result music_hobbit_melodies_spell()
+{
+ start_lasting_spell(MUSIC_TIME);
+ return CAST_OBVIOUS;
+}
+
+const char *music_hobbit_melodies_info()
+{
+ static char buf[128];
+ if (get_level_s(MUSIC_TIME, 50) >= 15)
+ {
+ sprintf(buf, "AC " FMTs32b " speed " FMTs32b,
+ 10 + get_level_s(MUSIC_TIME, 50),
+ 7 + get_level_s(MUSIC_TIME, 10));
+ }
+ else
+ {
+ sprintf(buf, "AC " FMTs32b,
+ 10 + get_level_s(MUSIC_TIME, 50));
+ }
+ return buf;
+}
+
+int music_clairaudience_lasting()
+{
+ set_tim_esp(5);
+ if (get_level_s(MUSIC_MIND, 50) >= 10)
+ {
+ fire_ball(GF_IDENTIFY, 0, 1, 1 + get_level(MUSIC_MIND, 3, 0));
+ }
+ return get_mana(MUSIC_MIND);
+}
+
+casting_result music_clairaudience_spell()
+{
+ start_lasting_spell(MUSIC_MIND);
+ return CAST_OBVIOUS;
+}
+
+const char *music_clairaudience_info()
+{
+ static char buf[128];
+
+ if (get_level_s(MUSIC_MIND, 50) >= 10)
+ {
+ sprintf(buf, "rad " FMTs32b,
+ 1 + get_level(MUSIC_MIND, 3, 0));
+ return buf;
+ }
+ else
+ {
+ return "";
+ }
+}
+
+casting_result music_blow_spell()
+{
+ 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 CAST_OBVIOUS;
+}
+
+const char *music_blow_info()
+{
+ static char buf[128];
+ sprintf(buf,
+ "dam " FMTs32b "d" FMTs32b " rad " FMTs32b,
+ 2 + get_level(MUSIC_BLOW, 10, 0),
+ 4 + get_level(MUSIC_BLOW, 40, 0),
+ 1 + get_level(MUSIC_BLOW, 12, 0));
+ return buf;
+}
+
+casting_result music_gush_of_wind_spell()
+{
+ fire_ball(GF_AWAY_ALL,
+ 0,
+ 10 + get_level(MUSIC_BLOW, 40, 0),
+ 1 + get_level(MUSIC_BLOW, 12, 0));
+ return CAST_OBVIOUS;
+}
+
+const char *music_gush_of_wind_info()
+{
+ static char buf[128];
+ sprintf(buf,
+ "dist " FMTs32b " rad " FMTs32b,
+ 10 + get_level(MUSIC_BLOW, 40, 0),
+ 1 + get_level(MUSIC_BLOW, 12, 0));
+ return buf;
+}
+
+casting_result music_horns_of_ylmir_spell()
+{
+ earthquake(p_ptr->py, p_ptr->px, 2 + get_level_s(MUSIC_YLMIR, 10));
+ return CAST_OBVIOUS;
+}
+
+const char *music_horns_of_ylmir_info()
+{
+ static char buf[128];
+ sprintf(buf,
+ "rad " FMTs32b,
+ 2 + get_level_s(MUSIC_YLMIR, 10));
+ return buf;
+}
+
+casting_result music_ambarkanta_spell()
+{
+ alter_reality();
+ return CAST_OBVIOUS;
+}
+
+casting_result aule_firebrand_spell()
+{
+ int rad = 0;
+ int type = GF_FIRE;
+ s32b level = get_level_s(AULE_FIREBRAND, 50);
+
+ if (level > 30)
+ {
+ type = GF_HOLY_FIRE;
+ }
+
+ if (level >= 15)
+ {
+ rad = 1;
+ }
+
+ return cast(set_project(level + randint(20),
+ type,
+ 4 + level,
+ rad,
+ PROJECT_STOP | PROJECT_KILL));
+}
+
+const char *aule_firebrand_info()
+{
+ s32b level = get_level_s(AULE_FIREBRAND, 50);
+ static char buf[128];
+
+ sprintf(buf,
+ "dur " FMTs32b "+d20 dam " FMTs32b "/blow",
+ level,
+ 4 + level);
+ return buf;
+}
+
+static object_filter_t const &aule_enchant_weapon_item_tester()
+{
+ using namespace object_filter;
+ static auto instance = And(
+ // Cannot enchant artifacts, spell is probably already too overpowered.
+ Not(IsArtifact()),
+ // Only weapons which Aule likes
+ Or(
+ TVal(TV_MSTAFF),
+ TVal(TV_BOW),
+ TVal(TV_HAFTED),
+ TVal(TV_POLEARM),
+ TVal(TV_SWORD),
+ TVal(TV_AXE)));
+ return instance;
+}
+
+casting_result aule_enchant_weapon_spell()
+{
+ s32b level = get_level_s(AULE_ENCHANT_WEAPON, 50);
+ s16b num_h, num_d, num_p;
+
+ num_h = 1 + randint(level/12);
+ num_d = 0;
+ num_p = 0;
+
+ if (level >= 5)
+ {
+ num_d = 1 + randint(level/12);
+ }
+ if (level >= 45)
+ {
+ num_p = 1;
+ }
+
+ int item;
+ if (!get_item(&item,
+ "Which object do you want to enchant?",
+ "You have no objects to enchant.",
+ USE_INVEN,
+ aule_enchant_weapon_item_tester()))
+ {
+ return NO_CAST;
+ }
+
+ object_type *o_ptr = get_object(item);
+
+ o_ptr->to_h = o_ptr->to_h + num_h;
+ o_ptr->to_d = o_ptr->to_d + num_d;
+ o_ptr->pval = o_ptr->pval + num_p;
+
+ return CAST_OBVIOUS;
+}
+
+const char *aule_enchant_weapon_info()
+{
+ static char buf[128];
+ sprintf(buf,
+ "tries " FMTs32b,
+ 1 + get_level_s(AULE_ENCHANT_WEAPON, 50)/12);
+ return buf;
+}
+
+static object_filter_t const &aule_enchant_armor_item_tester()
+{
+ using namespace object_filter;
+ static auto instance = And(
+ // No enchanting artifacts; the spell is already horribly
+ // overpowered.
+ Not(IsArtifact()),
+ // Only armor-like things can be enchanted
+ Or(
+ TVal(TV_BOOTS),
+ TVal(TV_GLOVES),
+ TVal(TV_HELM),
+ TVal(TV_CROWN),
+ TVal(TV_SHIELD),
+ TVal(TV_CLOAK),
+ TVal(TV_SOFT_ARMOR),
+ TVal(TV_HARD_ARMOR),
+ TVal(TV_DRAG_ARMOR)));
+ return instance;
+}
+
+casting_result aule_enchant_armour_spell()
+{
+ s32b level = get_level_s(AULE_ENCHANT_ARMOUR, 50);
+ s16b num_h, num_d, num_a, num_p;
+ int item;
+
+ num_a = 1 + randint(level/10);
+ num_h = 0;
+ num_d = 0;
+ num_p = 0;
+ if (level >= 20)
+ {
+ num_h = 1;
+ num_d = 1;
+ }
+ if (level >= 40)
+ {
+ num_p = 1;
+ }
+
+ if (!get_item(&item,
+ "Which object do you want to enchant?",
+ "You have no objects to enchant.",
+ USE_INVEN,
+ aule_enchant_armor_item_tester()))
+ {
+ return NO_CAST;
+ }
+
+ object_type *o_ptr = get_object(item);
+
+ o_ptr->to_h = o_ptr->to_h + num_h;
+ o_ptr->to_d = o_ptr->to_d + num_d;
+ o_ptr->pval = o_ptr->pval + num_p;
+ o_ptr->to_a = o_ptr->to_a + num_a;
+
+ return CAST_OBVIOUS;
+}
+
+const char *aule_enchant_armour_info()
+{
+ static char buf[128];
+ sprintf(buf,
+ "tries " FMTs32b,
+ 1 + get_level_s(AULE_ENCHANT_ARMOUR, 50)/10);
+ return buf;
+}
+
+casting_result aule_child_spell()
+{
+ int y, x;
+ s16b m_idx;
+
+ find_position(p_ptr->py, p_ptr->px, &y, &x);
+ m_idx = place_monster_one(y, x, test_monster_name("Dwarven warrior"),
+ 0, FALSE, MSTATUS_FRIEND);
+
+ if (m_idx)
+ {
+ monster_set_level(m_idx, 20 + get_level(AULE_CHILD, 70, 0));
+ return CAST_OBVIOUS;
+ }
+ else
+ {
+ return NO_CAST;
+ }
+}
+
+const char *aule_child_info()
+{
+ static char buf[128];
+ sprintf(buf,
+ "level " FMTs32b,
+ 20 + get_level_s(AULE_CHILD, 70));
+ return buf;
+}
+
+static int tears_of_luthien_hp()
+{
+ return 10 * get_level_s(MANDOS_TEARS_LUTHIEN, 30);
+}
+
+casting_result mandos_tears_of_luthien_spell()
+{
+ casting_result result = NO_CAST;
+
+ result = cplus(result, hp_player(tears_of_luthien_hp()));
+ result = cplus(result, set_stun(0));
+ result = cplus(result, set_cut(0));
+ result = cplus(result, set_afraid(0));
+
+ return result;
+}
+
+const char *mandos_tears_of_luthien_info()
+{
+ static char buf[128];
+ sprintf(buf,
+ "heals %d",
+ tears_of_luthien_hp());
+ return buf;
+}
+
+casting_result mandos_spirit_of_the_feanturi_spell()
+{
+ casting_result result = NO_CAST;
+ s32b level = get_level_s(MANDOS_SPIRIT_FEANTURI, 50);
+
+ result = cplus(result, set_afraid(0));
+ result = cplus(result, set_confused(0));
+
+ if (level >= 20)
+ {
+ result = cplus(result, do_res_stat(A_WIS, TRUE));
+ result = cplus(result, do_res_stat(A_INT, TRUE));
+ }
+
+ if (level >= 30)
+ {
+ result = cplus(result, set_image(0));
+ result = cplus(result, heal_insanity(p_ptr->msane * level / 100));
+ }
+
+ return result;
+}
+
+const char *mandos_spirit_of_the_feanturi_info()
+{
+ static char buf[128];
+ s32b level = get_level_s(MANDOS_SPIRIT_FEANTURI, 50) ;
+ if (level >= 20)
+ {
+ sprintf(buf, "heals " FMTs32b "%%", level);
+ return buf;
+ }
+ else
+ {
+ return "";
+ }
+}
+
+static int tale_of_doom_duration()
+{
+ return 5 + get_level_s(MANDOS_TALE_DOOM,10);
+}
+
+casting_result mandos_tale_of_doom_spell()
+{
+ return cast(set_tim_precognition(tale_of_doom_duration()));
+}
+
+const char *mandos_tale_of_doom_info()
+{
+ static char buf[128];
+ sprintf(buf,
+ "dur %d",
+ tale_of_doom_duration());
+ return buf;
+}
+
+int call_to_the_halls_mlev()
+{
+ return 20 + get_level(MANDOS_CALL_HALLS, 70, 0);
+}
+
+casting_result mandos_call_to_the_halls_spell()
+{
+ int y, x;
+ s16b m_idx;
+ std::vector<int> summons {
+ test_monster_name("Experienced spirit"),
+ test_monster_name("Wise spirit")
+ };
+
+ int r_idx = summons[rand_int(summons.size())];
+ assert(r_idx >= 0);
+
+ find_position(p_ptr->py, p_ptr->px, &y, &x);
+ m_idx = place_monster_one(y, x, r_idx, 0, FALSE, MSTATUS_FRIEND);
+ if (m_idx)
+ {
+ monster_set_level(m_idx, call_to_the_halls_mlev());
+ return CAST_OBVIOUS;
+ }
+ return NO_CAST;
+}
+
+const char *mandos_call_to_the_halls_info()
+{
+ static char buf[128];
+ sprintf(buf,
+ "level %d",
+ call_to_the_halls_mlev());
+ return buf;
+}
+
+static void get_belegaer_damage(int *dice, int *sides)
+{
+ *dice = get_level_s(ULMO_BELEGAER, 10);
+ *sides = 3 + get_level_s(ULMO_BELEGAER, 35);
+}
+
+casting_result ulmo_song_of_belegaer_spell()
+{
+ int dir, dice, sides;
+
+ if (!get_aim_dir(&dir))
+ {
+ return NO_CAST;
+ }
+
+ get_belegaer_damage(&dice, &sides);
+ return cast(fire_bolt_or_beam(2 * get_level_s(ULMO_BELEGAER, 85),
+ GF_WATER,
+ dir,
+ damroll(dice, sides)));
+}
+
+const char *ulmo_song_of_belegaer_info()
+{
+ static char buf[128];
+ int dice, sides;
+
+ get_belegaer_damage(&dice, &sides);
+ sprintf(buf,
+ "dam %dd%d",
+ dice,
+ sides);
+ return buf;
+}
+
+int draught_of_ulmonan_hp()
+{
+ return 5 * get_level_s(ULMO_DRAUGHT_ULMONAN, 50);
+}
+
+casting_result ulmo_draught_of_ulmonan_spell()
+{
+ casting_result result = NO_CAST;
+ s32b level = get_level_s(ULMO_DRAUGHT_ULMONAN, 50);
+
+ result = cplus(result, hp_player(draught_of_ulmonan_hp()));
+
+ result = cplus(result, set_poisoned(0));
+ result = cplus(result, set_cut(0));
+ result = cplus(result, set_stun(0));
+ result = cplus(result, set_blind(0));
+
+ if (level >= 10)
+ {
+ result = cplus(result, do_res_stat(A_STR, TRUE));
+ result = cplus(result, do_res_stat(A_CON, TRUE));
+ result = cplus(result, do_res_stat(A_DEX, TRUE));
+ }
+
+ if (level >= 20)
+ {
+ result = cplus(result, set_parasite(0, 0));
+ result = cplus(result, set_mimic(0, 0, 0));
+ }
+
+ return result;
+}
+
+const char *ulmo_draught_of_ulmonan_info()
+{
+ static char buf[128];
+ sprintf(buf,
+ "cure %d",
+ draught_of_ulmonan_hp());
+ return buf;
+}
+
+static int call_of_the_ulumuri_mlev()
+{
+ return 30 + get_level(ULMO_CALL_ULUMURI, 70, 0);
+}
+
+casting_result ulmo_call_of_the_ulumuri_spell()
+{
+ int x,y;
+ s16b m_idx;
+ std::vector<int> summons {
+ test_monster_name("Water spirit"),
+ test_monster_name("Water elemental")
+ };
+
+ int r_idx = summons[rand_int(summons.size())];
+ assert(r_idx >= 0);
+
+ find_position(p_ptr->py, p_ptr->px, &y, &x);
+
+ m_idx = place_monster_one(y, x, r_idx, 0, FALSE, MSTATUS_FRIEND);
+ if (m_idx)
+ {
+ monster_set_level(m_idx, call_of_the_ulumuri_mlev());
+ return CAST_OBVIOUS;
+ }
+
+ return NO_CAST;
+}
+
+const char *ulmo_call_of_the_ulumuri_info()
+{
+ static char buf[128];
+ sprintf(buf,
+ "level %d",
+ call_of_the_ulumuri_mlev());
+ return buf;
+}
+
+static int wrath_of_ulmo_damage()
+{
+ return 40 + get_level_s(ULMO_WRATH, 150);
+}
+
+static int wrath_of_ulmo_duration()
+{
+ return 10 + get_level_s(ULMO_WRATH, 14);
+}
+
+casting_result ulmo_wrath_of_ulmo_spell()
+{
+ int dir, type = GF_WATER;
+
+ if (get_level_s(ULMO_WRATH, 50) >= 30)
+ {
+ type = GF_WAVE;
+ }
+
+ if (!get_aim_dir(&dir))
+ {
+ return NO_CAST;
+ }
+
+ fire_wall(type,
+ dir,
+ wrath_of_ulmo_damage(),
+ wrath_of_ulmo_duration());
+ return CAST_OBVIOUS;
+}
+
+const char *ulmo_wrath_of_ulmo_info()
+{
+ static char buf[128];
+ sprintf(buf,
+ "dam %d dur %d",
+ wrath_of_ulmo_damage(),
+ wrath_of_ulmo_duration());
+ return buf;
+}
+
+static int light_of_valinor_damage()
+{
+ return 10 + get_level_s(VARDA_LIGHT_VALINOR, 100);
+}
+
+static int light_of_valinor_radius()
+{
+ return 5 + get_level_s(VARDA_LIGHT_VALINOR, 6);
+}
+
+casting_result varda_light_of_valinor_spell()
+{
+ casting_result result = NO_CAST;
+
+ if (get_level_s(VARDA_LIGHT_VALINOR, 50) >= 3)
+ {
+ result = cplus(result, lite_area(10, 4));
+ }
+ else
+ {
+ lite_room(p_ptr->py, p_ptr->px);
+ result = CAST_OBVIOUS;
+ }
+
+ if (get_level_s(VARDA_LIGHT_VALINOR, 50) >= 15)
+ {
+ result = cplus(result,
+ fire_ball(GF_LITE,
+ 0,
+ light_of_valinor_damage(),
+ light_of_valinor_radius()));
+ }
+
+ return result;
+}
+
+const char *varda_light_of_valinor_info()
+{
+ static char buf[128];
+ if (get_level_s(VARDA_LIGHT_VALINOR, 50) >= 15)
+ {
+ sprintf(buf,
+ "dam %d rad %d",
+ light_of_valinor_damage(),
+ light_of_valinor_radius());
+ return buf;
+ }
+ else
+ {
+ return "";
+ }
+}
+
+casting_result varda_call_of_almaren_spell()
+{
+ int power = 5 * p_ptr->lev;
+ if (get_level_s(VARDA_CALL_ALMAREN, 50) >= 20)
+ {
+ dispel_evil(power);
+ }
+ else
+ {
+ banish_evil(power);
+ }
+ return CAST_OBVIOUS;
+}
+
+casting_result varda_evenstar_spell()
+{
+ wiz_lite_extra();
+ if (get_level_s(VARDA_EVENSTAR, 50) >= 40)
+ {
+ identify_pack();
+ self_knowledge(NULL);
+ }
+
+ return CAST_OBVIOUS;
+}
+
+static int star_kindler_bursts()
+{
+ return p_ptr->lev / 5;
+}
+
+static int star_kindler_damage()
+{
+ return 20 + get_level_s(VARDA_STARKINDLER, 100);
+}
+
+casting_result varda_star_kindler_spell()
+{
+ int dir, i, n = star_kindler_bursts();
+
+ if (!get_aim_dir(&dir))
+ {
+ return NO_CAST;
+ }
+
+ for (i = 0; i < n; i++)
+ {
+ fire_ball(GF_LITE,
+ dir,
+ star_kindler_damage(),
+ 10);
+ }
+
+ return CAST_OBVIOUS;
+}
+
+const char *varda_star_kindler_info()
+{
+ static char buf[128];
+ sprintf(buf,
+ "dam %d bursts %d rad 10",
+ star_kindler_damage(),
+ star_kindler_bursts());
+ return buf;
+}
+
diff --git a/src/spells3.hpp b/src/spells3.hpp
new file mode 100644
index 00000000..3380203a
--- /dev/null
+++ b/src/spells3.hpp
@@ -0,0 +1,445 @@
+#pragma once
+
+#include "spell_type_fwd.hpp"
+#include "h-basic.h"
+#include "timer_type_fwd.hpp"
+
+extern s32b NOXIOUSCLOUD;
+extern s32b AIRWINGS;
+extern s32b INVISIBILITY;
+extern s32b POISONBLOOD;
+extern s32b THUNDERSTORM;
+extern s32b STERILIZE;
+
+casting_result air_noxious_cloud();
+const char *air_noxious_cloud_info();
+casting_result air_wings_of_winds();
+const char *air_wings_of_winds_info();
+casting_result air_invisibility();
+const char *air_invisibility_info();
+casting_result air_poison_blood();
+const char *air_poison_blood_info();
+casting_result air_thunderstorm();
+const char *air_thunderstorm_info();
+casting_result air_sterilize();
+const char *air_sterilize_info();
+
+extern s32b BLINK;
+extern s32b DISARM;
+extern s32b TELEPORT;
+extern s32b TELEAWAY;
+extern s32b RECALL;
+extern s32b PROBABILITY_TRAVEL;
+
+casting_result convey_blink();
+const char *convey_blink_info();
+casting_result convey_disarm();
+casting_result convey_teleport();
+const char *convey_teleport_info();
+casting_result convey_teleport_away();
+casting_result convey_recall();
+const char *convey_recall_info();
+casting_result convey_probability_travel();
+const char *convey_probability_travel_info();
+
+extern s32b DEMON_BLADE;
+extern s32b DEMON_MADNESS;
+extern s32b DEMON_FIELD;
+extern s32b DOOM_SHIELD;
+extern s32b UNHOLY_WORD;
+extern s32b DEMON_CLOAK;
+extern s32b DEMON_SUMMON;
+extern s32b DISCHARGE_MINION;
+extern s32b CONTROL_DEMON;
+
+casting_result demonology_demon_blade();
+const char *demonology_demon_blade_info();
+casting_result demonology_demon_madness();
+const char *demonology_demon_madness_info();
+casting_result demonology_demon_field();
+const char *demonology_demon_field_info();
+casting_result demonology_doom_shield();
+const char *demonology_doom_shield_info();
+casting_result demonology_unholy_word();
+const char *demonology_unholy_word_info();
+casting_result demonology_demon_cloak();
+const char *demonology_demon_cloak_info();
+casting_result demonology_summon_demon();
+const char *demonology_summon_demon_info();
+casting_result demonology_discharge_minion();
+const char *demonology_discharge_minion_info();
+casting_result demonology_control_demon();
+const char *demonology_control_demon_info();
+
+extern s32b STARIDENTIFY;
+extern s32b IDENTIFY;
+extern s32b VISION;
+extern s32b SENSEHIDDEN;
+extern s32b REVEALWAYS;
+extern s32b SENSEMONSTERS;
+
+casting_result divination_greater_identify();
+casting_result divination_identify();
+const char *divination_identify_info();
+casting_result divination_vision();
+casting_result divination_sense_hidden();
+const char *divination_sense_hidden_info();
+casting_result divination_reveal_ways();
+const char *divination_reveal_ways_info();
+casting_result divination_sense_monsters();
+const char *divination_sense_monsters_info();
+
+extern s32b STONESKIN;
+extern s32b DIG;
+extern s32b STONEPRISON;
+extern s32b STRIKE;
+extern s32b SHAKE;
+
+casting_result earth_stone_skin();
+const char *earth_stone_skin_info();
+casting_result earth_dig();
+casting_result earth_stone_prison();
+casting_result earth_strike();
+const char *earth_strike_info();
+casting_result earth_shake();
+const char *earth_shake_info();
+
+extern s32b ERU_SEE;
+extern s32b ERU_LISTEN;
+extern s32b ERU_UNDERSTAND;
+extern s32b ERU_PROT;
+
+casting_result eru_see_the_music();
+const char *eru_see_the_music_info();
+casting_result eru_listen_to_the_music();
+casting_result eru_know_the_music();
+casting_result eru_lay_of_protection();
+const char *eru_lay_of_protection_info();
+
+extern s32b GLOBELIGHT;
+extern s32b FIREFLASH;
+extern s32b FIERYAURA;
+extern s32b FIREWALL;
+extern s32b FIREGOLEM;
+
+casting_result fire_globe_of_light();
+const char *fire_globe_of_light_info();
+casting_result fire_fireflash();
+const char *fire_fireflash_info();
+casting_result fire_fiery_shield();
+const char *fire_fiery_shield_info();
+casting_result fire_firewall();
+const char *fire_firewall_info();
+casting_result fire_golem();
+const char *fire_golem_info();
+
+extern s32b CALL_THE_ELEMENTS;
+extern s32b CHANNEL_ELEMENTS;
+extern s32b ELEMENTAL_WAVE;
+extern s32b VAPORIZE;
+extern s32b GEOLYSIS;
+extern s32b DRIPPING_TREAD;
+extern s32b GROW_BARRIER;
+extern s32b ELEMENTAL_MINION;
+
+casting_result geomancy_call_the_elements();
+const char *geomancy_call_the_elements_info();
+casting_result geomancy_channel_elements();
+casting_result geomancy_elemental_wave();
+casting_result geomancy_vaporize();
+const char *geomancy_vaporize_info();
+bool_ geomancy_vaporize_depends();
+casting_result geomancy_geolysis();
+const char *geomancy_geolysis_info();
+bool_ geomancy_geolysis_depends();
+casting_result geomancy_dripping_tread();
+const char *geomancy_dripping_tread_info();
+bool_ geomancy_dripping_tread_depends();
+casting_result geomancy_grow_barrier();
+bool_ geomancy_grow_barrier_depends();
+casting_result geomancy_elemental_minion();
+const char *geomancy_elemental_minion_info();
+
+extern s32b MANATHRUST;
+extern s32b DELCURSES;
+extern s32b RESISTS;
+extern s32b MANASHIELD;
+
+casting_result mana_manathrust();
+const char *mana_manathrust_info();
+casting_result mana_remove_curses();
+casting_result mana_elemental_shield();
+const char *mana_elemental_shield_info();
+casting_result mana_disruption_shield();
+const char *mana_disruption_shield_info();
+
+extern s32b MANWE_SHIELD;
+extern s32b MANWE_AVATAR;
+extern s32b MANWE_BLESS;
+extern s32b MANWE_CALL;
+
+casting_result manwe_wind_shield();
+const char *manwe_wind_shield_info();
+casting_result manwe_avatar();
+const char *manwe_avatar_info();
+casting_result manwe_blessing();
+const char *manwe_blessing_info();
+casting_result manwe_call();
+const char *manwe_call_info();
+
+extern s32b MELKOR_CURSE;
+extern s32b MELKOR_CORPSE_EXPLOSION;
+extern s32b MELKOR_MIND_STEAL;
+
+void do_melkor_curse(int m_idx);
+
+casting_result melkor_curse();
+casting_result melkor_corpse_explosion();
+const char *melkor_corpse_explosion_info();
+casting_result melkor_mind_steal();
+const char *melkor_mind_steal_info();
+
+extern s32b RECHARGE;
+extern s32b SPELLBINDER;
+extern s32b DISPERSEMAGIC;
+extern s32b TRACKER;
+extern s32b INERTIA_CONTROL;
+extern timer_type *TIMER_INERTIA_CONTROL;
+
+casting_result meta_recharge();
+const char *meta_recharge_info();
+casting_result meta_spellbinder();
+const char *meta_spellbinder_info();
+casting_result meta_disperse_magic();
+casting_result meta_tracker();
+casting_result meta_inertia_control();
+const char *meta_inertia_control_info();
+
+void meta_inertia_control_timer_callback();
+void meta_inertia_control_calc_mana(int *msp);
+void meta_inertia_control_hook_birth_objects();
+
+extern s32b CHARM;
+extern s32b CONFUSE;
+extern s32b ARMOROFFEAR;
+extern s32b STUN;
+
+casting_result mind_charm();
+const char *mind_charm_info();
+casting_result mind_confuse();
+const char *mind_confuse_info();
+casting_result mind_armor_of_fear();
+const char *mind_armor_of_fear_info();
+casting_result mind_stun();
+const char *mind_stun_info();
+
+extern s32b MAGELOCK;
+extern s32b SLOWMONSTER;
+extern s32b ESSENCESPEED;
+extern s32b BANISHMENT;
+
+casting_result tempo_magelock();
+casting_result tempo_slow_monster();
+const char *tempo_slow_monster_info();
+casting_result tempo_essence_of_speed();
+const char *tempo_essence_of_speed_info();
+casting_result tempo_banishment();
+const char *tempo_banishment_info();
+
+extern s32b TULKAS_AIM;
+extern s32b TULKAS_WAVE;
+extern s32b TULKAS_SPIN;
+
+casting_result tulkas_divine_aim();
+const char *tulkas_divine_aim_info();
+casting_result tulkas_wave_of_power();
+const char *tulkas_wave_of_power_info();
+casting_result tulkas_whirlwind();
+
+extern s32b DRAIN;
+extern s32b GENOCIDE;
+extern s32b WRAITHFORM;
+extern s32b FLAMEOFUDUN;
+
+int udun_in_book(s32b sval, s32b pval);
+int levels_in_book(s32b sval, s32b pval);
+
+casting_result udun_drain();
+casting_result udun_genocide();
+casting_result udun_wraithform();
+const char *udun_wraithform_info();
+casting_result udun_flame_of_udun();
+const char *udun_flame_of_udun_info();
+
+extern s32b TIDALWAVE;
+extern s32b ICESTORM;
+extern s32b ENTPOTION;
+extern s32b VAPOR;
+extern s32b GEYSER;
+
+casting_result water_tidal_wave();
+const char *water_tidal_wave_info();
+casting_result water_ice_storm();
+const char *water_ice_storm_info();
+casting_result water_ent_potion();
+const char *water_ent_potion_info();
+casting_result water_vapor();
+const char *water_vapor_info();
+casting_result water_geyser();
+const char *water_geyser_info();
+
+extern s32b YAVANNA_CHARM_ANIMAL;
+extern s32b YAVANNA_GROW_GRASS;
+extern s32b YAVANNA_TREE_ROOTS;
+extern s32b YAVANNA_WATER_BITE;
+extern s32b YAVANNA_UPROOT;
+
+casting_result yavanna_charm_animal();
+const char *yavanna_charm_animal_info();
+casting_result yavanna_grow_grass();
+const char *yavanna_grow_grass_info();
+casting_result yavanna_tree_roots();
+const char *yavanna_tree_roots_info();
+casting_result yavanna_water_bite();
+const char *yavanna_water_bite_info();
+casting_result yavanna_uproot();
+const char *yavanna_uproot_info();
+
+extern s32b GROWTREE;
+extern s32b HEALING;
+extern s32b RECOVERY;
+extern s32b REGENERATION;
+extern s32b SUMMONANNIMAL;
+extern s32b GROW_ATHELAS;
+
+casting_result nature_grow_trees();
+const char *nature_grow_trees_info();
+casting_result nature_healing();
+const char *nature_healing_info();
+casting_result nature_recovery();
+casting_result nature_regeneration();
+const char *nature_regeneration_info();
+casting_result nature_summon_animal();
+const char *nature_summon_animal_info();
+casting_result nature_grow_athelas();
+
+extern s32b DEVICE_HEAL_MONSTER;
+extern s32b DEVICE_SPEED_MONSTER;
+extern s32b DEVICE_WISH;
+extern s32b DEVICE_SUMMON;
+extern s32b DEVICE_MANA;
+extern s32b DEVICE_NOTHING;
+extern s32b DEVICE_HOLY_FIRE;
+extern s32b DEVICE_THUNDERLORDS;
+
+casting_result device_heal_monster();
+const char *device_heal_monster_info();
+casting_result device_haste_monster();
+const char *device_haste_monster_info();
+casting_result device_wish();
+casting_result device_summon_monster();
+casting_result device_mana();
+const char *device_mana_info();
+casting_result device_nothing();
+casting_result device_holy_fire();
+const char *device_holy_fire_info();
+casting_result device_thunderlords();
+
+extern s32b MUSIC_STOP;
+extern s32b MUSIC_HOLD;
+extern s32b MUSIC_CONF;
+extern s32b MUSIC_STUN;
+extern s32b MUSIC_LITE;
+extern s32b MUSIC_HEAL;
+extern s32b MUSIC_HERO;
+extern s32b MUSIC_TIME;
+extern s32b MUSIC_MIND;
+extern s32b MUSIC_BLOW;
+extern s32b MUSIC_WIND;
+extern s32b MUSIC_YLMIR;
+extern s32b MUSIC_AMBARKANTA;
+
+casting_result music_stop_singing_spell();
+int music_holding_pattern_lasting();
+casting_result music_holding_pattern_spell();
+const char *music_holding_pattern_info();
+int music_illusion_pattern_lasting();
+casting_result music_illusion_pattern_spell();
+const char *music_illusion_pattern_info();
+int music_stun_pattern_lasting();
+casting_result music_stun_pattern_spell();
+const char *music_stun_pattern_info();
+int music_song_of_the_sun_lasting();
+casting_result music_song_of_the_sun_spell();
+int music_flow_of_life_lasting();
+casting_result music_flow_of_life_spell();
+const char *music_flow_of_life_info();
+int music_heroic_ballad_lasting();
+casting_result music_heroic_ballad_spell();
+int music_hobbit_melodies_lasting();
+casting_result music_hobbit_melodies_spell();
+const char *music_hobbit_melodies_info();
+int music_clairaudience_lasting();
+casting_result music_clairaudience_spell();
+const char *music_clairaudience_info();
+casting_result music_blow_spell();
+const char *music_blow_info();
+casting_result music_gush_of_wind_spell();
+const char *music_gush_of_wind_info();
+casting_result music_horns_of_ylmir_spell();
+const char *music_horns_of_ylmir_info();
+casting_result music_ambarkanta_spell();
+
+extern s32b AULE_FIREBRAND;
+extern s32b AULE_ENCHANT_WEAPON;
+extern s32b AULE_ENCHANT_ARMOUR;
+extern s32b AULE_CHILD;
+
+casting_result aule_firebrand_spell();
+const char *aule_firebrand_info();
+casting_result aule_enchant_weapon_spell();
+const char *aule_enchant_weapon_info();
+casting_result aule_enchant_armour_spell();
+const char *aule_enchant_armour_info();
+casting_result aule_child_spell();
+const char *aule_child_info();
+
+extern s32b MANDOS_TEARS_LUTHIEN;
+extern s32b MANDOS_SPIRIT_FEANTURI;
+extern s32b MANDOS_TALE_DOOM;
+extern s32b MANDOS_CALL_HALLS;
+
+casting_result mandos_tears_of_luthien_spell();
+const char *mandos_tears_of_luthien_info();
+casting_result mandos_spirit_of_the_feanturi_spell();
+const char *mandos_spirit_of_the_feanturi_info();
+casting_result mandos_tale_of_doom_spell();
+const char *mandos_tale_of_doom_info();
+casting_result mandos_call_to_the_halls_spell();
+const char *mandos_call_to_the_halls_info();
+
+extern s32b ULMO_BELEGAER;
+extern s32b ULMO_DRAUGHT_ULMONAN;
+extern s32b ULMO_CALL_ULUMURI;
+extern s32b ULMO_WRATH;
+
+casting_result ulmo_song_of_belegaer_spell();
+const char *ulmo_song_of_belegaer_info();
+casting_result ulmo_draught_of_ulmonan_spell();
+const char *ulmo_draught_of_ulmonan_info();
+casting_result ulmo_call_of_the_ulumuri_spell();
+const char *ulmo_call_of_the_ulumuri_info();
+casting_result ulmo_wrath_of_ulmo_spell();
+const char *ulmo_wrath_of_ulmo_info();
+
+extern s32b VARDA_LIGHT_VALINOR;
+extern s32b VARDA_CALL_ALMAREN;
+extern s32b VARDA_EVENSTAR;
+extern s32b VARDA_STARKINDLER;
+
+casting_result varda_light_of_valinor_spell();
+const char *varda_light_of_valinor_info();
+casting_result varda_call_of_almaren_spell();
+casting_result varda_evenstar_spell();
+casting_result varda_star_kindler_spell();
+const char *varda_star_kindler_info();
diff --git a/src/spells4.cc b/src/spells4.cc
new file mode 100644
index 00000000..62586758
--- /dev/null
+++ b/src/spells4.cc
@@ -0,0 +1,541 @@
+#include "spells4.hpp"
+
+#include "cave.hpp"
+#include "cmd5.hpp"
+#include "gods.hpp"
+#include "lua_bind.hpp"
+#include "options.hpp"
+#include "player_type.hpp"
+#include "school_book.hpp"
+#include "spell_type.hpp"
+#include "spells3.hpp"
+#include "spells5.hpp"
+#include "spells6.hpp"
+#include "util.hpp"
+#include "util.h"
+#include "variable.hpp"
+#include "z-rand.hpp"
+
+#include <algorithm>
+#include <array>
+#include <cassert>
+#include <sstream>
+
+static std::array<school_book, SCHOOL_BOOKS_SIZE> &school_books() {
+ static std::array<school_book, SCHOOL_BOOKS_SIZE> *instance = new std::array<school_book, SCHOOL_BOOKS_SIZE>;
+ return *instance;
+}
+
+
+s32b SCHOOL_AIR;
+s32b SCHOOL_AULE;
+s32b SCHOOL_CONVEYANCE;
+s32b SCHOOL_DEMON;
+s32b SCHOOL_DEVICE;
+s32b SCHOOL_DIVINATION;
+s32b SCHOOL_EARTH;
+s32b SCHOOL_ERU;
+s32b SCHOOL_FIRE;
+s32b SCHOOL_GEOMANCY;
+s32b SCHOOL_MANA;
+s32b SCHOOL_MANDOS;
+s32b SCHOOL_MANWE;
+s32b SCHOOL_MELKOR;
+s32b SCHOOL_META;
+s32b SCHOOL_MIND;
+s32b SCHOOL_MUSIC;
+s32b SCHOOL_NATURE;
+s32b SCHOOL_TEMPORAL;
+s32b SCHOOL_TULKAS;
+s32b SCHOOL_UDUN;
+s32b SCHOOL_ULMO;
+s32b SCHOOL_VARDA;
+s32b SCHOOL_WATER;
+s32b SCHOOL_YAVANNA;
+
+static bool_ uses_piety_to_cast(int s)
+{
+ return spell_type_uses_piety_to_cast(spell_at(s));
+}
+
+/** Describe what type of energy the spell uses for casting */
+cptr get_power_name(s32b s)
+{
+ return uses_piety_to_cast(s) ? "piety" : "mana";
+}
+
+/* Changes the amount of power(mana, piety, whatever) for the spell */
+void adjust_power(s32b s, s32b amount)
+{
+ if (uses_piety_to_cast(s))
+ {
+ inc_piety(GOD_ALL, amount);
+ }
+ else
+ {
+ increase_mana(amount);
+ }
+}
+
+/* Return the amount of power available for casting spell */
+s32b get_power(s32b s)
+{
+ return uses_piety_to_cast(s) ? p_ptr->grace : p_ptr->csp;
+}
+
+/* Output the describtion when it is used as a spell */
+void print_spell_desc(int s, int y)
+{
+ spell_type *spell = spell_at(s);
+
+ spell_type_description_foreach(spell,
+ [&y] (std::string const &text) -> void {
+ c_prt(TERM_L_BLUE, text.c_str(), y, 0);
+ y += 1;
+ });
+
+ if (spell_type_uses_piety_to_cast(spell))
+ {
+ c_prt(TERM_L_WHITE, "It uses piety to cast.", y, 0);
+ y++;
+ }
+
+ if (spell_type_castable_while_blind(spell))
+ {
+ c_prt(TERM_ORANGE, "It is castable even while blinded.", y, 0);
+ y++;
+ }
+
+ if (spell_type_castable_while_confused(spell))
+ {
+ c_prt(TERM_ORANGE, "It is castable even while confused.", y, 0);
+ y++;
+ }
+}
+
+school_book *school_books_at(int i)
+{
+ assert(i >= 0);
+ assert(i < SCHOOL_BOOKS_SIZE);
+ return &school_books()[i];
+}
+
+void school_book_add_spell(school_book *school_book, s32b spell_idx)
+{
+ assert(school_book != nullptr);
+ school_book->spell_idxs.insert(std::begin(school_book->spell_idxs), spell_idx);
+}
+
+int school_book_length(int sval)
+{
+ school_book *school_book = school_books_at(sval);
+ return school_book->spell_idxs.size();
+}
+
+int spell_x(int sval, int spell_idx, int i)
+{
+ assert(i >= 0);
+
+ if (sval == BOOK_RANDOM)
+ {
+ return spell_idx;
+ }
+ else
+ {
+ school_book *school_book = school_books_at(sval);
+ return school_book->spell_idxs.at(i);
+ }
+}
+
+bool_ school_book_contains_spell(int sval, s32b spell_idx)
+{
+ random_book_setup(sval, spell_idx);
+ school_book *school_book = school_books_at(sval);
+ return (school_book->spell_idxs.end() !=
+ std::find(school_book->spell_idxs.begin(),
+ school_book->spell_idxs.end(),
+ spell_idx));
+}
+
+static void push_spell(int book_idx, s32b spell_idx)
+{
+ school_book *school_book = school_books_at(book_idx);
+ assert(school_book != NULL);
+ school_book_add_spell(school_book, spell_idx);
+}
+
+void init_school_books()
+{
+ /* Note: We're adding the spells in the reverse order that
+ they appear in each book. This is because the list
+ operations insert at the front. */
+
+ /* Create the crystal of mana */
+ push_spell(TOME_MANA, MANASHIELD);
+ push_spell(TOME_MANA, RESISTS);
+ push_spell(TOME_MANA, DELCURSES);
+ push_spell(TOME_MANA, MANATHRUST);
+
+ /* The book of the eternal flame */
+ push_spell(TOME_FIRE, FIERYAURA);
+ push_spell(TOME_FIRE, FIREWALL);
+ push_spell(TOME_FIRE, FIREFLASH);
+ push_spell(TOME_FIRE, FIREGOLEM);
+ push_spell(TOME_FIRE, GLOBELIGHT);
+
+ /* The book of the blowing winds */
+ push_spell(TOME_WINDS, THUNDERSTORM);
+ push_spell(TOME_WINDS, AIRWINGS);
+ push_spell(TOME_WINDS, STERILIZE);
+ push_spell(TOME_WINDS, INVISIBILITY);
+ push_spell(TOME_WINDS, POISONBLOOD);
+ push_spell(TOME_WINDS, NOXIOUSCLOUD);
+
+ /* The book of the impenetrable earth */
+ push_spell(TOME_EARTH, STRIKE);
+ push_spell(TOME_EARTH, SHAKE);
+ push_spell(TOME_EARTH, STONEPRISON);
+ push_spell(TOME_EARTH, DIG);
+ push_spell(TOME_EARTH, STONESKIN);
+
+ /* The book of the unstopable wave */
+ push_spell(TOME_WATER, ICESTORM);
+ push_spell(TOME_WATER, TIDALWAVE);
+ push_spell(TOME_WATER, ENTPOTION);
+ push_spell(TOME_WATER, VAPOR);
+ push_spell(TOME_WATER, GEYSER);
+
+ /* Create the book of translocation */
+ push_spell(TOME_TRANSLOCATION, PROBABILITY_TRAVEL);
+ push_spell(TOME_TRANSLOCATION, RECALL);
+ push_spell(TOME_TRANSLOCATION, TELEAWAY);
+ push_spell(TOME_TRANSLOCATION, TELEPORT);
+ push_spell(TOME_TRANSLOCATION, DISARM);
+ push_spell(TOME_TRANSLOCATION, BLINK);
+
+ /* Create the book of the tree */
+ if (game_module_idx == MODULE_THEME)
+ {
+ push_spell(TOME_NATURE, GROW_ATHELAS);
+ }
+ push_spell(TOME_NATURE, SUMMONANNIMAL);
+ push_spell(TOME_NATURE, REGENERATION);
+ push_spell(TOME_NATURE, RECOVERY);
+ push_spell(TOME_NATURE, HEALING);
+ push_spell(TOME_NATURE, GROWTREE);
+
+ /* Create the book of Knowledge */
+ push_spell(TOME_KNOWLEDGE, STARIDENTIFY);
+ push_spell(TOME_KNOWLEDGE, VISION);
+ push_spell(TOME_KNOWLEDGE, IDENTIFY);
+ push_spell(TOME_KNOWLEDGE, REVEALWAYS);
+ push_spell(TOME_KNOWLEDGE, SENSEHIDDEN);
+ push_spell(TOME_KNOWLEDGE, SENSEMONSTERS);
+
+ /* Create the book of the Time */
+ push_spell(TOME_TIME, BANISHMENT);
+ push_spell(TOME_TIME, ESSENCESPEED);
+ push_spell(TOME_TIME, SLOWMONSTER);
+ push_spell(TOME_TIME, MAGELOCK);
+
+ /* Create the book of meta spells */
+ push_spell(TOME_META, INERTIA_CONTROL);
+ push_spell(TOME_META, TRACKER);
+ push_spell(TOME_META, SPELLBINDER);
+ push_spell(TOME_META, DISPERSEMAGIC);
+ push_spell(TOME_META, RECHARGE);
+
+ /* Create the book of the mind */
+ push_spell(TOME_MIND, STUN);
+ push_spell(TOME_MIND, ARMOROFFEAR);
+ push_spell(TOME_MIND, CONFUSE);
+ push_spell(TOME_MIND, CHARM);
+
+ /* Create the book of hellflame */
+ push_spell(TOME_HELLFLAME, FLAMEOFUDUN);
+ push_spell(TOME_HELLFLAME, WRAITHFORM);
+ push_spell(TOME_HELLFLAME, GENOCIDE);
+ push_spell(TOME_HELLFLAME, DRAIN);
+
+ /* Create the book of eru */
+ push_spell(TOME_ERU, ERU_PROT);
+ push_spell(TOME_ERU, ERU_UNDERSTAND);
+ push_spell(TOME_ERU, ERU_LISTEN);
+ push_spell(TOME_ERU, ERU_SEE);
+
+ /* Create the book of manwe */
+ push_spell(TOME_MANWE, MANWE_AVATAR);
+ push_spell(TOME_MANWE, MANWE_CALL);
+ push_spell(TOME_MANWE, MANWE_SHIELD);
+ push_spell(TOME_MANWE, MANWE_BLESS);
+
+ /* Create the book of tulkas */
+ push_spell(TOME_TULKAS, TULKAS_WAVE);
+ push_spell(TOME_TULKAS, TULKAS_SPIN);
+ push_spell(TOME_TULKAS, TULKAS_AIM);
+
+ /* Create the book of melkor */
+ push_spell(TOME_MELKOR, MELKOR_MIND_STEAL);
+ push_spell(TOME_MELKOR, MELKOR_CORPSE_EXPLOSION);
+ push_spell(TOME_MELKOR, MELKOR_CURSE);
+
+ /* Create the book of yavanna */
+ push_spell(TOME_YAVANNA, YAVANNA_UPROOT);
+ push_spell(TOME_YAVANNA, YAVANNA_WATER_BITE);
+ push_spell(TOME_YAVANNA, YAVANNA_TREE_ROOTS);
+ push_spell(TOME_YAVANNA, YAVANNA_GROW_GRASS);
+ push_spell(TOME_YAVANNA, YAVANNA_CHARM_ANIMAL);
+
+ /* Create the book of beginner's cantrip */
+ push_spell(BOOK_CANTRIPS, SENSEHIDDEN);
+ push_spell(BOOK_CANTRIPS, SENSEMONSTERS);
+ push_spell(BOOK_CANTRIPS, BLINK);
+ push_spell(BOOK_CANTRIPS, ENTPOTION);
+ push_spell(BOOK_CANTRIPS, GLOBELIGHT);
+ push_spell(BOOK_CANTRIPS, MANATHRUST);
+
+ /* Create the book of teleporatation */
+ push_spell(BOOK_TELEPORTATION, TELEAWAY);
+ push_spell(BOOK_TELEPORTATION, TELEPORT);
+ push_spell(BOOK_TELEPORTATION, BLINK);
+
+ /* Create the book of summoning */
+ push_spell(BOOK_SUMMONING, SUMMONANNIMAL);
+ push_spell(BOOK_SUMMONING, FIREGOLEM);
+
+ /* Create the Armageddon Demonblade */
+ push_spell(BOOK_DEMON_SWORD, DEMON_FIELD);
+ push_spell(BOOK_DEMON_SWORD, DEMON_MADNESS);
+ push_spell(BOOK_DEMON_SWORD, DEMON_BLADE);
+
+ /* Create the Shield Demonblade */
+ push_spell(BOOK_DEMON_SHIELD, UNHOLY_WORD);
+ push_spell(BOOK_DEMON_SHIELD, DEMON_CLOAK);
+ push_spell(BOOK_DEMON_SHIELD, DOOM_SHIELD);
+
+ /* Create the Control Demonblade */
+ push_spell(BOOK_DEMON_HELM, CONTROL_DEMON);
+ push_spell(BOOK_DEMON_HELM, DISCHARGE_MINION);
+ push_spell(BOOK_DEMON_HELM, DEMON_SUMMON);
+
+ /* Create the Drums */
+ push_spell(BOOK_DRUMS, MUSIC_STUN);
+ push_spell(BOOK_DRUMS, MUSIC_CONF);
+ push_spell(BOOK_DRUMS, MUSIC_HOLD);
+ push_spell(BOOK_DRUMS, MUSIC_STOP);
+
+ /* Create the Harps */
+ push_spell(BOOK_HARPS, MUSIC_MIND);
+ push_spell(BOOK_HARPS, MUSIC_TIME);
+ push_spell(BOOK_HARPS, MUSIC_HEAL);
+ push_spell(BOOK_HARPS, MUSIC_HERO);
+ push_spell(BOOK_HARPS, MUSIC_LITE);
+ push_spell(BOOK_HARPS, MUSIC_STOP);
+
+ /* Create the Horns */
+ push_spell(BOOK_HORNS, MUSIC_AMBARKANTA);
+ push_spell(BOOK_HORNS, MUSIC_YLMIR);
+ push_spell(BOOK_HORNS, MUSIC_WIND);
+ push_spell(BOOK_HORNS, MUSIC_BLOW);
+ push_spell(BOOK_HORNS, MUSIC_STOP);
+
+ /* Book of the Player, filled in by the Library Quest */
+ push_spell(BOOK_PLAYER, -1);
+
+ /* Geomancy spells, not a real book */
+ push_spell(BOOK_GEOMANCY, ELEMENTAL_MINION);
+ push_spell(BOOK_GEOMANCY, GROW_BARRIER);
+ push_spell(BOOK_GEOMANCY, DRIPPING_TREAD);
+ push_spell(BOOK_GEOMANCY, GEOLYSIS);
+ push_spell(BOOK_GEOMANCY, VAPORIZE);
+ push_spell(BOOK_GEOMANCY, ELEMENTAL_WAVE);
+ push_spell(BOOK_GEOMANCY, CHANNEL_ELEMENTS);
+ push_spell(BOOK_GEOMANCY, CALL_THE_ELEMENTS);
+
+ if (game_module_idx == MODULE_THEME)
+ {
+ /* Aule */
+ push_spell(BOOK_AULE, AULE_CHILD);
+ push_spell(BOOK_AULE, AULE_ENCHANT_ARMOUR);
+ push_spell(BOOK_AULE, AULE_ENCHANT_WEAPON);
+ push_spell(BOOK_AULE, AULE_FIREBRAND);
+
+ /* Varda */
+ push_spell(BOOK_VARDA, VARDA_STARKINDLER);
+ push_spell(BOOK_VARDA, VARDA_EVENSTAR);
+ push_spell(BOOK_VARDA, VARDA_CALL_ALMAREN);
+ push_spell(BOOK_VARDA, VARDA_LIGHT_VALINOR);
+
+ /* Ulmo */
+ push_spell(BOOK_ULMO, ULMO_WRATH);
+ push_spell(BOOK_ULMO, ULMO_CALL_ULUMURI);
+ push_spell(BOOK_ULMO, ULMO_DRAUGHT_ULMONAN);
+ push_spell(BOOK_ULMO, ULMO_BELEGAER);
+
+ /* Mandos */
+ push_spell(BOOK_MANDOS, MANDOS_CALL_HALLS);
+ push_spell(BOOK_MANDOS, MANDOS_TALE_DOOM);
+ push_spell(BOOK_MANDOS, MANDOS_SPIRIT_FEANTURI);
+ push_spell(BOOK_MANDOS, MANDOS_TEARS_LUTHIEN);
+ }
+
+ /* Random spell book; just initialize to anything */
+ push_spell(BOOK_RANDOM, -1);
+}
+
+void random_book_setup(s16b sval, s32b spell_idx)
+{
+ if (sval == BOOK_RANDOM)
+ {
+ school_book *school_book = school_books_at(sval);
+ school_book->spell_idxs.clear();
+ school_book->spell_idxs.push_back(spell_idx);
+ }
+}
+
+static std::string spell_school_name(spell_type *spell)
+{
+ std::ostringstream buf;
+ bool first = true;
+
+ for (s32b school_idx : spell_type_get_schools(spell))
+ {
+ school_type *school = school_at(school_idx);
+ // Add separator?
+ if (first)
+ {
+ first = false; // Skip separator
+ }
+ else
+ {
+ buf << "/";
+ }
+ // Put in the school's name
+ buf << school->name;
+ }
+
+ return buf.str();
+}
+
+int print_spell(cptr label_, byte color, int y, s32b s)
+{
+ s32b level;
+ bool_ na;
+ spell_type *spell = spell_at(s);
+ cptr spell_info = spell_type_info(spell);
+ cptr label = (label_ == NULL) ? "" : label_;
+ char level_str[8] = "n/a";
+ char buf[128];
+
+ get_level_school(spell, 50, -50, &level, &na);
+
+ std::string sch_str(spell_school_name(spell));
+
+ if (!na)
+ {
+ sprintf(level_str, "%3d", (int) level);
+ }
+
+ sprintf(buf, "%s%-20s%-16s %s %4d %3d%% %s",
+ label,
+ spell_type_name(spell_at(s)),
+ sch_str.c_str(),
+ level_str,
+ get_mana(s),
+ (int) spell_chance_book(s),
+ spell_info);
+ c_prt(color, buf, y, 0);
+
+ return y + 1;
+}
+
+void lua_cast_school_spell(s32b s, bool_ no_cost)
+{
+ bool_ use = FALSE;
+ spell_type *spell = spell_at(s);
+
+ /* No magic? */
+ if (p_ptr->antimagic > 0)
+ {
+ 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;
+ }
+
+ /* if it costs something then some condition must be met */
+ if (!no_cost)
+ {
+ /* Require lite */
+ if (!spell_type_castable_while_blind(spell) &&
+ ((p_ptr->blind > 0) || no_lite()))
+ {
+ msg_print("You cannot see!");
+ return;
+ }
+
+ /* Not when confused */
+ if (!spell_type_castable_while_confused(spell) &&
+ (p_ptr->confused > 0))
+ {
+ msg_print("You are too confused!");
+ return;
+ }
+
+ /* Enough mana */
+ if (get_mana(s) > get_power(s))
+ {
+ char buf[128];
+ sprintf(buf,
+ "You do not have enough %s, do you want to try anyway?",
+ get_power_name(s));
+
+ if (!get_check(buf))
+ {
+ return;
+ }
+ }
+
+ /* Invoke the spell effect */
+ if (!magik(spell_chance_book(s)))
+ {
+ use = (spell_type_produce_effect(spell) != NO_CAST);
+ }
+ else
+ {
+ use = TRUE;
+
+ /* failures are dangerous; we'll flush the input buffer
+ so it isn't missed. */
+ if (flush_failure)
+ {
+ flush();
+ }
+
+ msg_print("You failed to get the spell off!");
+ }
+ }
+ else
+ {
+ spell_type_produce_effect(spell);
+ }
+
+ /* Use the mana/piety */
+ if (use == TRUE)
+ {
+ /* Reduce mana */
+ adjust_power(s, -get_mana(s));
+
+ /* Take a turn */
+ energy_use = is_magestaff() ? 80 : 100;
+ }
+
+ /* Refresh player */
+ p_ptr->redraw |= PR_FRAME;
+ p_ptr->window |= PW_PLAYER;
+}
diff --git a/src/spells4.hpp b/src/spells4.hpp
new file mode 100644
index 00000000..02cdc3ce
--- /dev/null
+++ b/src/spells4.hpp
@@ -0,0 +1,42 @@
+#pragma once
+
+#include "h-basic.h"
+#include "object_type_fwd.hpp"
+#include "school_book_fwd.hpp"
+
+extern s32b SCHOOL_AIR;
+extern s32b SCHOOL_AULE;
+extern s32b SCHOOL_CONVEYANCE;
+extern s32b SCHOOL_DEMON;
+extern s32b SCHOOL_DEVICE;
+extern s32b SCHOOL_DIVINATION;
+extern s32b SCHOOL_EARTH;
+extern s32b SCHOOL_ERU;
+extern s32b SCHOOL_FIRE;
+extern s32b SCHOOL_GEOMANCY;
+extern s32b SCHOOL_MANA;
+extern s32b SCHOOL_MANDOS;
+extern s32b SCHOOL_MANWE;
+extern s32b SCHOOL_MELKOR;
+extern s32b SCHOOL_META;
+extern s32b SCHOOL_MIND;
+extern s32b SCHOOL_MUSIC;
+extern s32b SCHOOL_NATURE;
+extern s32b SCHOOL_TEMPORAL;
+extern s32b SCHOOL_TULKAS;
+extern s32b SCHOOL_UDUN;
+extern s32b SCHOOL_ULMO;
+extern s32b SCHOOL_VARDA;
+extern s32b SCHOOL_WATER;
+extern s32b SCHOOL_YAVANNA;
+
+void print_spell_desc(int s, int y);
+void init_school_books();
+school_book *school_books_at(int sval);
+void school_book_add_spell(school_book *school_book, s32b spell_idx);
+void random_book_setup(s16b sval, s32b spell_idx);
+int print_spell(cptr label, byte color, int y, s32b s);
+int school_book_length(int sval);
+int spell_x(int sval, int spell_idx, int i);
+bool_ school_book_contains_spell(int sval, s32b spell_idx);
+void lua_cast_school_spell(s32b spell_idx, bool_ no_cost);
diff --git a/src/spells5.cc b/src/spells5.cc
new file mode 100644
index 00000000..f503c822
--- /dev/null
+++ b/src/spells5.cc
@@ -0,0 +1,2395 @@
+#include "spells5.hpp"
+
+#include "spell_type.hpp"
+#include "device_allocation.hpp"
+#include "spells3.hpp"
+#include "spells4.hpp"
+#include "variable.hpp"
+#include "z-rand.hpp"
+
+#include <cassert>
+
+static s16b school_spells_count = 0;
+static struct spell_type *school_spells[SCHOOL_SPELLS_MAX];
+
+static spell_type *spell_new(s32b *index, cptr name)
+{
+ assert(school_spells_count < SCHOOL_SPELLS_MAX);
+
+ spell_type *spell = spell_type_new(name);
+ school_spells[school_spells_count] = spell;
+ *index = school_spells_count;
+ school_spells_count++;
+
+ return spell;
+}
+
+static cptr no_info()
+{
+ return "";
+}
+
+spell_type *spell_at(s32b index)
+{
+ assert(index >= 0);
+ assert(index < school_spells_count);
+
+ return school_spells[index];
+}
+
+int find_spell(cptr name)
+{
+ int i;
+
+ for (i = 0; i < school_spells_count; i++)
+ {
+ if (streq(spell_type_name(spell_at(i)), name))
+ {
+ return i;
+ }
+ }
+
+ /* Not found */
+ return -1;
+}
+
+s16b get_random_spell(s16b random_type, int level)
+{
+ int tries;
+
+ for (tries = 0; tries < 1000; tries++)
+ {
+ s16b spl = rand_int(school_spells_count);
+ spell_type *spell = spell_at(spl);
+
+ if ((spell_type_random_type(spell) == random_type) &&
+ (rand_int(spell_type_skill_level(spell) * 3) < level))
+ {
+ return spl;
+ }
+ }
+
+ return -1;
+}
+
+/*
+ * Get a spell for a device of a given tval (wand or staff).
+ */
+s16b get_random_stick(byte tval, int level)
+{
+ int tries;
+
+ for (tries = 0; tries < 1000; tries++)
+ {
+ long spell_idx = rand_int(school_spells_count);
+ spell_type *spell = spell_at(spell_idx);
+ device_allocation *device_allocation = spell_type_device_allocation(spell, tval);
+
+ if ((device_allocation != NULL) &&
+ (rand_int(spell_type_skill_level(spell) * 3) < level) &&
+ (magik(100 - device_allocation->rarity)))
+ {
+ return spell_idx;
+ }
+ }
+
+ return -1;
+}
+
+static void spells_init_tome()
+{
+ {
+ spell_type *spell = spell_new(&DEVICE_THUNDERLORDS, "Artifact Thunderlords");
+ spell_type_describe(spell, "A thunderlord will appear to transport you quickly to the surface.");
+ spell_type_set_mana(spell, 1, 1);
+ spell_type_set_difficulty(spell, 1, 20);
+ spell_type_init_device(spell,
+ no_info,
+ device_thunderlords);
+
+ spell_type_set_device_charges(spell, "3+d3");
+
+ {
+ device_allocation *device_allocation = device_allocation_new(TV_STAFF);
+ device_allocation->rarity = 999;
+ range_init(&device_allocation->base_level, 1, 1);
+ range_init(&device_allocation->max_level, 1, 1);
+ spell_type_add_device_allocation(spell, device_allocation);
+ }
+ }
+}
+
+static void spells_init_theme()
+{
+ {
+ spell_type *spell = spell_new(&GROW_ATHELAS, "Grow Athelas");
+ spell_type_describe(spell, "Cures the Black Breath");
+ spell_type_set_mana(spell, 60, 100);
+ spell_type_set_difficulty(spell, 30, 95);
+ spell_type_init_mage(spell,
+ RANDOM,
+ SCHOOL_NATURE,
+ no_info,
+ nature_grow_athelas);
+
+ spell_type_set_device_charges(spell, "1+d3");
+
+ {
+ device_allocation *device_allocation = device_allocation_new(TV_WAND);
+ device_allocation->rarity = 85;
+ range_init(&device_allocation->base_level, 1, 5);
+ range_init(&device_allocation->max_level, 15, 45);
+ spell_type_add_device_allocation(spell, device_allocation);
+ }
+ }
+
+ {
+ spell_type *spell = spell_new(&AULE_FIREBRAND, "Firebrand");
+ spell_type_describe(spell, "Imbues your melee weapon with fire to deal more damage");
+ spell_type_describe(spell, "At level 15 it spreads over a 1 radius zone around your target");
+ spell_type_describe(spell, "At level 30 it deals holy fire damage");
+ spell_type_set_mana(spell, 10, 100);
+ spell_type_set_difficulty(spell, 1, 20);
+ spell_type_init_priest(spell,
+ SCHOOL_AULE,
+ aule_firebrand_info,
+ aule_firebrand_spell);
+ }
+
+ {
+ spell_type *spell = spell_new(&AULE_ENCHANT_WEAPON, "Enchant Weapon");
+ spell_type_describe(spell, "Tries to enchant a weapon to-hit");
+ spell_type_describe(spell, "At level 5 it also enchants to-dam");
+ spell_type_describe(spell, "At level 45 it enhances the special powers of magical weapons");
+ spell_type_describe(spell, "The might of the enchantment increases with the level");
+ spell_type_set_mana(spell, 100, 200);
+ spell_type_set_difficulty(spell, 10, 20);
+ spell_type_init_priest(spell,
+ SCHOOL_AULE,
+ aule_enchant_weapon_info,
+ aule_enchant_weapon_spell);
+ }
+
+ {
+ spell_type *spell = spell_new(&AULE_ENCHANT_ARMOUR, "Enchant Armour");
+ spell_type_describe(spell, "Tries to enchant a piece of armour");
+ spell_type_describe(spell, "At level 20 it also enchants to-hit and to-dam");
+ spell_type_describe(spell, "At level 40 it enhances the special powers of magical armour");
+ spell_type_describe(spell, "The might of the enchantment increases with the level");
+ spell_type_set_mana(spell, 100, 200);
+ spell_type_set_difficulty(spell, 15, 20);
+ spell_type_init_priest(spell,
+ SCHOOL_AULE,
+ aule_enchant_armour_info,
+ aule_enchant_armour_spell);
+ }
+
+ {
+ spell_type *spell = spell_new(&AULE_CHILD, "Child of Aule");
+ spell_type_describe(spell, "Summons a levelled Dwarven warrior to help you battle the forces");
+ spell_type_describe(spell, "of Morgoth");
+ spell_type_set_mana(spell, 200, 500);
+ spell_type_set_difficulty(spell, 20, 40);
+ spell_type_init_priest(spell,
+ SCHOOL_AULE,
+ aule_child_info,
+ aule_child_spell);
+ }
+
+ {
+ spell_type *spell = spell_new(&VARDA_LIGHT_VALINOR, "Light of Valinor");
+ spell_type_describe(spell, "Lights a room");
+ spell_type_describe(spell, "At level 3 it starts damaging monsters");
+ spell_type_describe(spell, "At level 15 it starts creating a more powerful kind of light");
+ spell_type_set_mana(spell, 1, 100);
+ spell_type_set_difficulty(spell, 1, 20);
+ spell_type_init_priest(spell,
+ SCHOOL_VARDA,
+ varda_light_of_valinor_info,
+ varda_light_of_valinor_spell);
+ }
+
+ {
+ spell_type *spell = spell_new(&VARDA_CALL_ALMAREN, "Call of Almaren");
+ spell_type_describe(spell, "Banishes evil beings");
+ spell_type_describe(spell, "At level 20 it dispels evil beings");
+ spell_type_set_mana(spell, 5, 150);
+ spell_type_set_difficulty(spell, 10, 20);
+ spell_type_init_priest(spell,
+ SCHOOL_VARDA,
+ no_info,
+ varda_call_of_almaren_spell);
+ }
+
+ {
+ spell_type *spell = spell_new(&VARDA_EVENSTAR, "Evenstar");
+ spell_type_describe(spell, "Maps and lights the whole level.");
+ spell_type_describe(spell, "At level 40 it maps and lights the whole level,");
+ spell_type_describe(spell, "in addition to letting you know yourself better");
+ spell_type_describe(spell, "and identifying your whole pack.");
+ spell_type_set_mana(spell, 20, 200);
+ spell_type_set_difficulty(spell, 20, 20);
+ spell_type_init_priest(spell,
+ SCHOOL_VARDA,
+ no_info,
+ varda_evenstar_spell);
+ }
+
+ {
+ spell_type *spell = spell_new(&VARDA_STARKINDLER, "Star Kindler");
+ spell_type_describe(spell, "Does multiple bursts of light damage.");
+ spell_type_describe(spell, "The damage increases with level.");
+ spell_type_set_mana(spell, 50, 250);
+ spell_type_set_difficulty(spell, 30, 20);
+ spell_type_init_priest(spell,
+ SCHOOL_VARDA,
+ varda_star_kindler_info,
+ varda_star_kindler_spell);
+ }
+
+ {
+ spell_type *spell = spell_new(&ULMO_BELEGAER, "Song of Belegaer");
+ spell_type_describe(spell, "Channels the power of the Great Sea into your fingertips.");
+ spell_type_describe(spell, "Sometimes it can blast through its first target.");
+ spell_type_set_mana(spell, 1, 100);
+ spell_type_set_difficulty(spell, 1, 25);
+ spell_type_init_priest(spell,
+ SCHOOL_ULMO,
+ ulmo_song_of_belegaer_info,
+ ulmo_song_of_belegaer_spell);
+ }
+
+ {
+ spell_type *spell = spell_new(&ULMO_DRAUGHT_ULMONAN, "Draught of Ulmonan");
+ spell_type_describe(spell, "Fills you with a draught with powerful curing effects,");
+ spell_type_describe(spell, "prepared by Ulmo himself.");
+ spell_type_describe(spell, "Level 1: blindness, poison, cuts and stunning");
+ spell_type_describe(spell, "Level 10: drained STR, DEX and CON");
+ spell_type_describe(spell, "Level 20: parasites and mimicry");
+ spell_type_set_mana(spell, 25, 200);
+ spell_type_set_difficulty(spell, 15, 50);
+ spell_type_init_priest(spell,
+ SCHOOL_ULMO,
+ ulmo_draught_of_ulmonan_info,
+ ulmo_draught_of_ulmonan_spell);
+ }
+
+ {
+ spell_type *spell = spell_new(&ULMO_CALL_ULUMURI, "Call of the Ulumuri");
+ spell_type_describe(spell, "Summons a leveled water spirit or elemental");
+ spell_type_describe(spell, "to fight for you");
+ spell_type_set_mana(spell, 50, 300);
+ spell_type_set_difficulty(spell, 20, 75);
+ spell_type_init_priest(spell,
+ SCHOOL_ULMO,
+ ulmo_call_of_the_ulumuri_info,
+ ulmo_call_of_the_ulumuri_spell);
+ }
+
+ {
+ spell_type *spell = spell_new(&ULMO_WRATH, "Wrath of Ulmo");
+ spell_type_describe(spell, "Conjures up a sea storm.");
+ spell_type_describe(spell, "At level 30 it turns into a more forceful storm.");
+ spell_type_set_mana(spell, 100, 400);
+ spell_type_set_difficulty(spell, 30, 95);
+ spell_type_init_priest(spell,
+ SCHOOL_ULMO,
+ ulmo_wrath_of_ulmo_info,
+ ulmo_wrath_of_ulmo_spell);
+ }
+
+ {
+ spell_type *spell = spell_new(&MANDOS_TEARS_LUTHIEN, "Tears of Luthien");
+ spell_type_describe(spell, "Calls upon the spirit of Luthien to ask Mandos for healing and succour.");
+ spell_type_set_mana(spell, 10, 100);
+ spell_type_set_difficulty(spell, 5, 25);
+ spell_type_init_priest(spell,
+ SCHOOL_MANDOS,
+ mandos_tears_of_luthien_info,
+ mandos_tears_of_luthien_spell);
+ }
+
+ {
+ spell_type *spell = spell_new(&MANDOS_SPIRIT_FEANTURI, "Feanturi");
+ spell_type_describe(spell, "Channels the power of Mandos to cure fear and confusion.");
+ spell_type_describe(spell, "At level 20 it restores lost INT and WIS");
+ spell_type_describe(spell, "At level 30 it cures hallucinations and restores a percentage of lost sanity");
+ spell_type_set_mana(spell, 40, 200);
+ spell_type_set_difficulty(spell, 10, 50);
+ spell_type_init_priest(spell,
+ SCHOOL_MANDOS,
+ mandos_spirit_of_the_feanturi_info,
+ mandos_spirit_of_the_feanturi_spell);
+ }
+
+ {
+ spell_type *spell = spell_new(&MANDOS_TALE_DOOM, "Tale of Doom");
+ spell_type_describe(spell, "Allows you to predict the future for a short time.");
+ spell_type_set_mana(spell, 60, 300);
+ spell_type_set_difficulty(spell, 25, 75);
+ spell_type_init_priest(spell,
+ SCHOOL_MANDOS,
+ mandos_tale_of_doom_info,
+ mandos_tale_of_doom_spell);
+ }
+
+ {
+ spell_type *spell = spell_new(&MANDOS_CALL_HALLS, "Call to the Halls");
+ spell_type_describe(spell, "Summons a leveled spirit from the Halls of Mandos");
+ spell_type_describe(spell, "to fight for you.");
+ spell_type_set_mana(spell, 80, 400);
+ spell_type_set_difficulty(spell, 30, 95);
+ spell_type_init_priest(spell,
+ SCHOOL_MANDOS,
+ mandos_call_to_the_halls_info,
+ mandos_call_to_the_halls_spell);
+ }
+
+ {
+ spell_type *spell = spell_new(&DEVICE_THUNDERLORDS, "Artifact Thunderlords");
+ spell_type_describe(spell, "An Eagle of Manwe will appear to transport you quickly to the town.");
+ spell_type_set_mana(spell, 1, 1);
+ spell_type_set_difficulty(spell, 1, 20);
+ spell_type_init_device(spell,
+ no_info,
+ device_thunderlords);
+
+ spell_type_set_device_charges(spell, "5+d5");
+
+ {
+ device_allocation *device_allocation = device_allocation_new(TV_STAFF);
+ device_allocation->rarity = 999;
+ range_init(&device_allocation->base_level, 1, 1);
+ range_init(&device_allocation->max_level, 1, 1);
+ spell_type_add_device_allocation(spell, device_allocation);
+ }
+ }
+}
+
+void school_spells_init()
+{
+ /* Zero out spell array */
+ {
+ int i = 0;
+ for (i = 0; i < SCHOOL_SPELLS_MAX; i++)
+ {
+ school_spells[i] = NULL;
+ }
+ }
+
+ /* Spells */
+ {
+ spell_type *spell = spell_new(&GLOBELIGHT, "Globe of Light");
+ spell_type_describe(spell, "Creates a globe of pure light");
+ spell_type_describe(spell, "At level 3 it starts damaging monsters");
+ spell_type_describe(spell, "At level 15 it starts creating a more powerful kind of light");
+ spell_type_set_mana(spell, 2, 15);
+ spell_type_set_inertia(spell, 1, 40);
+ spell_type_set_difficulty(spell, 1, 10);
+ spell_type_init_mage(spell,
+ RANDOM,
+ SCHOOL_FIRE,
+ fire_globe_of_light_info,
+ fire_globe_of_light);
+
+ spell_type_set_device_charges(spell, "10+d5");
+
+ {
+ device_allocation *device_allocation = device_allocation_new(TV_STAFF);
+ device_allocation->rarity = 7;
+ range_init(&device_allocation->base_level, 1, 15);
+ range_init(&device_allocation->max_level, 10, 45);
+ spell_type_add_device_allocation(spell, device_allocation);
+ }
+ }
+
+ {
+ spell_type *spell = spell_new(&FIREFLASH, "Fireflash");
+ spell_type_describe(spell, "Conjures a ball of fire to burn your foes to ashes");
+ spell_type_describe(spell, "At level 20 it turns into a ball of holy fire");
+ spell_type_set_mana(spell, 5, 70);
+ spell_type_set_difficulty(spell, 10, 35);
+ spell_type_init_mage(spell,
+ RANDOM,
+ SCHOOL_FIRE,
+ fire_fireflash_info,
+ fire_fireflash);
+
+ spell_type_set_device_charges(spell, "5+d5");
+
+ {
+ device_allocation *device_allocation = device_allocation_new(TV_WAND);
+ device_allocation->rarity = 35;
+ range_init(&device_allocation->base_level, 1, 15);
+ range_init(&device_allocation->max_level, 15, 35);
+ spell_type_add_device_allocation(spell, device_allocation);
+ }
+ }
+
+ {
+ spell_type *spell = spell_new(&FIERYAURA, "Fiery Shield");
+ spell_type_describe(spell, "Creates a shield of fierce flames around you");
+ spell_type_describe(spell, "At level 8 it turns into a greater kind of flame that can not be resisted");
+ spell_type_set_mana(spell, 20, 60);
+ spell_type_set_inertia(spell, 2, 15);
+ spell_type_set_difficulty(spell, 20, 50);
+ spell_type_init_mage(spell,
+ RANDOM,
+ SCHOOL_FIRE,
+ fire_fiery_shield_info,
+ fire_fiery_shield);
+
+ spell_type_set_device_charges(spell, "3+d5");
+
+ {
+ device_allocation *device_allocation = device_allocation_new(TV_STAFF);
+ device_allocation->rarity = 50;
+ range_init(&device_allocation->base_level, 1, 10);
+ range_init(&device_allocation->max_level, 5, 40);
+ spell_type_add_device_allocation(spell, device_allocation);
+ }
+ }
+
+ {
+ spell_type *spell = spell_new(&FIREWALL, "Firewall");
+ spell_type_describe(spell, "Creates a fiery wall to incinerate monsters stupid enough to attack you");
+ spell_type_describe(spell, "At level 6 it turns into a wall of hell fire");
+ spell_type_set_mana(spell, 25, 100);
+ spell_type_set_difficulty(spell, 15, 40);
+ spell_type_init_mage(spell,
+ RANDOM,
+ SCHOOL_FIRE,
+ fire_firewall_info,
+ fire_firewall);
+
+ spell_type_set_device_charges(spell, "4+d5");
+
+ {
+ device_allocation *device_allocation = device_allocation_new(TV_WAND);
+ device_allocation->rarity = 55;
+ range_init(&device_allocation->base_level, 1, 10);
+ range_init(&device_allocation->max_level, 5, 40);
+ spell_type_add_device_allocation(spell, device_allocation);
+ }
+ }
+
+ {
+ spell_type *spell = spell_new(&FIREGOLEM, "Fire Golem");
+ spell_type_describe(spell, "Creates a fiery golem and controls it");
+ spell_type_describe(spell, "During the control the available keylist is:");
+ spell_type_describe(spell, "Movement keys: movement of the golem(depending on its speed");
+ spell_type_describe(spell, " it can move more than one square)");
+ spell_type_describe(spell, ", : pickup all items on the floor");
+ spell_type_describe(spell, "d : drop all carried items");
+ spell_type_describe(spell, "i : list all carried items");
+ spell_type_describe(spell, "m : end the possession/use golem powers");
+ spell_type_describe(spell, "Most of the other keys are disabled, you cannot interact with your");
+ spell_type_describe(spell, "real body while controlling the golem");
+ spell_type_describe(spell, "But to cast the spell you will need a lantern or a wooden torch to");
+ spell_type_describe(spell, "Create the golem from");
+ spell_type_add_school(spell, SCHOOL_MIND);
+ spell_type_set_mana(spell, 16, 70);
+ spell_type_set_difficulty(spell, 7, 40);
+ spell_type_init_mage(spell,
+ RANDOM,
+ SCHOOL_FIRE,
+ fire_golem_info,
+ fire_golem);
+ }
+
+ {
+ spell_type *spell = spell_new(&MANATHRUST, "Manathrust");
+ spell_type_describe(spell, "Conjures up mana into a powerful bolt");
+ spell_type_describe(spell, "The damage is irresistible and will increase with level");
+ spell_type_set_mana(spell, 1, 25);
+ spell_type_set_difficulty(spell, 1, 10);
+ spell_type_init_mage(spell,
+ RANDOM,
+ SCHOOL_MANA,
+ mana_manathrust_info,
+ mana_manathrust);
+
+ spell_type_set_device_charges(spell, "7+d10");
+
+ {
+ device_allocation *device_allocation = device_allocation_new(TV_WAND);
+ device_allocation->rarity = 5;
+ range_init(&device_allocation->base_level, 1, 20);
+ range_init(&device_allocation->max_level, 15, 33);
+ spell_type_add_device_allocation(spell, device_allocation);
+ }
+ }
+
+ {
+ spell_type *spell = spell_new(&DELCURSES, "Remove Curses");
+ spell_type_describe(spell, "Remove curses of worn objects");
+ spell_type_describe(spell, "At level 20 switches to *remove curses*");
+ spell_type_set_mana(spell, 20, 40);
+ spell_type_set_inertia(spell, 1, 10);
+ spell_type_set_difficulty(spell, 10, 30);
+ spell_type_init_mage(spell,
+ RANDOM,
+ SCHOOL_MANA,
+ no_info,
+ mana_remove_curses);
+
+ spell_type_set_device_charges(spell, "3+d8");
+
+ {
+ device_allocation *device_allocation = device_allocation_new(TV_STAFF);
+ device_allocation->rarity = 70;
+ range_init(&device_allocation->base_level, 1, 5);
+ range_init(&device_allocation->max_level, 15, 50);
+ spell_type_add_device_allocation(spell, device_allocation);
+ }
+ }
+
+ {
+ spell_type *spell = spell_new(&RESISTS, "Elemental Shield");
+ spell_type_describe(spell, "Provide resistances to the four basic elements");
+ spell_type_set_mana(spell, 17, 20);
+ spell_type_set_inertia(spell, 2, 25);
+ spell_type_set_difficulty(spell, 20, 40);
+ spell_type_init_mage(spell,
+ RANDOM,
+ SCHOOL_MANA,
+ mana_elemental_shield_info,
+ mana_elemental_shield);
+ }
+
+ {
+ spell_type *spell = spell_new(&MANASHIELD, "Disruption Shield");
+ spell_type_describe(spell, "Uses mana instead of hp to take damage");
+ spell_type_describe(spell, "At level 5 switches to Globe of Invulnerability.");
+ spell_type_describe(spell, "The spell breaks as soon as a melee, shooting, throwing or magical");
+ spell_type_describe(spell, "skill action is attempted, and lasts only a short time.");
+ spell_type_set_mana(spell, 50, 50);
+ spell_type_set_inertia(spell, 9, 10);
+ spell_type_set_difficulty(spell, 45, 90);
+ spell_type_init_mage(spell,
+ RANDOM,
+ SCHOOL_MANA,
+ mana_disruption_shield_info,
+ mana_disruption_shield);
+ }
+
+ {
+ spell_type *spell = spell_new(&TIDALWAVE, "Tidal Wave");
+ spell_type_describe(spell, "Summons a monstrous tidal wave that will expand and crush the");
+ spell_type_describe(spell, "monsters under its mighty waves.");
+ spell_type_set_mana(spell, 16, 40);
+ spell_type_set_inertia(spell, 4, 100);
+ spell_type_set_difficulty(spell, 16, 65);
+ spell_type_init_mage(spell,
+ RANDOM,
+ SCHOOL_WATER,
+ water_tidal_wave_info,
+ water_tidal_wave);
+
+ spell_type_set_device_charges(spell, "6+d5");
+
+ {
+ device_allocation *device_allocation = device_allocation_new(TV_WAND);
+ device_allocation->rarity = 54;
+ range_init(&device_allocation->base_level, 1, 10);
+ range_init(&device_allocation->max_level, 20, 50);
+ spell_type_add_device_allocation(spell, device_allocation);
+ }
+ }
+
+ {
+ spell_type *spell = spell_new(&ICESTORM, "Ice Storm");
+ spell_type_describe(spell, "Engulfs you in a storm of roaring cold that strikes your foes.");
+ spell_type_describe(spell, "At level 10 it turns into shards of ice.");
+ spell_type_set_mana(spell, 30, 60);
+ spell_type_set_inertia(spell, 3, 40);
+ spell_type_set_difficulty(spell, 22, 80);
+ spell_type_init_mage(spell,
+ RANDOM,
+ SCHOOL_WATER,
+ water_ice_storm_info,
+ water_ice_storm);
+
+ spell_type_set_device_charges(spell, "3+d7");
+
+ {
+ device_allocation *device_allocation = device_allocation_new(TV_WAND);
+ device_allocation->rarity = 65;
+ range_init(&device_allocation->base_level, 1, 5);
+ range_init(&device_allocation->max_level, 25, 45);
+ spell_type_add_device_allocation(spell, device_allocation);
+ }
+ }
+
+ {
+ spell_type *spell = spell_new(&ENTPOTION, "Ent's Potion");
+ spell_type_describe(spell, "Fills up your stomach.");
+ spell_type_describe(spell, "At level 5 it boldens your heart.");
+ spell_type_describe(spell, "At level 12 it makes you heroic.");
+ spell_type_set_mana(spell, 7, 15);
+ spell_type_set_inertia(spell, 1, 30);
+ spell_type_set_difficulty(spell, 6, 35);
+ spell_type_init_mage(spell,
+ RANDOM,
+ SCHOOL_WATER,
+ water_ent_potion_info,
+ water_ent_potion);
+ }
+
+ {
+ spell_type *spell = spell_new(&VAPOR, "Vapor");
+ spell_type_describe(spell, "Fills the air with toxic moisture to eradicate annoying critters.");
+ spell_type_set_mana(spell, 2, 12);
+ spell_type_set_inertia(spell, 1, 30);
+ spell_type_set_difficulty(spell, 2, 20);
+ spell_type_init_mage(spell,
+ RANDOM,
+ SCHOOL_WATER,
+ water_vapor_info,
+ water_vapor);
+ }
+
+ {
+ spell_type *spell = spell_new(&GEYSER, "Geyser");
+ spell_type_describe(spell, "Shoots a geyser of water from your fingertips.");
+ spell_type_describe(spell, "Sometimes it can blast through its first target.");
+ spell_type_set_mana(spell, 1, 35);
+ spell_type_set_difficulty(spell, 1, 5);
+ spell_type_init_mage(spell,
+ RANDOM,
+ SCHOOL_WATER,
+ water_geyser_info,
+ water_geyser);
+ }
+
+ {
+ spell_type *spell = spell_new(&NOXIOUSCLOUD, "Noxious Cloud");
+ spell_type_describe(spell, "Creates a cloud of poison");
+ spell_type_describe(spell, "The cloud will persist for some turns, damaging all monsters passing by");
+ spell_type_describe(spell, "At spell level 30 it turns into a thick gas attacking all living beings");
+ spell_type_set_mana(spell, 3, 30);
+ spell_type_set_difficulty(spell, 3, 20);
+ spell_type_init_mage(spell,
+ RANDOM,
+ SCHOOL_AIR,
+ air_noxious_cloud_info,
+ air_noxious_cloud);
+
+ spell_type_set_device_charges(spell, "5+d7");
+
+ {
+ device_allocation *device_allocation = device_allocation_new(TV_WAND);
+ device_allocation->rarity = 15;
+ range_init(&device_allocation->base_level, 1, 15);
+ range_init(&device_allocation->max_level, 25, 50);
+ spell_type_add_device_allocation(spell, device_allocation);
+ }
+ }
+
+ {
+ spell_type *spell = spell_new(&AIRWINGS, "Wings of Winds");
+ spell_type_describe(spell, "Grants the power of levitation");
+ spell_type_describe(spell, "At level 16 it grants the power of controlled flight");
+ spell_type_add_school(spell, SCHOOL_CONVEYANCE);
+ spell_type_set_mana(spell, 30, 40);
+ spell_type_set_inertia(spell, 1, 10);
+ spell_type_set_difficulty(spell, 22, 60);
+ spell_type_init_mage(spell,
+ RANDOM,
+ SCHOOL_AIR,
+ air_wings_of_winds_info,
+ air_wings_of_winds);
+
+ spell_type_set_device_charges(spell, "7+d5");
+
+ {
+ device_allocation *device_allocation = device_allocation_new(TV_STAFF);
+ device_allocation->rarity = 27;
+ range_init(&device_allocation->base_level, 1, 10);
+ range_init(&device_allocation->max_level, 20, 50);
+ spell_type_add_device_allocation(spell, device_allocation);
+ }
+ }
+
+ {
+ spell_type *spell = spell_new(&INVISIBILITY, "Invisibility");
+ spell_type_describe(spell, "Grants invisibility");
+ spell_type_set_mana(spell, 10, 20);
+ spell_type_set_inertia(spell, 1, 30);
+ spell_type_set_difficulty(spell, 16, 50);
+ spell_type_init_mage(spell,
+ RANDOM,
+ SCHOOL_AIR,
+ air_invisibility_info,
+ air_invisibility);
+ }
+
+ {
+ spell_type *spell = spell_new(&POISONBLOOD, "Poison Blood");
+ spell_type_describe(spell, "Grants resist poison");
+ spell_type_describe(spell, "At level 15 it provides poison branding to wielded weapon");
+ spell_type_set_mana(spell, 10, 20);
+ spell_type_set_inertia(spell, 1, 35);
+ spell_type_set_difficulty(spell, 12, 30);
+ spell_type_init_mage(spell,
+ RANDOM,
+ SCHOOL_AIR,
+ air_poison_blood_info,
+ air_poison_blood);
+
+ spell_type_set_device_charges(spell, "10+d15");
+
+ {
+ device_allocation *device_allocation = device_allocation_new(TV_WAND);
+ device_allocation->rarity = 45;
+ range_init(&device_allocation->base_level, 1, 25);
+ range_init(&device_allocation->max_level, 35, 50);
+ spell_type_add_device_allocation(spell, device_allocation);
+ }
+ }
+
+ {
+ spell_type *spell = spell_new(&THUNDERSTORM, "Thunderstorm");
+ spell_type_describe(spell, "Charges up the air around you with electricity");
+ spell_type_describe(spell, "Each turn it will throw a thunder bolt at a random monster in sight");
+ spell_type_describe(spell, "The thunder does 3 types of damage, one third of lightning");
+ spell_type_describe(spell, "one third of sound and one third of light");
+ spell_type_add_school(spell, SCHOOL_NATURE);
+ spell_type_set_mana(spell, 40, 60);
+ spell_type_set_inertia(spell, 2, 15);
+ spell_type_set_difficulty(spell, 25, 60);
+ spell_type_init_mage(spell,
+ RANDOM,
+ SCHOOL_AIR,
+ air_thunderstorm_info,
+ air_thunderstorm);
+
+ spell_type_set_device_charges(spell, "5+d5");
+
+ {
+ device_allocation *device_allocation = device_allocation_new(TV_WAND);
+ device_allocation->rarity = 85;
+ range_init(&device_allocation->base_level, 1, 5);
+ range_init(&device_allocation->max_level, 25, 50);
+ spell_type_add_device_allocation(spell, device_allocation);
+ }
+ }
+
+ {
+ spell_type *spell = spell_new(&STERILIZE, "Sterilize");
+ spell_type_describe(spell, "Prevents explosive breeding for a while.");
+ spell_type_set_mana(spell, 10, 100);
+ spell_type_set_difficulty(spell, 20, 50);
+ spell_type_init_mage(spell,
+ RANDOM,
+ SCHOOL_AIR,
+ air_sterilize_info,
+ air_sterilize);
+
+ spell_type_set_device_charges(spell, "7+d5");
+
+ {
+ device_allocation *device_allocation = device_allocation_new(TV_STAFF);
+ device_allocation->rarity = 20;
+ range_init(&device_allocation->base_level, 1, 10);
+ range_init(&device_allocation->max_level, 20, 50);
+ spell_type_add_device_allocation(spell, device_allocation);
+ }
+ }
+
+ {
+ spell_type *spell = spell_new(&STONESKIN, "Stone Skin");
+ spell_type_describe(spell, "Creates a shield of earth around you to protect you");
+ spell_type_describe(spell, "At level 25 it starts dealing damage to attackers");
+ spell_type_set_mana(spell, 1, 50);
+ spell_type_set_inertia(spell, 2, 50);
+ spell_type_set_difficulty(spell, 1, 10);
+ spell_type_init_mage(spell,
+ RANDOM,
+ SCHOOL_EARTH,
+ earth_stone_skin_info,
+ earth_stone_skin);
+ }
+
+ {
+ spell_type *spell = spell_new(&DIG, "Dig");
+ spell_type_describe(spell, "Digs a hole in a wall much faster than any shovels");
+ spell_type_set_mana(spell, 14, 14);
+ spell_type_set_difficulty(spell, 12, 20);
+ spell_type_init_mage(spell,
+ RANDOM,
+ SCHOOL_EARTH,
+ no_info,
+ earth_dig);
+
+ spell_type_set_device_charges(spell, "15+d5");
+
+ {
+ device_allocation *device_allocation = device_allocation_new(TV_WAND);
+ device_allocation->rarity = 25;
+ range_init(&device_allocation->base_level, 1, 1);
+ range_init(&device_allocation->max_level, 1, 1);
+ spell_type_add_device_allocation(spell, device_allocation);
+ }
+ }
+
+ {
+ spell_type *spell = spell_new(&STONEPRISON, "Stone Prison");
+ spell_type_describe(spell, "Creates a prison of walls around you");
+ spell_type_describe(spell, "At level 10 it allows you to target a monster");
+ spell_type_set_mana(spell, 30, 50);
+ spell_type_set_difficulty(spell, 25, 65);
+ spell_type_init_mage(spell,
+ RANDOM,
+ SCHOOL_EARTH,
+ no_info,
+ earth_stone_prison);
+
+ spell_type_set_device_charges(spell, "5+d3");
+
+ {
+ device_allocation *device_allocation = device_allocation_new(TV_WAND);
+ device_allocation->rarity = 57;
+ range_init(&device_allocation->base_level, 1, 3);
+ range_init(&device_allocation->max_level, 5, 20);
+ spell_type_add_device_allocation(spell, device_allocation);
+ }
+ }
+
+ {
+ spell_type *spell = spell_new(&STRIKE, "Strike");
+ spell_type_describe(spell, "Creates a micro-ball of force that will push monsters backwards");
+ spell_type_describe(spell, "If the monster is caught near a wall, it'll be crushed against it");
+ spell_type_describe(spell, "At level 12 it turns into a ball of radius 1");
+ spell_type_set_mana(spell, 30, 50);
+ spell_type_set_difficulty(spell, 30, 60);
+ spell_type_init_mage(spell,
+ RANDOM,
+ SCHOOL_EARTH,
+ earth_strike_info,
+ earth_strike);
+
+ spell_type_set_device_charges(spell, "2+d6");
+
+ {
+ device_allocation *device_allocation = device_allocation_new(TV_WAND);
+ device_allocation->rarity = 635;
+ range_init(&device_allocation->base_level, 1, 5);
+ range_init(&device_allocation->max_level, 10, 50);
+ spell_type_add_device_allocation(spell, device_allocation);
+ }
+ }
+
+ {
+ spell_type *spell = spell_new(&SHAKE, "Shake");
+ spell_type_describe(spell, "Creates a localised earthquake");
+ spell_type_describe(spell, "At level 10 it can be targeted at any location");
+ spell_type_set_mana(spell, 25, 30);
+ spell_type_set_inertia(spell, 2, 50);
+ spell_type_set_difficulty(spell, 27, 60);
+ spell_type_init_mage(spell,
+ RANDOM,
+ SCHOOL_EARTH,
+ earth_shake_info,
+ earth_shake);
+
+ spell_type_set_device_charges(spell, "5+d10");
+
+ {
+ device_allocation *device_allocation = device_allocation_new(TV_STAFF);
+ device_allocation->rarity = 75;
+ range_init(&device_allocation->base_level, 1, 3);
+ range_init(&device_allocation->max_level, 9, 20);
+ spell_type_add_device_allocation(spell, device_allocation);
+ }
+ }
+
+ {
+ spell_type *spell = spell_new(&BLINK, "Phase Door");
+ spell_type_describe(spell, "Teleports you on a small scale range");
+ spell_type_describe(spell, "At level 30 it creates void jumpgates");
+ spell_type_set_mana(spell, 1, 3);
+ spell_type_set_inertia(spell, 1, 5);
+ spell_type_set_difficulty(spell, 1, 10);
+ spell_type_init_mage(spell,
+ RANDOM,
+ SCHOOL_CONVEYANCE,
+ convey_blink_info,
+ convey_blink);
+ }
+
+ {
+ spell_type *spell = spell_new(&DISARM, "Disarm");
+ spell_type_describe(spell, "Destroys doors and traps");
+ spell_type_describe(spell, "At level 10 it destroys doors and traps, then reveals and unlocks any secret");
+ spell_type_describe(spell, "doors");
+ spell_type_set_mana(spell, 2, 4);
+ spell_type_set_difficulty(spell, 3, 15);
+ spell_type_init_mage(spell,
+ RANDOM,
+ SCHOOL_CONVEYANCE,
+ no_info,
+ convey_disarm);
+
+ spell_type_set_device_charges(spell, "10+d15");
+
+ {
+ device_allocation *device_allocation = device_allocation_new(TV_STAFF);
+ device_allocation->rarity = 4;
+ range_init(&device_allocation->base_level, 1, 10);
+ range_init(&device_allocation->max_level, 10, 50);
+ spell_type_add_device_allocation(spell, device_allocation);
+ }
+ }
+
+ {
+ spell_type *spell = spell_new(&TELEPORT, "Teleportation");
+ spell_type_describe(spell, "Teleports you around the level. The casting time decreases with level");
+ spell_type_set_mana(spell, 8, 14);
+ spell_type_set_inertia(spell, 1, 10);
+ spell_type_set_difficulty(spell, 10, 30);
+ spell_type_init_mage(spell,
+ RANDOM,
+ SCHOOL_CONVEYANCE,
+ convey_teleport_info,
+ convey_teleport);
+
+ spell_type_set_device_charges(spell, "7+d7");
+
+ {
+ device_allocation *device_allocation = device_allocation_new(TV_STAFF);
+ device_allocation->rarity = 50;
+ range_init(&device_allocation->base_level, 1, 20);
+ range_init(&device_allocation->max_level, 20, 50);
+ spell_type_add_device_allocation(spell, device_allocation);
+ }
+ }
+
+ {
+ spell_type *spell = spell_new(&TELEAWAY, "Teleport Away");
+ spell_type_describe(spell, "Teleports a line of monsters away");
+ spell_type_describe(spell, "At level 10 it turns into a ball");
+ spell_type_describe(spell, "At level 20 it teleports all monsters in sight");
+ spell_type_set_mana(spell, 15, 40);
+ spell_type_set_difficulty(spell, 23, 60);
+ spell_type_init_mage(spell,
+ RANDOM,
+ SCHOOL_CONVEYANCE,
+ no_info,
+ convey_teleport_away);
+
+ spell_type_set_device_charges(spell, "3+d5");
+
+ {
+ device_allocation *device_allocation = device_allocation_new(TV_WAND);
+ device_allocation->rarity = 75;
+ range_init(&device_allocation->base_level, 1, 20);
+ range_init(&device_allocation->max_level, 20, 50);
+ spell_type_add_device_allocation(spell, device_allocation);
+ }
+ }
+
+ {
+ spell_type *spell = spell_new(&RECALL, "Recall");
+ spell_type_describe(spell, "Cast on yourself it will recall you to the surface/dungeon.");
+ spell_type_describe(spell, "Cast at a monster you will swap positions with the monster.");
+ spell_type_describe(spell, "Cast at an object it will fetch the object to you.");
+ spell_type_set_mana(spell, 25, 25);
+ spell_type_set_difficulty(spell, 30, 60);
+ spell_type_init_mage(spell,
+ RANDOM,
+ SCHOOL_CONVEYANCE,
+ convey_recall_info,
+ convey_recall);
+ }
+
+ {
+ spell_type *spell = spell_new(&PROBABILITY_TRAVEL, "Probability Travel");
+ spell_type_describe(spell, "Renders you immaterial, when you hit a wall you travel through it and");
+ spell_type_describe(spell, "instantly appear on the other side of it. You can also float up and down");
+ spell_type_describe(spell, "at will");
+ spell_type_set_mana(spell, 30, 50);
+ spell_type_set_inertia(spell, 6, 40);
+ spell_type_set_difficulty(spell, 35, 90);
+ spell_type_init_mage(spell,
+ RANDOM,
+ SCHOOL_CONVEYANCE,
+ convey_probability_travel_info,
+ convey_probability_travel);
+
+ spell_type_set_device_charges(spell, "1+d2");
+
+ {
+ device_allocation *device_allocation = device_allocation_new(TV_STAFF);
+ device_allocation->rarity = 97;
+ range_init(&device_allocation->base_level, 1, 5);
+ range_init(&device_allocation->max_level, 8, 25);
+ spell_type_add_device_allocation(spell, device_allocation);
+ }
+ }
+
+ {
+ spell_type *spell = spell_new(&GROWTREE, "Grow Trees");
+ spell_type_describe(spell, "Makes trees grow extremely quickly around you");
+ spell_type_add_school(spell, SCHOOL_TEMPORAL);
+ spell_type_set_mana(spell, 6, 30);
+ spell_type_set_inertia(spell, 5, 50);
+ spell_type_set_difficulty(spell, 6, 35);
+ spell_type_init_mage(spell,
+ RANDOM,
+ SCHOOL_NATURE,
+ nature_grow_trees_info,
+ nature_grow_trees);
+ }
+
+ {
+ spell_type *spell = spell_new(&HEALING, "Healing");
+ spell_type_describe(spell, "Heals a percent of hitpoints");
+ spell_type_set_mana(spell, 15, 50);
+ spell_type_set_difficulty(spell, 10, 45);
+ spell_type_init_mage(spell,
+ RANDOM,
+ SCHOOL_NATURE,
+ nature_healing_info,
+ nature_healing);
+
+ spell_type_set_device_charges(spell, "2+d3");
+
+ {
+ device_allocation *device_allocation = device_allocation_new(TV_STAFF);
+ device_allocation->rarity = 90;
+ range_init(&device_allocation->base_level, 1, 5);
+ range_init(&device_allocation->max_level, 20, 40);
+ spell_type_add_device_allocation(spell, device_allocation);
+ }
+ }
+
+ {
+ spell_type *spell = spell_new(&RECOVERY, "Recovery");
+ spell_type_describe(spell, "Reduces the length of time that you are poisoned");
+ spell_type_describe(spell, "At level 5 it cures poison and cuts");
+ spell_type_describe(spell, "At level 10 it restores drained stats");
+ spell_type_describe(spell, "At level 15 it restores lost experience");
+ spell_type_set_mana(spell, 10, 25);
+ spell_type_set_inertia(spell, 2, 100);
+ spell_type_set_difficulty(spell, 15, 60);
+ spell_type_init_mage(spell,
+ RANDOM,
+ SCHOOL_NATURE,
+ no_info,
+ nature_recovery);
+
+ spell_type_set_device_charges(spell, "5+d10");
+
+ {
+ device_allocation *device_allocation = device_allocation_new(TV_STAFF);
+ device_allocation->rarity = 50;
+ range_init(&device_allocation->base_level, 1, 5);
+ range_init(&device_allocation->max_level, 10, 30);
+ spell_type_add_device_allocation(spell, device_allocation);
+ }
+ }
+
+ {
+ spell_type *spell = spell_new(&REGENERATION, "Regeneration");
+ spell_type_describe(spell, "Increases your body's regeneration rate");
+ spell_type_set_mana(spell, 30, 55);
+ spell_type_set_inertia(spell, 4, 40);
+ spell_type_set_difficulty(spell, 20, 70);
+ spell_type_init_mage(spell,
+ RANDOM,
+ SCHOOL_NATURE,
+ nature_regeneration_info,
+ nature_regeneration);
+ }
+
+ {
+ spell_type *spell = spell_new(&SUMMONANNIMAL, "Summon Animal");
+ spell_type_describe(spell, "Summons a leveled animal to your aid");
+ spell_type_set_mana(spell, 25, 50);
+ spell_type_set_difficulty(spell, 25, 90);
+ spell_type_init_mage(spell,
+ RANDOM,
+ SCHOOL_NATURE,
+ nature_summon_animal_info,
+ nature_summon_animal);
+
+ spell_type_set_device_charges(spell, "1+d3");
+
+ {
+ device_allocation *device_allocation = device_allocation_new(TV_WAND);
+ device_allocation->rarity = 85;
+ range_init(&device_allocation->base_level, 1, 5);
+ range_init(&device_allocation->max_level, 15, 45);
+ spell_type_add_device_allocation(spell, device_allocation);
+ }
+ }
+
+ {
+ spell_type *spell = spell_new(&STARIDENTIFY, "Greater Identify");
+ spell_type_describe(spell, "Asks for an object and fully identify it, providing the full list of powers");
+ spell_type_describe(spell, "Cast at yourself it will reveal your powers");
+ spell_type_set_mana(spell, 30, 30);
+ spell_type_set_difficulty(spell, 35, 80);
+ spell_type_init_mage(spell,
+ RANDOM,
+ SCHOOL_DIVINATION,
+ no_info,
+ divination_greater_identify);
+ }
+
+ {
+ spell_type *spell = spell_new(&IDENTIFY, "Identify");
+ spell_type_describe(spell, "Asks for an object and identifies it");
+ spell_type_describe(spell, "At level 17 it identifies all objects in the inventory");
+ spell_type_describe(spell, "At level 27 it identifies all objects in the inventory and in a");
+ spell_type_describe(spell, "radius on the floor, as well as probing monsters in that radius");
+ spell_type_set_mana(spell, 10, 50);
+ spell_type_set_difficulty(spell, 8, 40);
+ spell_type_init_mage(spell,
+ RANDOM,
+ SCHOOL_DIVINATION,
+ divination_identify_info,
+ divination_identify);
+
+ spell_type_set_device_charges(spell, "7+d10");
+
+ {
+ device_allocation *device_allocation = device_allocation_new(TV_STAFF);
+ device_allocation->rarity = 45;
+ range_init(&device_allocation->base_level, 1, 15);
+ range_init(&device_allocation->max_level, 15, 40);
+ spell_type_add_device_allocation(spell, device_allocation);
+ }
+ }
+
+ {
+ spell_type *spell = spell_new(&VISION, "Vision");
+ spell_type_describe(spell, "Detects the layout of the surrounding area");
+ spell_type_describe(spell, "At level 25 it maps and lights the whole level");
+ spell_type_set_mana(spell, 7, 55);
+ spell_type_set_inertia(spell, 2, 200);
+ spell_type_set_difficulty(spell, 15, 45);
+ spell_type_init_mage(spell,
+ RANDOM,
+ SCHOOL_DIVINATION,
+ no_info,
+ divination_vision);
+
+ spell_type_set_device_charges(spell, "4+d6");
+
+ {
+ device_allocation *device_allocation = device_allocation_new(TV_STAFF);
+ device_allocation->rarity = 60;
+ range_init(&device_allocation->base_level, 1, 5);
+ range_init(&device_allocation->max_level, 10, 30);
+ spell_type_add_device_allocation(spell, device_allocation);
+ }
+ }
+
+ {
+ spell_type *spell = spell_new(&SENSEHIDDEN, "Sense Hidden");
+ spell_type_describe(spell, "Detects the traps in a certain radius around you");
+ spell_type_describe(spell, "At level 15 it allows you to sense invisible for a while");
+ spell_type_set_mana(spell, 2, 10);
+ spell_type_set_inertia(spell, 1, 10);
+ spell_type_set_difficulty(spell, 5, 25);
+ spell_type_init_mage(spell,
+ RANDOM,
+ SCHOOL_DIVINATION,
+ divination_sense_hidden_info,
+ divination_sense_hidden);
+
+ spell_type_set_device_charges(spell, "1+d15");
+
+ {
+ device_allocation *device_allocation = device_allocation_new(TV_STAFF);
+ device_allocation->rarity = 20;
+ range_init(&device_allocation->base_level, 1, 15);
+ range_init(&device_allocation->max_level, 10, 50);
+ spell_type_add_device_allocation(spell, device_allocation);
+ }
+ }
+
+ {
+ spell_type *spell = spell_new(&REVEALWAYS, "Reveal Ways");
+ spell_type_describe(spell, "Detects the doors/stairs/ways in a certain radius around you");
+ spell_type_set_mana(spell, 3, 15);
+ spell_type_set_inertia(spell, 1, 10);
+ spell_type_set_difficulty(spell, 9, 20);
+ spell_type_init_mage(spell,
+ RANDOM,
+ SCHOOL_DIVINATION,
+ divination_reveal_ways_info,
+ divination_reveal_ways);
+
+ spell_type_set_device_charges(spell, "6+d6");
+
+ {
+ device_allocation *device_allocation = device_allocation_new(TV_STAFF);
+ device_allocation->rarity = 35;
+ range_init(&device_allocation->base_level, 1, 15);
+ range_init(&device_allocation->max_level, 25, 50);
+ spell_type_add_device_allocation(spell, device_allocation);
+ }
+ }
+
+ {
+ spell_type *spell = spell_new(&SENSEMONSTERS, "Sense Monsters");
+ spell_type_describe(spell, "Detects all monsters near you");
+ spell_type_describe(spell, "At level 30 it allows you to sense monster minds for a while");
+ spell_type_set_mana(spell, 1, 20);
+ spell_type_set_inertia(spell, 1, 10);
+ spell_type_set_difficulty(spell, 1, 10);
+ spell_type_init_mage(spell,
+ RANDOM,
+ SCHOOL_DIVINATION,
+ divination_sense_monsters_info,
+ divination_sense_monsters);
+
+ spell_type_set_device_charges(spell, "5+d10");
+
+ {
+ device_allocation *device_allocation = device_allocation_new(TV_STAFF);
+ device_allocation->rarity = 37;
+ range_init(&device_allocation->base_level, 1, 10);
+ range_init(&device_allocation->max_level, 15, 40);
+ spell_type_add_device_allocation(spell, device_allocation);
+ }
+ }
+
+ {
+ spell_type *spell = spell_new(&MAGELOCK, "Magelock");
+ spell_type_describe(spell, "Magically locks a door");
+ spell_type_describe(spell, "At level 30 it creates a glyph of warding");
+ spell_type_describe(spell, "At level 40 the glyph can be placed anywhere in the field of vision");
+ spell_type_set_mana(spell, 1, 35);
+ spell_type_set_difficulty(spell, 1, 10);
+ spell_type_init_mage(spell,
+ RANDOM,
+ SCHOOL_TEMPORAL,
+ no_info,
+ tempo_magelock);
+
+ spell_type_set_device_charges(spell, "7+d5");
+
+ {
+ device_allocation *device_allocation = device_allocation_new(TV_WAND);
+ device_allocation->rarity = 30;
+ range_init(&device_allocation->base_level, 1, 5);
+ range_init(&device_allocation->max_level, 15, 45);
+ spell_type_add_device_allocation(spell, device_allocation);
+ }
+ }
+
+ {
+ spell_type *spell = spell_new(&SLOWMONSTER, "Slow Monster");
+ spell_type_describe(spell, "Magically slows down the passing of time around a monster");
+ spell_type_describe(spell, "At level 20 it affects a zone");
+ spell_type_set_mana(spell, 10, 15);
+ spell_type_set_difficulty(spell, 10, 35);
+ spell_type_init_mage(spell,
+ RANDOM,
+ SCHOOL_TEMPORAL,
+ tempo_slow_monster_info,
+ tempo_slow_monster);
+
+ spell_type_set_device_charges(spell, "5+d5");
+
+ {
+ device_allocation *device_allocation = device_allocation_new(TV_WAND);
+ device_allocation->rarity = 23;
+ range_init(&device_allocation->base_level, 1, 15);
+ range_init(&device_allocation->max_level, 20, 50);
+ spell_type_add_device_allocation(spell, device_allocation);
+ }
+ }
+
+ {
+ spell_type *spell = spell_new(&ESSENCESPEED, "Essence of Speed");
+ spell_type_describe(spell, "Magically decreases the passing of time around you, making you move faster with");
+ spell_type_describe(spell, "respect to the rest of the universe.");
+ spell_type_set_mana(spell, 20, 40);
+ spell_type_set_inertia(spell, 5, 20);
+ spell_type_set_difficulty(spell, 15, 50);
+ spell_type_init_mage(spell,
+ RANDOM,
+ SCHOOL_TEMPORAL,
+ tempo_essence_of_speed_info,
+ tempo_essence_of_speed);
+
+ spell_type_set_device_charges(spell, "3+d3");
+
+ {
+ device_allocation *device_allocation = device_allocation_new(TV_WAND);
+ device_allocation->rarity = 80;
+ range_init(&device_allocation->base_level, 1, 1);
+ range_init(&device_allocation->max_level, 10, 39);
+ spell_type_add_device_allocation(spell, device_allocation);
+ }
+ }
+
+ {
+ spell_type *spell = spell_new(&BANISHMENT, "Banishment");
+ spell_type_describe(spell, "Disrupts the space/time continuum in your area and teleports all monsters away.");
+ spell_type_describe(spell, "At level 15 it may also lock them in a time bubble for a while.");
+ spell_type_add_school(spell, SCHOOL_CONVEYANCE);
+ spell_type_set_mana(spell, 30, 40);
+ spell_type_set_inertia(spell, 5, 50);
+ spell_type_set_difficulty(spell, 30, 95);
+ spell_type_init_mage(spell,
+ RANDOM,
+ SCHOOL_TEMPORAL,
+ tempo_banishment_info,
+ tempo_banishment);
+
+ spell_type_set_device_charges(spell, "1+d3");
+
+ {
+ device_allocation *device_allocation = device_allocation_new(TV_WAND);
+ device_allocation->rarity = 98;
+ range_init(&device_allocation->base_level, 1, 15);
+ range_init(&device_allocation->max_level, 10, 36);
+ spell_type_add_device_allocation(spell, device_allocation);
+ }
+ }
+
+ {
+ spell_type *spell = spell_new(&RECHARGE, "Recharge");
+ spell_type_describe(spell, "Taps on the ambient mana to recharge an object's power (charges or mana)");
+ spell_type_set_mana(spell, 10, 100);
+ spell_type_set_difficulty(spell, 5, 20);
+ spell_type_init_mage(spell,
+ RANDOM,
+ SCHOOL_META,
+ meta_recharge_info,
+ meta_recharge);
+ }
+
+ {
+ spell_type *spell = spell_new(&SPELLBINDER, "Spellbinder");
+ spell_type_describe(spell, "Stores spells in a trigger.");
+ spell_type_describe(spell, "When the condition is met all spells fire off at the same time");
+ spell_type_describe(spell, "This spell takes a long time to cast so you are advised to prepare it");
+ spell_type_describe(spell, "in a safe area.");
+ spell_type_describe(spell, "Also it will use the mana for the Spellbinder and the mana for the");
+ spell_type_describe(spell, "selected spells");
+ spell_type_set_mana(spell, 100, 300);
+ spell_type_set_difficulty(spell, 20, 85);
+ spell_type_init_mage(spell,
+ RANDOM,
+ SCHOOL_META,
+ meta_spellbinder_info,
+ meta_spellbinder);
+ }
+
+ {
+ spell_type *spell = spell_new(&DISPERSEMAGIC, "Disperse Magic");
+ spell_type_describe(spell, "Dispels a lot of magic that can affect you, be it good or bad");
+ spell_type_describe(spell, "Level 1: blindness and light");
+ spell_type_describe(spell, "Level 5: confusion and hallucination");
+ spell_type_describe(spell, "Level 10: speed (both bad or good) and light speed");
+ spell_type_describe(spell, "Level 15: stunning, meditation, cuts");
+ spell_type_describe(spell, "Level 20: hero, super hero, bless, shields, afraid, parasites, mimicry");
+ spell_type_set_mana(spell, 30, 60);
+ spell_type_set_inertia(spell, 1, 5);
+ spell_type_set_difficulty(spell, 15, 40);
+ spell_type_set_castable_while_blind(spell, TRUE);
+ spell_type_set_castable_while_confused(spell, TRUE);
+ spell_type_init_mage(spell,
+ RANDOM,
+ SCHOOL_META,
+ no_info,
+ meta_disperse_magic);
+
+ spell_type_set_device_charges(spell, "5+d5");
+
+ {
+ device_allocation *device_allocation = device_allocation_new(TV_WAND);
+ device_allocation->rarity = 25;
+ range_init(&device_allocation->base_level, 1, 15);
+ range_init(&device_allocation->max_level, 5, 40);
+ spell_type_add_device_allocation(spell, device_allocation);
+ }
+ }
+
+ {
+ spell_type *spell = spell_new(&TRACKER, "Tracker");
+ spell_type_describe(spell, "Tracks down the last teleportation that happened on the level and teleports");
+ spell_type_describe(spell, "you to it");
+ spell_type_add_school(spell, SCHOOL_CONVEYANCE);
+ spell_type_set_mana(spell, 50, 50);
+ spell_type_set_difficulty(spell, 30, 95);
+ spell_type_init_mage(spell,
+ RANDOM,
+ SCHOOL_META,
+ no_info,
+ meta_tracker);
+ }
+
+ {
+ spell_type *spell = spell_new(&INERTIA_CONTROL, "Inertia Control");
+ spell_type_describe(spell, "Changes the energy flow of a spell to be continuously recasted");
+ spell_type_describe(spell, "at a given interval. The inertia controlled spell reduces your");
+ spell_type_describe(spell, "maximum mana by four times its cost.");
+ spell_type_set_mana(spell, 300, 700);
+ spell_type_set_difficulty(spell, 37, 95);
+ spell_type_init_mage(spell,
+ RANDOM,
+ SCHOOL_META,
+ meta_inertia_control_info,
+ meta_inertia_control);
+ }
+
+ {
+ spell_type *spell = spell_new(&CHARM, "Charm");
+ spell_type_describe(spell, "Tries to manipulate the mind of a monster to make it friendly");
+ spell_type_describe(spell, "At level 15 it turns into a ball");
+ spell_type_describe(spell, "At level 35 it affects all monsters in sight");
+ spell_type_set_mana(spell, 1, 20);
+ spell_type_set_difficulty(spell, 1, 10);
+ spell_type_init_mage(spell,
+ RANDOM,
+ SCHOOL_MIND,
+ mind_charm_info,
+ mind_charm);
+
+ spell_type_set_device_charges(spell, "7+d5");
+
+ {
+ device_allocation *device_allocation = device_allocation_new(TV_WAND);
+ device_allocation->rarity = 35;
+ range_init(&device_allocation->base_level, 1, 15);
+ range_init(&device_allocation->max_level, 20, 40);
+ spell_type_add_device_allocation(spell, device_allocation);
+ }
+ }
+
+ {
+ spell_type *spell = spell_new(&CONFUSE, "Confuse");
+ spell_type_describe(spell, "Tries to manipulate the mind of a monster to confuse it");
+ spell_type_describe(spell, "At level 15 it turns into a ball");
+ spell_type_describe(spell, "At level 35 it affects all monsters in sight");
+ spell_type_set_mana(spell, 5, 30);
+ spell_type_set_difficulty(spell, 5, 20);
+ spell_type_init_mage(spell,
+ RANDOM,
+ SCHOOL_MIND,
+ mind_confuse_info,
+ mind_confuse);
+
+ spell_type_set_device_charges(spell, "3+d4");
+
+ {
+ device_allocation *device_allocation = device_allocation_new(TV_WAND);
+ device_allocation->rarity = 45;
+ range_init(&device_allocation->base_level, 1, 5);
+ range_init(&device_allocation->max_level, 20, 40);
+ spell_type_add_device_allocation(spell, device_allocation);
+ }
+ }
+
+ {
+ spell_type *spell = spell_new(&ARMOROFFEAR, "Armor of Fear");
+ spell_type_describe(spell, "Creates a shield of pure fear around you. Any monster attempting to hit you");
+ spell_type_describe(spell, "must save or flee");
+ spell_type_set_mana(spell, 10, 50);
+ spell_type_set_inertia(spell, 2, 20);
+ spell_type_set_difficulty(spell, 10, 35);
+ spell_type_init_mage(spell,
+ RANDOM,
+ SCHOOL_MIND,
+ mind_armor_of_fear_info,
+ mind_armor_of_fear);
+ }
+
+ {
+ spell_type *spell = spell_new(&STUN, "Stun");
+ spell_type_describe(spell, "Tries to manipulate the mind of a monster to stun it");
+ spell_type_describe(spell, "At level 20 it turns into a ball");
+ spell_type_set_mana(spell, 10, 90);
+ spell_type_set_difficulty(spell, 15, 45);
+ spell_type_init_mage(spell,
+ RANDOM,
+ SCHOOL_MIND,
+ mind_stun_info,
+ mind_stun);
+ }
+
+ {
+ spell_type *spell = spell_new(&DRAIN, "Drain");
+ spell_type_describe(spell, "Drains the mana contained in wands, staves and rods to increase yours");
+ spell_type_add_school(spell, SCHOOL_MANA);
+ spell_type_set_mana(spell, 0, 0);
+ spell_type_set_difficulty(spell, 1, 20);
+ spell_type_init_mage(spell,
+ RANDOM,
+ SCHOOL_UDUN,
+ no_info,
+ udun_drain);
+ }
+
+ {
+ spell_type *spell = spell_new(&GENOCIDE, "Genocide");
+ spell_type_describe(spell, "Genocides all monsters of a race on the level");
+ spell_type_describe(spell, "At level 10 it can genocide all monsters near you");
+ spell_type_add_school(spell, SCHOOL_NATURE);
+ spell_type_set_mana(spell, 50, 50);
+ spell_type_set_difficulty(spell, 25, 90);
+ spell_type_init_mage(spell,
+ RANDOM,
+ SCHOOL_UDUN,
+ no_info,
+ udun_genocide);
+
+ spell_type_set_device_charges(spell, "2+d2");
+
+ {
+ device_allocation *device_allocation = device_allocation_new(TV_STAFF);
+ device_allocation->rarity = 85;
+ range_init(&device_allocation->base_level, 1, 1);
+ range_init(&device_allocation->max_level, 5, 15);
+ spell_type_add_device_allocation(spell, device_allocation);
+ }
+ }
+
+ {
+ spell_type *spell = spell_new(&WRAITHFORM, "Wraithform");
+ spell_type_describe(spell, "Turns you into an immaterial being");
+ spell_type_add_school(spell, SCHOOL_CONVEYANCE);
+ spell_type_set_mana(spell, 20, 40);
+ spell_type_set_inertia(spell, 4, 30);
+ spell_type_set_difficulty(spell, 30, 95);
+ spell_type_init_mage(spell,
+ RANDOM,
+ SCHOOL_UDUN,
+ udun_wraithform_info,
+ udun_wraithform);
+ }
+
+ {
+ spell_type *spell = spell_new(&FLAMEOFUDUN, "Flame of Udun");
+ spell_type_describe(spell, "Turns you into a powerful Balrog");
+ spell_type_add_school(spell, SCHOOL_FIRE);
+ spell_type_set_mana(spell, 70, 100);
+ spell_type_set_inertia(spell, 7, 15);
+ spell_type_set_difficulty(spell, 35, 95);
+ spell_type_init_mage(spell,
+ RANDOM,
+ SCHOOL_UDUN,
+ udun_flame_of_udun_info,
+ udun_flame_of_udun);
+ }
+
+ {
+ spell_type *spell = spell_new(&CALL_THE_ELEMENTS, "Call the Elements");
+ spell_type_describe(spell, "Randomly creates various elements around you");
+ spell_type_describe(spell, "Each type of element chance is controlled by your level");
+ spell_type_describe(spell, "in the corresponding skill");
+ spell_type_describe(spell, "At level 17 it can be targeted");
+ spell_type_set_mana(spell, 2, 20);
+ spell_type_set_difficulty(spell, 1, 10);
+ spell_type_set_castable_while_blind(spell, TRUE);
+ spell_type_init_mage(spell,
+ NO_RANDOM,
+ SCHOOL_GEOMANCY,
+ geomancy_call_the_elements_info,
+ geomancy_call_the_elements);
+ }
+
+ {
+ spell_type *spell = spell_new(&CHANNEL_ELEMENTS, "Channel Elements");
+ spell_type_describe(spell, "Draws on the caster's immediate environs to form an attack or other effect.");
+ spell_type_describe(spell, "Grass/Flower heals.");
+ spell_type_describe(spell, "Water creates water bolt attacks.");
+ spell_type_describe(spell, "Ice creates ice bolt attacks.");
+ spell_type_describe(spell, "Sand creates a wall of thick, blinding, burning sand around you.");
+ spell_type_describe(spell, "Lava creates fire bolt attacks.");
+ spell_type_describe(spell, "Deep lava creates fire ball attacks.");
+ spell_type_describe(spell, "Chasm creates darkness bolt attacks.");
+ spell_type_describe(spell, "At Earth level 18, darkness becomes nether.");
+ spell_type_describe(spell, "At Water level 8, water attacks become beams with a striking effect.");
+ spell_type_describe(spell, "At Water level 12, ice attacks become balls of ice shards.");
+ spell_type_describe(spell, "At Water level 18, water attacks push monsters back.");
+ spell_type_describe(spell, "At Fire level 15, fire become hellfire.");
+ spell_type_set_mana(spell, 3, 30);
+ spell_type_set_difficulty(spell, 3, 20);
+ spell_type_set_castable_while_blind(spell, TRUE);
+ spell_type_init_mage(spell,
+ NO_RANDOM,
+ SCHOOL_GEOMANCY,
+ no_info,
+ geomancy_channel_elements);
+ }
+
+ {
+ spell_type *spell = spell_new(&ELEMENTAL_WAVE, "Elemental Wave");
+ spell_type_describe(spell, "Draws on an adjacent special square to project a slow-moving");
+ spell_type_describe(spell, "wave of that element in that direction");
+ spell_type_describe(spell, "Abyss squares cannot be channeled into a wave.");
+ spell_type_set_mana(spell, 15, 50);
+ spell_type_set_difficulty(spell, 15, 20);
+ spell_type_set_castable_while_blind(spell, TRUE);
+ spell_type_init_mage(spell,
+ NO_RANDOM,
+ SCHOOL_GEOMANCY,
+ no_info,
+ geomancy_elemental_wave);
+ }
+
+ {
+ spell_type *spell = spell_new(&VAPORIZE, "Vaporize");
+ spell_type_describe(spell, "Draws upon your immediate environs to form a cloud of damaging vapors");
+ spell_type_set_mana(spell, 3, 30);
+ spell_type_set_difficulty(spell, 4, 15);
+ spell_type_set_castable_while_blind(spell, TRUE);
+ spell_type_init_geomancy(
+ spell,
+ geomancy_vaporize_info,
+ geomancy_vaporize,
+ geomancy_vaporize_depends);
+ }
+
+ {
+ spell_type *spell = spell_new(&GEOLYSIS, "Geolysis");
+ spell_type_describe(spell, "Burrows deeply and slightly at random into a wall,");
+ spell_type_describe(spell, "leaving behind tailings of various different sorts of walls in the passage.");
+ spell_type_set_mana(spell, 15, 40);
+ spell_type_set_difficulty(spell, 7, 15);
+ spell_type_set_castable_while_blind(spell, TRUE);
+ spell_type_init_geomancy(
+ spell,
+ geomancy_geolysis_info,
+ geomancy_geolysis,
+ geomancy_geolysis_depends);
+ }
+
+ {
+ spell_type *spell = spell_new(&DRIPPING_TREAD, "Dripping Tread");
+ spell_type_describe(spell, "Causes you to leave random elemental forms behind as you walk");
+ spell_type_set_mana(spell, 15, 25);
+ spell_type_set_difficulty(spell, 10, 15);
+ spell_type_set_castable_while_blind(spell, TRUE);
+ spell_type_init_geomancy(
+ spell,
+ geomancy_dripping_tread_info,
+ geomancy_dripping_tread,
+ geomancy_dripping_tread_depends);
+ }
+
+ {
+ spell_type *spell = spell_new(&GROW_BARRIER, "Grow Barrier");
+ spell_type_describe(spell, "Creates impassable terrain (walls, trees, etc.) around you.");
+ spell_type_describe(spell, "At level 20 it can be projected around another area.");
+ spell_type_set_mana(spell, 30, 40);
+ spell_type_set_difficulty(spell, 12, 15);
+ spell_type_set_castable_while_blind(spell, TRUE);
+ spell_type_init_geomancy(
+ spell,
+ no_info,
+ geomancy_grow_barrier,
+ geomancy_grow_barrier_depends);
+ }
+
+ {
+ spell_type *spell = spell_new(&ELEMENTAL_MINION, "Elemental Minion");
+ spell_type_describe(spell, "Summons a minion from a nearby element.");
+ spell_type_describe(spell, "Walls can summon Earth elmentals, Xorns and Xarens");
+ spell_type_describe(spell, "Dark Pits can summon Air elementals, Ancient blue dragons, Great Storm Wyrms");
+ spell_type_describe(spell, "and Sky Drakes");
+ spell_type_describe(spell, "Sandwalls and lava can summon Fire elementals and Ancient red dragons");
+ spell_type_describe(spell, "Icewall, and water can summon Water elementals, Water trolls and Water demons");
+ spell_type_set_mana(spell, 40, 80);
+ spell_type_set_difficulty(spell, 20, 25);
+ spell_type_init_geomancy(
+ spell,
+ geomancy_elemental_minion_info,
+ geomancy_elemental_minion,
+ NULL);
+ }
+
+ {
+ spell_type *spell = spell_new(&ERU_SEE, "See the Music");
+ spell_type_describe(spell, "Allows you to 'see' the Great Music from which the world");
+ spell_type_describe(spell, "originates, allowing you to see unseen things");
+ spell_type_describe(spell, "At level 10 it allows you to see your surroundings");
+ spell_type_describe(spell, "At level 20 it allows you to cure blindness");
+ spell_type_describe(spell, "At level 30 it allows you to fully see all the level");
+ spell_type_set_mana(spell, 1, 50);
+ spell_type_set_difficulty(spell, 1, 20);
+ spell_type_init_priest(spell,
+ SCHOOL_ERU,
+ eru_see_the_music_info,
+ eru_see_the_music);
+ spell_type_set_castable_while_blind(spell, TRUE);
+ }
+
+ {
+ spell_type *spell = spell_new(&ERU_LISTEN, "Listen to the Music");
+ spell_type_describe(spell, "Allows you to listen to the Great Music from which the world");
+ spell_type_describe(spell, "originates, allowing you to understand the meaning of things");
+ spell_type_describe(spell, "At level 14 it allows you to identify all your pack");
+ spell_type_describe(spell, "At level 30 it allows you to identify all items on the level");
+ spell_type_set_mana(spell, 15, 200);
+ spell_type_set_difficulty(spell, 7, 25);
+ spell_type_init_priest(spell,
+ SCHOOL_ERU,
+ no_info,
+ eru_listen_to_the_music);
+ }
+
+ {
+ spell_type *spell = spell_new(&ERU_UNDERSTAND, "Know the Music");
+ spell_type_describe(spell, "Allows you to understand the Great Music from which the world");
+ spell_type_describe(spell, "originates, allowing you to know the full abilities of things");
+ spell_type_describe(spell, "At level 10 it allows you to *identify* all your pack");
+ spell_type_set_mana(spell, 200, 600);
+ spell_type_set_difficulty(spell, 30, 50);
+ spell_type_init_priest(spell,
+ SCHOOL_ERU,
+ no_info,
+ eru_know_the_music);
+ }
+
+ {
+ spell_type *spell = spell_new(&ERU_PROT, "Lay of Protection");
+ spell_type_describe(spell, "Creates a circle of safety around you");
+ spell_type_set_mana(spell, 400, 400);
+ spell_type_set_difficulty(spell, 35, 80);
+ spell_type_init_priest(spell,
+ SCHOOL_ERU,
+ eru_lay_of_protection_info,
+ eru_lay_of_protection);
+ }
+
+ {
+ spell_type *spell = spell_new(&MANWE_SHIELD, "Wind Shield");
+ spell_type_describe(spell, "It surrounds you with a shield of wind that deflects blows from evil monsters");
+ spell_type_describe(spell, "At level 10 it increases your armour rating");
+ spell_type_describe(spell, "At level 20 it retaliates against monsters that melee you");
+ spell_type_set_mana(spell, 100, 500);
+ spell_type_set_difficulty(spell, 10, 30);
+ spell_type_init_priest(spell,
+ SCHOOL_MANWE,
+ manwe_wind_shield_info,
+ manwe_wind_shield);
+ }
+
+ {
+ spell_type *spell = spell_new(&MANWE_AVATAR, "Avatar");
+ spell_type_describe(spell, "It turns you into a full grown Maia");
+ spell_type_set_mana(spell, 1000, 1000);
+ spell_type_set_difficulty(spell, 35, 80);
+ spell_type_init_priest(spell,
+ SCHOOL_MANWE,
+ manwe_avatar_info,
+ manwe_avatar);
+ }
+
+ {
+ spell_type *spell = spell_new(&MANWE_BLESS, "Manwe's Blessing");
+ spell_type_describe(spell, "Manwe's Blessing removes your fears, blesses you and surrounds you with");
+ spell_type_describe(spell, "holy light");
+ spell_type_describe(spell, "At level 10 it also grants heroism");
+ spell_type_describe(spell, "At level 20 it also grants super heroism");
+ spell_type_describe(spell, "At level 30 it also grants holy luck and life protection");
+ spell_type_set_mana(spell, 10, 100);
+ spell_type_set_difficulty(spell, 1, 20);
+ spell_type_init_priest(spell,
+ SCHOOL_MANWE,
+ manwe_blessing_info,
+ manwe_blessing);
+ }
+
+ {
+ spell_type *spell = spell_new(&MANWE_CALL, "Manwe's Call");
+ spell_type_describe(spell, "Manwe's Call summons a Great Eagle to help you battle the forces");
+ spell_type_describe(spell, "of Morgoth");
+ spell_type_set_mana(spell, 200, 500);
+ spell_type_set_difficulty(spell, 20, 40);
+ spell_type_init_priest(spell,
+ SCHOOL_MANWE,
+ manwe_call_info,
+ manwe_call);
+ }
+
+ {
+ spell_type *spell = spell_new(&TULKAS_AIM, "Divine Aim");
+ spell_type_describe(spell, "It makes you more accurate in combat");
+ spell_type_describe(spell, "At level 20 all your blows are critical hits");
+ spell_type_set_mana(spell, 30, 500);
+ spell_type_set_difficulty(spell, 1, 20);
+ spell_type_init_priest(spell,
+ SCHOOL_TULKAS,
+ tulkas_divine_aim_info,
+ tulkas_divine_aim);
+ }
+
+ {
+ spell_type *spell = spell_new(&TULKAS_WAVE, "Wave of Power");
+ spell_type_describe(spell, "It allows you to project a number of melee blows across a distance");
+ spell_type_set_mana(spell, 200, 200);
+ spell_type_set_difficulty(spell, 20, 75);
+ spell_type_init_priest(spell,
+ SCHOOL_TULKAS,
+ tulkas_wave_of_power_info,
+ tulkas_wave_of_power);
+ }
+
+ {
+ spell_type *spell = spell_new(&TULKAS_SPIN, "Whirlwind");
+ spell_type_describe(spell, "It allows you to spin around and hit all monsters nearby");
+ spell_type_set_mana(spell, 100, 100);
+ spell_type_set_difficulty(spell, 10, 45);
+ spell_type_init_priest(spell,
+ SCHOOL_TULKAS,
+ no_info,
+ tulkas_whirlwind);
+ }
+
+ {
+ spell_type *spell = spell_new(&MELKOR_CURSE, "Curse");
+ spell_type_describe(spell, "It curses a monster, reducing its melee power");
+ spell_type_describe(spell, "At level 5 it can be auto-casted (with no piety cost) while fighting");
+ spell_type_describe(spell, "At level 15 it also reduces armor");
+ spell_type_describe(spell, "At level 25 it also reduces speed");
+ spell_type_describe(spell, "At level 35 it also reduces max life (but it is never fatal)");
+ spell_type_set_mana(spell, 50, 300);
+ spell_type_set_difficulty(spell, 1, 20);
+ spell_type_init_priest(spell,
+ SCHOOL_MELKOR,
+ no_info,
+ melkor_curse);
+ }
+
+ {
+ spell_type *spell = spell_new(&MELKOR_CORPSE_EXPLOSION, "Corpse Explosion");
+ spell_type_describe(spell, "It makes corpses in an area around you explode for a percent of their");
+ spell_type_describe(spell, "hit points as damage");
+ spell_type_set_mana(spell, 100, 500);
+ spell_type_set_difficulty(spell, 10, 45);
+ spell_type_init_priest(spell,
+ SCHOOL_MELKOR,
+ melkor_corpse_explosion_info,
+ melkor_corpse_explosion);
+ }
+
+ {
+ spell_type *spell = spell_new(&MELKOR_MIND_STEAL, "Mind Steal");
+ spell_type_describe(spell, "It allows your spirit to temporarily leave your own body, which will");
+ spell_type_describe(spell, "be vulnerable, to control one of your enemies body.");
+ spell_type_set_mana(spell, 1000, 3000);
+ spell_type_set_difficulty(spell, 20, 90);
+ spell_type_init_priest(spell,
+ SCHOOL_MELKOR,
+ melkor_mind_steal_info,
+ melkor_mind_steal);
+ }
+
+ {
+ spell_type *spell = spell_new(&YAVANNA_CHARM_ANIMAL, "Charm Animal");
+ spell_type_describe(spell, "It tries to tame an animal");
+ spell_type_set_mana(spell, 10, 100);
+ spell_type_set_difficulty(spell, 1, 30);
+ spell_type_init_priest(spell,
+ SCHOOL_YAVANNA,
+ yavanna_charm_animal_info,
+ yavanna_charm_animal);
+ }
+
+ {
+ spell_type *spell = spell_new(&YAVANNA_GROW_GRASS, "Grow Grass");
+ spell_type_describe(spell, "Create a floor of grass around you. While on grass and praying");
+ spell_type_describe(spell, "a worshipper of Yavanna will know a greater regeneration rate");
+ spell_type_set_mana(spell, 70, 150);
+ spell_type_set_difficulty(spell, 10, 65);
+ spell_type_init_priest(spell,
+ SCHOOL_YAVANNA,
+ yavanna_grow_grass_info,
+ yavanna_grow_grass);
+ }
+
+ {
+ spell_type *spell = spell_new(&YAVANNA_TREE_ROOTS, "Tree Roots");
+ spell_type_describe(spell, "Creates roots deep in the floor from your feet, making you more stable and able");
+ spell_type_describe(spell, "to make stronger attacks, but prevents any movement (even teleportation).");
+ spell_type_describe(spell, "It also makes you recover from stunning almost immediately.");
+ spell_type_set_mana(spell, 50, 1000);
+ spell_type_set_difficulty(spell, 15, 70);
+ spell_type_init_priest(spell,
+ SCHOOL_YAVANNA,
+ yavanna_tree_roots_info,
+ yavanna_tree_roots);
+ }
+
+ {
+ spell_type *spell = spell_new(&YAVANNA_WATER_BITE, "Water Bite");
+ spell_type_describe(spell, "Imbues your melee weapon with a natural stream of water");
+ spell_type_describe(spell, "At level 25, it spreads over a 1 radius zone around your target");
+ spell_type_set_mana(spell, 150, 300);
+ spell_type_set_difficulty(spell, 20, 90);
+ spell_type_init_priest(spell,
+ SCHOOL_YAVANNA,
+ yavanna_water_bite_info,
+ yavanna_water_bite);
+ }
+
+ {
+ spell_type *spell = spell_new(&YAVANNA_UPROOT, "Uproot");
+ spell_type_describe(spell, "Awakes a tree to help you battle the forces of Morgoth");
+ spell_type_set_mana(spell, 250, 350);
+ spell_type_set_difficulty(spell, 35, 95);
+ spell_type_init_priest(spell,
+ SCHOOL_YAVANNA,
+ yavanna_uproot_info,
+ yavanna_uproot);
+ }
+
+ {
+ spell_type *spell = spell_new(&DEMON_BLADE, "Demon Blade");
+ spell_type_describe(spell, "Imbues your blade with fire to deal more damage");
+ spell_type_describe(spell, "At level 30 it deals hellfire damage");
+ spell_type_describe(spell, "At level 45 it spreads over a 1 radius zone around your target");
+ spell_type_set_mana(spell, 4, 44);
+ spell_type_set_difficulty(spell, 1, 10);
+ spell_type_init_demonology(spell,
+ demonology_demon_blade_info,
+ demonology_demon_blade);
+
+ spell_type_set_device_charges(spell, "3+d7");
+
+ {
+ device_allocation *device_allocation = device_allocation_new(TV_WAND);
+ device_allocation->rarity = 75;
+ range_init(&device_allocation->base_level, 1, 17);
+ range_init(&device_allocation->max_level, 20, 40);
+ spell_type_add_device_allocation(spell, device_allocation);
+ }
+ }
+
+ {
+ spell_type *spell = spell_new(&DEMON_MADNESS, "Demon Madness");
+ spell_type_describe(spell, "Fire 2 balls in opposite directions of randomly chaos, confusion or charm");
+ spell_type_set_mana(spell, 5, 20);
+ spell_type_set_difficulty(spell, 10, 25);
+ spell_type_init_demonology(spell,
+ demonology_demon_madness_info,
+ demonology_demon_madness);
+ }
+
+ {
+ spell_type *spell = spell_new(&DEMON_FIELD, "Demon Field");
+ spell_type_describe(spell, "Fires a cloud of deadly nexus over a radius of 7");
+ spell_type_set_mana(spell, 20, 60);
+ spell_type_set_difficulty(spell, 20, 60);
+ spell_type_init_demonology(spell,
+ demonology_demon_field_info,
+ demonology_demon_field);
+ }
+
+ {
+ spell_type *spell = spell_new(&DOOM_SHIELD, "Doom Shield");
+ spell_type_describe(spell, "Raises a mirror of pain around you, doing very high damage to your foes");
+ spell_type_describe(spell, "that dare hit you, but greatly reduces your armour class");
+ spell_type_set_mana(spell, 2, 30);
+ spell_type_set_difficulty(spell, 1, 10);
+ spell_type_init_demonology(spell,
+ demonology_doom_shield_info,
+ demonology_doom_shield);
+ }
+
+ {
+ spell_type *spell = spell_new(&UNHOLY_WORD, "Unholy Word");
+ spell_type_describe(spell, "Kills a pet to heal you");
+ spell_type_describe(spell, "There is a chance that the pet won't die but will turn against you");
+ spell_type_describe(spell, "it will decrease with higher level");
+ spell_type_set_mana(spell, 15, 45);
+ spell_type_set_difficulty(spell, 25, 55);
+ spell_type_init_demonology(spell,
+ demonology_unholy_word_info,
+ demonology_unholy_word);
+ }
+
+ {
+ spell_type *spell = spell_new(&DEMON_CLOAK, "Demon Cloak");
+ spell_type_describe(spell, "Raises a mirror that can reflect bolts and arrows for a time");
+ spell_type_set_mana(spell, 10, 40);
+ spell_type_set_difficulty(spell, 20, 70);
+ spell_type_init_demonology(spell,
+ demonology_demon_cloak_info,
+ demonology_demon_cloak);
+ }
+
+ {
+ spell_type *spell = spell_new(&DEMON_SUMMON, "Summon Demon");
+ spell_type_describe(spell, "Summons a leveled demon to your side");
+ spell_type_describe(spell, "At level 35 it summons a high demon");
+ spell_type_set_mana(spell, 10, 50);
+ spell_type_set_difficulty(spell, 5, 30);
+ spell_type_init_demonology(spell,
+ demonology_summon_demon_info,
+ demonology_summon_demon);
+ }
+
+ {
+ spell_type *spell = spell_new(&DISCHARGE_MINION, "Discharge Minion");
+ spell_type_describe(spell, "The targeted pet will explode in a burst of gravity");
+ spell_type_set_mana(spell, 20, 50);
+ spell_type_set_difficulty(spell, 10, 30);
+ spell_type_init_demonology(spell,
+ demonology_discharge_minion_info,
+ demonology_discharge_minion);
+ }
+
+ {
+ spell_type *spell = spell_new(&CONTROL_DEMON, "Control Demon");
+ spell_type_describe(spell, "Attempts to control a demon");
+ spell_type_set_mana(spell, 30, 70);
+ spell_type_set_difficulty(spell, 25, 55);
+ spell_type_init_demonology(spell,
+ demonology_control_demon_info,
+ demonology_control_demon);
+ }
+
+ {
+ spell_type *spell = spell_new(&DEVICE_HEAL_MONSTER, "Heal Monster");
+ spell_type_describe(spell, "Heals a monster");
+ spell_type_set_mana(spell, 5, 20);
+ spell_type_set_difficulty(spell, 3, 15);
+ spell_type_init_device(spell,
+ device_heal_monster_info,
+ device_heal_monster);
+
+ spell_type_set_device_charges(spell, "10+d10");
+
+ {
+ device_allocation *device_allocation = device_allocation_new(TV_WAND);
+ device_allocation->rarity = 17;
+ range_init(&device_allocation->base_level, 1, 15);
+ range_init(&device_allocation->max_level, 20, 50);
+ spell_type_add_device_allocation(spell, device_allocation);
+ }
+ }
+
+ {
+ spell_type *spell = spell_new(&DEVICE_SPEED_MONSTER, "Haste Monster");
+ spell_type_describe(spell, "Haste a monster");
+ spell_type_set_mana(spell, 10, 10);
+ spell_type_set_difficulty(spell, 10, 30);
+ spell_type_init_device(spell,
+ device_haste_monster_info,
+ device_haste_monster);
+
+ spell_type_set_device_charges(spell, "10+d5");
+
+ {
+ device_allocation *device_allocation = device_allocation_new(TV_WAND);
+ device_allocation->rarity = 7;
+ range_init(&device_allocation->base_level, 1, 1);
+ range_init(&device_allocation->max_level, 20, 50);
+ spell_type_add_device_allocation(spell, device_allocation);
+ }
+ }
+
+ {
+ spell_type *spell = spell_new(&DEVICE_WISH, "Wish");
+ spell_type_describe(spell, "This grants you a wish, beware of what you ask for!");
+ spell_type_set_mana(spell, 400, 400);
+ spell_type_set_difficulty(spell, 50, 99);
+ spell_type_init_device(spell,
+ no_info,
+ device_wish);
+
+ spell_type_set_device_charges(spell, "1+d2");
+
+ {
+ device_allocation *device_allocation = device_allocation_new(TV_STAFF);
+ device_allocation->rarity = 98;
+ range_init(&device_allocation->base_level, 1, 1);
+ range_init(&device_allocation->max_level, 1, 1);
+ spell_type_add_device_allocation(spell, device_allocation);
+ }
+ }
+
+ {
+ spell_type *spell = spell_new(&DEVICE_SUMMON, "Summon");
+ spell_type_describe(spell, "Summons hostile monsters near you");
+ spell_type_set_mana(spell, 5, 25);
+ spell_type_set_difficulty(spell, 5, 20);
+ spell_type_init_device(spell,
+ no_info,
+ device_summon_monster);
+
+ spell_type_set_device_charges(spell, "1+d20");
+
+ {
+ device_allocation *device_allocation = device_allocation_new(TV_STAFF);
+ device_allocation->rarity = 13;
+ range_init(&device_allocation->base_level, 1, 40);
+ range_init(&device_allocation->max_level, 25, 50);
+ spell_type_add_device_allocation(spell, device_allocation);
+ }
+ }
+
+ {
+ spell_type *spell = spell_new(&DEVICE_MANA, "Mana");
+ spell_type_describe(spell, "Restores a part(or all) of your mana");
+ spell_type_set_mana(spell, 1, 1);
+ spell_type_set_difficulty(spell, 30, 80);
+ spell_type_init_device(spell,
+ device_mana_info,
+ device_mana);
+
+ spell_type_set_device_charges(spell, "2+d3");
+
+ {
+ device_allocation *device_allocation = device_allocation_new(TV_STAFF);
+ device_allocation->rarity = 78;
+ range_init(&device_allocation->base_level, 1, 5);
+ range_init(&device_allocation->max_level, 20, 35);
+ spell_type_add_device_allocation(spell, device_allocation);
+ }
+ }
+
+ {
+ spell_type *spell = spell_new(&DEVICE_NOTHING, "Nothing");
+ spell_type_describe(spell, "It does nothing.");
+ spell_type_set_mana(spell, 0, 0);
+ spell_type_set_difficulty(spell, 1, 0);
+ spell_type_init_device(spell,
+ no_info,
+ device_nothing);
+
+ spell_type_set_device_charges(spell, "0+d0");
+
+ {
+ device_allocation *device_allocation = device_allocation_new(TV_STAFF);
+ device_allocation->rarity = 3;
+ range_init(&device_allocation->base_level, 1, 1);
+ range_init(&device_allocation->max_level, 1, 1);
+ spell_type_add_device_allocation(spell, device_allocation);
+ }
+
+ {
+ device_allocation *device_allocation = device_allocation_new(TV_WAND);
+ device_allocation->rarity = 3;
+ range_init(&device_allocation->base_level, 1, 1);
+ range_init(&device_allocation->max_level, 1, 1);
+ spell_type_add_device_allocation(spell, device_allocation);
+ }
+ }
+
+ {
+ spell_type *spell = spell_new(&DEVICE_HOLY_FIRE, "Holy Fire of Mithrandir");
+ spell_type_describe(spell, "The Holy Fire created by this staff will deeply(double damage) burn");
+ spell_type_describe(spell, "all that is evil.");
+ spell_type_set_mana(spell, 50, 150);
+ spell_type_set_difficulty(spell, 30, 75);
+ spell_type_init_device(spell,
+ device_holy_fire_info,
+ device_holy_fire);
+
+ spell_type_set_device_charges(spell, "2+d5");
+
+ {
+ device_allocation *device_allocation = device_allocation_new(TV_STAFF);
+ device_allocation->rarity = 999;
+ range_init(&device_allocation->base_level, 1, 1);
+ range_init(&device_allocation->max_level, 35, 35);
+ spell_type_add_device_allocation(spell, device_allocation);
+ }
+ }
+
+ {
+ spell_type *spell = spell_new(&MUSIC_STOP, "Stop singing(I)");
+ spell_type_describe(spell, "Stops the current song, if any.");
+ spell_type_set_mana(spell, 0, 0);
+ spell_type_set_difficulty(spell, 1, -400);
+ spell_type_set_castable_while_blind(spell, TRUE);
+ spell_type_init_music(spell,
+ 1,
+ no_info,
+ music_stop_singing_spell);
+ }
+
+ {
+ spell_type *spell = spell_new(&MUSIC_HOLD, "Holding Pattern(I)");
+ spell_type_describe(spell, "Slows down all monsters listening the song.");
+ spell_type_describe(spell, "Consumes the amount of mana each turn.");
+ spell_type_set_mana(spell, 1, 10);
+ spell_type_set_difficulty(spell, 1, 20);
+ spell_type_set_castable_while_blind(spell, TRUE);
+ spell_type_init_music_lasting(
+ spell,
+ 1,
+ music_holding_pattern_info,
+ music_holding_pattern_spell,
+ music_holding_pattern_lasting);
+ }
+
+ {
+ spell_type *spell = spell_new(&MUSIC_CONF, "Illusion Pattern(II)");
+ spell_type_describe(spell, "Tries to confuse all monsters listening the song.");
+ spell_type_describe(spell, "Consumes the amount of mana each turn.");
+ spell_type_set_mana(spell, 2, 15);
+ spell_type_set_difficulty(spell, 5, 30);
+ spell_type_set_castable_while_blind(spell, TRUE);
+ spell_type_init_music_lasting(
+ spell,
+ 2,
+ music_illusion_pattern_info,
+ music_illusion_pattern_spell,
+ music_illusion_pattern_lasting);
+ }
+
+ {
+ spell_type *spell = spell_new(&MUSIC_STUN, "Stun Pattern(IV)");
+ spell_type_describe(spell, "Stuns all monsters listening the song.");
+ spell_type_describe(spell, "Consumes the amount of mana each turn.");
+ spell_type_set_mana(spell, 3, 25);
+ spell_type_set_difficulty(spell, 10, 45);
+ spell_type_set_castable_while_blind(spell, TRUE);
+ spell_type_init_music_lasting(
+ spell,
+ 4,
+ music_stun_pattern_info,
+ music_stun_pattern_spell,
+ music_stun_pattern_lasting);
+ }
+
+ {
+ spell_type *spell = spell_new(&MUSIC_LITE, "Song of the Sun(I)");
+ spell_type_describe(spell, "Provides light as long as you sing.");
+ spell_type_describe(spell, "Consumes the amount of mana each turn.");
+ spell_type_set_mana(spell, 1, 1);
+ spell_type_set_difficulty(spell, 1, 20);
+ spell_type_set_castable_while_blind(spell, TRUE);
+ spell_type_init_music_lasting(
+ spell,
+ 1,
+ no_info,
+ music_song_of_the_sun_spell,
+ music_song_of_the_sun_lasting);
+ }
+
+ {
+ spell_type *spell = spell_new(&MUSIC_HEAL, "Flow of Life(II)");
+ spell_type_describe(spell, "Heals you as long as you sing.");
+ spell_type_describe(spell, "Consumes the amount of mana each turn.");
+ spell_type_set_mana(spell, 5, 30);
+ spell_type_set_difficulty(spell, 7, 35);
+ spell_type_init_music_lasting(
+ spell,
+ 2,
+ music_flow_of_life_info,
+ music_flow_of_life_spell,
+ music_flow_of_life_lasting);
+ }
+
+ {
+ spell_type *spell = spell_new(&MUSIC_HERO, "Heroic Ballad(II)");
+ spell_type_describe(spell, "Increases melee accuracy");
+ spell_type_describe(spell, "At level 10 it increases it even more and reduces armour a bit");
+ spell_type_describe(spell, "At level 20 it increases it again");
+ spell_type_describe(spell, "At level 25 it grants protection against chaos and confusion");
+ spell_type_describe(spell, "Consumes the amount of mana each turn.");
+ spell_type_set_mana(spell, 4, 14);
+ spell_type_set_difficulty(spell, 10, 45);
+ spell_type_init_music_lasting(
+ spell,
+ 2,
+ no_info,
+ music_heroic_ballad_spell,
+ music_heroic_ballad_lasting);
+ }
+
+ {
+ spell_type *spell = spell_new(&MUSIC_TIME, "Hobbit Melodies(III)");
+ spell_type_describe(spell, "Greatly increases your reflexes allowing you to block more melee blows.");
+ spell_type_describe(spell, "At level 15 it also makes you faster.");
+ spell_type_describe(spell, "Consumes the amount of mana each turn.");
+ spell_type_set_mana(spell, 10, 30);
+ spell_type_set_difficulty(spell, 20, 70);
+ spell_type_init_music_lasting(
+ spell,
+ 3,
+ music_hobbit_melodies_info,
+ music_hobbit_melodies_spell,
+ music_hobbit_melodies_lasting);
+ }
+
+ {
+ spell_type *spell = spell_new(&MUSIC_MIND, "Clairaudience(IV)");
+ spell_type_describe(spell, "Allows you to sense monster minds as long as you sing.");
+ spell_type_describe(spell, "At level 10 it identifies all objects in a radius on the floor,");
+ spell_type_describe(spell, "as well as probing monsters in that radius.");
+ spell_type_describe(spell, "Consumes the amount of mana each turn.");
+ spell_type_set_mana(spell, 15, 30);
+ spell_type_set_difficulty(spell, 25, 75);
+ spell_type_init_music_lasting(
+ spell,
+ 4,
+ music_clairaudience_info,
+ music_clairaudience_spell,
+ music_clairaudience_lasting);
+ }
+
+ {
+ spell_type *spell = spell_new(&MUSIC_BLOW, "Blow(I)");
+ spell_type_describe(spell, "Produces a powerful, blowing, sound all around you.");
+ spell_type_set_mana(spell, 3, 30);
+ spell_type_set_difficulty(spell, 4, 20);
+ spell_type_init_music(spell,
+ 1,
+ music_blow_info,
+ music_blow_spell);
+ }
+
+ {
+ spell_type *spell = spell_new(&MUSIC_WIND, "Gush of Wind(II)");
+ spell_type_describe(spell, "Produces a outgoing gush of wind that sends monsters away.");
+ spell_type_set_mana(spell, 15, 45);
+ spell_type_set_difficulty(spell, 14, 30);
+ spell_type_init_music(spell,
+ 2,
+ music_gush_of_wind_info,
+ music_gush_of_wind_spell);
+ }
+
+ {
+ spell_type *spell = spell_new(&MUSIC_YLMIR, "Horns of Ylmir(III)");
+ spell_type_describe(spell, "Produces an earth shaking sound.");
+ spell_type_set_mana(spell, 25, 30);
+ spell_type_set_difficulty(spell, 20, 20);
+ spell_type_init_music(spell,
+ 3,
+ music_horns_of_ylmir_info,
+ music_horns_of_ylmir_spell);
+ }
+
+ {
+ spell_type *spell = spell_new(&MUSIC_AMBARKANTA, "Ambarkanta(IV)");
+ spell_type_describe(spell, "Produces a reality shaking sound that transports you to a nearly");
+ spell_type_describe(spell, "identical reality.");
+ spell_type_set_mana(spell, 70, 70);
+ spell_type_set_difficulty(spell, 25, 60);
+ spell_type_init_music(spell,
+ 4,
+ no_info,
+ music_ambarkanta_spell);
+ }
+
+ /* Module-specific spells */
+ switch (game_module_idx)
+ {
+ case MODULE_TOME:
+ spells_init_tome();
+ break;
+ case MODULE_THEME:
+ spells_init_theme();
+ break;
+ default:
+ assert(FALSE);
+ }
+
+}
diff --git a/src/spells5.hpp b/src/spells5.hpp
new file mode 100644
index 00000000..7359fa16
--- /dev/null
+++ b/src/spells5.hpp
@@ -0,0 +1,9 @@
+#pragma once
+
+#include "h-basic.h"
+
+void school_spells_init();
+struct spell_type *spell_at(s32b index);
+s16b get_random_spell(s16b random_type, int lev);
+s16b get_random_stick(byte tval, int level);
+int find_spell(cptr name);
diff --git a/src/spells6.cc b/src/spells6.cc
new file mode 100644
index 00000000..a4564ae3
--- /dev/null
+++ b/src/spells6.cc
@@ -0,0 +1,402 @@
+#include "spells6.hpp"
+
+#include "gods.hpp"
+#include "lua_bind.hpp"
+#include "object2.hpp"
+#include "object_type.hpp"
+#include "player_type.hpp"
+#include "skills.hpp"
+#include "skill_type.hpp"
+#include "spell_type.hpp"
+#include "spells4.hpp"
+#include "variable.hpp"
+
+#include <cassert>
+#include <vector>
+#include <type_traits>
+
+struct school_provider
+{
+ byte deity_idx; /* Deity which provides school levels */
+
+ s16b skill_idx; /* Skill used for determining the boost */
+
+ long mul; /* Multiplier */
+
+ long div; /* Divisor */
+};
+
+struct school_provider_list {
+public:
+ std::vector<school_provider> v;
+};
+
+static school_provider school_provider_new(byte deity_idx, long mul, long div)
+{
+ school_provider p;
+ p.deity_idx = deity_idx;
+ p.skill_idx = SKILL_PRAY;
+ p.mul = mul;
+ p.div = div;
+ return p;
+}
+
+school_type *school_at(int index)
+{
+ assert(index >= 0);
+ assert(index < schools_count);
+
+ return &schools[index];
+}
+
+static void school_init(school_type *school, cptr name, s16b skill)
+{
+ assert(school != NULL);
+
+ static_assert(std::is_pod<school_type>::value, "Cannot initialize non-POD using memset!");
+ memset(school, 0, sizeof(school_type));
+
+ school->providers = new school_provider_list();
+ school->name = name;
+ school->skill = skill;
+
+ school->deity_idx = -1;
+}
+
+static school_type *school_new(s32b *school_idx, cptr name, s16b skill)
+{
+ assert(schools_count < SCHOOLS_MAX);
+
+ *school_idx = schools_count;
+ schools_count++;
+
+ school_type *school = &schools[*school_idx];
+ school_init(school, name, skill);
+
+ return school;
+}
+
+static school_type *sorcery_school_new(s32b *school_idx, cptr name, s16b skill)
+{
+ school_type *school = school_new(school_idx, name, skill);
+ school->spell_power = TRUE;
+ school->sorcery = TRUE;
+ return school;
+}
+
+static school_type *god_school_new(s32b *school_idx, byte god)
+{
+ school_type *school = NULL;
+ deity_type *deity = NULL;
+
+ /* Get the god */
+ deity = god_at(god);
+ assert(deity != NULL);
+
+ /* Ignore gods which aren't enabled for this module. */
+ if (god_enabled(deity))
+ {
+ school = school_new(school_idx, deity->name, SKILL_PRAY);
+ school->spell_power = TRUE;
+ school->deity_idx = god;
+ school->deity = deity;
+ return school;
+ }
+ else
+ {
+ return NULL;
+ }
+}
+
+static void school_god(school_type *school, byte god, int mul, int div)
+{
+ assert(school->providers != nullptr);
+
+ deity_type *deity = god_at(god);
+ assert(deity != NULL);
+
+ /* Ignore gods which aren't enabled for this module. */
+ if (god_enabled(deity))
+ {
+ school->providers->v.push_back(school_provider_new(god, mul, div));
+ }
+}
+
+static int udun_bonus_levels()
+{
+ return (p_ptr->lev * 2) / 3;
+}
+
+static bool_ geomancy_depends_satisfied()
+{
+ object_type *o_ptr = NULL;
+
+ /* Require at least one point in each school */
+ if ((get_skill(SKILL_FIRE) <= 0) ||
+ (get_skill(SKILL_AIR) <= 0) ||
+ (get_skill(SKILL_EARTH) <= 0) ||
+ (get_skill(SKILL_WATER) <= 0))
+ {
+ return FALSE;
+ }
+
+ /* Require to wield a Mage Staff, as the spells requries the
+ * caster to stomp the floor with it. */
+ o_ptr = get_object(INVEN_WIELD);
+
+ return ((o_ptr != NULL) &&
+ (o_ptr->k_idx > 0) &&
+ (o_ptr->tval == TV_MSTAFF));
+}
+
+long get_provided_levels(school_type *school)
+{
+ for (auto school_provider: school->providers->v)
+ {
+ if (school_provider.deity_idx == p_ptr->pgod)
+ {
+ return (s_info[school_provider.skill_idx].value * school_provider.mul) / school_provider.div;
+ }
+ }
+
+ return 0;
+}
+
+struct get_level_school_callback_data {
+ bool_ allow_spell_power;
+ long bonus;
+ long lvl;
+ long num;
+};
+
+static bool get_level_school_callback(struct get_level_school_callback_data *data, int school_idx)
+{
+ school_type *school = school_at(school_idx);
+ long r = 0, s = 0, p = 0, ok = 0;
+
+ /* Does it require we worship a specific god? */
+ if ((school->deity_idx > 0) &&
+ (school->deity_idx != p_ptr->pgod))
+ {
+ return false;
+ }
+
+ /* Take the basic skill value */
+ r = s_info[school->skill].value;
+
+ /* Do we pass tests? */
+ if ((school->depends_satisfied != NULL) &&
+ (!school->depends_satisfied()))
+ {
+ return false;
+ }
+
+ /* Include effects of Sorcery (if applicable) */
+ if (school->sorcery)
+ {
+ s = s_info[SKILL_SORCERY].value;
+ }
+
+ /* Include effects of Spell Power? Every school must
+ * allow use of Spell Power for it to apply. */
+ if (!school->spell_power)
+ {
+ data->allow_spell_power = FALSE;
+ }
+
+ /* Calculate effects of provided levels */
+ p = get_provided_levels(school);
+
+ /* Find the highest of Skill, Sorcery and Provided levels. */
+ ok = r;
+ if (ok < s)
+ {
+ ok = s;
+ }
+ if (ok < p)
+ {
+ ok = p;
+ }
+
+ /* Do we need to add a special bonus? */
+ if (school->bonus_levels != NULL)
+ {
+ data->bonus += (school->bonus_levels() * (SKILL_STEP / 10));
+ }
+
+ /* All schools must be non-zero to be able to use it. */
+ if (ok <= 0)
+ {
+ return false;
+ }
+
+ /* Apply it */
+ data->lvl += ok;
+ data->num += 1;
+
+ /* Keep going */
+ return true;
+}
+
+void get_level_school(spell_type *spell, s32b max, s32b min, s32b *level, bool_ *na)
+{
+ assert(level != NULL);
+ assert(na != NULL);
+
+ /* Do we pass tests? */
+ if (!spell_type_dependencies_satisfied(spell))
+ {
+ *level = min;
+ *na = TRUE;
+ return;
+ }
+
+ /* Set up initial state */
+ get_level_school_callback_data data;
+ data.allow_spell_power = TRUE;
+ data.bonus = 0;
+ data.lvl = 0;
+ data.num = 0;
+
+ // Go through all the spell's schools and count up all the
+ // levels and make sure we can actually cast the spell.
+ for (auto school_idx : spell_type_get_schools(spell))
+ {
+ if (!get_level_school_callback(&data, school_idx))
+ {
+ *level = min;
+ *na = TRUE;
+ return;
+ }
+ }
+
+ /* Add the Spellpower skill as a bonus on top */
+ if (data.allow_spell_power)
+ {
+ data.bonus += (get_skill_scale(SKILL_SPELL, 20) * (SKILL_STEP / 10));
+ }
+
+ /* Add bonus from objects */
+ data.bonus += (p_ptr->to_s * (SKILL_STEP / 10));
+
+ /* We divide by 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
+ * point is 1000 internally. */
+ data.lvl = (data.lvl / data.num) / 10;
+ data.lvl = lua_get_level(spell, data.lvl, max, min, data.bonus);
+
+ /* Result */
+ *level = data.lvl;
+ *na = FALSE;
+}
+
+void schools_init()
+{
+ {
+ school_type *school = sorcery_school_new(&SCHOOL_MANA, "Mana", SKILL_MANA);
+ school_god(school, GOD_ERU, 1, 2);
+ school_god(school, GOD_VARDA, 1, 4);
+ }
+
+ {
+ school_type *school = sorcery_school_new(&SCHOOL_FIRE, "Fire", SKILL_FIRE);
+ school_god(school, GOD_AULE, 3, 5);
+ }
+
+ {
+ school_type *school = sorcery_school_new(&SCHOOL_AIR, "Air", SKILL_AIR);
+ school_god(school, GOD_MANWE, 2, 3);
+ }
+
+ {
+ school_type *school = sorcery_school_new(&SCHOOL_WATER, "Water", SKILL_WATER);
+ school_god(school, GOD_YAVANNA, 1, 2);
+ school_god(school, GOD_ULMO, 3, 5);
+ }
+
+ {
+ school_type *school = sorcery_school_new(&SCHOOL_EARTH, "Earth", SKILL_EARTH);
+ school_god(school, GOD_TULKAS, 4, 5);
+ school_god(school, GOD_YAVANNA, 1, 2);
+ }
+
+ {
+ school_type *school = sorcery_school_new(&SCHOOL_CONVEYANCE, "Conveyance", SKILL_CONVEYANCE);
+ school_god(school, GOD_MANWE, 1, 2);
+ }
+
+ {
+ school_type *school = school_new(&SCHOOL_GEOMANCY, "Geomancy", SKILL_GEOMANCY);
+ school->spell_power = TRUE;
+ school->depends_satisfied = geomancy_depends_satisfied;
+ }
+
+ {
+ school_type *school = sorcery_school_new(&SCHOOL_DIVINATION, "Divination", SKILL_DIVINATION);
+ school_god(school, GOD_ERU, 2, 3);
+ school_god(school, GOD_MANDOS, 1, 3);
+ }
+
+ {
+ school_type *school = sorcery_school_new(&SCHOOL_TEMPORAL, "Temporal", SKILL_TEMPORAL);
+ school_god(school, GOD_YAVANNA, 1, 6);
+ school_god(school, GOD_MANDOS, 1, 4);
+ }
+
+ {
+ school_type *school = sorcery_school_new(&SCHOOL_NATURE, "Nature", SKILL_NATURE);
+ school_god(school, GOD_YAVANNA, 1, 2);
+ school_god(school, GOD_ULMO, 1, 2);
+ }
+
+ {
+ school_type *school = sorcery_school_new(&SCHOOL_META, "Meta", SKILL_META);
+ school_god(school, GOD_MANWE, 1, 3);
+ school_god(school, GOD_VARDA, 1, 2);
+ }
+
+ {
+ school_type *school = sorcery_school_new(&SCHOOL_MIND, "Mind", SKILL_MIND);
+ school_god(school, GOD_ERU, 1, 3);
+ school_god(school, GOD_MELKOR, 1, 3);
+ }
+
+ {
+ school_type *school = school_new(&SCHOOL_UDUN, "Udun", SKILL_UDUN);
+ school->bonus_levels = udun_bonus_levels;
+ }
+
+ {
+ school_new(&SCHOOL_DEMON, "Demon", SKILL_DAEMON);
+ }
+
+ /* God-specific schools; all with a standard setup */
+ {
+ god_school_new(&SCHOOL_ERU, GOD_ERU);
+ god_school_new(&SCHOOL_MANWE, GOD_MANWE);
+ god_school_new(&SCHOOL_TULKAS, GOD_TULKAS);
+ god_school_new(&SCHOOL_MELKOR, GOD_MELKOR);
+ god_school_new(&SCHOOL_YAVANNA, GOD_YAVANNA);
+
+ god_school_new(&SCHOOL_AULE, GOD_AULE);
+ god_school_new(&SCHOOL_VARDA, GOD_VARDA);
+ god_school_new(&SCHOOL_ULMO, GOD_ULMO);
+ god_school_new(&SCHOOL_MANDOS, GOD_MANDOS);
+ }
+
+ /* Placeholder schools */
+ {
+ school_new(&SCHOOL_DEVICE, "Device", SKILL_DEVICE);
+ school_new(&SCHOOL_MUSIC, "Music", SKILL_MUSIC);
+ }
+
+}
+
+void mana_school_calc_mana(int *msp)
+{
+ if (get_skill(SKILL_MANA) >= 35)
+ {
+ *msp = *msp + (*msp * ((get_skill(SKILL_MANA) - 34)) / 100);
+ }
+}
diff --git a/src/spells6.hpp b/src/spells6.hpp
new file mode 100644
index 00000000..bbd32d9b
--- /dev/null
+++ b/src/spells6.hpp
@@ -0,0 +1,7 @@
+#pragma once
+
+#include "school_type_fwd.hpp"
+
+void schools_init();
+school_type *school_at(int index);
+void mana_school_calc_mana(int *msp);
diff --git a/src/squelch/CMakeLists.txt b/src/squelch/CMakeLists.txt
new file mode 100644
index 00000000..7b1495ba
--- /dev/null
+++ b/src/squelch/CMakeLists.txt
@@ -0,0 +1,9 @@
+ADD_LIBRARY(squelch
+ automatizer.cc
+ condition.cc
+ condition_metadata.cc
+ cursor.cc
+ object_status.cc
+ rule.cc
+ tree_printer.cc
+)
diff --git a/src/squelch/automatizer.cc b/src/squelch/automatizer.cc
new file mode 100644
index 00000000..c3c52b1b
--- /dev/null
+++ b/src/squelch/automatizer.cc
@@ -0,0 +1,278 @@
+#include "tome/squelch/automatizer_fwd.hpp"
+#include "tome/squelch/automatizer.hpp"
+
+#include "tome/squelch/rule.hpp"
+#include "tome/squelch/cursor.hpp"
+#include "tome/squelch/tree_printer.hpp"
+#include "util.hpp"
+#include "z-term.h"
+
+namespace squelch {
+
+/**
+ * Parse rules from JSON array
+ */
+static std::vector< std::shared_ptr < Rule > > parse_rules(json_t *rules_j)
+{
+ std::vector< std::shared_ptr < Rule > > rules;
+
+ if (!json_is_array(rules_j))
+ {
+ msg_format("Error 'rules' is not an array");
+ return rules;
+ }
+
+ for (size_t i = 0; i < json_array_size(rules_j); i++)
+ {
+ json_t *rule_j = json_array_get(rules_j, i);
+ auto rule = Rule::parse_rule(rule_j);
+ if (rule)
+ {
+ rules.push_back(rule);
+ }
+ }
+
+ return rules;
+}
+
+//----------------------------------------------------------
+// Automatizer
+//----------------------------------------------------------
+
+int Automatizer::append_rule(std::shared_ptr< Rule > rule)
+{
+ m_rules.push_back(rule);
+ return m_rules.size() - 1;
+}
+
+void Automatizer::swap_rules(int i, int j)
+{
+ swap(m_rules.at(i), m_rules.at(j));
+}
+
+bool Automatizer::apply_rules(object_type *o_ptr, int item_idx) const
+{
+ for (auto rule : m_rules)
+ {
+ if (rule->apply_rule(o_ptr, item_idx))
+ {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+std::shared_ptr<json_t> Automatizer::to_json() const
+{
+ auto rules_json = std::shared_ptr<json_t>(json_array(), &json_decref);
+
+ for (auto rule : m_rules)
+ {
+ json_array_append_new(rules_json.get(), rule->to_json());
+ }
+
+ return rules_json;
+}
+
+void Automatizer::load_json(json_t *json)
+{
+ // Go through all the found rules
+ auto rules = parse_rules(json);
+
+ // Load rule
+ for (auto rule : rules)
+ {
+ append_rule(rule);
+ }
+}
+
+int Automatizer::remove_current_selection()
+{
+ assert(!m_rules.empty());
+
+ // Previously selected rule
+ int prev_selected_rule = m_selected_rule;
+ int new_selected_rule;
+
+ // If the cursor is at the top level then we want to delete
+ // the rule itself
+ if (m_cursor->size() < 1)
+ {
+ // Remove rule
+ m_rules.erase(m_rules.begin() + m_selected_rule);
+ // Select previous
+ new_selected_rule = prev_selected_rule - 1;
+ }
+ else
+ {
+ // Delete the currently selected condition in rule.
+ m_rules.at(m_selected_rule)->delete_selected_condition(m_cursor.get());
+ // Keep selection
+ new_selected_rule = m_selected_rule;
+ }
+
+ // Do we need to adjust to select a different rule?
+ if ((prev_selected_rule != new_selected_rule) && (new_selected_rule >= 0))
+ {
+ select_rule(new_selected_rule);
+ }
+
+ // Return the selected rule.
+ return m_selected_rule;
+}
+
+void Automatizer::reset_view()
+{
+ // Clear cursor
+ m_cursor->clear();
+
+ // Empty rules?
+ if (m_rules.empty())
+ {
+ return;
+ }
+
+ // Reset scroll position
+ m_tree_printer->reset_scroll();
+
+ // Put the top-level condition into cursor
+ auto condition = m_rules.at(m_selected_rule)->get_condition();
+ if (condition)
+ {
+ m_cursor->push(condition.get());
+ }
+}
+
+void Automatizer::show_current() const
+{
+ if (m_rules.empty())
+ {
+ return;
+ }
+
+ m_tree_printer->reset();
+ m_rules.at(m_selected_rule)->write_tree(
+ m_tree_printer.get(),
+ m_cursor.get());
+}
+
+void Automatizer::scroll_up()
+{
+ m_tree_printer->scroll_up();
+}
+
+void Automatizer::scroll_down()
+{
+ m_tree_printer->scroll_down();
+}
+
+void Automatizer::scroll_left()
+{
+ m_tree_printer->scroll_left();
+}
+
+void Automatizer::scroll_right()
+{
+ m_tree_printer->scroll_right();
+}
+
+void Automatizer::move_up()
+{
+ m_cursor->move_up();
+}
+
+void Automatizer::move_down()
+{
+ m_cursor->move_down();
+}
+
+void Automatizer::move_left()
+{
+ m_cursor->move_left();
+}
+
+void Automatizer::move_right()
+{
+ m_cursor->move_right();
+}
+
+void Automatizer::add_new_condition(std::function<std::shared_ptr<Condition> ()> factory)
+{
+ m_rules.at(m_selected_rule)->add_new_condition(
+ m_cursor.get(),
+ factory);
+}
+
+void Automatizer::get_rule_names(std::vector<const char *> *names) const
+{
+ names->resize(m_rules.size());
+ for (size_t i = 0; i < m_rules.size(); i++)
+ {
+ (*names)[i] = m_rules.at(i)->get_name();
+ }
+}
+
+int Automatizer::rules_count() const
+{
+ return m_rules.size();
+}
+
+int Automatizer::rules_begin() const
+{
+ return m_begin;
+}
+
+void Automatizer::select_rule(int selected_rule)
+{
+ m_selected_rule = selected_rule;
+
+ int wid, hgt;
+ Term_get_size(&wid, &hgt);
+
+ // Adjust selection to conform to bounds.
+ {
+ int rules_size = m_rules.size(); // Convert to int to avoid warnings
+
+ if (m_selected_rule < 0)
+ {
+ m_selected_rule = rules_size - 1;
+ m_begin = m_selected_rule - hgt + 3;
+ if (m_begin < 0)
+ {
+ m_begin = 0;
+ }
+ }
+
+ if (m_selected_rule < m_begin)
+ {
+ m_begin = m_selected_rule;
+ }
+
+ if (m_selected_rule >= rules_size)
+ {
+ m_selected_rule = 0;
+ m_begin = 0;
+ }
+
+ if (m_selected_rule >= m_begin + hgt - 2)
+ {
+ m_begin++;
+ }
+ }
+
+ // Adjust tree printer and cursor.
+ reset_view();
+}
+
+int Automatizer::selected_rule() const
+{
+ return m_selected_rule;
+}
+
+std::shared_ptr<Rule> Automatizer::current_rule()
+{
+ return m_rules.at(m_selected_rule);
+}
+
+} // namespace
diff --git a/src/squelch/condition.cc b/src/squelch/condition.cc
new file mode 100644
index 00000000..c3b8c3f5
--- /dev/null
+++ b/src/squelch/condition.cc
@@ -0,0 +1,1078 @@
+#include "tome/squelch/condition_fwd.hpp"
+#include "tome/squelch/condition.hpp"
+
+#include <boost/algorithm/string/predicate.hpp>
+
+#include "tome/squelch/cursor.hpp"
+#include "tome/squelch/tree_printer.hpp"
+#include "../ability_type.hpp"
+#include "../object1.hpp"
+#include "../object2.hpp"
+#include "../object_kind.hpp"
+#include "../object_type.hpp"
+#include "../player_race.hpp"
+#include "../player_race_mod.hpp"
+#include "../player_spec.hpp"
+#include "../player_type.hpp"
+#include "../skills.hpp"
+#include "../skill_type.hpp"
+#include "../quark.hpp"
+#include "../util.hpp"
+#include "../variable.hpp"
+
+namespace squelch {
+
+EnumStringMap<match_type> &match_mapping()
+{
+ // TODO: This is quite ugly and leads to valgrind complaints
+ static auto m = new EnumStringMap<match_type> {
+ { match_type::AND, "and" },
+ { match_type::OR, "or" },
+ { match_type::NOT, "not" },
+ { match_type::NAME, "name" },
+ { match_type::CONTAIN, "contain" },
+ { match_type::INSCRIBED, "inscribed" },
+ { match_type::DISCOUNT, "discount" },
+ { match_type::SYMBOL, "symbol" },
+ { match_type::STATE, "state" },
+ { match_type::STATUS, "status" },
+ { match_type::TVAL, "tval" },
+ { match_type::SVAL, "sval" },
+ { match_type::RACE, "race" },
+ { match_type::SUBRACE, "subrace" },
+ { match_type::CLASS, "class" },
+ { match_type::LEVEL, "level" },
+ { match_type::SKILL, "skill" },
+ { match_type::ABILITY, "ability" },
+ { match_type::INVENTORY, "inventory" },
+ { match_type::EQUIPMENT, "equipment" } };
+ return *m;
+};
+
+EnumStringMap<identification_state> &identification_state_mapping()
+{
+ // TODO: This is quite ugly and leads to valgrind complaints
+ static auto m = new EnumStringMap<identification_state> {
+ { identification_state::IDENTIFIED, "identified" },
+ { identification_state::NOT_IDENTIFIED, "not identified" } };
+ return *m;
+}
+
+json_t *Condition::to_json() const
+{
+ json_t *j = json_object();
+ json_object_set_new(j, "type",
+ json_string(match_mapping().stringify(match)));
+ to_json(j);
+ return j;
+}
+
+void Condition::display(TreePrinter *tree_printer, Cursor *cursor) const
+{
+ assert(tree_printer);
+
+ // Use normal or "selected" colours?
+ uint8_t bcol = TERM_L_GREEN;
+ uint8_t ecol = TERM_GREEN;
+ if (cursor->is_selected(this))
+ {
+ bcol = TERM_VIOLET;
+ ecol = TERM_VIOLET;
+ }
+
+ // Indent a level and display tree.
+ tree_printer->indent();
+ write_tree(tree_printer, cursor, ecol, bcol);
+ tree_printer->dedent();
+}
+
+std::shared_ptr<Condition> Condition::parse_condition(json_t *condition_json)
+{
+ // Parsers for concrete types of conditions.
+ static std::map< match_type,
+ std::function< std::shared_ptr< Condition > ( json_t * ) > > parsers {
+ { match_type::AND, &AndCondition::from_json },
+ { match_type::OR, &OrCondition::from_json },
+ { match_type::NOT, &NotCondition::from_json },
+ { match_type::INVENTORY, &InventoryCondition::from_json },
+ { match_type::EQUIPMENT, &EquipmentCondition::from_json },
+ { match_type::NAME, &NameCondition::from_json },
+ { match_type::CONTAIN, &ContainCondition::from_json },
+ { match_type::SYMBOL, &SymbolCondition::from_json },
+ { match_type::INSCRIBED, &InscriptionCondition::from_json },
+ { match_type::DISCOUNT, &DiscountCondition::from_json },
+ { match_type::TVAL, &TvalCondition::from_json },
+ { match_type::SVAL, &SvalCondition::from_json },
+ { match_type::STATUS, &StatusCondition::from_json },
+ { match_type::STATE, &StateCondition::from_json },
+ { match_type::RACE, &RaceCondition::from_json },
+ { match_type::SUBRACE, &SubraceCondition::from_json },
+ { match_type::CLASS, &ClassCondition::from_json },
+ { match_type::LEVEL, &LevelCondition::from_json },
+ { match_type::SKILL, &SkillCondition::from_json },
+ { match_type::ABILITY, &AbilityCondition::from_json } };
+
+ if ((condition_json == nullptr) || json_is_null(condition_json))
+ {
+ return nullptr;
+ }
+
+ cptr type_s = nullptr;
+ if (json_unpack(condition_json,
+ "{s:s}",
+ "type", &type_s) < 0)
+ {
+ msg_print("Missing/invalid 'type' in condition");
+ return nullptr;
+ }
+
+ match_type match;
+ if (!match_mapping().parse(type_s, &match))
+ {
+ msg_format("Invalid 'type' in condition: %s", type_s);
+ return nullptr;
+ }
+
+ // Look up parser and... parse
+ auto parser_i = parsers.find(match);
+ if (parser_i != parsers.end())
+ {
+ return parser_i->second(condition_json);
+ }
+
+ assert(false && "Missing parser");
+ return nullptr;
+}
+
+json_t *Condition::optional_to_json(std::shared_ptr<Condition> condition)
+{
+ return condition
+ ? condition->to_json()
+ : json_null();
+}
+
+bool TvalCondition::is_match(object_type *o_ptr) const
+{
+ return (o_ptr->tval == m_tval);
+}
+
+std::shared_ptr<Condition> TvalCondition::from_json(json_t *j)
+{
+ int tval;
+
+ if (json_unpack(j, "{s:i}", "tval", &tval) < 0)
+ {
+ msg_print("Missing/invalid 'tval' property");
+ return nullptr;
+ }
+
+ return std::make_shared<TvalCondition>(tval);
+}
+
+void TvalCondition::to_json(json_t *j) const
+{
+ json_object_set_new(j, "tval", json_integer(m_tval));
+}
+
+void TvalCondition::write_tree(TreePrinter *p, Cursor *, uint8_t ecol, uint8_t bcol) const
+{
+ p->write(ecol, "Its ");
+ p->write(bcol, "tval");
+ p->write(ecol, " is ");
+ p->write(ecol, "\"");
+ p->write(TERM_WHITE, format("%d", (int) m_tval));
+ p->write(ecol, "\"");
+ p->write(TERM_WHITE, "\n");
+}
+
+bool NameCondition::is_match(object_type *o_ptr) const
+{
+ char buf1[128];
+ object_desc(buf1, o_ptr, -1, 0);
+
+ return boost::algorithm::iequals(m_name, buf1);
+}
+
+std::shared_ptr<Condition> NameCondition::from_json(json_t *j)
+{
+ cptr s = nullptr;
+ if (json_unpack(j, "{s:s}", "name", &s) < 0)
+ {
+ msg_print("Missing/invalid 'name' property");
+ return nullptr;
+ }
+ return std::make_shared<NameCondition>(s);
+}
+
+void NameCondition::write_tree(TreePrinter *p, Cursor *cursor, uint8_t ecol, uint8_t bcol) const
+{
+ p->write(ecol, "Its ");
+ p->write(bcol, "name");
+ p->write(ecol, " is \"");
+ p->write(TERM_WHITE, m_name.c_str());
+ p->write(ecol, "\"");
+ p->write(TERM_WHITE, "\n");
+}
+
+void NameCondition::to_json(json_t *j) const
+{
+ json_object_set_new(j, "name", json_string(m_name.c_str()));
+}
+
+bool ContainCondition::is_match(object_type *o_ptr) const
+{
+ char buf1[128];
+ object_desc(buf1, o_ptr, -1, 0);
+ return boost::algorithm::icontains(buf1, m_contain);
+}
+
+std::shared_ptr<Condition> ContainCondition::from_json(json_t *j)
+{
+ cptr s = nullptr;
+ if (json_unpack(j, "{s:s}", "contain", &s) < 0)
+ {
+ msg_print("Missing/invalid 'contain' property");
+ return nullptr;
+ }
+ return std::make_shared<ContainCondition>(s);
+}
+
+void ContainCondition::write_tree(TreePrinter *p, Cursor *, uint8_t ecol, uint8_t bcol) const
+{
+ p->write(ecol, "Its ");
+ p->write(bcol, "name");
+ p->write(ecol, " contains \"");
+ p->write(TERM_WHITE, m_contain.c_str());
+ p->write(ecol, "\"");
+ p->write(TERM_WHITE, "\n");
+}
+
+void ContainCondition::to_json(json_t *j) const
+{
+ json_object_set_new(j, "contain", json_string(m_contain.c_str()));
+}
+
+bool SvalCondition::is_match(object_type *o_ptr) const
+{
+ return (object_aware_p(o_ptr) &&
+ (o_ptr->sval >= m_min) &&
+ (o_ptr->sval <= m_max));
+}
+
+std::shared_ptr<Condition> SvalCondition::from_json(json_t *j)
+{
+ int min, max;
+
+ if (json_unpack(j, "{s:i,s:i}",
+ "min", &min,
+ "max", &max) < 0)
+ {
+ msg_print("Missing/invalid 'min'/'max' properties");
+ return nullptr;
+ }
+
+ return std::make_shared<SvalCondition>(min, max);
+}
+
+void SvalCondition::write_tree(TreePrinter *p, Cursor *, uint8_t ecol, uint8_t bcol) const
+{
+ p->write(ecol, "Its ");
+ p->write(bcol, "sval");
+ p->write(ecol, " is from ");
+ p->write(TERM_WHITE, format("%d", m_min));
+ p->write(ecol, " to ");
+ p->write(TERM_WHITE, format("%d", m_max));
+ p->write(TERM_WHITE, "\n");
+}
+
+void SvalCondition::to_json(json_t *j) const
+{
+ json_object_set_new(j, "min", json_integer(m_min));
+ json_object_set_new(j, "max", json_integer(m_max));
+}
+
+void GroupingCondition::add_child(ConditionFactory const &factory)
+{
+ auto c_ptr = factory();
+ if (c_ptr)
+ {
+ m_conditions.push_back(c_ptr);
+ }
+}
+
+void GroupingCondition::remove_child(Condition *condition)
+{
+ m_conditions.erase(
+ std::remove_if(
+ std::begin(m_conditions),
+ std::end(m_conditions),
+ [&] (std::shared_ptr<Condition> p) {
+ return p.get() == condition;
+ }),
+ std::end(m_conditions));
+}
+
+std::shared_ptr<Condition> GroupingCondition::first_child()
+{
+ if (!m_conditions.empty())
+ {
+ return m_conditions.front();
+ }
+ return nullptr;
+}
+
+std::shared_ptr<Condition> GroupingCondition::previous_child(Condition *current)
+{
+ std::shared_ptr<Condition> prev_condition;
+
+ for (auto condition_p : m_conditions)
+ {
+ if (condition_p.get() == current)
+ {
+ // Do we have a previous child?
+ if (prev_condition)
+ {
+ return prev_condition;
+ }
+ else
+ {
+ // No predecessor
+ return nullptr;
+ }
+ }
+ // Keep track of predecessor
+ prev_condition = condition_p;
+ }
+
+ return nullptr;
+}
+
+std::shared_ptr<Condition> GroupingCondition::next_child(Condition *current)
+{
+ for (auto it = m_conditions.begin();
+ it != m_conditions.end();
+ it++)
+ {
+ if (it->get() == current)
+ {
+ it++;
+ // Move to next child (if any)
+ if (it == m_conditions.end())
+ {
+ // No successor
+ return nullptr;
+ }
+
+ return *it;
+ }
+ }
+
+ return nullptr;
+}
+
+std::vector< std::shared_ptr<Condition> > GroupingCondition::parse_conditions(json_t *j)
+{
+ json_t *conditions_j = json_object_get(j, "conditions");
+
+ if ((conditions_j == nullptr) ||
+ (json_is_null(conditions_j)))
+ {
+ return std::vector< std::shared_ptr<Condition> >();
+ }
+ else if (!json_is_array(conditions_j))
+ {
+ msg_print("'conditions' property has invalid type");
+ return std::vector< std::shared_ptr<Condition> >();
+ }
+ else
+ {
+ std::vector< std::shared_ptr<Condition> > subconditions;
+ for (size_t i = 0; i < json_array_size(conditions_j); i++)
+ {
+ json_t *subcondition_j =
+ json_array_get(conditions_j, i);
+
+ std::shared_ptr<Condition> subcondition =
+ parse_condition(subcondition_j);
+
+ if (subcondition != nullptr)
+ {
+ subconditions.push_back(subcondition);
+ }
+ }
+ return subconditions;
+ }
+}
+
+void GroupingCondition::to_json(json_t *j) const
+{
+ json_t *ja = json_array();
+ for (auto condition_p : m_conditions)
+ {
+ json_array_append_new(ja, optional_to_json(condition_p));
+ }
+ json_object_set_new(j, "conditions", ja);
+}
+
+bool AndCondition::is_match(object_type *o_ptr) const
+{
+ for (auto condition_p : m_conditions)
+ {
+ if (!condition_p->is_match(o_ptr))
+ {
+ return false;
+ }
+ }
+ return true;
+}
+
+std::shared_ptr<Condition> AndCondition::from_json(json_t *j)
+{
+ auto condition = std::make_shared<AndCondition>();
+ for (auto subcondition : parse_conditions(j))
+ {
+ condition->add_condition(subcondition);
+ }
+ return condition;
+}
+
+void AndCondition::write_tree(TreePrinter *p, Cursor *c, uint8_t ecol, uint8_t bcol) const
+{
+ p->write(ecol, "All of the following are true:");
+ p->write(TERM_WHITE, "\n");
+
+ for (auto condition_p : m_conditions)
+ {
+ condition_p->display(p, c);
+ }
+}
+
+bool OrCondition::is_match(object_type *o_ptr) const
+{
+ for (auto condition_p : m_conditions)
+ {
+ if (condition_p->is_match(o_ptr))
+ {
+ return true;
+ }
+ }
+ return false;
+}
+
+std::shared_ptr<Condition> OrCondition::from_json(json_t *j)
+{
+ std::shared_ptr<OrCondition> condition =
+ std::make_shared<OrCondition>();
+
+ for (auto subcondition : parse_conditions(j))
+ {
+ condition->add_condition(subcondition);
+ }
+
+ return condition;
+}
+
+void OrCondition::write_tree(TreePrinter *p, Cursor *c, uint8_t ecol, uint8_t bcol) const
+{
+ p->write(ecol, "At least one of the following are true:");
+ p->write(TERM_WHITE, "\n");
+
+ for (auto condition_p : m_conditions)
+ {
+ condition_p->display(p, c);
+ }
+}
+
+bool StatusCondition::is_match(object_type *o_ptr) const
+{
+ return m_status == object_status(o_ptr);
+}
+
+std::shared_ptr<Condition> StatusCondition::from_json(json_t *j)
+{
+ cptr s;
+ if (json_unpack(j, "{s:s}", "status", &s) < 0)
+ {
+ msg_print("Missing/invalid 'status' property");
+ return nullptr;
+ }
+
+ status_type status;
+ if (!status_mapping().parse(s, &status))
+ {
+ msg_format("Invalid 'status' property: %s", s);
+ return nullptr;
+ }
+
+ return std::make_shared<StatusCondition>(status);
+}
+
+void StatusCondition::write_tree(TreePrinter *p, Cursor *, uint8_t ecol, uint8_t bcol) const
+{
+ p->write(ecol, "Its ");
+ p->write(bcol, "status");
+ p->write(ecol, " is ");
+ p->write(ecol, "\"");
+ p->write(TERM_WHITE, status_mapping().stringify(m_status));
+ p->write(ecol, "\"");
+ p->write(TERM_WHITE, "\n");
+}
+
+void StatusCondition::to_json(json_t *j) const
+{
+ json_object_set_new(j, "status", json_string(status_mapping().stringify(m_status)));
+}
+
+bool RaceCondition::is_match(object_type *o_ptr) const
+{
+ return boost::algorithm::iequals(m_race, rp_ptr->title);
+}
+
+std::shared_ptr<Condition> RaceCondition::from_json(json_t *j)
+{
+ cptr s;
+
+ if (json_unpack(j, "{s:s}", "race", &s) < 0)
+ {
+ msg_print("Missing/invalid 'race' property");
+ return nullptr;
+ }
+
+ return std::make_shared<RaceCondition>(s);
+}
+
+void RaceCondition::write_tree(TreePrinter *p, Cursor *, uint8_t ecol, uint8_t bcol) const
+{
+ p->write(ecol, "Player ");
+ p->write(bcol, "race");
+ p->write(ecol, " is ");
+ p->write(ecol, "\"");
+ p->write(TERM_WHITE, m_race.c_str());
+ p->write(ecol, "\"");
+ p->write(TERM_WHITE, "\n");
+}
+
+void RaceCondition::to_json(json_t *j) const
+{
+ json_object_set_new(j, "race", json_string(m_race.c_str()));
+}
+
+bool SubraceCondition::is_match(object_type *o_ptr) const
+{
+ return boost::algorithm::iequals(m_subrace, rmp_ptr->title);
+}
+
+std::shared_ptr<Condition> SubraceCondition::from_json(json_t *j)
+{
+ cptr s;
+
+ if (json_unpack(j, "{s:s}", "subrace", &s) < 0)
+ {
+ msg_print("Missing/invalid 'subrace' property");
+ return nullptr;
+ }
+
+ return std::make_shared<SubraceCondition>(s);
+}
+
+void SubraceCondition::write_tree(TreePrinter *p, Cursor *, uint8_t ecol, uint8_t bcol) const
+{
+ p->write(ecol, "Player ");
+ p->write(bcol, "subrace");
+ p->write(ecol, " is ");
+ p->write(ecol, "\"");
+ p->write(TERM_WHITE, m_subrace.c_str());
+ p->write(ecol, "\"");
+ p->write(TERM_WHITE, "\n");
+}
+
+void SubraceCondition::to_json(json_t *j) const
+{
+ json_object_set_new(j, "subrace", json_string(m_subrace.c_str()));
+}
+
+bool ClassCondition::is_match(object_type *o_ptr) const
+{
+ return boost::algorithm::iequals(m_class, spp_ptr->title);
+}
+
+std::shared_ptr<Condition> ClassCondition::from_json(json_t *j)
+{
+ cptr s;
+
+ if (json_unpack(j, "{s:s}", "class", &s) < 0)
+ {
+ msg_print("Missing/invalid 'class' property");
+ return nullptr;
+ }
+
+ return std::make_shared<ClassCondition>(s);
+}
+
+void ClassCondition::write_tree(TreePrinter *p, Cursor *, uint8_t ecol, uint8_t bcol) const
+{
+ p->write(ecol, "Player ");
+ p->write(bcol, "class");
+ p->write(ecol, " is ");
+ p->write(ecol, "\"");
+ p->write(TERM_WHITE, m_class.c_str());
+ p->write(ecol, "\"");
+ p->write(TERM_WHITE, "\n");
+}
+
+void ClassCondition::to_json(json_t *j) const
+{
+ json_object_set_new(j, "class", json_string(m_class.c_str()));
+}
+
+bool InscriptionCondition::is_match(object_type *o_ptr) const
+{
+ if (o_ptr->note == 0)
+ {
+ return false;
+ }
+ return boost::algorithm::icontains(
+ quark_str(o_ptr->note),
+ m_inscription);
+}
+
+std::shared_ptr<Condition> InscriptionCondition::from_json(json_t *j)
+{
+ cptr s = nullptr;
+ if (json_unpack(j, "{s:s}", "inscription", &s) < 0)
+ {
+ msg_print("Missing/invalid 'inscription' property");
+ return nullptr;
+ }
+ return std::make_shared<InscriptionCondition>(s);
+}
+
+void InscriptionCondition::write_tree(TreePrinter *p, Cursor *, uint8_t ecol, uint8_t bcol) const
+{
+ p->write(ecol, "It is ");
+ p->write(bcol, "inscribed");
+ p->write(ecol, " with ");
+ p->write(ecol, "\"");
+ p->write(TERM_WHITE, m_inscription.c_str());
+ p->write(ecol, "\"");
+ p->write(TERM_WHITE, "\n");
+}
+
+void InscriptionCondition::to_json(json_t *j) const
+{
+ json_object_set_new(j, "inscription", json_string(m_inscription.c_str()));
+}
+
+bool DiscountCondition::is_match(object_type *o_ptr) const
+{
+ return (object_aware_p(o_ptr) &&
+ (o_ptr->discount >= m_min) &&
+ (o_ptr->discount <= m_max));
+}
+
+std::shared_ptr<Condition> DiscountCondition::from_json(json_t *j)
+{
+ int min, max;
+
+ if (json_unpack(j, "{s:i,s:i}",
+ "min", &min,
+ "max", &max) < 0)
+ {
+ msg_print("Missing/invalid 'min'/'max' properties");
+ return nullptr;
+ }
+
+ return std::make_shared<DiscountCondition>(min, max);
+}
+
+void DiscountCondition::write_tree(TreePrinter *p, Cursor *, uint8_t ecol, uint8_t bcol) const
+{
+ p->write(ecol, "Its ");
+ p->write(bcol, "discount");
+ p->write(ecol, " is from ");
+ p->write(TERM_WHITE, format("%d", m_min));
+ p->write(ecol, " to ");
+ p->write(TERM_WHITE, format("%d", m_max));
+ p->write(TERM_WHITE, "\n");
+}
+
+void DiscountCondition::to_json(json_t *j) const
+{
+ json_object_set_new(j, "min", json_integer(m_min));
+ json_object_set_new(j, "max", json_integer(m_max));
+}
+
+bool LevelCondition::is_match(object_type *) const
+{
+ return ((p_ptr->lev >= m_min) &&
+ (p_ptr->lev <= m_max));
+}
+
+std::shared_ptr<Condition> LevelCondition::from_json(json_t *j)
+{
+ int min, max;
+ if (json_unpack(j, "{s:i,s:i}",
+ "min", &min,
+ "max", &max) < 0)
+ {
+ msg_print("Missing/invalid 'min'/'max' properties");
+ return nullptr;
+ }
+
+ return std::make_shared<LevelCondition>(min, max);
+}
+
+void LevelCondition::write_tree(TreePrinter *p, Cursor *, uint8_t ecol, uint8_t bcol) const
+{
+ p->write(ecol, "Your ");
+ p->write(bcol, "level");
+ p->write(ecol, " is from ");
+
+ p->write(TERM_WHITE, format("%d", m_min));
+ p->write(ecol, " to ");
+ p->write(TERM_WHITE, format("%d", m_max));
+ p->write(TERM_WHITE, "\n");
+}
+
+void LevelCondition::to_json(json_t *j) const
+{
+ json_object_set_new(j, "min", json_integer(m_min));
+ json_object_set_new(j, "max", json_integer(m_max));
+}
+
+bool SkillCondition::is_match(object_type *) const
+{
+ uint16_t sk = get_skill(m_skill_idx);
+ return ((sk >= m_min) &&
+ (sk <= m_max));
+}
+
+std::shared_ptr<Condition> SkillCondition::from_json(json_t *j)
+{
+ cptr s;
+ int min, max;
+ if (json_unpack(j, "{s:i,s:i,s:s}",
+ "min", &min,
+ "max", &max,
+ "name", &s) < 0)
+ {
+ msg_print("Missing/invalid 'min'/'max'/'name' properties");
+ return nullptr;
+ }
+
+ auto si = find_skill_i(s);
+ if (si < 0)
+ {
+ msg_print("Invalid 'name' property");
+ return nullptr;
+ }
+
+ return std::make_shared<SkillCondition>(si, min, max);
+}
+
+void SkillCondition::write_tree(TreePrinter *p, Cursor *, uint8_t ecol, uint8_t bcol) const
+{
+ p->write(ecol, "Your skill in ");
+ p->write(bcol, s_info[m_skill_idx].name);
+ p->write(ecol, " is from ");
+ p->write(TERM_WHITE, format("%d", (int) m_min));
+ p->write(ecol, " to ");
+ p->write(TERM_WHITE, format("%d", (int) m_max));
+ p->write(TERM_WHITE, "\n");
+}
+
+void SkillCondition::to_json(json_t *j) const
+{
+ json_object_set_new(j, "name",
+ json_string(s_info[m_skill_idx].name));
+ json_object_set_new(j, "min",
+ json_integer(m_min));
+ json_object_set_new(j, "max",
+ json_integer(m_max));
+}
+
+bool StateCondition::is_match(object_type *o_ptr) const
+{
+ switch (m_state)
+ {
+ case identification_state::IDENTIFIED:
+ return object_known_p(o_ptr);
+ case identification_state::NOT_IDENTIFIED:
+ return !object_known_p(o_ptr);
+ }
+
+ assert(false);
+ return false;
+}
+
+std::shared_ptr<Condition> StateCondition::from_json(json_t *j)
+{
+ cptr s;
+ if (json_unpack(j, "{s:s}", "state", &s) < 0)
+ {
+ msg_print("Missing/invalid 'state' property");
+ return nullptr;
+ }
+
+ identification_state state;
+ if (!identification_state_mapping().parse(s, &state))
+ {
+ msg_format("Invalid 'state' property: %s", s);
+ return nullptr;
+ }
+
+ return std::make_shared<StateCondition>(state);
+}
+
+void StateCondition::write_tree(TreePrinter *p, Cursor *, uint8_t ecol, uint8_t bcol) const
+{
+ p->write(ecol, "Its ");
+ p->write(bcol, "state");
+ p->write(ecol, " is ");
+ p->write(ecol, "\"");
+ p->write(TERM_WHITE, identification_state_mapping().stringify(m_state));
+ p->write(ecol, "\"");
+ p->write(TERM_WHITE, "\n");
+}
+
+void StateCondition::to_json(json_t *j) const
+{
+ json_object_set_new(j, "state",
+ json_string(identification_state_mapping().
+ stringify(m_state)));
+}
+
+bool SymbolCondition::is_match(object_type *o_ptr) const
+{
+ object_kind *k_ptr = &k_info[o_ptr->k_idx];
+ return k_ptr->d_char == m_symbol;
+}
+
+std::shared_ptr<Condition> SymbolCondition::from_json(json_t *j)
+{
+ cptr s_ = nullptr;
+ if (json_unpack(j, "{s:s}", "symbol", &s_) < 0)
+ {
+ msg_print("Missing/invalid 'symbol' property");
+ return nullptr;
+ }
+
+ std::string s(s_);
+ if (s.empty())
+ {
+ msg_print("Invalid 'symbol' property: Too short");
+ return nullptr;
+ }
+ if (s.size() > 1)
+ {
+ msg_print("Invalid 'symbol' property: Too long");
+ return nullptr;
+ }
+
+ return std::make_shared<SymbolCondition>(s[0]);
+}
+
+void SymbolCondition::write_tree(TreePrinter *p, Cursor *, uint8_t ecol, uint8_t bcol) const
+{
+ p->write(ecol, "Its ");
+ p->write(bcol, "symbol");
+ p->write(ecol, " is ");
+ p->write(ecol, "\"");
+ p->write(TERM_WHITE, format("%c", m_symbol));
+ p->write(ecol, "\"");
+ p->write(TERM_WHITE, "\n");
+}
+
+void SymbolCondition::to_json(json_t *j) const
+{
+ json_object_set_new(j, "symbol",
+ json_string(format("%c", m_symbol)));
+}
+
+bool AbilityCondition::is_match(object_type *) const
+{
+ return has_ability(m_ability_idx);
+}
+
+std::shared_ptr<Condition> AbilityCondition::from_json(json_t *j)
+{
+ cptr a;
+ if (json_unpack(j, "{s:s}", "ability", &a) < 0)
+ {
+ msg_print("Missing/invalid 'ability' property");
+ return nullptr;
+ }
+
+ auto ai = find_ability(a);
+ if (ai < 0)
+ {
+ msg_print("Invalid 'ability' property");
+ return nullptr;
+ }
+
+ return std::make_shared<AbilityCondition>(ai);
+}
+
+void AbilityCondition::write_tree(TreePrinter *p, Cursor *, uint8_t ecol, uint8_t bcol) const
+{
+ cptr ability_s = ab_info[m_ability_idx].name;
+
+ p->write(ecol, "You have the ");
+ p->write(bcol, ability_s);
+ p->write(ecol, " ability");
+ p->write(TERM_WHITE, "\n");
+}
+
+void AbilityCondition::to_json(json_t *j) const
+{
+ cptr ability_s = ab_info[m_ability_idx].name;
+ json_object_set_new(j, "ability", json_string(ability_s));
+}
+
+void SingleSubconditionCondition::add_child(std::function< std::shared_ptr<Condition> () > const &factory)
+{
+ // If we already have a subcondition then we cannot
+ // add one.
+ if (!m_subcondition)
+ {
+ m_subcondition = factory();
+ }
+}
+
+void SingleSubconditionCondition::remove_child(Condition *c)
+{
+ if (m_subcondition.get() == c) {
+ m_subcondition.reset();
+ }
+}
+
+std::shared_ptr<Condition> SingleSubconditionCondition::first_child()
+{
+ return m_subcondition;
+}
+
+void SingleSubconditionCondition::to_json(json_t *j) const
+{
+ json_object_set_new(j, "condition",
+ optional_to_json(m_subcondition));
+}
+
+std::shared_ptr<Condition> SingleSubconditionCondition::parse_single_subcondition(json_t *in_json)
+{
+ json_t *condition_j =
+ json_object_get(in_json, "condition");
+
+ if ((condition_j == nullptr) ||
+ (json_is_null(condition_j)))
+ {
+ return nullptr;
+ }
+ else if (!json_is_object(condition_j))
+ {
+ msg_format("Invalid 'condition' property");
+ return nullptr;
+ }
+ else
+ {
+ return parse_condition(condition_j);
+ }
+}
+
+bool NotCondition::is_match(object_type *o_ptr) const
+{
+ if (!m_subcondition)
+ {
+ return true;
+ }
+
+ return !m_subcondition->is_match(o_ptr);
+}
+
+std::shared_ptr<Condition> NotCondition::from_json(json_t *j)
+{
+ return std::make_shared<NotCondition>(parse_single_subcondition(j));
+}
+
+void NotCondition::write_tree(TreePrinter *p, Cursor *c, byte ecol, byte bcol) const
+{
+ p->write(ecol, "Negate the following:");
+ p->write(TERM_WHITE, "\n");
+ if (m_subcondition)
+ {
+ m_subcondition->display(p, c);
+ }
+}
+
+bool InventoryCondition::is_match(object_type *) const
+{
+ if (!m_subcondition)
+ {
+ return false;
+ }
+
+ for (int i = 0; i < INVEN_WIELD; i++)
+ {
+ if (m_subcondition->is_match(&p_ptr->inventory[i]))
+ {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+std::shared_ptr<Condition> InventoryCondition::from_json(json_t *j)
+{
+ return std::make_shared<InventoryCondition>(
+ parse_single_subcondition(j));
+}
+
+void InventoryCondition::write_tree(TreePrinter *p, Cursor *c, byte ecol, byte bcol) const
+{
+ p->write(ecol, "Something in your ");
+ p->write(bcol, "inventory");
+ p->write(ecol, " matches the following:");
+ p->write(TERM_WHITE, "\n");
+ if (m_subcondition)
+ {
+ m_subcondition->display(p, c);
+ }
+}
+
+bool EquipmentCondition::is_match(object_type *) const
+{
+ if (!m_subcondition)
+ {
+ return false;
+ }
+
+ for (int i = INVEN_WIELD; i < INVEN_TOTAL; i++)
+ {
+ if (m_subcondition->is_match(&p_ptr->inventory[i]))
+ {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+std::shared_ptr<Condition> EquipmentCondition::from_json(json_t *j)
+{
+ return std::make_shared<EquipmentCondition>(
+ parse_single_subcondition(j));
+}
+
+void EquipmentCondition::write_tree(TreePrinter *p, Cursor *c, byte ecol, byte bcol) const
+{
+ p->write(ecol, "Something in your ");
+ p->write(bcol, "equipment");
+ p->write(ecol, " matches the following:");
+ p->write(TERM_WHITE, "\n");
+ if (m_subcondition)
+ {
+ m_subcondition->display(p, c);
+ }
+}
+
+} // namespace
diff --git a/src/squelch/condition_metadata.cc b/src/squelch/condition_metadata.cc
new file mode 100644
index 00000000..62a90e58
--- /dev/null
+++ b/src/squelch/condition_metadata.cc
@@ -0,0 +1,496 @@
+#include "tome/squelch/condition_metadata.hpp"
+#include "tome/squelch/condition.hpp"
+
+#include <vector>
+
+#include "tome/squelch/object_status.hpp"
+#include "lua_bind.hpp"
+#include "skills.hpp"
+#include "util.hpp"
+#include "util.h"
+#include "z-term.h"
+
+namespace squelch {
+
+static std::shared_ptr<Condition> create_condition_name()
+{
+ cptr s = lua_input_box("Object name to match?", 79);
+ if (strlen(s) == 0)
+ {
+ return nullptr;
+ }
+
+ return std::make_shared<NameCondition>(s);
+}
+
+static std::shared_ptr<Condition> create_condition_contain()
+{
+ cptr s = lua_input_box("Word to find in object name?", 79);
+ if (strlen(s) == 0)
+ {
+ return nullptr;
+ }
+
+ return std::make_shared<ContainCondition>(s);
+}
+
+static std::shared_ptr<Condition> create_condition_inscribed()
+{
+ cptr s = lua_input_box("Word to find in object inscription?", 79);
+ if (strlen(s) == 0)
+ {
+ return nullptr;
+ }
+
+ return std::make_shared<InscriptionCondition>(s);
+}
+
+static std::shared_ptr<Condition> create_condition_discount()
+{
+ int min, max;
+
+ {
+ cptr s = lua_input_box("Min discount?", 79);
+ if (sscanf(s, "%d", &min) < 1)
+ {
+ return nullptr;
+ }
+ }
+
+ {
+ cptr s = lua_input_box("Max discount?", 79);
+ if (sscanf(s, "%d", &max) < 1)
+ {
+ return nullptr;
+ }
+ }
+
+ return std::make_shared<DiscountCondition>(min, max);
+}
+
+static std::shared_ptr<Condition> create_condition_symbol()
+{
+ char c;
+ cptr s = lua_input_box("Symbol to match?", 1);
+ if (sscanf(s, "%c", &c) < 1)
+ {
+ return nullptr;
+ }
+
+ return std::make_shared<SymbolCondition>(c);
+}
+
+static std::shared_ptr<Condition> create_condition_status()
+{
+ status_type status;
+ char c;
+
+ c = lua_msg_box("[t]errible, [v]ery bad, [b]ad, "
+ "[a]verage, [G]ood, [V]ery good, [S]pecial?");
+
+ switch (c)
+ {
+ case 't': status = status_type::TERRIBLE; break;
+ case 'v': status = status_type::VERY_BAD; break;
+ case 'b': status = status_type::BAD; break;
+ case 'a': status = status_type::AVERAGE; break;
+ case 'G': status = status_type::GOOD; break;
+ case 'V': status = status_type::VERY_GOOD; break;
+ case 'S': status = status_type::SPECIAL; break;
+ default: return nullptr;
+ }
+
+ return std::make_shared<StatusCondition>(status);
+}
+
+static std::shared_ptr<Condition> create_condition_state()
+{
+ char c = lua_msg_box("[i]dentified, [n]on identified?");
+
+ identification_state s;
+ switch (c)
+ {
+ case 'i': s = identification_state::IDENTIFIED; break;
+ case 'n': s = identification_state::NOT_IDENTIFIED; break;
+ default: return nullptr;
+ }
+
+ return std::make_shared<StateCondition>(s);
+}
+
+static bool in_byte_range(int x)
+{
+ return (x >= 0) && (x < 256);
+}
+
+static std::shared_ptr<Condition> create_condition_tval()
+{
+ cptr s = lua_input_box("Tval to match?", 79);
+ int tval;
+ if (sscanf(s, "%d", &tval) < 1)
+ {
+ return nullptr;
+ }
+
+ if (!in_byte_range(tval))
+ {
+ return nullptr;
+ }
+
+ return std::make_shared<TvalCondition>(tval);
+}
+
+static std::shared_ptr<Condition> create_condition_sval()
+{
+ int sval_min, sval_max;
+
+ {
+ cptr s = lua_input_box("Min sval?", 79);
+ if ((sscanf(s, "%d", &sval_min) < 1) ||
+ (!in_byte_range(sval_min)))
+ {
+ return nullptr;
+ }
+ }
+
+ {
+ cptr s = lua_input_box("Max sval?", 79);
+ if ((sscanf(s, "%d", &sval_max) < 1) ||
+ (!in_byte_range(sval_max)))
+ {
+ return nullptr;
+ }
+ }
+
+ return std::make_shared<SvalCondition>(sval_min, sval_max);
+}
+
+static std::shared_ptr<Condition> create_condition_race()
+{
+ cptr s = lua_input_box("Player race to match?", 79);
+ if (strlen(s) == 0)
+ {
+ return nullptr;
+ }
+
+ return std::make_shared<RaceCondition>(s);
+}
+
+static std::shared_ptr<Condition> create_condition_subrace()
+{
+ cptr s = lua_input_box("Player subrace to match?", 79);
+ if (strlen(s) == 0)
+ {
+ return nullptr;
+ }
+
+ return std::make_shared<SubraceCondition>(s);
+}
+
+static std::shared_ptr<Condition> create_condition_class()
+{
+ cptr s = lua_input_box("Player class to match?", 79);
+ if (strlen(s) == 0)
+ {
+ return nullptr;
+ }
+
+ return std::make_shared<ClassCondition>(s);
+}
+
+static std::shared_ptr<Condition> create_condition_level()
+{
+ int min, max;
+
+ {
+ cptr s = lua_input_box("Min player level?", 79);
+ if (sscanf(s, "%d", &min) < 1)
+ {
+ return nullptr;
+ }
+ }
+
+ {
+ cptr s = lua_input_box("Max player level?", 79);
+ if (sscanf(s, "%d", &max) < 1)
+ {
+ return nullptr;
+ }
+ }
+
+ return std::make_shared<LevelCondition>(min, max);
+}
+
+static std::shared_ptr<Condition> create_condition_skill()
+{
+ int min, max;
+
+ {
+ cptr s = lua_input_box("Min skill level?", 79);
+ if (sscanf(s, "%d", &min) < 1)
+ {
+ return nullptr;
+ }
+ }
+
+ {
+ cptr s = lua_input_box("Max skill level?", 79);
+ if (sscanf(s, "%d", &max) < 1)
+ {
+ return nullptr;
+ }
+ }
+
+ s16b skill_idx;
+ {
+ cptr s = lua_input_box("Skill name?", 79);
+ if (strlen(s) == 0)
+ {
+ return nullptr;
+ }
+
+ skill_idx = find_skill_i(s);
+ if (skill_idx < 0)
+ {
+ return nullptr;
+ }
+ }
+
+ return std::make_shared<SkillCondition>(skill_idx, min, max);
+}
+
+static std::shared_ptr<Condition> create_condition_ability()
+{
+ cptr s = lua_input_box("Ability name?", 79);
+ if (strlen(s) == 0)
+ {
+ return nullptr;
+ }
+
+ s16b ai = find_ability(s);
+ if (ai < 0)
+ {
+ return nullptr;
+ }
+
+ return std::make_shared<AbilityCondition>(ai);
+}
+
+static void display_desc(match_type match_type_)
+{
+ int i = 0;
+ auto line = [&i] (const char *s) {
+ c_prt(TERM_WHITE, s, i + 1, 17);
+ i++;
+ };
+
+ switch (match_type_)
+ {
+ case match_type::AND:
+ line("Check is true if all rules within it are true");
+ break;
+
+ case match_type::OR:
+ line("Check is true if at least one rule within it is true");
+ break;
+
+ case match_type::NOT:
+ line("Invert the result of its child rule");
+ break;
+
+ case match_type::NAME:
+ line("Check is true if object name matches name");
+ break;
+
+ case match_type::CONTAIN:
+ line("Check is true if object name contains word");
+ break;
+
+ case match_type::INSCRIBED:
+ line("Check is true if object inscription contains word");
+ break;
+
+ case match_type::DISCOUNT:
+ line("Check is true if object discount is between two values");
+ break;
+
+ case match_type::SYMBOL:
+ line("Check is true if object symbol is ok");
+ break;
+
+ case match_type::STATE:
+ line("Check is true if object is identified/unidentified");
+ break;
+
+ case match_type::STATUS:
+ line("Check is true if object status is ok");
+ break;
+
+ case match_type::TVAL:
+ line("Check is true if object tval(from k_info.txt) is ok");
+
+ case match_type::SVAL:
+ line("Check is true if object sval(from k_info.txt) is between");
+ line("two values");
+ break;
+
+ case match_type::RACE:
+ line("Check is true if player race is ok");
+ break;
+
+ case match_type::SUBRACE:
+ line("Check is true if player subrace is ok");
+ break;
+
+ case match_type::CLASS:
+ line("Check is true if player class is ok");
+ break;
+
+ case match_type::LEVEL:
+ line("Check is true if player level is between 2 values");
+ break;
+
+ case match_type::SKILL:
+ line("Check is true if player skill level is between 2 values");
+ break;
+
+ case match_type::ABILITY:
+ line("Check is true if player has the ability");
+ break;
+
+ case match_type::INVENTORY:
+ line("Check is true if something in player's inventory matches");
+ line("the contained rule");
+ break;
+
+ case match_type::EQUIPMENT:
+ line("Check is true if something in player's equipment matches");
+ line("the contained rule");
+ break;
+ }
+}
+
+std::shared_ptr<Condition> new_condition_interactive()
+{
+ static std::vector<match_type> condition_types = {
+ match_type::AND,
+ match_type::OR,
+ match_type::NOT,
+ match_type::NAME,
+ match_type::CONTAIN,
+ match_type::INSCRIBED,
+ match_type::DISCOUNT,
+ match_type::SYMBOL,
+ match_type::STATE,
+ match_type::STATUS,
+ match_type::TVAL,
+ match_type::SVAL,
+ match_type::RACE,
+ match_type::SUBRACE,
+ match_type::CLASS,
+ match_type::LEVEL,
+ match_type::SKILL,
+ match_type::ABILITY,
+ match_type::INVENTORY,
+ match_type::EQUIPMENT
+ };
+ static std::vector<const char *> condition_type_names;
+
+ // Fill in types names?
+ if (condition_type_names.empty())
+ {
+ for (auto condition_type : condition_types)
+ {
+ condition_type_names.push_back(
+ match_mapping().stringify(condition_type));
+ }
+ }
+
+ // Choose
+ int begin = 0, sel = 0;
+ while (1)
+ {
+ int wid, hgt;
+ Term_clear();
+ Term_get_size(&wid, &hgt);
+
+ display_list(0, 0, hgt - 1, 15, "Rule types", condition_type_names.data(), condition_types.size(), begin, sel, TERM_L_GREEN);
+
+ display_desc(condition_types[sel]);
+
+ char c = inkey();
+
+ if (c == ESCAPE) break;
+ else if (c == '8')
+ {
+ sel--;
+ if (sel < 0)
+ {
+ sel = condition_types.size() - 1;
+ begin = condition_types.size() - hgt;
+ if (begin < 0) begin = 0;
+ }
+ if (sel < begin) begin = sel;
+ }
+ else if (c == '2')
+ {
+ sel++;
+ if (sel >= static_cast<int>(condition_types.size()))
+ {
+ sel = 0;
+ begin = 0;
+ }
+ if (sel >= begin + hgt - 1) begin++;
+ }
+ else if (c == '\r')
+ {
+ switch (condition_types[sel])
+ {
+ case match_type::AND:
+ return std::make_shared<AndCondition>();
+ case match_type::OR:
+ return std::make_shared<OrCondition>();
+ case match_type::NOT:
+ return std::make_shared<NotCondition>();
+ case match_type::NAME:
+ return create_condition_name();
+ case match_type::CONTAIN:
+ return create_condition_contain();
+ case match_type::INSCRIBED:
+ return create_condition_inscribed();
+ case match_type::DISCOUNT:
+ return create_condition_discount();
+ case match_type::SYMBOL:
+ return create_condition_symbol();
+ case match_type::STATE:
+ return create_condition_state();
+ case match_type::STATUS:
+ return create_condition_status();
+ case match_type::TVAL:
+ return create_condition_tval();
+ case match_type::SVAL:
+ return create_condition_sval();
+ case match_type::RACE:
+ return create_condition_race();
+ case match_type::SUBRACE:
+ return create_condition_subrace();
+ case match_type::CLASS:
+ return create_condition_class();
+ case match_type::LEVEL:
+ return create_condition_level();
+ case match_type::SKILL:
+ return create_condition_skill();
+ case match_type::ABILITY:
+ return create_condition_ability();
+ case match_type::INVENTORY:
+ return std::make_shared<InventoryCondition>();
+ case match_type::EQUIPMENT:
+ return std::make_shared<EquipmentCondition>();
+
+ }
+ }
+ }
+ return nullptr;
+}
+
+} // namespace
diff --git a/src/squelch/cursor.cc b/src/squelch/cursor.cc
new file mode 100644
index 00000000..3a3bec46
--- /dev/null
+++ b/src/squelch/cursor.cc
@@ -0,0 +1,96 @@
+#include "tome/squelch/cursor_fwd.hpp"
+#include "tome/squelch/cursor.hpp"
+
+#include <algorithm>
+#include <cassert>
+
+#include "tome/squelch/condition.hpp"
+
+namespace squelch {
+
+bool Cursor::is_selected(Condition const *condition) const
+{
+ return std::end(m_conditions) !=
+ std::find(std::begin(m_conditions),
+ std::end(m_conditions),
+ condition);
+}
+
+Condition *Cursor::pop()
+{
+ assert(!m_conditions.empty());
+ Condition *c = m_conditions.back();
+ m_conditions.pop_back();
+ return c;
+}
+
+Condition *Cursor::current()
+{
+ assert(!m_conditions.empty());
+ return m_conditions.back();
+}
+
+void Cursor::move_right()
+{
+ if (m_conditions.empty()) {
+ return;
+ }
+ // Go right if the currently selected condition has children.
+ std::shared_ptr<Condition> c = current()->first_child();
+ if (c)
+ {
+ push(c.get());
+ }
+}
+
+void Cursor::move_left()
+{
+ if (size() > 1)
+ {
+ pop();
+ }
+}
+
+void Cursor::move_up()
+{
+ if (size() > 1)
+ {
+ Condition *prev_top = pop();
+
+ // Find previous child
+ std::shared_ptr<Condition> prev_condition =
+ current()->previous_child(prev_top);
+
+ // Do we have a previous child?
+ if (prev_condition)
+ {
+ push(prev_condition.get());
+ }
+ else
+ {
+ push(prev_top);
+ }
+ }
+}
+
+void Cursor::move_down()
+{
+ if (size() > 1)
+ {
+ Condition *prev_top = pop();
+
+ std::shared_ptr<Condition> next_condition =
+ current()->next_child(prev_top);
+
+ if (next_condition)
+ {
+ push(next_condition.get());
+ }
+ else
+ {
+ push(prev_top);
+ }
+ }
+}
+
+} // namespace
diff --git a/src/squelch/object_status.cc b/src/squelch/object_status.cc
new file mode 100644
index 00000000..075c0529
--- /dev/null
+++ b/src/squelch/object_status.cc
@@ -0,0 +1,153 @@
+#include "tome/squelch/object_status_fwd.hpp"
+#include "tome/squelch/object_status.hpp"
+
+#include "../inventory.hpp"
+#include "../object1.hpp"
+#include "../object2.hpp"
+#include "../object_type.hpp"
+#include "../variable.hpp"
+
+namespace squelch {
+
+EnumStringMap<status_type> &status_mapping()
+{
+ // TODO: This is quite ugly and leads to valgrind complaints
+ static auto m = new EnumStringMap<status_type> {
+ { status_type::BAD, "bad" },
+ { status_type::VERY_BAD, "very bad" },
+ { status_type::AVERAGE, "average" },
+ { status_type::GOOD, "good" },
+ { status_type::VERY_GOOD, "very good" },
+ { status_type::SPECIAL, "special" },
+ { status_type::TERRIBLE, "terrible" },
+ { status_type::NONE, "none" },
+ { status_type::CHEST_EMPTY, "(empty chest)" },
+ { status_type::CHEST_DISARMED, "(disarmed chest)" } };
+ return *m;
+}
+
+status_type object_status(object_type *o_ptr)
+{
+ if (!object_known_p(o_ptr))
+ {
+ switch (o_ptr->sense)
+ {
+ case SENSE_CURSED: return status_type::BAD;
+ case SENSE_WORTHLESS: return status_type::VERY_BAD;
+ case SENSE_AVERAGE: return status_type::AVERAGE;
+ case SENSE_GOOD_LIGHT: return status_type::GOOD;
+ case SENSE_GOOD_HEAVY: return status_type::GOOD;
+ case SENSE_EXCELLENT: return status_type::VERY_GOOD;
+ case SENSE_SPECIAL: return status_type::SPECIAL;
+ case SENSE_TERRIBLE: return status_type::TERRIBLE;
+ default: return status_type::NONE;
+ }
+ }
+ else
+ {
+ s16b slot = wield_slot_ideal(o_ptr, TRUE);
+
+ if (artifact_p(o_ptr))
+ {
+ if (!(o_ptr->ident & IDENT_CURSED))
+ {
+ return status_type::SPECIAL;
+ }
+ else
+ {
+ return status_type::TERRIBLE;
+ }
+ }
+ else if ((o_ptr->name2 > 0) ||
+ (o_ptr->name2b > 0))
+ {
+ if (!(o_ptr->ident & IDENT_CURSED))
+ {
+ return status_type::VERY_GOOD;
+ }
+ else
+ {
+ return status_type::VERY_BAD;
+ }
+ }
+ else if ((slot == INVEN_WIELD) ||
+ (slot == INVEN_BOW) ||
+ (slot == INVEN_AMMO) ||
+ (slot == INVEN_TOOL))
+ {
+ if (o_ptr->to_h + o_ptr->to_d < 0)
+ {
+ return status_type::BAD;
+ }
+ else if (o_ptr->to_h + o_ptr->to_d > 0)
+ {
+ return status_type::GOOD;
+ }
+ else
+ {
+ return status_type::AVERAGE;
+ }
+ }
+ else if ((slot >= INVEN_BODY) &&
+ (slot <= INVEN_FEET))
+ {
+ if (o_ptr->to_a < 0)
+ {
+ return status_type::BAD;
+ }
+ else if (o_ptr->to_a > 0)
+ {
+ return status_type::GOOD;
+ }
+ else
+ {
+ return status_type::AVERAGE;
+ }
+ }
+ else if (slot == INVEN_RING)
+ {
+ if ((o_ptr->to_d + o_ptr->to_h < 0) ||
+ (o_ptr->to_a < 0) ||
+ (o_ptr->pval < 0))
+ {
+ return status_type::BAD;
+ }
+ else
+ {
+ return status_type::AVERAGE;
+ }
+ }
+ else if (slot == INVEN_NECK)
+ {
+ if (o_ptr->pval < 0)
+ {
+ return status_type::BAD;
+ }
+ else
+ {
+ return status_type::AVERAGE;
+ }
+ }
+ else if (o_ptr->tval == TV_CHEST)
+ {
+ if (o_ptr->pval == 0)
+ {
+ return status_type::CHEST_EMPTY;
+ }
+ else if (o_ptr->pval < 0)
+ {
+ return status_type::CHEST_DISARMED;
+ }
+ else
+ {
+ return status_type::AVERAGE;
+ }
+ }
+ else
+ {
+ return status_type::AVERAGE;
+ }
+ }
+}
+
+} // namespace
diff --git a/src/squelch/rule.cc b/src/squelch/rule.cc
new file mode 100644
index 00000000..1c17d2fd
--- /dev/null
+++ b/src/squelch/rule.cc
@@ -0,0 +1,332 @@
+#include "tome/squelch/rule_fwd.hpp"
+#include "tome/squelch/rule.hpp"
+
+#include "tome/squelch/cursor.hpp"
+#include "tome/squelch/condition.hpp"
+#include "tome/squelch/tree_printer.hpp"
+#include "../angband.h"
+#include "../modules.hpp"
+#include "../object1.hpp"
+#include "../object2.hpp"
+#include "../object_type.hpp"
+#include "../quark.hpp"
+#include "../tables.hpp"
+#include "../util.hpp"
+#include "../variable.hpp"
+
+namespace squelch {
+
+EnumStringMap<action_type> &action_mapping()
+{
+ static auto m = new EnumStringMap<action_type> {
+ { action_type::AUTO_DESTROY, "destroy" },
+ { action_type::AUTO_PICKUP, "pickup" },
+ { action_type::AUTO_INSCRIBE, "inscribe" } };
+ return *m;
+}
+
+void Rule::set_name(const char *new_name)
+{
+ assert(new_name != nullptr);
+ m_name = new_name;
+}
+
+const char *Rule::get_name() const
+{
+ return m_name.c_str();
+}
+
+std::shared_ptr<Condition> Rule::get_condition() const
+{
+ return m_condition;
+}
+
+json_t *Rule::to_json() const
+{
+ json_t *rule_json = json_object();
+ json_object_set_new(rule_json,
+ "name",
+ json_string(m_name.c_str()));
+ json_object_set_new(rule_json,
+ "action",
+ json_string(action_mapping().stringify(m_action)));
+ json_object_set_new(rule_json,
+ "module",
+ json_string(modules[m_module_idx].meta.name));
+ json_object_set_new(rule_json,
+ "condition",
+ Condition::optional_to_json(m_condition));
+ return rule_json;
+}
+
+void Rule::add_new_condition(Cursor *cursor,
+ ConditionFactory const &factory)
+{
+ // Top-level condition?
+ if (!m_condition)
+ {
+ // Sanity check for navigation stack
+ assert(cursor->empty());
+
+ // Create new top-level condition
+ m_condition = factory();
+
+ // Select the condition
+ if (m_condition)
+ {
+ cursor->push(m_condition.get());
+ }
+ }
+ else
+ {
+ cursor->current()->add_child(factory);
+ }
+}
+
+void Rule::delete_selected_condition(Cursor *cursor)
+{
+ assert(cursor->size() >= 1);
+
+ if (cursor->size() == 1)
+ {
+ cursor->pop();
+ m_condition.reset();
+ }
+ else
+ {
+ Condition *prev_top = cursor->pop();
+ Condition *top = cursor->current();
+
+ // Jump up a level; this is a simple way to ensure a
+ // valid cursor. We could be a little cleverer here by
+ // trying to move inside the current level, but it
+ // gets a little complicated.
+ cursor->move_left();
+
+ // Now we can remove the condition from its parent
+ top->remove_child(prev_top);
+ }
+}
+
+void Rule::write_tree(TreePrinter *tree_printer, Cursor *cursor) const
+{
+ // Write out the main rule
+ do_write_tree(tree_printer);
+
+ // Write out the condition
+ if (m_condition)
+ {
+ m_condition->display(tree_printer, cursor);
+ }
+}
+
+bool Rule::apply_rule(object_type *o_ptr, int item_idx) const
+{
+ // Check module
+ if (m_module_idx != game_module_idx)
+ {
+ return false;
+ }
+
+ // Check condition
+ if (m_condition && m_condition->is_match(o_ptr))
+ {
+ return do_apply_rule(o_ptr, item_idx);
+ }
+
+ // Doesn't apply
+ return false;
+}
+
+std::shared_ptr<Rule> Rule::parse_rule(json_t *rule_json)
+{
+ if (!json_is_object(rule_json))
+ {
+ msg_print("Rule is not an object");
+ return nullptr;
+ }
+
+ // Retrieve the attributes
+ char *rule_name_s = nullptr;
+ char *rule_action_s = nullptr;
+ char *rule_module_s = nullptr;
+ if (json_unpack(rule_json,
+ "{s:s,s:s,s:s}",
+ "name", &rule_name_s,
+ "action", &rule_action_s,
+ "module", &rule_module_s) < 0)
+ {
+ msg_print("Rule missing required field(s)");
+ return nullptr;
+ }
+
+ // Convert attributes
+ action_type action;
+ if (!action_mapping().parse((cptr) rule_action_s, &action))
+ {
+ msg_format("Invalid rule action '%s'", rule_action_s);
+ return nullptr;
+ }
+
+ int module_idx = find_module((cptr) rule_module_s);
+ if (module_idx < 0)
+ {
+ msg_format("Skipping rule for unrecognized module '%s'",
+ (cptr) rule_module_s);
+ return nullptr;
+ }
+
+ // Parse condition
+ std::shared_ptr<Condition> condition =
+ Condition::parse_condition(json_object_get(rule_json, "condition"));
+
+ // Parse rule
+ switch (action)
+ {
+ case action_type::AUTO_INSCRIBE:
+ {
+ json_t *rule_inscription_j = json_object_get(rule_json, "inscription");
+
+ if (rule_inscription_j == nullptr)
+ {
+ msg_print("Inscription rule missing 'inscription' attribute");
+ return nullptr;
+ }
+ if (!json_is_string(rule_inscription_j))
+ {
+ msg_print("Inscription rule 'inscription' attribute wrong type");
+ return nullptr;
+ }
+
+ std::string inscription =
+ json_string_value(rule_inscription_j);
+ return std::make_shared<InscribeRule>(
+ rule_name_s, module_idx, condition, inscription);
+ }
+
+ case action_type::AUTO_PICKUP:
+ return std::make_shared<PickUpRule>(
+ rule_name_s, module_idx, condition);
+
+ case action_type::AUTO_DESTROY:
+ return std::make_shared<DestroyRule>(
+ rule_name_s, module_idx, condition);
+ }
+
+ assert(false);
+ return nullptr;
+}
+
+
+void DestroyRule::do_write_tree(TreePrinter *p) const
+{
+ p->write(TERM_GREEN, "A rule named \"");
+ p->write(TERM_WHITE, m_name.c_str());
+ p->write(TERM_GREEN, "\" to ");
+ p->write(TERM_L_GREEN, "destroy");
+ p->write(TERM_GREEN, " when");
+ p->write(TERM_WHITE, "\n");
+}
+
+bool DestroyRule::do_apply_rule(object_type *o_ptr, int item_idx) const
+{
+ // Must be identified
+ if (object_aware_p(o_ptr) == FALSE)
+ {
+ return false;
+ }
+
+ // Never destroy inscribed items
+ if (o_ptr->note)
+ {
+ return false;
+ }
+
+ // Ignore artifacts; cannot be destroyed anyway
+ if (artifact_p(o_ptr))
+ {
+ return false;
+ }
+
+ // Cannot destroy CURSE_NO_DROP objects.
+ {
+ u32b f1, f2, f3, f4, f5, esp;
+ object_flags(o_ptr, &f1, &f2, &f3, &f4, &f5, &esp);
+
+ if ((f4 & TR4_CURSE_NO_DROP) != 0)
+ {
+ return false;
+ }
+ }
+
+ // Destroy
+ msg_print("<Auto-destroy>");
+ inc_stack_size(item_idx, -o_ptr->number);
+ return true;
+}
+
+void PickUpRule::do_write_tree(TreePrinter *p) const
+{
+ p->write(TERM_GREEN, "A rule named \"");
+ p->write(TERM_WHITE, m_name.c_str());
+ p->write(TERM_GREEN, "\" to ");
+ p->write(TERM_L_GREEN, "pick up");
+ p->write(TERM_GREEN, " when");
+ p->write(TERM_WHITE, "\n");
+}
+
+bool PickUpRule::do_apply_rule(object_type *o_ptr, int item_idx) const
+{
+ if (item_idx >= 0)
+ {
+ return false;
+ }
+
+ if (!inven_carry_okay(o_ptr))
+ {
+ return false;
+ }
+
+ msg_print("<Auto-pickup>");
+ object_pickup(-item_idx);
+ return true;
+}
+
+json_t *InscribeRule::to_json() const
+{
+ json_t *j = Rule::to_json();
+
+ json_object_set_new(j,
+ "inscription",
+ json_string(m_inscription.c_str()));
+
+ return j;
+}
+
+void InscribeRule::do_write_tree(TreePrinter *p) const
+{
+ p->write(TERM_GREEN, "A rule named \"");
+ p->write(TERM_WHITE, m_name.c_str());
+ p->write(TERM_GREEN, "\" to ");
+ p->write(TERM_L_GREEN, "inscribe");
+ p->write(TERM_GREEN, " an item with \"");
+ p->write(TERM_WHITE, m_inscription.c_str());
+ p->write(TERM_GREEN, "\" when");
+ p->write(TERM_WHITE, "\n");
+}
+
+bool InscribeRule::do_apply_rule(object_type *o_ptr, int) const
+{
+ // Already inscribed?
+ if (o_ptr->note != 0)
+ {
+ return false;
+ }
+
+ // Inscribe
+ msg_format("<Auto-Inscribe {%s}>", m_inscription.c_str());
+ o_ptr->note = quark_add(m_inscription.c_str());
+ return true;
+}
+
+} // namespace
diff --git a/src/squelch/tree_printer.cc b/src/squelch/tree_printer.cc
new file mode 100644
index 00000000..2be098dc
--- /dev/null
+++ b/src/squelch/tree_printer.cc
@@ -0,0 +1,89 @@
+#include "tome/squelch/tree_printer_fwd.hpp"
+#include "tome/squelch/tree_printer.hpp"
+
+#include "../z-term.h"
+
+namespace squelch {
+
+TreePrinter::TreePrinter() : m_indent(0)
+{
+ int wid, hgt;
+ // Output window
+ Term_get_size(&wid, &hgt);
+ m_write_out_y = 1;
+ m_write_out_x = 16;
+ m_write_out_h = hgt - 4 - 1;
+ m_write_out_w = wid - 1 - 15 - 1;
+ // Set position
+ reset();
+ reset_scroll();
+}
+
+void TreePrinter::indent() {
+ m_indent++;
+}
+
+void TreePrinter::dedent() {
+ m_indent--;
+}
+
+void TreePrinter::reset() {
+ m_write_x = 0;
+ m_write_y = 0;
+}
+
+void TreePrinter::reset_scroll() {
+ m_write_off_y = 0;
+ m_write_off_x = 0;
+}
+
+void TreePrinter::scroll_up() {
+ m_write_off_y--;
+}
+
+void TreePrinter::scroll_down() {
+ m_write_off_y++;
+}
+
+void TreePrinter::scroll_left() {
+ m_write_off_x++;
+}
+
+void TreePrinter::scroll_right() {
+ m_write_off_x--;
+}
+
+void TreePrinter::write(uint8_t color, cptr line)
+{
+ cptr p = line;
+
+ for (p = line; *p != '\0'; p++)
+ {
+ char c = *p;
+ int x = m_write_x - m_write_off_x + 3*m_indent;
+ int y = m_write_y - m_write_off_y;
+
+ if (c != '\n')
+ {
+ if ((y >= 0) &&
+ (y < m_write_out_h) &&
+ (x >= 0) &&
+ (x < m_write_out_w))
+ {
+ Term_putch(x + m_write_out_x,
+ y + m_write_out_y,
+ color,
+ c);
+ }
+
+ m_write_x += 1;
+ }
+ else
+ {
+ m_write_x = 0;
+ m_write_y += 1;
+ }
+ }
+}
+
+} // namespace
diff --git a/src/squeltch.c b/src/squeltch.c
deleted file mode 100644
index 603eaa0e..00000000
--- a/src/squeltch.c
+++ /dev/null
@@ -1,553 +0,0 @@
-/* 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/squeltch.cc b/src/squeltch.cc
new file mode 100644
index 00000000..bab1e5c0
--- /dev/null
+++ b/src/squeltch.cc
@@ -0,0 +1,593 @@
+/*
+ * Copyright (c) 2002 DarkGod
+ * Copyright (c) 2012 Bardur Arantsson
+ *
+ * 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 "squeltch.hpp"
+
+#include "cave_type.hpp"
+#include "files.hpp"
+#include "loadsave.hpp"
+#include "lua_bind.hpp"
+#include "object1.hpp"
+#include "object2.hpp"
+#include "object_kind.hpp"
+#include "object_type.hpp"
+#include "player_type.hpp"
+#include "tome/squelch/tree_printer.hpp"
+#include "tome/squelch/condition.hpp"
+#include "tome/squelch/condition_metadata.hpp"
+#include "tome/squelch/rule.hpp"
+#include "tome/squelch/cursor.hpp"
+#include "tome/squelch/object_status.hpp"
+#include "tome/squelch/automatizer.hpp"
+#include "util.hpp"
+#include "util.h"
+#include "variable.h"
+#include "variable.hpp"
+
+#include <jansson.h>
+#include <algorithm>
+#include <memory>
+#include <deque>
+#include <list>
+#include <string>
+#include <vector>
+
+using squelch::action_type;
+using squelch::action_mapping;
+
+using squelch::status_type;
+
+using squelch::Rule;
+using squelch::DestroyRule;
+using squelch::PickUpRule;
+using squelch::InscribeRule;
+
+using squelch::Condition;
+using squelch::AndCondition;
+using squelch::TvalCondition;
+using squelch::SvalCondition;
+using squelch::NameCondition;
+using squelch::StatusCondition;
+
+static squelch::Automatizer *automatizer = nullptr;
+
+void squeltch_grid(void)
+{
+ if (!automatizer_enabled)
+ {
+ return;
+ }
+
+ // Copy list of objects since we may modify it
+ auto const object_idxs(cave[p_ptr->py][p_ptr->px].o_idxs);
+
+ // Scan the pile of objects
+ for (auto const this_o_idx: object_idxs)
+ {
+ // 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);
+ }
+
+ // Apply rules
+ automatizer->apply_rules(o_ptr, -this_o_idx);
+ }
+}
+
+void squeltch_inventory(void)
+{
+ if (!automatizer_enabled)
+ {
+ return;
+ }
+
+ bool changed = true;
+ for (int num_iter = 0; changed && (num_iter < 100); num_iter++)
+ {
+ // No changes on this iteration.
+ changed = false;
+ // Traverse inventory
+ for (int i = 0; i < INVEN_PACK; i++)
+ {
+ object_type *o_ptr = &p_ptr->inventory[i];
+ if ((o_ptr->k_idx > 0) && automatizer->apply_rules(o_ptr, i))
+ {
+ // We have changes
+ changed = true;
+ // Re-traverse inventory
+ break;
+ }
+ }
+ }
+ // If we reached the iteration limit, "changed" will be true
+ if (changed)
+ {
+ cmsg_format(TERM_VIOLET, "'apply_rules' ran too often.");
+ }
+}
+
+static int create_new_rule()
+{
+ char name[20] = { '\0' };
+ int wid = 0, hgt = 0;
+
+ Term_get_size(&wid, &hgt);
+
+ sprintf(name, "%s", "No name");
+ if (!input_box("Name?", hgt / 2, wid / 2, name, sizeof(name)))
+ {
+ return -1;
+ }
+
+ char typ = lua_msg_box("[D]estroy, [P]ickup, [I]nscribe?");
+
+ std::shared_ptr<Rule> rule;
+ switch (typ)
+ {
+ case 'd':
+ case 'D':
+ rule = std::make_shared<DestroyRule>(name, game_module_idx, nullptr);
+ break;
+
+ case 'p':
+ case 'P':
+ rule = std::make_shared<PickUpRule>(name, game_module_idx, nullptr);
+ break;
+
+ case 'i':
+ case 'I':
+ {
+ cptr i = lua_input_box("Inscription?", 79);
+ if ((i == nullptr) || (strlen(i) == 0))
+ {
+ return -1;
+ }
+
+ rule = std::make_shared<InscribeRule>(
+ name, game_module_idx, nullptr, std::string(i));
+
+ break;
+ }
+
+ default:
+ return -1;
+ }
+
+ return automatizer->append_rule(rule);
+}
+
+static void automatizer_save_rules()
+{
+ char name[30] = { '\0' };
+ char buf[1025];
+ char ch;
+ int hgt, wid;
+
+ Term_get_size(&wid, &hgt);
+
+ sprintf(name, "%s.atm", player_name);
+
+ if (!input_box("Save name?", hgt / 2, wid / 2, name, sizeof(name)))
+ {
+ return;
+ }
+
+ // Build the filename
+ path_build(buf, 1024, ANGBAND_DIR_USER, name);
+
+ 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'))
+ {
+ return;
+ }
+ }
+
+ // Write to file
+ {
+ auto rules_json = automatizer->to_json();
+
+ int status = json_dump_file(rules_json.get(), buf,
+ JSON_INDENT(2) |
+ JSON_SORT_KEYS);
+ if (status == 0)
+ {
+ c_put_str(TERM_WHITE, "Saved rules in file ",
+ hgt / 2,
+ wid / 2 - 14);
+ }
+ else
+ {
+ c_put_str(TERM_WHITE, "Saving rules failed! ",
+ hgt / 2,
+ wid / 2 - 14);
+ }
+
+ // Wait for keypress
+ inkey();
+ }
+}
+
+static void rename_rule(Rule *rule)
+{
+ char name[16];
+ int wid, hgt;
+
+ assert(rule != nullptr);
+
+ Term_get_size(&wid, &hgt);
+
+ sprintf(name, "%s", rule->get_name());
+ if (input_box("New name?", hgt / 2, wid / 2, name, sizeof(name)))
+ {
+ rule->set_name(name);
+ }
+}
+
+#define ACTIVE_LIST 0
+#define ACTIVE_RULE 1
+void do_cmd_automatizer()
+{
+ int wid = 0, hgt = 0;
+ int active = ACTIVE_LIST;
+ cptr keys;
+ cptr keys2;
+ cptr keys3;
+ std::vector<cptr> rule_names;
+
+ 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();
+
+ automatizer->reset_view();
+
+ while (1)
+ {
+ Term_clear();
+ Term_get_size(&wid, &hgt);
+
+ automatizer->get_rule_names(&rule_names);
+
+ display_list(0, 0, hgt - 1, 15, "Rules", rule_names.data(), automatizer->rules_count(), automatizer->rules_begin(), automatizer->selected_rule(), (active == ACTIVE_LIST) ? TERM_L_GREEN : TERM_GREEN);
+
+ 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 = "#G?#W for Automatizer help";
+ }
+ 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";
+ }
+ 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);
+
+ automatizer->show_current();
+
+ char 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 (!automatizer->rules_count()) continue;
+
+ automatizer->select_rule(
+ automatizer->selected_rule() - 1);
+ }
+ else if (c == '2')
+ {
+ if (!automatizer->rules_count()) continue;
+
+ automatizer->select_rule(
+ automatizer->selected_rule() + 1);
+ }
+ else if (c == 'u')
+ {
+ int sel = automatizer->selected_rule();
+ if (sel > 0)
+ {
+ automatizer->swap_rules(sel-1, sel);
+ automatizer->select_rule(sel-1);
+ }
+ }
+ else if (c == 'd')
+ {
+ if (!automatizer->rules_count()) continue;
+
+ int sel = automatizer->selected_rule();
+ if (sel < automatizer->rules_count() - 1)
+ {
+ automatizer->swap_rules(sel, sel+1);
+ automatizer->select_rule(sel+1);
+ }
+ }
+ else if (c == 'n')
+ {
+ int i = create_new_rule();
+ if (i >= 0)
+ {
+ automatizer->select_rule(i);
+ active = ACTIVE_RULE;
+ }
+ }
+ else if (c == 's')
+ {
+ automatizer_save_rules();
+ }
+ else if (c == 'r')
+ {
+ if (!automatizer->rules_count()) continue;
+
+ rename_rule(automatizer->current_rule().get());
+ continue;
+ }
+ else if (c == 'k')
+ {
+ automatizer_enabled = FALSE;
+ break;
+ }
+ else if (c == '\t')
+ {
+ if (!automatizer->rules_count()) continue;
+
+ active = ACTIVE_RULE;
+ }
+ }
+ else if (active == ACTIVE_RULE)
+ {
+ if (c == '?')
+ {
+ screen_save();
+ show_file("automat.txt", "Automatizer help", 0, 0);
+ screen_load();
+ }
+ else if (c == '8')
+ {
+ automatizer->move_up();
+ }
+ else if (c == '2')
+ {
+ automatizer->move_down();
+ }
+ else if (c == '6')
+ {
+ automatizer->move_right();
+ }
+ else if (c == '4')
+ {
+ automatizer->move_left();
+ }
+ else if (c == '9')
+ {
+ automatizer->scroll_up();
+ }
+ else if (c == '3')
+ {
+ automatizer->scroll_down();
+ }
+ else if (c == '7')
+ {
+ automatizer->scroll_left();
+ }
+ else if (c == '1')
+ {
+ automatizer->scroll_right();
+ }
+ else if (c == 'a')
+ {
+ automatizer->add_new_condition(
+ squelch::new_condition_interactive);
+ }
+ else if (c == 'd')
+ {
+ if (!automatizer->rules_count())
+ {
+ continue;
+ }
+
+ int new_sel =
+ automatizer->remove_current_selection();
+
+ if (new_sel == -1)
+ {
+ active = ACTIVE_LIST;
+ }
+ }
+ else if (c == '\t')
+ {
+ active = ACTIVE_LIST;
+ }
+ }
+ }
+
+ screen_load();
+}
+
+enum class add_rule_mode { TVAL, TSVAL, NAME };
+
+static void easy_add_rule(add_rule_mode mode, bool do_status, object_type *o_ptr)
+{
+ std::shared_ptr<Condition> condition;
+
+ switch (mode)
+ {
+
+ case add_rule_mode::TVAL:
+ condition = std::make_shared<TvalCondition>(o_ptr->tval);
+ break;
+
+ case add_rule_mode::TSVAL:
+ {
+ auto andCondition = std::make_shared<AndCondition>();
+
+ andCondition->add_condition(
+ std::make_shared<TvalCondition>(o_ptr->tval));
+ andCondition->add_condition(
+ std::make_shared<SvalCondition>(o_ptr->sval, o_ptr->sval));
+
+ condition = andCondition;
+ break;
+ }
+
+ case add_rule_mode::NAME:
+ {
+ char buf[128];
+ object_desc(buf, o_ptr, -1, 0);
+
+ condition = std::make_shared<NameCondition>(buf);
+ break;
+ }
+
+ }
+
+ // Use object status?
+ if (do_status)
+ {
+ status_type status = squelch::object_status(o_ptr);
+
+ auto andCondition = std::make_shared<AndCondition>();
+
+ andCondition->add_condition(
+ std::shared_ptr<Condition>(condition)); // cycle
+ andCondition->add_condition(
+ std::make_shared<StatusCondition>(status));
+
+ // Replace condition; breaks cycle
+ condition = andCondition;
+ }
+
+ // Rule name
+ auto rule_name = action_mapping().stringify(action_type::AUTO_DESTROY);
+
+ // Append to list of rules
+ automatizer->append_rule(
+ std::make_shared<DestroyRule>(
+ rule_name, game_module_idx, condition));
+
+ msg_print("Rule added. Please go to the Automatizer screen (press = then T)");
+ msg_print("to save the modified ruleset.");
+}
+
+void automatizer_add_rule(object_type *o_ptr)
+{
+ bool do_status = false;
+
+ while (true)
+ {
+ char ch;
+
+ if (!get_com(format("Destroy all of the same [T]ype, [F]amily or [N]ame, also use [S]tatus (%s)? ", (do_status) ? "Yes" : "No"), &ch))
+ {
+ break;
+ }
+
+ if (ch == 'S' || ch == 's')
+ {
+ do_status = !do_status;
+ continue;
+ }
+
+ if (ch == 'T' || ch == 't')
+ {
+ easy_add_rule(add_rule_mode::TSVAL, do_status, o_ptr);
+ break;
+ }
+
+ if (ch == 'F' || ch == 'f')
+ {
+ easy_add_rule(add_rule_mode::TVAL, do_status, o_ptr);
+ break;
+ }
+
+ if (ch == 'N' || ch == 'n')
+ {
+ easy_add_rule(add_rule_mode::NAME, do_status, o_ptr);
+ break;
+ }
+ }
+}
+
+/**
+ * Initialize the automatizer.
+ */
+void automatizer_init()
+{
+ // Only permit single initialization.
+ assert(automatizer == nullptr);
+
+ // Set up dependencies
+ auto tree_printer(std::make_shared<squelch::TreePrinter>());
+ auto cursor(std::make_shared<squelch::Cursor>());
+
+ // Initialize
+ automatizer = new squelch::Automatizer(tree_printer, cursor);
+}
+
+/**
+ * Load automatizer file. Returns true iff automatizer
+ * rules were loaded successfully.
+ */
+bool automatizer_load(boost::filesystem::path const &path)
+{
+ assert(automatizer != NULL);
+
+ // Does the path exist?
+ if (!boost::filesystem::exists(path))
+ {
+ return false; // Not fatal; just skip
+ }
+
+ // Parse file
+ json_error_t error;
+ std::shared_ptr<json_t> rules_json(
+ json_load_file(path.c_str(), 0, &error),
+ &json_decref);
+ if (rules_json == nullptr)
+ {
+ msg_format("Error parsing automatizer rules from '%s'.", path.c_str());
+ msg_format("Line %d, Column %d", error.line, error.column);
+ msg_print(nullptr);
+ return false;
+ }
+
+ // Load rules
+ automatizer->load_json(rules_json.get());
+ return true;
+}
diff --git a/src/squeltch.hpp b/src/squeltch.hpp
new file mode 100644
index 00000000..65ddfb51
--- /dev/null
+++ b/src/squeltch.hpp
@@ -0,0 +1,13 @@
+#pragma once
+
+#include "h-basic.h"
+#include "object_type_fwd.hpp"
+#include <boost/filesystem.hpp>
+
+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);
+extern bool_ automatizer_create;
+extern void automatizer_init();
+extern bool automatizer_load(boost::filesystem::path const &path);
diff --git a/src/stairs_direction.hpp b/src/stairs_direction.hpp
new file mode 100644
index 00000000..b0b5f25d
--- /dev/null
+++ b/src/stairs_direction.hpp
@@ -0,0 +1,3 @@
+#pragma once
+
+typedef enum { STAIRS_UP, STAIRS_DOWN } stairs_direction;
diff --git a/src/stats.hpp b/src/stats.hpp
new file mode 100644
index 00000000..e682446c
--- /dev/null
+++ b/src/stats.hpp
@@ -0,0 +1,11 @@
+#pragma once
+
+/*
+ * 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
diff --git a/src/status.c b/src/status.c
deleted file mode 100644
index 967a8323..00000000
--- a/src/status.c
+++ /dev/null
@@ -1,773 +0,0 @@
-/* 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/status.cc b/src/status.cc
new file mode 100644
index 00000000..0a3977c7
--- /dev/null
+++ b/src/status.cc
@@ -0,0 +1,783 @@
+/* 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 "files.hpp"
+#include "monster2.hpp"
+#include "monster_type.hpp"
+#include "object1.hpp"
+#include "player_type.hpp"
+#include "stats.hpp"
+#include "util.hpp"
+#include "util.h"
+#include "variable.h"
+#include "variable.hpp"
+#include "xtra1.hpp"
+
+static void row_trival(const char*, s16b, u32b, s16b, u32b, int, u32b[INVEN_TOTAL - INVEN_WIELD + 2][7]);
+static void row_bival(const char*, s16b, u32b, int, u32b[INVEN_TOTAL - INVEN_WIELD + 2][7]);
+static void row_npval(const char*, s16b, u32b, int, u32b[INVEN_TOTAL - INVEN_WIELD + 2][7]);
+static void statline(const 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(const 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);
+static void status_sight(void);
+static void status_attr(void);
+static void status_combat(void);
+static void status_move(void);
+static void status_item(void);
+static 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)
+
+static 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;
+ }
+ }
+}
+
+static 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;
+ }
+ }
+}
+
+static 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;
+ }
+ }
+}
+
+static 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;
+ }
+ }
+}
+
+static 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_bival("Antimagic", 4, TR4_ANTIMAGIC_50, 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;
+ }
+ }
+}
+
+static 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()
+{
+ 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_FRAME | PR_MAP);
+ handle_stuff();
+}
+
+static 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(const 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(const 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(const 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(const 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(const 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(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/status.hpp b/src/status.hpp
new file mode 100644
index 00000000..74624446
--- /dev/null
+++ b/src/status.hpp
@@ -0,0 +1,3 @@
+#pragma once
+
+void status_main();
diff --git a/src/store.c b/src/store.c
deleted file mode 100644
index 78120846..00000000
--- a/src/store.c
+++ /dev/null
@@ -1,4458 +0,0 @@
-/* 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/store.cc b/src/store.cc
new file mode 100644
index 00000000..0fbe2e9b
--- /dev/null
+++ b/src/store.cc
@@ -0,0 +1,3878 @@
+/*
+ * 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 "store.hpp"
+
+#include "bldg.hpp"
+#include "cave.hpp"
+#include "cave_type.hpp"
+#include "cmd3.hpp"
+#include "cmd4.hpp"
+#include "cmd5.hpp"
+#include "files.hpp"
+#include "hooks.hpp"
+#include "obj_theme.hpp"
+#include "object1.hpp"
+#include "object2.hpp"
+#include "object_kind.hpp"
+#include "options.hpp"
+#include "owner_type.hpp"
+#include "player_type.hpp"
+#include "quark.hpp"
+#include "spell_type.hpp"
+#include "skills.hpp"
+#include "spells5.hpp"
+#include "stats.hpp"
+#include "store_action_type.hpp"
+#include "store_type.hpp"
+#include "store_info_type.hpp"
+#include "tables.hpp"
+#include "town_type.hpp"
+#include "util.hpp"
+#include "util.h"
+#include "variable.h"
+#include "variable.hpp"
+#include "xtra1.hpp"
+#include "z-rand.hpp"
+
+#include <cassert>
+
+#define STORE_GENERAL_STORE "General Store"
+#define STORE_ARMOURY "Armoury"
+#define STORE_WEAPONSMITH "Weaponsmith"
+#define STORE_TEMPLE "Temple"
+#define STORE_ALCHEMY "Alchemy shop"
+#define STORE_MAGIC "Magic shop"
+#define STORE_BLACK_MARKET "Black Market"
+#define STORE_BOOKS "Book Store"
+#define STORE_PETS "Pet Shop"
+#define STORE_HUNTING_SUPPLIES "Hunting Supply Store"
+#define STORE_RUNIC_MAGIC "Runic Magic Shop"
+#define STORE_CONSTRUCTION_SUPPLIES "Construction Supply Store"
+#define STORE_MUSIC "Music Store"
+
+#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_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!"
+};
+
+
+/*
+ * 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)
+ {
+ msg_print("The shopkeeper whispers something into your ear:");
+ get_rnd_line("rumors.txt", rumour);
+ msg_print(rumour);
+ }
+}
+
+
+/*
+ * 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)]);
+}
+
+
+
+/*
+ * 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;
+
+ /* No selling means you get no money */
+ if (no_selling) price = 0;
+ }
+
+ /* 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;
+
+ /* Never give items away for free */
+ if (price <= 0L) price = 1L;
+ }
+
+ /* Compute the final price (with rounding) */
+ price = (price * adjust + 50L) / 100L;
+
+ /* 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);
+}
+
+
+static bool_ is_blessed(object_type const *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 const *o_ptr)
+{
+ cptr store_name = st_info[st_ptr->st_idx].name;
+
+ /* 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;
+ }
+
+ /* What do stores buy? */
+ if (streq(store_name, STORE_GENERAL_STORE))
+ {
+ switch (o_ptr->tval)
+ {
+ case TV_CORPSE:
+ case TV_FOOD:
+ case TV_LITE:
+ case TV_FLASK:
+ case TV_SPIKE:
+ case TV_SHOT:
+ case TV_ARROW:
+ case TV_BOLT:
+ case TV_DIGGING:
+ case TV_CLOAK:
+ case TV_BOTTLE:
+ return true;
+ }
+ }
+ else if (streq(store_name, STORE_ARMOURY))
+ {
+ switch (o_ptr->tval)
+ {
+ case TV_BOOTS:
+ case TV_GLOVES:
+ case TV_CROWN:
+ case TV_HELM:
+ case TV_SHIELD:
+ case TV_CLOAK:
+ case TV_SOFT_ARMOR:
+ case TV_HARD_ARMOR:
+ case TV_DRAG_ARMOR:
+ return true;
+ }
+ }
+ else if (streq(store_name, STORE_WEAPONSMITH))
+ {
+ switch (o_ptr->tval)
+ {
+ case TV_SHOT:
+ case TV_BOLT:
+ case TV_ARROW:
+ case TV_BOOMERANG:
+ case TV_BOW:
+ case TV_DIGGING:
+ case TV_HAFTED:
+ case TV_POLEARM:
+ case TV_SWORD:
+ case TV_AXE:
+ case TV_MSTAFF:
+ return true;
+ }
+ }
+ else if (streq(store_name, STORE_TEMPLE))
+ {
+ switch (o_ptr->tval)
+ {
+ case TV_DRUID_BOOK:
+ case TV_SCROLL:
+ case TV_POTION2:
+ case TV_POTION:
+ case TV_HAFTED:
+ return true;
+ }
+
+ if ((o_ptr->tval == TV_BOOK) &&
+ (o_ptr->sval == BOOK_RANDOM) &&
+ (spell_type_random_type(spell_at(o_ptr->pval)) == SKILL_SPIRITUALITY))
+ {
+ return true;
+ }
+ else if ((o_ptr->tval == TV_POLEARM) &&
+ is_blessed(o_ptr))
+ {
+ return true;
+ }
+ else if ((o_ptr->tval == TV_SWORD) &&
+ is_blessed(o_ptr))
+ {
+ return true;
+ }
+ else if ((o_ptr->tval == TV_AXE) &&
+ is_blessed(o_ptr))
+ {
+ return true;
+ }
+ else if ((o_ptr->tval == TV_BOOMERANG) &&
+ is_blessed(o_ptr))
+ {
+ return true;
+ }
+ }
+ else if (streq(store_name, STORE_ALCHEMY))
+ {
+ switch (o_ptr->tval)
+ {
+ case TV_SCROLL:
+ case TV_POTION2:
+ case TV_POTION:
+ case TV_BOTTLE:
+ return true;
+ }
+ }
+ else if (streq(store_name, STORE_MAGIC))
+ {
+ switch (o_ptr->tval)
+ {
+ case TV_SYMBIOTIC_BOOK:
+ case TV_AMULET:
+ case TV_RING:
+ case TV_STAFF:
+ case TV_WAND:
+ case TV_ROD:
+ case TV_ROD_MAIN:
+ case TV_SCROLL:
+ case TV_POTION2:
+ case TV_POTION:
+ case TV_MSTAFF:
+ case TV_RANDART:
+ return true;
+ }
+
+ if ((o_ptr->tval == TV_BOOK) &&
+ (o_ptr->sval == BOOK_RANDOM) &&
+ (spell_type_random_type(spell_at(o_ptr->pval)) == SKILL_MAGIC))
+ {
+ return true;
+ }
+ else if ((o_ptr->tval == TV_BOOK) &&
+ (o_ptr->sval != BOOK_RANDOM))
+ {
+ return true;
+ }
+ }
+ else if (streq(store_name, STORE_BLACK_MARKET))
+ {
+ return true;
+ }
+ else if (streq(store_name, STORE_BOOKS))
+ {
+ switch (o_ptr->tval)
+ {
+ case TV_BOOK:
+ case TV_SYMBIOTIC_BOOK:
+ case TV_MUSIC_BOOK:
+ case TV_DAEMON_BOOK:
+ case TV_DRUID_BOOK:
+ return true;
+ }
+ }
+ else if (streq(store_name, STORE_PETS))
+ {
+ return (o_ptr->tval == TV_EGG);
+ }
+ else if (streq(store_name, STORE_HUNTING_SUPPLIES))
+ {
+ switch (o_ptr->tval)
+ {
+ case TV_TRAPKIT:
+ case TV_BOOMERANG:
+ case TV_SHOT:
+ case TV_BOLT:
+ case TV_ARROW:
+ case TV_BOW:
+ case TV_POTION2:
+ return true;
+ }
+ }
+ else if (streq(store_name, STORE_RUNIC_MAGIC))
+ {
+ switch (o_ptr->tval)
+ {
+ case TV_RUNE1:
+ case TV_RUNE2:
+ return true;
+ }
+ }
+ else if (streq(store_name, STORE_CONSTRUCTION_SUPPLIES))
+ {
+ switch (o_ptr->tval)
+ {
+ case TV_LITE:
+ case TV_DIGGING:
+ return true;
+ }
+ }
+ else if (streq(store_name, STORE_MUSIC))
+ {
+ return (o_ptr->tval == TV_INSTRUMENT);
+ }
+
+ /* 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;
+
+ /* Magic Shop */
+ if (streq(st_info[st_ptr->st_idx].name, STORE_MAGIC) &&
+ magik(20))
+ {
+ s16b spell;
+
+ object_prep(&forge, lookup_kind(TV_BOOK, BOOK_RANDOM));
+ spell = get_random_spell(SKILL_MAGIC, 20);
+ assert (spell > -1);
+ forge.pval = spell;
+
+ /* Use the forged object */
+ q_ptr = &forge;
+ obj_all_done = TRUE;
+ }
+
+ /* Temple */
+ else if (streq(st_info[st_ptr->st_idx].name, STORE_TEMPLE) &&
+ magik(20))
+ {
+ s16b spell;
+
+ object_prep(&forge, lookup_kind(TV_BOOK, BOOK_RANDOM));
+ spell = get_random_spell(SKILL_SPIRITUALITY, 20);
+ assert(spell > -1);
+ forge.pval = spell;
+
+ /* Use the forged object */
+ q_ptr = &forge;
+ obj_all_done = TRUE;
+ }
+
+ /* 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;
+ }
+}
+
+
+
+/*
+ * 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;
+ {
+ 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);
+ 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 */
+ 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 */
+ {
+ /* 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 */
+ 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 */
+ {
+ /* 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);
+ }
+
+ /* Extract the "minimum" price */
+ x = price_item(o_ptr, ot_ptr->inflation, FALSE);
+
+ /* Can we buy one ? */
+ if (x > p_ptr->au) color = TERM_L_DARK;
+
+ /* Actually draw the price */
+ strnfmt(out_val, 160, "%9ld ", static_cast<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", static_cast<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 */
+ put_str("Weight", 5, 70);
+ }
+
+ else if (st_info[st_ptr->st_idx].flags1 & SF1_MUSEUM)
+ {
+ /* Show the name of the store */
+ strnfmt(buf, 80, "%s", st_info[cur_store_num].name);
+ prt(buf, 3, 30);
+
+ /* Label the item descriptions */
+ put_str("Item Description", 5, 3);
+
+ /* If showing weights, show label */
+ put_str("Weight", 5, 70);
+ }
+
+ /* Normal stores */
+ else
+ {
+ /* Put the owner name and race */
+ strnfmt(buf, 80, "%s", ot_ptr->name);
+ put_str(buf, 3, 10);
+
+ /* Show the max price in the store (above prices) */
+ strnfmt(buf, 80, "%s (" FMTs16b ")",
+ st_info[cur_store_num].name,
+ ot_ptr->max_cost);
+ prt(buf, 3, 50);
+
+ /* Label the item descriptions */
+ put_str("Item Description", 5, 3);
+
+ /* If showing weights, show label */
+ 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);
+}
+
+
+
+/**
+ * Prompt for a yes/no during selling/buying
+ *
+ * @return TRUE if 'yes' was selected, otherwise returns FALSE.
+ */
+static bool_ prompt_yesno(cptr prompt)
+{
+ cptr allowed = "yn\r\n";
+ cptr yes = "y\r\n";
+ char buf[128];
+ bool_ ret;
+
+ /* Build prompt */
+ snprintf(buf, sizeof(buf), "%s [y/n/RET/ESC] ", prompt);
+
+ /* Prompt for it */
+ msg_print(NULL);
+ prt(buf, 0, 0);
+
+ /* Get answer */
+ while (TRUE)
+ {
+ int key = inkey();
+
+ /* ESC means no. */
+ if (key == ESCAPE) {
+ ret = FALSE;
+ break;
+ }
+
+ /* Any other key must be in the allowed set to break the loop. */
+ if ((strchr(allowed, key) != NULL) || quick_messages) {
+ /* Check for presence in the 'yes' set */
+ ret = (strchr(yes, key) != NULL);
+ break;
+ }
+
+ /* Retry */
+ bell();
+ }
+
+ /* Erase the prompt */
+ prt("", 0, 0);
+
+ /* Success */
+ return ret;
+}
+
+
+
+/*
+ * Haggling routine -RAK-
+ *
+ * Return TRUE if purchase is NOT successful
+ */
+static bool_ purchase_haggle(object_type *o_ptr, s32b *price)
+{
+ s32b cur_ask;
+ bool_ cancel = FALSE;
+ char out_val[160];
+ char prompt[128];
+ char o_name[80];
+
+
+ *price = 0;
+
+ /* Extract the price */
+ cur_ask = price_item(o_ptr, ot_ptr->inflation, FALSE);
+
+ /* Buy for the whole pile */
+ cur_ask *= o_ptr->number;
+
+ /* Describe the object (fully) */
+ object_desc_store(o_name, o_ptr, TRUE, 3);
+
+ /* Prompt */
+ strnfmt(out_val, sizeof(out_val), "%s: " FMTs32b, "Price", cur_ask);
+ put_str(out_val, 1, 0);
+ strnfmt(prompt, sizeof(prompt), "Buy %s?", o_name);
+ cancel = !prompt_yesno(prompt);
+
+ /* Handle result */
+ if (cancel)
+ {
+ /* Cancel */
+ return (TRUE);
+ }
+ else
+ {
+ *price = cur_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 cur_ask;
+ bool_ cancel = FALSE;
+ char out_val[160];
+ char prompt[128];
+ char o_name[80];
+
+
+ *price = 0;
+
+ /* Extract price */
+ cur_ask = price_item(o_ptr, ot_ptr->inflation, TRUE);
+
+ /* Limit to shopkeeper's purse */
+ if (cur_ask > ot_ptr->max_cost) {
+ cur_ask = ot_ptr->max_cost;
+ }
+
+ /* Sell the whole pile */
+ cur_ask *= o_ptr->number;
+
+ /* Describe the object */
+ object_desc(o_name, o_ptr, TRUE, 3);
+
+ /* Prompt */
+ strnfmt(out_val, sizeof(out_val), "%s: " FMTs32b, "Price", cur_ask);
+ put_str(out_val, 1, 0);
+ strnfmt(prompt, sizeof(prompt), "Sell %s?", o_name);
+ cancel = !prompt_yesno(prompt);
+
+ /* Handle result */
+ if (cancel)
+ {
+ /* Cancel */
+ return (TRUE);
+ }
+ else
+ {
+ *price = cur_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;
+
+ /* "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();
+
+ /* 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->inflation, FALSE);
+
+ /* Find out how many the player wants */
+ if (o_ptr->number > 1)
+ {
+ s32b q;
+
+
+ /* 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
+ {
+ 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)
+ {
+ /* 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)
+ {
+ /* Player can afford it */
+ if (p_ptr->au >= price)
+ {
+ /* Say "okay" */
+ say_comment_1();
+
+ /* Make a sound */
+ sound(SOUND_BUY);
+
+ /* 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;
+
+ /* Describe the transaction */
+ object_desc(o_name, j_ptr, TRUE, 3);
+
+ /* Message */
+ msg_format("You bought %s for " FMTs32b " gold.", o_name, 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;
+
+ 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 prompt */
+ cptr q, s;
+ if (cur_store_num == STORE_HOME)
+ {
+ q = "Drop which item? ";
+ s = "You have nothing to drop.";
+ }
+ else if (museum)
+ {
+ q = "Donate which item?";
+ s = "You have nothing to donate.";
+ }
+ else
+ {
+ q = "Sell which item? ";
+ s = "You have nothing that I want.";
+ }
+
+ /* Get an item */
+ if (!get_item(&item, q, s, (USE_EQUIP | USE_INVEN), store_will_buy))
+ {
+ 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)
+ {
+ /* 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);
+
+ /* 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 " FMTs32b " gold.", o_name, 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 ***/
+
+ /* 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_FRAME);
+
+ /* 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->store_open = 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;
+
+ /* 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];
+
+ /* 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;
+
+ /* 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]);
+ }
+}
+
+
+/*
+ * 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_FRAME);
+
+ /* Redraw map */
+ p_ptr->redraw |= (PR_MAP);
+
+ /* Window stuff */
+ p_ptr->window |= (PW_OVERHEAD);
+}
diff --git a/src/store.hpp b/src/store.hpp
new file mode 100644
index 00000000..f67d94eb
--- /dev/null
+++ b/src/store.hpp
@@ -0,0 +1,12 @@
+#pragma once
+
+extern void do_cmd_store();
+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 do_cmd_home_trump();
+extern void store_sell();
+extern void store_purchase();
+extern void store_examine();
+extern void store_stole();
+extern void store_prt_gold();
diff --git a/src/store_action_type.hpp b/src/store_action_type.hpp
new file mode 100644
index 00000000..048e13a0
--- /dev/null
+++ b/src/store_action_type.hpp
@@ -0,0 +1,17 @@
+#pragma once
+
+#include "h-basic.h"
+
+/**
+ * Store/building actions.
+ */
+struct store_action_type
+{
+ const char *name; /* Name */
+
+ 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 */
+};
diff --git a/src/store_action_type_fwd.hpp b/src/store_action_type_fwd.hpp
new file mode 100644
index 00000000..e1746dad
--- /dev/null
+++ b/src/store_action_type_fwd.hpp
@@ -0,0 +1,3 @@
+#pragma once
+
+struct store_action_type;
diff --git a/src/store_info_type.hpp b/src/store_info_type.hpp
new file mode 100644
index 00000000..030afe91
--- /dev/null
+++ b/src/store_info_type.hpp
@@ -0,0 +1,32 @@
+#pragma once
+
+#include "h-basic.h"
+
+/**
+ * Number of items to choose stock from
+ */
+constexpr int STORE_CHOICES = 56;
+
+/**
+ * Store descriptor.
+ */
+struct store_info_type
+{
+ const char *name; /* Name */
+
+ 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 */
+};
diff --git a/src/store_info_type_fwd.hpp b/src/store_info_type_fwd.hpp
new file mode 100644
index 00000000..a0dace90
--- /dev/null
+++ b/src/store_info_type_fwd.hpp
@@ -0,0 +1,3 @@
+#pragma once
+
+struct store_info_type;
diff --git a/src/store_type.hpp b/src/store_type.hpp
new file mode 100644
index 00000000..e3f917ac
--- /dev/null
+++ b/src/store_type.hpp
@@ -0,0 +1,43 @@
+#pragma once
+
+#include "h-basic.h"
+#include "object_type.hpp"
+
+/**
+ * A store, with an owner, various state flags, a current stock
+ * of items, and a table of items that are often purchased.
+ */
+struct store_type
+{
+ u16b st_idx;
+
+ /**
+ * Owner index
+ */
+ u16b owner;
+
+ /**
+ * Closed until this turn.
+ */
+ s32b store_open;
+
+ /**
+ * Last visited on this turn.
+ */
+ s32b last_visit;
+
+ /**
+ * Stock: Number of entries.
+ */
+ byte stock_num;
+
+ /**
+ * Stock: Total size of array
+ */
+ s16b stock_size;
+
+ /**
+ * Stock: Actual stock items
+ */
+ object_type *stock;
+};
diff --git a/src/store_type_fwd.hpp b/src/store_type_fwd.hpp
new file mode 100644
index 00000000..15410563
--- /dev/null
+++ b/src/store_type_fwd.hpp
@@ -0,0 +1,3 @@
+#pragma once
+
+struct store_type;
diff --git a/src/tables.c b/src/tables.c
deleted file mode 100644
index e976e234..00000000
--- a/src/tables.c
+++ /dev/null
@@ -1,4792 +0,0 @@
-/* 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/tables.cc b/src/tables.cc
new file mode 100644
index 00000000..09e6c18c
--- /dev/null
+++ b/src/tables.cc
@@ -0,0 +1,4506 @@
+/*
+ * 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 "tables.hpp"
+#include "tables.h"
+
+#include "modules.hpp"
+#include "options.hpp"
+#include "q_library.hpp"
+#include "q_fireprof.hpp"
+#include "q_bounty.hpp"
+#include "q_thrain.hpp"
+#include "q_narsil.hpp"
+#include "q_evil.hpp"
+#include "q_betwen.hpp"
+#include "q_haunted.hpp"
+#include "q_invas.hpp"
+#include "q_nirna.hpp"
+#include "q_eol.hpp"
+#include "q_god.hpp"
+#include "q_dragons.hpp"
+#include "q_poison.hpp"
+#include "q_spider.hpp"
+#include "q_wolves.hpp"
+#include "q_shroom.hpp"
+#include "q_nazgul.hpp"
+#include "q_wight.hpp"
+#include "q_troll.hpp"
+#include "q_hobbit.hpp"
+#include "q_thief.hpp"
+#include "q_ultrae.hpp"
+#include "q_ultrag.hpp"
+#include "q_one.hpp"
+#include "q_main.hpp"
+#include "q_rand.hpp"
+#include "stats.hpp"
+#include "variable.hpp"
+
+
+
+/*
+ * 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) -- 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 (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 },
+};
+
+
+
+/*
+ * 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" },
+
+ { &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" },
+
+ { &always_repeat, TRUE, 1, 7,
+ "always_repeat", "Repeat obvious commands" },
+
+ { &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" },
+
+ { &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" },
+
+ /*** Game-Play ***/
+
+ { &auto_scum, TRUE, 3, 1,
+ "auto_scum", "Auto-scum for good levels" },
+
+ { &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" },
+
+ { &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)" },
+
+ { &smart_learn, FALSE, 3, 14,
+ "smart_learn", "Monsters learn from their mistakes" },
+
+ { &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" },
+
+ { &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" },
+
+ { &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 ***/
+
+ { &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" },
+
+ { &joke_monsters, FALSE, 6, 14,
+ "joke_monsters", "Allow use of some 'joke' monsters" },
+
+ { &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" },
+
+ { &no_selling, FALSE, 6, 20,
+ "no_selling", "Items always sell for 0 gold" },
+
+ /*** End of Table ***/
+
+ { NULL, 0, 0, 0,
+ NULL, NULL }
+};
+
+
+
+/* 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."
+ },
+};
+
+
+/*
+ * Name and description (max. 10 lines) of the gods.
+ * Only the first four lines are printed at birth.
+ */
+
+deity_type deity_info[MAX_GODS] =
+{
+ {
+ { MODULE_TOME, MODULE_THEME, -1, },
+ "Nobody",
+ {
+ "Atheist",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ },
+ },
+ {
+ { MODULE_TOME, MODULE_THEME, -1, },
+ "Eru Iluvatar",
+ {
+ "He is the supreme god, he created the world, and most of its inhabitants.",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ },
+ },
+ {
+ { MODULE_TOME, MODULE_THEME, -1, },
+ "Manwe Sulimo",
+ {
+ "He is the king of the Valar, most powerful of them after Melkor.",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ },
+ },
+ {
+ { MODULE_TOME, MODULE_THEME, -1, },
+ "Tulkas",
+ {
+ "He is the last of the Valar that came to the world, and the fiercest fighter.",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ },
+ },
+ {
+ { MODULE_TOME, MODULE_THEME, -1, },
+ "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.",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ },
+ },
+ {
+ { MODULE_TOME, MODULE_THEME, -1, },
+ "Yavanna Kementari",
+ {
+ "She is the Vala of nature, protectress of the great forests of Middle-earth.",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ },
+ },
+ {
+ { MODULE_THEME, -1, },
+ "Aule the Smith",
+ {
+ "Aule is a smith, and the creator of the Dwarves.",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ },
+ },
+ {
+ { MODULE_THEME, -1, },
+ "Varda Elentari",
+ {
+ "The Queen of the Stars. In light is her power and joy.",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ },
+ },
+ {
+ { MODULE_THEME, -1, },
+ "Ulmo",
+ {
+ "Ulmo is called Lord of Waters, he rules all that is water on Arda.",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ },
+ },
+ {
+ { MODULE_THEME, -1, },
+ "Mandos",
+ {
+ "The Doomsman of the Valar and keeper of the slain.",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ },
+ },
+};
+
+/* 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_50,
+ 0,
+ },
+};
+
+/* Powers */
+power_type powers_type[POWER_MAX] =
+{
+ {
+ "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,
+ },
+ {
+ "notused", /* Merchant abilities; no longer used, but want to
+ * avoid having to move all potential places where
+ * we're indexing into this table. */
+ "notused",
+ "notused",
+ "notused",
+ 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,
+ },
+ {
+ "invisibility",
+ "You are able melt into the shadows to become invisible.",
+ "You suddenly become able to melt into the shadows.",
+ "You lose your shadow-melting ability.",
+ 30, 10, A_DEX, 20,
+ },
+ {
+ "web",
+ "You are able throw a thick and very resistant spider web.",
+ "You suddenly become able to weave webs.",
+ "You lose your web-weaving capability.",
+ 25, 30, A_DEX, 20,
+ },
+ {
+ "control space/time continuum",
+ "You are able to control the space/time continuum.",
+ "You become able to control the space/time continuum.",
+ "You are no more able to control the space/time continuum.",
+ 1, 10, A_WIS, 10,
+ },
+};
+
+/*
+ * The Quests
+ */
+quest_type quest[MAX_Q_IDX] =
+{
+ {
+ FALSE,
+ "",
+ {
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ },
+ QUEST_STATUS_UNTAKEN,
+ 0,
+
+ NULL,
+ NULL,
+ {0, 0},
+ NULL,
+ },
+ {
+ 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],
+ quest_necro_init_hook,
+ {0, 0},
+ NULL,
+ },
+ {
+ 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],
+ quest_sauron_init_hook,
+ {0, 0},
+ NULL,
+ },
+ {
+ 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],
+ quest_morgoth_init_hook,
+ {0, 0},
+ NULL,
+ },
+
+ /* Bree plot */
+ {
+ 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],
+ quest_thieves_init_hook,
+ {0, 0},
+ NULL,
+ },
+
+ {
+ FALSE,
+ "Random Quest",
+ {
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ },
+ QUEST_STATUS_UNTAKEN,
+ 5,
+
+ NULL,
+ quest_random_init_hook,
+ {0, 0},
+ quest_random_describe,
+ },
+
+ {
+ 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],
+ quest_hobbit_init_hook,
+ {0, 0},
+ NULL,
+ },
+
+ {
+ 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],
+ quest_nazgul_init_hook,
+ {0, 0},
+ NULL,
+ },
+
+ {
+ 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],
+ quest_troll_init_hook,
+ {FALSE, 0},
+ NULL,
+ },
+
+ {
+ 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],
+ quest_wight_init_hook,
+ {FALSE, 0},
+ NULL,
+ },
+
+ /* Lorien plot */
+ {
+ 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],
+ quest_spider_init_hook,
+ {0, 0},
+ NULL,
+ },
+ {
+ 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],
+ quest_poison_init_hook,
+ {0, 0},
+ NULL,
+ },
+ /* Other quests */
+ {
+ 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],
+ quest_narsil_init_hook,
+ {0, 0},
+ NULL,
+ },
+ /* Gondolin plot */
+ {
+ 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],
+ quest_eol_init_hook,
+ {0, 0},
+ NULL,
+ },
+ {
+ 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],
+ quest_nirnaeth_init_hook,
+ {0, 0},
+ NULL,
+ },
+ {
+ 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],
+ quest_invasion_init_hook,
+ {0, 0},
+ NULL,
+ },
+ /* Minas Anor Plot*/
+ {
+ 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],
+ quest_between_init_hook,
+ {0, 0},
+ NULL,
+ },
+ {
+ 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],
+ quest_one_init_hook,
+ {0, 0},
+ NULL,
+ },
+
+ {
+ 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],
+ quest_shroom_init_hook,
+ {0, 0},
+ NULL,
+ },
+
+ {
+ 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],
+ quest_thrain_init_hook,
+ {0, 0},
+ NULL,
+ },
+
+ /* The 2 ultra endings go here */
+ {
+ 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],
+ quest_ultra_good_init_hook,
+ {0, 0},
+ NULL,
+ },
+ {
+ 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],
+ quest_ultra_evil_init_hook,
+ {0, 0},
+ NULL,
+ },
+ /* More Lorien */
+ {
+ 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],
+ quest_wolves_init_hook,
+ {0, 0},
+ NULL,
+ },
+ /* More Gondolin */
+ {
+ 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],
+ quest_dragons_init_hook,
+ {0, 0},
+ NULL,
+ },
+ /* More Minas Anor */
+ {
+ 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],
+ quest_haunted_init_hook,
+ {0, 0},
+ NULL,
+ },
+ /* Khazad-Dum Plot*/
+ {
+ 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],
+ quest_evil_init_hook,
+ {0, 0},
+ NULL,
+ },
+ /* Bounty */
+ {
+ FALSE,
+ "Bounty quest",
+ {
+ "", /* dynamic desc */
+ },
+ QUEST_STATUS_UNTAKEN,
+ -1,
+ NULL,
+ quest_bounty_init_hook,
+ {0, 0, 0, 0},
+ quest_bounty_describe,
+ },
+ /* Fireproofing */
+ {
+ FALSE,
+ "Old Mages quest",
+ {
+ "", /* dynamic desc */
+ },
+ QUEST_STATUS_UNTAKEN,
+ 20,
+ NULL,
+ quest_fireproof_init_hook,
+ {0, 0, 0, 0},
+ quest_fireproof_describe,
+ },
+ /* Library */
+ {
+ FALSE,
+ "Library quest",
+ {
+ "", /* dynamic desc */
+ },
+ QUEST_STATUS_UNTAKEN,
+ 35,
+ NULL,
+ quest_library_init_hook,
+ { -1, -1, -1, -1 },
+ quest_library_describe,
+ },
+ /* God quest */
+ {
+ FALSE,
+ "God quest",
+ {
+ "", /* dynamic desc */
+ },
+ QUEST_STATUS_UNTAKEN,
+ -1,
+ NULL,
+ quest_god_init_hook,
+ { 0 /* quests_given */,
+ 0 /* relics_found */,
+ 1 /* dun_mindepth */,
+ 4 /* dun_maxdepth */,
+ 0 /* dun_minplev */,
+ 0 /* relic_gen_tries */,
+ FALSE /* relic_generated */,
+ 1 /* dung_x */,
+ 1 /* dung_y */,
+ },
+ quest_god_describe,
+ },
+};
+
+
+/* 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_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."
+ },
+ {
+ 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."
+ },
+ {
+ 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."
+ },
+ {
+ 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
+ },
+ /* Theme: Minas Tirith -> Gondolin link */
+ {
+ 0,
+ FALSE,
+ 3, 11,
+ 119, 25,
+ 0, 0
+ },
+};
+
+/*
+ * 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 },
+};
+
+/**
+ * Modules
+ */
+module_type modules[MAX_MODULES] =
+{
+ {
+ { "ToME",
+ { 2, 4, 0 },
+ { "DarkGod", "darkgod@t-o-m-e.net" },
+ "The Tales of Middle-earth, the standard and official game.\n"
+ "You are set on a quest to investigate the old tower of Dol Guldur.\n"
+ "But who knows what will happen...",
+ "ToME",
+ NULL /* default dir */,
+ },
+ /* Randarts: */
+ { 30, 20, 20 },
+ /* Max player level: */
+ 50,
+ /* Skills: */
+ { 6, 4, },
+ /* Intro function */
+ tome_intro,
+ /* Race status function: ToME requires no special handling */
+ NULL
+ },
+
+ {
+ { "Theme",
+ { 1, 2, 0 },
+ { "furiosity", "furiosity@gmail.com" },
+ "A module that goes back to Tolkien roots, though by no means canonical.\n"
+ "A new wilderness map, new monsters, objects, artifacts, uniques, ego items,\n"
+ "terrain features, gods, races, subraces, and classes. Have fun. :-)",
+ "Theme",
+ "theme",
+ },
+ /* Randarts: */
+ { 30, 30, 30 },
+ /* Max player level: */
+ 50,
+ /* Skill overage: */
+ { 6, 5, },
+ /* Intro function */
+ theme_intro,
+ /* Race status function */
+ theme_race_status
+ }
+
+};
+
diff --git a/src/tables.h b/src/tables.h
new file mode 100644
index 00000000..9a5cfb58
--- /dev/null
+++ b/src/tables.h
@@ -0,0 +1,12 @@
+#pragma once
+
+// C linkage required for these functions since main-* code uses them.
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern char hexsym[16];
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
diff --git a/src/tables.hpp b/src/tables.hpp
new file mode 100644
index 00000000..4a3e33d6
--- /dev/null
+++ b/src/tables.hpp
@@ -0,0 +1,82 @@
+#pragma once
+
+#include "angband.h"
+#include "activation.hpp"
+#include "between_exit.hpp"
+#include "body.hpp"
+#include "cli_comm_fwd.hpp"
+#include "flags_group.hpp"
+#include "gf_name_type.hpp"
+#include "inscription_info_type.hpp"
+#include "magic_power.hpp"
+#include "martial_arts.hpp"
+#include "module_type.hpp"
+#include "monster_power.hpp"
+#include "move_info_type.hpp"
+#include "option_type.hpp"
+#include "player_defs.hpp"
+#include "player_sex.hpp"
+#include "power_type.hpp"
+#include "powers.hpp"
+#include "quest_type.hpp"
+#include "tactic_info_type.hpp"
+#include "tval_desc.hpp"
+
+extern s16b ddd[9];
+extern s16b ddx[10];
+extern s16b ddy[10];
+extern s16b ddx_ddd[9];
+extern s16b ddy_ddd[9];
+extern byte adj_mag_mana[];
+extern byte adj_mag_fail[];
+extern byte adj_mag_stat[];
+extern byte adj_chr_gold[];
+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 byte extract_energy[300];
+extern s32b player_exp[PY_MAX_LEVEL];
+extern player_sex sex_info[MAX_SEXES];
+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 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 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[POWER_MAX];
+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[MAX_Q_IDX];
+extern int max_body_part[BODY_MAX];
+extern gf_name_type gf_names[];
+extern module_type modules[MAX_MODULES];
diff --git a/src/tactic_info_type.hpp b/src/tactic_info_type.hpp
new file mode 100644
index 00000000..da94767d
--- /dev/null
+++ b/src/tactic_info_type.hpp
@@ -0,0 +1,17 @@
+#pragma once
+
+#include "h-basic.h"
+
+/**
+ * Tactics descriptor.
+ */
+struct tactic_info_type
+{
+ s16b to_hit;
+ s16b to_dam;
+ s16b to_ac;
+ s16b to_stealth;
+ s16b to_disarm;
+ s16b to_saving;
+ cptr name;
+};
diff --git a/src/terrain.hpp b/src/terrain.hpp
new file mode 100644
index 00000000..118a877a
--- /dev/null
+++ b/src/terrain.hpp
@@ -0,0 +1,19 @@
+#pragma once
+
+/*
+ * 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
diff --git a/src/timer_type.hpp b/src/timer_type.hpp
new file mode 100644
index 00000000..0ce6b095
--- /dev/null
+++ b/src/timer_type.hpp
@@ -0,0 +1,18 @@
+#pragma once
+
+#include "h-basic.h"
+
+/*
+ * Timer descriptor and runtime data.
+ */
+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 */
+
+ void (*callback)(); /* The C function to call upon firing */
+};
diff --git a/src/timer_type_fwd.hpp b/src/timer_type_fwd.hpp
new file mode 100644
index 00000000..bda03716
--- /dev/null
+++ b/src/timer_type_fwd.hpp
@@ -0,0 +1,3 @@
+#pragma once
+
+struct timer_type;
diff --git a/src/town_type.hpp b/src/town_type.hpp
new file mode 100644
index 00000000..f8458c60
--- /dev/null
+++ b/src/town_type.hpp
@@ -0,0 +1,21 @@
+#pragma once
+
+#include "h-basic.h"
+#include "store_type_fwd.hpp"
+
+/**
+ * Town descriptor.
+ */
+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? */
+};
diff --git a/src/town_type_fwd.hpp b/src/town_type_fwd.hpp
new file mode 100644
index 00000000..9de8c448
--- /dev/null
+++ b/src/town_type_fwd.hpp
@@ -0,0 +1,3 @@
+#pragma once
+
+struct town_type;
diff --git a/src/trap_type.hpp b/src/trap_type.hpp
new file mode 100644
index 00000000..d82c925b
--- /dev/null
+++ b/src/trap_type.hpp
@@ -0,0 +1,24 @@
+#pragma once
+
+#include "h-basic.h"
+
+/**
+ * Trap descriptor.
+ */
+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 */
+ const char *name; /* normal name like weakness */
+ s16b dd, ds; /* base damage */
+ char *text; /* longer description once you've met this trap */
+ byte g_attr; /* Overlay graphic attribute */
+ char g_char; /* Overlay graphic character */
+};
diff --git a/src/trap_type_fwd.hpp b/src/trap_type_fwd.hpp
new file mode 100644
index 00000000..480edfef
--- /dev/null
+++ b/src/trap_type_fwd.hpp
@@ -0,0 +1,3 @@
+#pragma once
+
+struct trap_type;
diff --git a/src/traps.c b/src/traps.c
deleted file mode 100644
index 1c8e36c9..00000000
--- a/src/traps.c
+++ /dev/null
@@ -1,3169 +0,0 @@
-/* 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/traps.cc b/src/traps.cc
new file mode 100644
index 00000000..99428cf9
--- /dev/null
+++ b/src/traps.cc
@@ -0,0 +1,3174 @@
+/* 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 "traps.hpp"
+
+#include "artifact_type.hpp"
+#include "cave.hpp"
+#include "cave_type.hpp"
+#include "cmd1.hpp"
+#include "cmd2.hpp"
+#include "dungeon_info_type.hpp"
+#include "feature_type.hpp"
+#include "files.hpp"
+#include "gods.hpp"
+#include "monster2.hpp"
+#include "monster_race.hpp"
+#include "monster_type.hpp"
+#include "object1.hpp"
+#include "object2.hpp"
+#include "object_kind.hpp"
+#include "player_race.hpp"
+#include "player_race_mod.hpp"
+#include "player_spec.hpp"
+#include "player_type.hpp"
+#include "spells1.hpp"
+#include "spells2.hpp"
+#include "stats.hpp"
+#include "tables.hpp"
+#include "trap_type.hpp"
+#include "util.hpp"
+#include "variable.hpp"
+#include "xtra1.hpp"
+#include "xtra2.hpp"
+#include "z-rand.hpp"
+
+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];
+ auto const r_ptr = m_ptr->race();
+
+ /* 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_FRAME);
+
+ /* 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)
+{
+ trap_type *t_ptr = &t_info[trap];
+ s16b dam = damroll(t_ptr->dd, t_ptr->ds);
+ take_hit(dam, 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;
+ }
+
+ 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(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:
+ {
+ /* teleport away all items */
+ while (!cave[y][x].o_idxs.empty())
+ {
+ auto item = cave[y][x].o_idxs.front();
+
+ object_type *o_ptr = &o_list[item];
+
+ int 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(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_FRAME);
+ 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);
+ }
+ 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_FRAME);
+ 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_idxs.empty())) 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));
+ apply_magic(j_ptr, 0, FALSE, FALSE, FALSE, boost::make_optional(0));
+ 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));
+ apply_magic(j_ptr, 0, FALSE, FALSE, FALSE, boost::make_optional(0));
+ 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);
+ }
+ 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);
+ }
+ 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);
+
+ /* 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_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;
+}
+
+
+/*
+ * Place a leveled trap at given position
+ */
+void place_trap_leveled(int y, int x, int lev)
+{
+ int prev_dun_level = dun_level;
+ dun_level = lev;
+ place_trap(y,x);
+ dun_level = prev_dun_level;
+}
+
+/*
+ * 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 const *o_ptr)
+{
+ return (((o_ptr->tval == TV_ROD_MAIN) && (o_ptr->pval != 0)) ||
+ (o_ptr->tval == TV_STAFF) ||
+ (o_ptr->tval == TV_WAND));
+}
+
+/*
+ * 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;
+ }
+
+ /* Get an item */
+ q = "Use which trapping kit? ";
+ s = "You have no trapping kits.";
+ if (!get_item(&item_kit,
+ q, s,
+ USE_INVEN,
+ object_filter::TVal(TV_TRAPKIT)))
+ {
+ return;
+ }
+
+ o_ptr = &p_ptr->inventory[item_kit];
+
+ /* Trap kits need a second object */
+ object_filter_t object_filter = object_filter::Or(
+ object_filter::And(
+ object_filter::SVal(SV_TRAPKIT_BOW),
+ object_filter::TVal(TV_ARROW)),
+ object_filter::And(
+ object_filter::SVal(SV_TRAPKIT_XBOW),
+ object_filter::TVal(TV_BOLT)),
+ object_filter::And(
+ object_filter::SVal(SV_TRAPKIT_SLING),
+ object_filter::TVal(TV_SHOT)),
+ object_filter::And(
+ object_filter::SVal(SV_TRAPKIT_POTION),
+ object_filter::Or(
+ object_filter::TVal(TV_POTION),
+ object_filter::TVal(TV_POTION2))),
+ object_filter::And(
+ object_filter::SVal(SV_TRAPKIT_SCROLL),
+ object_filter::TVal(TV_SCROLL)),
+ object_filter::And(
+ object_filter::SVal(SV_TRAPKIT_DEVICE),
+ &item_tester_hook_device));
+
+ /* 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, object_filter)) 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);
+ 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];
+
+ 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 */
+ auto kit_o_idx = cave[my][mx].special2;
+ auto kit_o_ptr = &o_list[kit_o_idx];
+ auto load_o_ptr = &o_list[cave[my][mx].special];
+ auto 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_idx);
+ }
+
+ /* 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_idx);
+ }
+ }
+
+ 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_idx);
+ }
+ }
+
+ 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/traps.hpp b/src/traps.hpp
new file mode 100644
index 00000000..3df1e430
--- /dev/null
+++ b/src/traps.hpp
@@ -0,0 +1,13 @@
+#pragma once
+
+#include "h-basic.h"
+#include "object_type_fwd.hpp"
+
+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_leveled(int y, int x, int lev);
+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);
diff --git a/src/tval_desc.hpp b/src/tval_desc.hpp
new file mode 100644
index 00000000..abf0b5e2
--- /dev/null
+++ b/src/tval_desc.hpp
@@ -0,0 +1,17 @@
+#pragma once
+
+/**
+ * TVal description entry.
+ */
+struct tval_desc
+{
+ /**
+ * TVal
+ */
+ int tval;
+
+ /**
+ * Description
+ */
+ char const *desc;
+};
diff --git a/src/types.h b/src/types.h
deleted file mode 100644
index 49acb383..00000000
--- a/src/types.h
+++ /dev/null
@@ -1,2522 +0,0 @@
-/* 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
deleted file mode 100644
index 93e38e4a..00000000
--- a/src/util.c
+++ /dev/null
@@ -1,4479 +0,0 @@
-/* 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.cc b/src/util.cc
new file mode 100644
index 00000000..08af0658
--- /dev/null
+++ b/src/util.cc
@@ -0,0 +1,3685 @@
+/* File: util.c */
+
+/* Purpose: Angband utilities -BEN- */
+
+#include "util.hpp"
+#include "util.h"
+
+#include "cli_comm.hpp"
+#include "cmd3.hpp"
+#include "cmd4.hpp"
+#include "init1.hpp"
+#include "messages.hpp"
+#include "monster_ego.hpp"
+#include "monster_race.hpp"
+#include "object_kind.hpp"
+#include "options.hpp"
+#include "player_race.hpp"
+#include "player_race_mod.hpp"
+#include "player_type.hpp"
+#include "quark.hpp"
+#include "tables.h"
+#include "tables.hpp"
+#include "timer_type.hpp"
+#include "variable.h"
+#include "variable.hpp"
+#include "xtra1.hpp"
+
+#include <boost/algorithm/string/predicate.hpp>
+#include <chrono>
+#include <thread>
+
+using boost::algorithm::iequals;
+using std::this_thread::sleep_for;
+using std::chrono::milliseconds;
+
+/*
+* 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");
+}
+
+
+
+/*
+* 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)
+{
+
+ 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));
+
+}
+
+
+/*
+* 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);
+}
+
+
+/*
+* 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 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"
+*
+*/
+int fd_make(cptr file, int mode)
+{
+ char buf[1024];
+
+ /* Hack -- Try to parse the path */
+ if (path_parse(buf, 1024, file)) return ( -1);
+
+
+/* Create the file, fail if exists, write-only, binary */
+return (open(buf, O_CREAT | O_EXCL | O_WRONLY | O_BINARY, mode));
+
+
+}
+
+
+/*
+* 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);
+
+
+/* Attempt to open the file */
+return (open(buf, flags | O_BINARY, 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 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 (iequals(str, macro_modifier_name[i]))
+ 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 (iequals(str, macro_trigger_name[i]) && ']' == 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 (iequals(key_code, macro_trigger_keycode[0][i])
+ || iequals(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 */
+ free(macro__act[n]);
+ }
+
+ /* Create a new macro */
+ else
+ {
+ /* Acquire a new index */
+ n = macro__num++;
+
+ /* Save the pattern */
+ macro__pat[n] = strdup(pat);
+ }
+
+ /* Save the action */
+ macro__act[n] = strdup(act);
+
+ /* Efficiency */
+ macro__use[(byte)(pat[0])] = TRUE;
+
+ /* 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_bell();
+ }
+
+ /* Flush the input (later!) */
+ flush();
+}
+
+
+/*
+* Hack -- Make a (relevant?) sound
+*/
+void sound(int val)
+{
+ /* Ignore; sound not currently supported. */
+ return;
+}
+
+
+
+/*
+* 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 */
+ sleep_for(milliseconds(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;
+
+bool_ inkey_flag = FALSE;
+
+
+/*
+* 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_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.
+*/
+static char inkey_real(bool_ inkey_scan)
+{
+ int v;
+
+ char kk;
+
+ char ch = 0;
+
+ bool_ done = FALSE;
+
+ term *old = Term;
+
+ /* Hack -- Use the "inkey_next" pointer */
+ if (inkey_next && *inkey_next)
+ {
+ /* Get next character, and advance */
+ ch = *inkey_next++;
+
+ /* Cancel the various "global parameters" */
+ inkey_base = inkey_flag = inkey_scan = FALSE;
+
+ /* Accept result */
+ macro_recorder_add(ch);
+ return (ch);
+ }
+
+ /* Forget pointer */
+ inkey_next = NULL;
+
+
+ /* 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]);
+
+ /* 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 */
+ sleep_for(milliseconds(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;
+
+ /* Do an html dump */
+ do_cmd_html_dump();
+
+ /* 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_flag = FALSE;
+
+
+ /* Return the keypress */
+ macro_recorder_add(ch);
+ return (ch);
+}
+
+char inkey(void) {
+ return inkey_real(FALSE);
+}
+
+char inkey_scan() {
+ return inkey_real(TRUE);
+}
+
+/*
+* 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;
+ int wid;
+
+ char *t;
+
+ char buf[1024];
+
+ Term_get_size(&wid, nullptr);
+ int lim = 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(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);
+
+ /* Wrapping boundary */
+ 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 column 75 ; 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 = 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;
+ int hgt;
+ Term_get_size(nullptr, &hgt);
+
+ /* Erase requested rows */
+ for (y = row; y < 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.
+*/
+static 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 - 1] = '\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);
+}
+
+bool_ askfor_aux_with_completion(char *buf, int len)
+{
+ askfor_aux_complete = TRUE;
+ bool_ res = askfor_aux(buf, len);
+ askfor_aux_complete = FALSE;
+ return res;
+}
+
+/*
+* 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];
+ if (r_ptr->name && iequals(name, r_ptr->name)) 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];
+ if (re_ptr->name && iequals(name, re_ptr->name)) 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];
+ /* If name matches, give us the number */
+ if (k_ptr->name && iequals(name, k_ptr->name)) 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_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, race_mod_info[ps].title);
+ }
+ else
+ {
+ sprintf(buf, "%s %s", race_mod_info[ps].title, race_info[pr].title);
+ }
+ }
+ else
+ {
+ sprintf(buf, "%s", race_info[pr].title);
+ }
+
+ return (buf);
+}
+
+/*
+ * Ask to select an item in a list
+ */
+int ask_menu(cptr ask, const std::vector<std::string> &items)
+{
+ int ret = -1, i, start = 0;
+ char c;
+ int size = items.size(); // Convert to int to avoid warnings
+
+ /* 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 < size) && (i < start + 20); i++)
+ {
+ prt(format("%c) %s", I2A(i - start), items[i].c_str()), i - start + 1, 0);
+ }
+
+ /* Wait for user input */
+ c = inkey();
+
+ /* Leave the screen */
+ if (c == ESCAPE) break;
+
+ /* Scroll */
+ else if (c == '+')
+ {
+ if (start + 20 < size)
+ 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 >= size)
+ {
+ 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("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);
+}
+
+/*
+ * 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();
+}
+
+/*
+ * Timers
+ */
+timer_type *new_timer(void (*callback)(), s32b delay)
+{
+ timer_type *t_ptr = new timer_type();
+
+ static_assert(std::is_pod<timer_type>::value, "Cannot memset a non-POD type");
+ memset(t_ptr, 0, sizeof(timer_type));
+
+ t_ptr->next = gl_timers;
+ gl_timers = t_ptr;
+
+ t_ptr->callback = callback;
+ t_ptr->delay = delay;
+ t_ptr->countdown = delay;
+ t_ptr->enabled = FALSE;
+
+ return t_ptr;
+}
+
+int get_keymap_mode()
+{
+ if (rogue_like_commands)
+ {
+ return KEYMAP_MODE_ROGUE;
+ }
+ else
+ {
+ return KEYMAP_MODE_ORIG;
+ }
+}
+
+/**
+ * Determines if a map location is fully inside the outer walls
+ */
+bool in_bounds(int y, int x)
+{
+ return (y > 0) && (x > 0) && (y < cur_hgt-1) && (x < cur_wid-1);
+}
+
+/**
+ * Determines if a map location is on or inside the outer walls
+ */
+bool in_bounds2(int y, int x)
+{
+ return (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)".
+ */
+bool panel_contains(int y, int x)
+{
+ return (y >= panel_row_min) && (y <= panel_row_max) && (x >= panel_col_min) && (x <= panel_col_max);
+}
diff --git a/src/util.h b/src/util.h
new file mode 100644
index 00000000..4ae797b9
--- /dev/null
+++ b/src/util.h
@@ -0,0 +1,22 @@
+#pragma once
+
+#include "h-basic.h"
+
+// C linkage required for these functions since main-* code uses them.
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern errr path_parse(char *buf, int max, cptr file);
+extern errr path_build(char *buf, int max, cptr path, cptr file);
+extern void bell(void);
+extern errr macro_add(cptr pat, cptr act);
+extern sint macro_find_exact(cptr pat);
+extern char inkey(void);
+extern void prt(cptr str, int row, int col);
+extern void pause_line(int row);
+extern void user_name(char *buf, int id);
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
diff --git a/src/util.hpp b/src/util.hpp
new file mode 100644
index 00000000..bb8a64f4
--- /dev/null
+++ b/src/util.hpp
@@ -0,0 +1,74 @@
+#pragma once
+
+#include "h-basic.h"
+#include "timer_type_fwd.hpp"
+
+#include <vector>
+#include <string>
+
+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 cptr get_player_race_name(int pr, int ps);
+extern cptr get_day(int day);
+extern s32b bst(s32b what, s32b t);
+extern errr path_temp(char *buf, int max);
+extern FILE *my_fopen(cptr file, cptr mode);
+extern errr my_fgets(FILE *fff, char *buf, huge n);
+extern errr my_fclose(FILE *fff);
+extern errr fd_kill(cptr file);
+extern errr fd_move(cptr file, cptr what);
+extern int fd_make(cptr file, int mode);
+extern int fd_open(cptr file, int flags);
+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 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 char inkey_scan(void);
+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 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_from(int row);
+extern int ask_menu(cptr ask, const std::vector<std::string> &items);
+extern bool_ askfor_aux(char *buf, int len);
+extern bool_ askfor_aux_with_completion(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 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(void (*callback)(), s32b delay);
+extern int get_keymap_mode();
+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);
+extern bool in_bounds(int y, int x);
+extern bool in_bounds2(int y, int x);
+extern bool panel_contains(int y, int x);
diff --git a/src/util.pkg b/src/util.pkg
deleted file mode 100644
index 39f70b40..00000000
--- a/src/util.pkg
+++ /dev/null
@@ -1,2683 +0,0 @@
-/* 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
deleted file mode 100644
index 0eb0fadf..00000000
--- a/src/variable.c
+++ /dev/null
@@ -1,1604 +0,0 @@
-/* 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/variable.cc b/src/variable.cc
new file mode 100644
index 00000000..f0d18111
--- /dev/null
+++ b/src/variable.cc
@@ -0,0 +1,1065 @@
+/*
+ * 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 "variable.hpp"
+#include "variable.h"
+
+#include "cli_comm_fwd.hpp"
+#include "player_type.hpp"
+#include "randart_gen_type.hpp"
+#include "util.hpp"
+
+
+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;
+
+/*
+ * Savefile version
+ */
+byte sf_major; /* Savefile's "version_major" */
+byte sf_minor; /* Savefile's "version_minor" */
+byte sf_patch; /* Savefile's "version_patch" */
+
+/*
+ * Savefile information
+ */
+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 aruments
+ */
+bool_ arg_wizard; /* Command arg -- Request wizard mode */
+bool_ arg_force_original; /* Command arg -- Request original keyset */
+bool_ arg_force_roguelike; /* Command arg -- Request roguelike keyset */
+
+/*
+ * 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_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? */
+
+u16b total_winner; /* Semi-Hack -- Game has been won */
+u16b has_won; /* Semi-Hack -- Game has been won */
+
+u16b noscore; /* Track various "cheating" conditions */
+
+bool_ inkey_base; /* 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_ hack_mind;
+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()" */
+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 -- Indentation for the text when using text_out().
+ */
+int text_out_indent = 0;
+
+
+/*
+ * Software options (set via the '=' command). See "tables.c"
+ */
+
+
+
+
+/* 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 */
+
+/*
+ * 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;
+
+
+
+/*
+ * 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]
+ */
+char **macro__pat;
+
+/*
+ * Array of macro actions [MACRO_MAX]
+ */
+char **macro__act;
+
+/*
+ * Array of macro types [MACRO_MAX]
+ */
+bool_ *macro__cmd;
+
+/*
+ * Current macro action [1024]
+ */
+char *macro__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 */
+};
+
+
+/*
+ * The array of "cave grids" [MAX_WID][MAX_HGT].
+ */
+cave_type **cave = nullptr;
+
+/*
+ * 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 * ALLOCATIONS_MAX)
+ */
+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.
+ */
+char *keymap_act[KEYMAP_MODES][256];
+
+
+
+/*** Player information ***/
+
+/*
+ * Pointer to the player info
+ */
+player_type *p_ptr = nullptr;
+
+/*
+ * 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;
+
+
+/*
+ * 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 vault generation arrays
+ */
+vault_type *v_info;
+
+/*
+ * The terrain feature arrays
+ */
+feature_type *f_info;
+
+/*
+ * The object kind arrays
+ */
+object_kind *k_info;
+
+/*
+ * The artifact arrays
+ */
+artifact_type *a_info;
+
+/*
+ * The item set arrays
+ */
+set_type *set_info;
+
+/*
+ * The ego-item arrays
+ */
+ego_item_type *e_info;
+
+/*
+ * The randart arrays
+ */
+randart_part_type *ra_info;
+randart_gen_type ra_gen[30];
+
+/* jk */
+/* the trap-arrays */
+trap_type *t_info;
+
+/*
+ * The monster race arrays
+ */
+monster_race *r_info;
+
+/*
+ * The monster ego race arrays
+ */
+monster_ego *re_info;
+
+/*
+ * The dungeon types arrays
+ */
+dungeon_info_type *d_info;
+
+/*
+ * Player abilities arrays
+ */
+ability_type *ab_info;
+
+/*
+ * Player skills arrays
+ */
+skill_type *s_info;
+
+/*
+ * Player race arrays
+ */
+player_race *race_info;
+
+/*
+ * Player mod race arrays
+ */
+player_race_mod *race_mod_info;
+
+/*
+ * Player class arrays
+ */
+player_class *class_info;
+meta_class_type *meta_class_info;
+
+/*
+ * The wilderness features arrays
+ */
+wilderness_type_info *wf_info;
+int wildc2i[256];
+
+/*
+ * The store/building types arrays
+ */
+store_info_type *st_info;
+
+/*
+ * The building actions types arrays
+ */
+store_action_type *ba_info;
+
+/*
+ * The owner types arrays
+ */
+owner_type *ow_info;
+
+/*
+ * Default texts for feature information.
+ */
+cptr DEFAULT_FEAT_TEXT = "a wall blocking your way";
+cptr DEFAULT_FEAT_TUNNEL = "You cannot tunnel through that.";
+cptr DEFAULT_FEAT_BLOCK = DEFAULT_FEAT_TEXT;
+
+/*
+ * Hack -- The special Angband "System Suffix"
+ * This variable is used to choose an appropriate "pref-xxx" file
+ */
+cptr ANGBAND_SYS = "xxx";
+
+/*
+ * Path name: The main "lib" directory
+ * This variable is not actually used anywhere in the code
+ */
+char *ANGBAND_DIR;
+
+/*
+ * Core lua system
+ * These files are portable between platforms
+ */
+char *ANGBAND_DIR_CORE;
+
+/*
+ * Textual dungeon level definition files
+ * These files are portable between platforms
+ */
+char *ANGBAND_DIR_DNGN;
+
+/*
+ * Binary image files for the "*_info" arrays (binary)
+ * These files are not portable between platforms
+ */
+char *ANGBAND_DIR_DATA;
+
+/*
+ * Textual template files for the "*_info" arrays (ascii)
+ * These files are portable between platforms
+ */
+char *ANGBAND_DIR_EDIT;
+
+/*
+ * Various extra files (ascii)
+ * These files may be portable between platforms
+ */
+char *ANGBAND_DIR_FILE;
+
+/*
+ * Help files (normal) for the online help (ascii)
+ * These files are portable between platforms
+ */
+char *ANGBAND_DIR_HELP;
+
+/*
+ * Help files (spoilers) for the online help (ascii)
+ * These files are portable between platforms
+ */
+char *ANGBAND_DIR_INFO;
+
+/*
+ * Modules, those subdirectories are half-mirrors of lib/
+ */
+char *ANGBAND_DIR_MODULES;
+
+/*
+ * Textual template files for the plot files (ascii)
+ * These files are portable between platforms
+ */
+char *ANGBAND_DIR_NOTE;
+
+/*
+ * Savefiles for current characters (binary)
+ * These files are portable between platforms
+ */
+char *ANGBAND_DIR_SAVE;
+
+/*
+ * Default "preference" files (ascii)
+ * These files are rarely portable between platforms
+ */
+char *ANGBAND_DIR_PREF;
+
+/*
+ * User "preference" files (ascii)
+ * These files are rarely portable between platforms
+ */
+char *ANGBAND_DIR_USER;
+
+/*
+ * Various extra files (binary)
+ * These files are rarely portable between platforms
+ */
+char *ANGBAND_DIR_XTRA;
+
+
+
+/*
+ * 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);
+
+/*
+ * Devices
+ */
+s32b get_level_max_stick = -1;
+s32b get_level_use_stick = -1;
+
+/*
+ * 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 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
+ */
+u16b 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;
+
+/*
+ * 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;
+
+/* The Doppleganger index in m_list */
+s16b doppleganger;
+
+/* To allow wilderness encounters */
+bool_ generate_encounter;
+
+/* Special levels */
+bool_ special_lvls;
+
+/*
+ * Such an ugly hack ...
+ */
+bool_ *m_allow_special;
+bool_ *k_allow_special;
+bool_ *a_allow_special;
+
+/*
+ * Plots
+ */
+s16b plots[MAX_PLOTS];
+
+/*
+ * Random quest
+ */
+random_quest random_quests[MAX_RANDOM_QUEST];
+
+/*
+ * Special levels
+ */
+bool_ *special_lvl[MAX_DUNGEON_DEPTH];
+bool_ generate_special_feeling = FALSE;
+
+/*
+ * Dungeon flags
+ */
+u32b dungeon_flags1;
+u32b dungeon_flags2;
+
+/*
+ * The last character displayed
+ */
+birther previous_char;
+
+/*
+ * Race histories
+ */
+hist_type *bg;
+int max_bg_idx;
+
+/*
+ * The spell list of schools
+ */
+s16b schools_count = 0;
+school_type schools[SCHOOLS_MAX];
+
+/*
+ * 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];
+
+/*
+ * 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 = 127;
+
+/*
+ * Automatizer enabled status
+ */
+bool_ automatizer_enabled = FALSE;
+bool_ automatizer_create = 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 game_module_idx;
+s32b VERSION_MAJOR;
+s32b VERSION_MINOR;
+s32b VERSION_PATCH;
+
+/*
+ * Some module info
+ */
+s32b max_plev = 50;
+s32b DUNGEON_BASE = 4;
+s32b DUNGEON_DEATH = 28;
+s32b DUNGEON_ASTRAL = 8;
+s32b DUNGEON_ASTRAL_WILD_X = 45;
+s32b DUNGEON_ASTRAL_WILD_Y = 19;
+
+/*
+ * 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;
+}
+
+/*
+ * A list of tvals and their textual names
+ */
+tval_desc 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_PARCHMENT, "Parchment" },
+ { TV_INSTRUMENT, "Musical Instrument" },
+ { TV_RUNE1, "Rune 1" },
+ { TV_RUNE2, "Rune 2" },
+ { TV_JUNK, "Junk" },
+ { TV_TRAPKIT, "Trapping Kit" },
+ { 0, NULL }
+};
diff --git a/src/variable.h b/src/variable.h
new file mode 100644
index 00000000..7621149a
--- /dev/null
+++ b/src/variable.h
@@ -0,0 +1,39 @@
+#pragma once
+
+#include "angband.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern cptr ANGBAND_SYS;
+extern char *ANGBAND_DIR_MODULES;
+extern char *ANGBAND_DIR_SAVE;
+extern char *ANGBAND_DIR_CORE;
+extern char *ANGBAND_DIR_DNGN;
+extern char *ANGBAND_DIR_DATA;
+extern char *ANGBAND_DIR_EDIT;
+extern char *ANGBAND_DIR_FILE;
+extern char *ANGBAND_DIR_HELP;
+extern char *ANGBAND_DIR_INFO;
+extern char *ANGBAND_DIR_NOTE;
+extern char *ANGBAND_DIR_PREF;
+extern char *ANGBAND_DIR_USER;
+extern char *ANGBAND_DIR_XTRA;
+extern term *angband_term[ANGBAND_TERM_MAX];
+extern char angband_term_name[ANGBAND_TERM_MAX][80];
+extern byte angband_color_table[256][4];
+extern bool_ arg_wizard;
+extern bool_ arg_force_original;
+extern bool_ arg_force_roguelike;
+extern bool_ character_generated;
+extern bool_ character_icky;
+extern bool_ inkey_flag;
+extern bool_ msg_flag;
+extern char player_name[32];
+extern char player_base[32];
+extern char savefile[1024];
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
diff --git a/src/variable.hpp b/src/variable.hpp
new file mode 100644
index 00000000..ab52f5b6
--- /dev/null
+++ b/src/variable.hpp
@@ -0,0 +1,308 @@
+#pragma once
+
+#include "angband.h"
+#include "ability_type_fwd.hpp"
+#include "alloc_entry_fwd.hpp"
+#include "artifact_type_fwd.hpp"
+#include "birther.hpp"
+#include "cave_type_fwd.hpp"
+#include "deity_type.hpp"
+#include "dungeon_info_type_fwd.hpp"
+#include "effect_type.hpp"
+#include "ego_item_type_fwd.hpp"
+#include "fate.hpp"
+#include "feature_type_fwd.hpp"
+#include "hist_type_fwd.hpp"
+#include "meta_class_type_fwd.hpp"
+#include "monster_ego_fwd.hpp"
+#include "monster_race_fwd.hpp"
+#include "monster_type_fwd.hpp"
+#include "object_kind_fwd.hpp"
+#include "object_type_fwd.hpp"
+#include "owner_type_fwd.hpp"
+#include "player_class_fwd.hpp"
+#include "player_defs.hpp"
+#include "player_race_fwd.hpp"
+#include "player_race_mod_fwd.hpp"
+#include "player_sex_fwd.hpp"
+#include "player_spec_fwd.hpp"
+#include "player_type_fwd.hpp"
+#include "randart_gen_type_fwd.hpp"
+#include "randart_part_type_fwd.hpp"
+#include "random_artifact.hpp"
+#include "random_quest.hpp"
+#include "random_spell.hpp"
+#include "rune_spell.hpp"
+#include "school_type.hpp"
+#include "set_type_fwd.hpp"
+#include "skill_type_fwd.hpp"
+#include "skills_defs.hpp"
+#include "store_action_type_fwd.hpp"
+#include "store_info_type_fwd.hpp"
+#include "timer_type_fwd.hpp"
+#include "town_type_fwd.hpp"
+#include "trap_type_fwd.hpp"
+#include "tval_desc.hpp"
+#include "vault_type_fwd.hpp"
+#include "wilderness_map_fwd.hpp"
+#include "wilderness_type_info_fwd.hpp"
+
+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];
+extern byte version_major;
+extern byte version_minor;
+extern byte version_patch;
+extern byte sf_major;
+extern byte sf_minor;
+extern byte sf_patch;
+extern u32b sf_when;
+extern u16b sf_lives;
+extern u16b sf_saves;
+extern bool_ character_dungeon;
+extern bool_ character_loaded;
+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 bool_ create_up_stair;
+extern bool_ create_down_stair;
+extern bool_ create_up_shaft;
+extern bool_ create_down_shaft;
+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 u16b total_winner;
+extern u16b has_won;
+extern u16b noscore;
+extern bool_ inkey_base;
+extern s16b coin_type;
+extern bool_ opening_chest;
+extern bool_ shimmer_monsters;
+extern bool_ shimmer_objects;
+extern bool_ repair_monsters;
+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 int total_friends;
+extern s32b total_friend_levels;
+extern int leaving_quest;
+extern char summon_kin_type;
+extern bool_ hack_mind;
+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_indent;
+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 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 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 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 char died_from[80];
+extern char history[4][60];
+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 char **macro__pat;
+extern char **macro__act;
+extern bool_ *macro__cmd;
+extern char *macro__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 cave_type **cave;
+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 char *keymap_act[KEYMAP_MODES][256];
+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 s16b player_hp[PY_MAX_LEVEL];
+extern ability_type *ab_info;
+extern skill_type *s_info;
+extern vault_type *v_info;
+extern feature_type *f_info;
+extern object_kind *k_info;
+extern artifact_type *a_info;
+extern ego_item_type *e_info;
+extern randart_part_type *ra_info;
+extern randart_gen_type ra_gen[30];
+extern monster_race *r_info;
+extern monster_ego *re_info;
+extern dungeon_info_type *d_info;
+extern player_class *class_info;
+extern meta_class_type *meta_class_info;
+extern player_race *race_info;
+extern player_race_mod *race_mod_info;
+extern trap_type *t_info;
+extern wilderness_type_info *wf_info;
+extern int wildc2i[256];
+extern store_info_type *st_info;
+extern store_action_type *ba_info;
+extern owner_type *ow_info;
+extern set_type *set_info;
+extern cptr DEFAULT_FEAT_TEXT;
+extern cptr DEFAULT_FEAT_TUNNEL;
+extern cptr DEFAULT_FEAT_BLOCK;
+extern char *ANGBAND_DIR;
+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 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_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 u16b 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 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 s16b doppleganger;
+extern bool_ generate_encounter;
+extern bool_ special_lvls;
+extern bool_ *m_allow_special;
+extern bool_ *k_allow_special;
+extern bool_ *a_allow_special;
+extern s16b plots[MAX_PLOTS];
+extern random_quest random_quests[MAX_RANDOM_QUEST];
+extern bool_ *special_lvl[MAX_DUNGEON_DEPTH];
+extern bool_ generate_special_feeling;
+extern u32b dungeon_flags1;
+extern u32b dungeon_flags2;
+extern birther previous_char;
+extern int max_bg_idx;
+extern s16b schools_count;
+extern school_type schools[SCHOOLS_MAX];
+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 int max_bact;
+extern bool_ automatizer_enabled;
+extern s16b last_teleportation_y;
+extern s16b last_teleportation_x;
+extern cptr game_module;
+extern s32b game_module_idx;
+extern s32b VERSION_MAJOR;
+extern s32b VERSION_MINOR;
+extern s32b VERSION_PATCH;
+extern s32b max_plev;
+extern s32b DUNGEON_BASE;
+extern s32b DUNGEON_DEATH;
+extern s32b DUNGEON_ASTRAL;
+extern s32b DUNGEON_ASTRAL_WILD_X;
+extern s32b DUNGEON_ASTRAL_WILD_Y;
+extern deity_type deity_info[MAX_GODS];
+extern timer_type *gl_timers;
+extern const char *get_version_string();
+extern tval_desc tvals[];
+extern hist_type *bg;
diff --git a/src/vault_type.hpp b/src/vault_type.hpp
new file mode 100644
index 00000000..650599cb
--- /dev/null
+++ b/src/vault_type.hpp
@@ -0,0 +1,24 @@
+#pragma once
+
+#include "h-basic.h"
+
+/**
+ * Vault descriptors.
+ */
+struct vault_type
+{
+ char *data; /* Vault data */
+
+ 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) */
+};
diff --git a/src/vault_type_fwd.hpp b/src/vault_type_fwd.hpp
new file mode 100644
index 00000000..25ffd8cc
--- /dev/null
+++ b/src/vault_type_fwd.hpp
@@ -0,0 +1,3 @@
+#pragma once
+
+struct vault_type;
diff --git a/src/wild.c b/src/wild.c
deleted file mode 100644
index 7a9d1c51..00000000
--- a/src/wild.c
+++ /dev/null
@@ -1,1275 +0,0 @@
-/* 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/wild.cc b/src/wild.cc
new file mode 100644
index 00000000..7724176f
--- /dev/null
+++ b/src/wild.cc
@@ -0,0 +1,1301 @@
+/*
+ * 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 "wild.hpp"
+
+#include "cave.hpp"
+#include "cave_type.hpp"
+#include "feature_type.hpp"
+#include "hook_wild_gen_in.hpp"
+#include "hooks.hpp"
+#include "init1.hpp"
+#include "monster2.hpp"
+#include "monster_race.hpp"
+#include "monster_type.hpp"
+#include "options.hpp"
+#include "player_type.hpp"
+#include "store_info_type.hpp"
+#include "tables.hpp"
+#include "town_type.hpp"
+#include "util.hpp"
+#include "variable.hpp"
+#include "wilderness_map.hpp"
+#include "wilderness_type_info.hpp"
+#include "z-rand.hpp"
+
+#include <memory>
+
+
+/*
+ * 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 = static_cast<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 = static_cast<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
+ */
+static int generate_area(int y, int x, bool_ border, bool_ corner)
+{
+ 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;
+
+ /* 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, rand_int(MAX_WILD_TERRAIN));
+ cave_set_feat(MAX_HGT - 2, 1, rand_int(MAX_WILD_TERRAIN));
+ cave_set_feat(1, MAX_WID - 2, rand_int(MAX_WILD_TERRAIN));
+ cave_set_feat(MAX_HGT - 2, MAX_WID - 2, 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
+ */
+namespace {
+
+ 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;
+ };
+
+ border_type border;
+
+}
+
+/*
+ * Build the wilderness area outside of the town.
+ * -KMW-
+ */
+void wilderness_gen()
+{
+ 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);
+
+ 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);
+
+ for (i = 1; i < MAX_WID - 1; i++)
+ {
+ border.south[i] = cave[1][i].feat;
+ }
+
+ /* West border */
+ generate_area(y, x - 1, TRUE, FALSE);
+
+ 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);
+
+ 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);
+ border.north_west = cave[MAX_HGT - 2][MAX_WID - 2].feat;
+
+ /* North east corner */
+ generate_area(y - 1, x + 1, FALSE, TRUE);
+ border.north_east = cave[MAX_HGT - 2][1].feat;
+
+ /* South west corner */
+ generate_area(y + 1, x - 1, FALSE, TRUE);
+ border.south_west = cave[1][MAX_WID - 2].feat;
+
+ /* South east corner */
+ generate_area(y + 1, x + 1, FALSE, TRUE);
+ border.south_east = cave[1][1].feat;
+
+
+ /* Create terrain of the current area */
+ hack_floor = generate_area(y, x, FALSE, FALSE);
+
+
+ /* 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);
+
+ {
+ 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;
+ }
+ }
+
+ struct hook_wild_gen_in in = { FALSE };
+ process_hooks_new(HOOK_WILD_GEN, &in, NULL);
+}
+
+/*
+ * 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;
+ }
+ }
+
+ struct hook_wild_gen_in in = { TRUE };
+ process_hooks_new(HOOK_WILD_GEN, &in, NULL);
+}
+
+/* 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);
+
+ /* 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 */
+ std::unique_ptr<int[]> rooms(new int[max_st_idx]);
+ num = get_shops(rooms.get());
+
+ /* 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);
+ }
+ }
+ }
+
+ /* 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);
+
+ /* 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 */
+ std::unique_ptr<int[]> rooms(new int[max_st_idx]);
+ num = get_shops(rooms.get());
+
+ /* 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);
+ }
+ }
+ }
+
+ /* 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;
+
+ /* Prepare an Array of "remaining stores", and count them */
+ std::unique_ptr<int[]> rooms(new int[max_st_idx]);
+ num = get_shops(rooms.get());
+
+ /* 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);
+ }
+ }
+}
+
+
+
+/*
+ * 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/wild.hpp b/src/wild.hpp
new file mode 100644
index 00000000..4cd9f0e7
--- /dev/null
+++ b/src/wild.hpp
@@ -0,0 +1,6 @@
+#pragma once
+
+extern void wilderness_gen();
+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);
diff --git a/src/wilderness_map.hpp b/src/wilderness_map.hpp
new file mode 100644
index 00000000..41e873bd
--- /dev/null
+++ b/src/wilderness_map.hpp
@@ -0,0 +1,15 @@
+#pragma once
+
+#include "h-basic.h"
+
+/**
+ * A structure describing a 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 ? */
+};
diff --git a/src/wilderness_map_fwd.hpp b/src/wilderness_map_fwd.hpp
new file mode 100644
index 00000000..806efb1b
--- /dev/null
+++ b/src/wilderness_map_fwd.hpp
@@ -0,0 +1,3 @@
+#pragma once
+
+struct wilderness_map;
diff --git a/src/wilderness_type_info.hpp b/src/wilderness_type_info.hpp
new file mode 100644
index 00000000..bc23c03e
--- /dev/null
+++ b/src/wilderness_type_info.hpp
@@ -0,0 +1,25 @@
+#pragma once
+
+#include "h-basic.h"
+#include "terrain.hpp"
+
+/**
+ * A structure describing a wilderness area
+ * with a terrain, a town or a dungeon entrance
+ */
+struct wilderness_type_info
+{
+ const char *name; /* Name */
+ const char *text; /* Text */
+
+ 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 */
+};
diff --git a/src/wilderness_type_info_fwd.hpp b/src/wilderness_type_info_fwd.hpp
new file mode 100644
index 00000000..a206c9e3
--- /dev/null
+++ b/src/wilderness_type_info_fwd.hpp
@@ -0,0 +1,3 @@
+#pragma once
+
+struct wilderness_type_info;
diff --git a/src/wizard1.c b/src/wizard1.c
deleted file mode 100644
index 7daef324..00000000
--- a/src/wizard1.c
+++ /dev/null
@@ -1,2756 +0,0 @@
-/* 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/wizard1.cc b/src/wizard1.cc
new file mode 100644
index 00000000..616a46cd
--- /dev/null
+++ b/src/wizard1.cc
@@ -0,0 +1,2499 @@
+#include "wizard1.hpp"
+
+#include "artifact_type.hpp"
+#include "cmd7.hpp"
+#include "ego_item_type.hpp"
+#include "monster_race.hpp"
+#include "object1.hpp"
+#include "object2.hpp"
+#include "object_kind.hpp"
+#include "object_type.hpp"
+#include "skill_type.hpp"
+#include "tables.hpp"
+#include "util.hpp"
+#include "util.h"
+#include "variable.h"
+#include "variable.hpp"
+
+#include <vector>
+
+/*
+ * 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_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))
+ {
+ apply_magic(q_ptr, 0, FALSE, FALSE, FALSE, boost::make_optional(0));
+ }
+
+ /* 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);
+
+ /* 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);
+
+ /* 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)
+{
+ 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);
+
+ /* Open the file */
+ fff = my_fopen(buf, "w");
+
+ /* Oops */
+ if (!fff)
+ {
+ msg_print("Cannot create spoiler file.");
+ return;
+ }
+
+ /* Allocate the "who" array */
+ std::vector<s16b> who;
+
+ /* 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 (size_t i = 1; i < max_r_idx; i++)
+ {
+ monster_race *r_ptr = &r_info[i];
+
+ /* Use that monster */
+ if (r_ptr->name) {
+ who.push_back(i);
+ }
+ }
+
+
+ /* Scan again */
+ for (auto const who_i : who)
+ {
+ monster_race *r_ptr = &r_info[who_i];
+
+ /* Get the "name" */
+ if (r_ptr->flags1 & (RF1_UNIQUE))
+ {
+ sprintf(nam, "[U] %s", r_ptr->name);
+ }
+ else
+ {
+ sprintf(nam, "The %s", r_ptr->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");
+
+ /* 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);
+
+ /* 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_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_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.");
+}
+
+/*
+ * 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);
+ 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);
+
+ 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.");
+}
+
+
+/*
+ * Create Spoiler files -BEN-
+ */
+void do_cmd_spoilers()
+{
+ 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) 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_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/wizard1.hpp b/src/wizard1.hpp
new file mode 100644
index 00000000..0429aa70
--- /dev/null
+++ b/src/wizard1.hpp
@@ -0,0 +1,3 @@
+#pragma once
+
+void do_cmd_spoilers();
diff --git a/src/wizard2.c b/src/wizard2.c
deleted file mode 100644
index a19b72e0..00000000
--- a/src/wizard2.c
+++ /dev/null
@@ -1,1950 +0,0 @@
-/* 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/wizard2.cc b/src/wizard2.cc
new file mode 100644
index 00000000..837d778b
--- /dev/null
+++ b/src/wizard2.cc
@@ -0,0 +1,1868 @@
+/*
+ * 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 "wizard2.hpp"
+
+#include "artifact_type.hpp"
+#include "cave.hpp"
+#include "cave_type.hpp"
+#include "cmd4.hpp"
+#include "corrupt.hpp"
+#include "dungeon_info_type.hpp"
+#include "files.hpp"
+#include "hooks.hpp"
+#include "monster2.hpp"
+#include "monster_race.hpp"
+#include "monster_type.hpp"
+#include "object1.hpp"
+#include "object2.hpp"
+#include "object_kind.hpp"
+#include "player_type.hpp"
+#include "randart.hpp"
+#include "status.hpp"
+#include "spells1.hpp"
+#include "spells2.hpp"
+#include "stats.hpp"
+#include "tables.hpp"
+#include "traps.hpp"
+#include "util.hpp"
+#include "util.h"
+#include "variable.h"
+#include "variable.hpp"
+#include "wilderness_map.hpp"
+#include "wilderness_type_info.hpp"
+#include "wizard1.hpp"
+#include "xtra1.hpp"
+#include "xtra2.hpp"
+#include "z-rand.hpp"
+
+/*
+ * Adds a lvl to a monster
+ */
+static 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);
+ }
+}
+
+static 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
+ */
+static 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;
+
+ 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_FRAME);
+
+ /* 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.");
+}
+
+/* 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);
+}
+
+
+/*
+ * 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, "%ld", (long) (p_ptr->grace));
+
+ /* Query */
+ if (!get_string("Piety: ", tmp_val, 9)) return;
+
+ /* Extract */
+ tmp_long = atol(tmp_val);
+
+ /* Verify */
+ if (tmp_long < 0) tmp_long = 0L;
+
+ /* Save */
+ p_ptr->grace = tmp_long;
+
+
+ /* 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);
+}
+
+
+
+/*
+ * 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_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);
+ apply_magic(q_ptr, dun_level, FALSE, FALSE, FALSE, boost::make_optional(-2));
+ }
+
+ /* 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;
+ const 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))
+ {
+ /* Allow interupt */
+ if (inkey_scan())
+ {
+ /* 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)
+{
+ /* Get an item */
+ int item;
+ if (!get_item(&item,
+ "Play with which object? ",
+ "You have nothing to play with.",
+ (USE_EQUIP | USE_INVEN | USE_FLOOR)))
+ {
+ return;
+ }
+
+ /* Get the item */
+ object_type *o_ptr = get_object(item);
+
+
+ /* The item was not changed */
+ bool_ changed = FALSE;
+
+
+ /* Icky */
+ character_icky = TRUE;
+
+ /* Save the screen */
+ Term_save();
+
+
+ /* Get local object */
+ object_type forge;
+ object_type *q_ptr = &forge;
+
+ /* Copy object */
+ object_copy(q_ptr, o_ptr);
+
+
+ /* The main loop */
+ while (TRUE)
+ {
+ char ch;
+
+ /* 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;
+
+ 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;
+ int m_idx = place_monster_aux(y, x, r_idx, slp, TRUE, MSTATUS_ENEMY);
+ m_allow_special[r_idx] = FALSE;
+
+ // If summoning succeeded, we stop.
+ if (m_idx)
+ {
+ break;
+ }
+ }
+}
+
+
+/*
+ * 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 */
+ 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;
+ int m_idx = place_monster_aux(y, x, r_idx, slp, TRUE, MSTATUS_PET);
+ m_allow_special[r_idx] = FALSE;
+
+ // Stop if we succeeded
+ if (m_idx)
+ {
+ break;
+ }
+ }
+}
+
+
+
+/*
+ * 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);
+ }
+}
+
+
+static 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();
+}
+
+
+/*
+ * Ask for and parse a "debug command"
+ * The "command_arg" may have been set.
+ */
+void do_cmd_debug()
+{
+ 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_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;
+
+ case 'H':
+ do_cmd_summon_horde(); break;
+
+ /* 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':
+ gain_random_corruption();
+ 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) && (command_arg != QUEST_RANDOM))
+ {
+ quest[command_arg].status = QUEST_STATUS_TAKEN;
+ *(quest[command_arg].plot) = command_arg;
+ 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_FRAME);
+
+ /* 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;
+
+ /* Mimic shape changing */
+ case '*':
+ p_ptr->tim_mimic = 100;
+ p_ptr->mimic_form = command_arg;
+ /* Redraw title */
+ p_ptr->redraw |= (PR_FRAME);
+ /* 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;
+
+ /* Not a Wizard Command */
+ default:
+ msg_print("That is not a valid debug command.");
+ break;
+ }
+}
diff --git a/src/wizard2.hpp b/src/wizard2.hpp
new file mode 100644
index 00000000..cec515c8
--- /dev/null
+++ b/src/wizard2.hpp
@@ -0,0 +1,8 @@
+#pragma once
+
+#include "h-basic.h"
+
+extern void do_cmd_rerate(void);
+extern void do_cmd_wiz_cure_all(void);
+extern void do_cmd_wiz_named_friendly(int r_idx, bool_ slp);
+extern void do_cmd_debug();
diff --git a/src/xtra1.c b/src/xtra1.c
deleted file mode 100644
index 933bc265..00000000
--- a/src/xtra1.c
+++ /dev/null
@@ -1,4772 +0,0 @@
-/* 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/xtra1.cc b/src/xtra1.cc
new file mode 100644
index 00000000..fd4a11fd
--- /dev/null
+++ b/src/xtra1.cc
@@ -0,0 +1,4684 @@
+/*
+ * 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 "xtra1.hpp"
+
+#include "artifact_type.hpp"
+#include "cave.hpp"
+#include "cave_type.hpp"
+#include "corrupt.hpp"
+#include "cmd7.hpp"
+#include "dungeon_info_type.hpp"
+#include "files.hpp"
+#include "gods.hpp"
+#include "hook_calculate_hp_in.hpp"
+#include "hook_calculate_hp_out.hpp"
+#include "hooks.hpp"
+#include "levels.hpp"
+#include "messages.hpp"
+#include "mimic.hpp"
+#include "monster1.hpp"
+#include "monster2.hpp"
+#include "monster_race.hpp"
+#include "monster_type.hpp"
+#include "object1.hpp"
+#include "object2.hpp"
+#include "object_kind.hpp"
+#include "options.hpp"
+#include "player_class.hpp"
+#include "player_race.hpp"
+#include "player_race_mod.hpp"
+#include "player_type.hpp"
+#include "skill_type.hpp"
+#include "skills.hpp"
+#include "spells3.hpp"
+#include "spells6.hpp"
+#include "stats.hpp"
+#include "tables.hpp"
+#include "util.hpp"
+#include "util.h"
+#include "variable.h"
+#include "variable.hpp"
+#include "wilderness_map.hpp"
+#include "wilderness_type_info.hpp"
+#include "xtra2.hpp"
+#include "z-rand.hpp"
+
+#include <cassert>
+
+/*
+ * 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--;
+ }
+ }
+
+ /* Clip to permissible range */
+ if (value < 3)
+ {
+ value = 3;
+ }
+
+ /* 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)
+ {
+ p = get_mimic_name(p_ptr->mimic_form);
+ }
+
+ /* 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];
+
+ }
+
+ 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 ((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(int row, int col)
+{
+ char depths[32];
+ dungeon_info_type *d_ptr = &d_info[dungeon_type];
+
+ if (p_ptr->wild_mode)
+ {
+ strcpy(depths, " ");
+ }
+ 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)
+ {
+ strcpy(depths, wf_info[wild_map[p_ptr->wilderness_y][p_ptr->wilderness_x].feat].name);
+ }
+ else
+ {
+ strcpy(depths, "Town/Wild");
+ }
+ }
+ 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, col);
+ else
+ prt(format("%13s", depths), row, col);
+}
+
+
+/*
+ * 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(int row, int col)
+{
+ 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, col);
+}
+
+
+/*
+ * Prints the speed of a character. -CJS-
+ */
+static void prt_speed(int row, int col)
+{
+ 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, col);
+}
+
+
+
+/*
+ * Prints status line
+ */
+static void prt_status_line(void)
+{
+ int wid, hgt;
+ Term_get_size(&wid, &hgt);
+ int row = hgt - 1;
+
+ /* Fainting / Starving */
+ int col = 0;
+ if (p_ptr->food < PY_FOOD_FAINT)
+ {
+ c_put_str(TERM_RED, "Weak ", row, col);
+ }
+ else if (p_ptr->food < PY_FOOD_WEAK)
+ {
+ c_put_str(TERM_ORANGE, "Weak ", row, col);
+ }
+ else if (p_ptr->food < PY_FOOD_ALERT)
+ {
+ c_put_str(TERM_YELLOW, "Hungry", row, col);
+ }
+ else if (p_ptr->food < PY_FOOD_FULL)
+ {
+ c_put_str(TERM_L_GREEN, " ", row, col);
+ }
+ else if (p_ptr->food < PY_FOOD_MAX)
+ {
+ c_put_str(TERM_L_GREEN, "Full ", row, col);
+ }
+ else
+ {
+ c_put_str(TERM_GREEN, "Gorged", row, col);
+ }
+
+ /* Blind */
+ col = 7;
+ if (p_ptr->blind)
+ {
+ c_put_str(TERM_ORANGE, "Blind", row, col);
+ }
+ else
+ {
+ put_str(" ", row, col);
+ }
+
+ /* Confusion */
+ col = 13;
+ if (p_ptr->confused)
+ {
+ c_put_str(TERM_ORANGE, "Conf", row, col);
+ }
+ else
+ {
+ put_str(" ", row, col);
+ }
+
+ /* Fear */
+ col = 18;
+ if (p_ptr->afraid)
+ {
+ c_put_str(TERM_ORANGE, "Afraid", row, col);
+ }
+ else
+ {
+ put_str(" ", row, col);
+ }
+
+ /* Poison */
+ col = 25;
+ if (p_ptr->poisoned)
+ {
+ c_put_str(TERM_ORANGE, "Poison", row, col);
+ }
+ else
+ {
+ put_str(" ", row, col);
+ }
+
+ /* Dtrap */
+ col = 32;
+ if (cave[p_ptr->py][p_ptr->px].info & CAVE_DETECT)
+ {
+ c_put_str(TERM_L_GREEN, "DTrap", row, col);
+ }
+ else
+ {
+ put_str(" ", row, col);
+ }
+
+ /* State */
+ col = 38;
+ prt_state(row, col);
+
+ /* Speed */
+ col = 49;
+ prt_speed(row, col);
+
+ /* "Study" */
+ col = 60;
+ if (p_ptr->skill_points)
+ {
+ put_str("Skill", row, col);
+ }
+ else
+ {
+ put_str(" ", row, col);
+ }
+
+ /* Depth */
+ col = wid - 14;
+ prt_depth(row, col);
+}
+
+
+
+static void prt_cut(void)
+{
+ int c = p_ptr->cut;
+ int hgt;
+ Term_get_size(nullptr, &hgt);
+ int row = hgt - 3;
+ int col = 0;
+
+ if (c > 1000)
+ {
+ c_put_str(TERM_L_RED, "Mortal wound", row, col);
+ }
+ else if (c > 200)
+ {
+ c_put_str(TERM_RED, "Deep gash ", row, col);
+ }
+ else if (c > 100)
+ {
+ c_put_str(TERM_RED, "Severe cut ", row, col);
+ }
+ else if (c > 50)
+ {
+ c_put_str(TERM_ORANGE, "Nasty cut ", row, col);
+ }
+ else if (c > 25)
+ {
+ c_put_str(TERM_ORANGE, "Bad cut ", row, col);
+ }
+ else if (c > 10)
+ {
+ c_put_str(TERM_YELLOW, "Light cut ", row, col);
+ }
+ else if (c)
+ {
+ c_put_str(TERM_YELLOW, "Graze ", row, col);
+ }
+ else
+ {
+ put_str(" ", row, col);
+ }
+}
+
+
+
+static void prt_stun(void)
+{
+ int s = p_ptr->stun;
+ int hgt;
+ Term_get_size(nullptr, &hgt);
+ int row = hgt - 2;
+ int col = 0;
+
+ if (s > 100)
+ {
+ c_put_str(TERM_RED, "Knocked out ", row, col);
+ }
+ else if (s > 50)
+ {
+ c_put_str(TERM_ORANGE, "Heavy stun ", row, col);
+ }
+ else if (s)
+ {
+ c_put_str(TERM_ORANGE, "Stun ", row, col);
+ }
+ else
+ {
+ put_str(" ", row, col);
+ }
+}
+
+
+
+/*
+ * 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)
+{
+ int hgt;
+ Term_get_size(nullptr, &hgt);
+ int col = 0;
+ int row = hgt - 4;
+
+ /* Not tracking */
+ if (!health_who)
+ {
+ /* Erase the health bar */
+ Term_erase(col, row, 12);
+ }
+
+ /* Tracking an unseen monster */
+ else if (!m_list[health_who].ml)
+ {
+ /* Indicate that the monster health is "unknown" */
+ Term_putstr(col, row, 12, TERM_WHITE, "[----------]");
+ }
+
+ /* Tracking a hallucinatory monster */
+ else if (p_ptr->image)
+ {
+ /* Indicate that the monster health is "unknown" */
+ Term_putstr(col, row, 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, row, 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, row, 12, TERM_WHITE, "[----------]");
+
+ /* Dump the current "health" (use '*' symbols) */
+ if (m_ptr->stunned) {
+ Term_putstr(col + 1, row, len, attr, "ssssssssss");
+ } else if (m_ptr->confused) {
+ Term_putstr(col + 1, row, len, attr, "cccccccccc");
+ } else {
+ Term_putstr(col + 1, row, len, attr, "**********");
+ }
+ }
+}
+
+
+
+/*
+ * Display basic info (mostly left of map)
+ */
+static void prt_frame(void)
+{
+ int i;
+
+ /* Race and Class */
+ prt_field(rp_ptr->title, ROW_RACE, COL_RACE);
+ prt_field(spp_ptr->title, 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();
+
+ /* Cut/Stun */
+ prt_cut();
+ prt_stun();
+
+ /* Current depth */
+ prt_status_line();
+
+ /* Special */
+ health_redraw();
+}
+
+
+/*
+ * 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)
+ {
+ /* Acquire object */
+ object_type *o_ptr = &o_list[m_ptr->mimic_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_ptr->name, (num % (h - 1)) + 1, (num / (h - 1) * 26));
+ }
+ else
+ {
+ c_prt(attr, format("%s (x%d)", 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 powers of player given the current set of corruptions.
+ */
+static void calc_powers_corruption()
+{
+ /* Map of corruptions to a power */
+ int i;
+
+ /* Grant powers according to whatever corruptions the player has */
+ for (i = 0; i < CORRUPTIONS_MAX; i++)
+ {
+ if (player_has_corruption(i))
+ {
+ int p = get_corruption_power(i);
+ if (p >= 0)
+ {
+ p_ptr->powers[p] = TRUE;
+ }
+ }
+ }
+}
+
+
+/* Ugly hack */
+bool_ calc_powers_silent = FALSE;
+
+/* Calc the player powers */
+static void calc_powers(void)
+{
+ int i, p = 0;
+ bool_ old_powers[POWER_MAX];
+
+ /* Hack -- wait for creation */
+ if (!character_generated) return;
+
+ /* Hack -- handle "xtra" mode */
+ if (character_xtra) return;
+
+ /* 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; i++) p_ptr->powers[i] = p_ptr->powers_mod[i];
+ for (; i < POWER_MAX; i++) p_ptr->powers[i] = 0;
+
+ /* Calculate powers granted by corruptions */
+ calc_powers_corruption();
+
+ /* 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)
+ {
+ calc_mimic_power();
+ }
+
+ /* 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;
+}
+
+
+/*
+ * Calculate the player's sanity
+ */
+static void calc_sanity()
+{
+ 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_FRAME);
+ 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 */
+ if (p_ptr->pgod == 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 (p_ptr->to_m)
+ {
+ msp += msp * p_ptr->to_m / 5;
+ }
+
+ /* 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);
+ }
+
+ /* Sp mods? */
+ mana_school_calc_mana(&msp);
+ meta_inertia_control_calc_mana(&msp);
+
+ /* 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_FRAME);
+
+ /* 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 */
+ assert(p_ptr->lev - 1 >= 0);
+ assert(p_ptr->lev - 1 < PY_MAX_LEVEL);
+ 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 */
+ if (p_ptr->pgod == 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 */
+ mhp += mhp * p_ptr->to_l / 5;
+
+ 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? */
+ {
+ struct hook_calculate_hp_in in = { mhp };
+ struct hook_calculate_hp_out out = { 0 };
+ if (process_hooks_new(HOOK_CALC_HP, &in, &out))
+ {
+ mhp = out.mhp;
+ }
+ }
+
+ /* 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_FRAME);
+
+ /* Window stuff */
+ p_ptr->window |= (PW_PLAYER);
+ }
+}
+
+
+/*
+ * God hooks for light
+ */
+static void calc_torch_gods()
+{
+ if (p_ptr->pgod == GOD_VARDA)
+ {
+ /* increase lite radius */
+ p_ptr->cur_lite += 1;
+ }
+}
+
+
+/*
+ * 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;
+
+ /* gods */
+ calc_torch_gods();
+
+ /* 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;
+
+ /* 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;
+}
+
+
+/* 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 */
+static void calc_gods()
+{
+ /* Boost WIS if the player follows Eru */
+ if (p_ptr->pgod == 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 */
+ if (p_ptr->pgod == 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;
+
+ if (praying_to(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 */
+ if (praying_to(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 */
+ if (p_ptr->pgod == GOD_MANWE)
+ {
+ if (p_ptr->grace >= 2000) p_ptr->ffall = TRUE;
+ }
+
+ /* Boost Str and Con if the player is following Tulkas */
+ if (p_ptr->pgod == 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;
+ }
+
+ /* Aule provides to-hit/damage bonuses and fire resistance */
+ if (p_ptr->pgod == GOD_AULE)
+ {
+ if (p_ptr->grace > 0)
+ {
+ int bonus;
+ /* Resist fire*/
+ if (p_ptr->grace > 5000)
+ {
+ p_ptr->resist_fire = TRUE;
+ }
+
+ bonus = p_ptr->grace / 5000;
+ if (bonus > 5)
+ {
+ bonus = 5;
+ }
+
+ p_ptr->to_h = p_ptr->to_h + bonus;
+ p_ptr->dis_to_h = p_ptr->dis_to_h + bonus;
+ p_ptr->to_d = p_ptr->to_d + bonus;
+ p_ptr->dis_to_d = p_ptr->dis_to_d + bonus;
+ }
+ }
+
+ /* Mandos provides nether resistance and, while praying,
+ nether immunity and prevents teleportation. */
+ if (p_ptr->pgod == GOD_MANDOS)
+ {
+ p_ptr->resist_neth = TRUE;
+
+ if ((p_ptr->grace > 10000) &&
+ (p_ptr->praying == TRUE))
+ {
+ p_ptr->resist_continuum = TRUE;
+ }
+
+ if ((p_ptr->grace > 20000) &&
+ (p_ptr->praying == TRUE))
+ {
+ p_ptr->immune_neth = TRUE;
+ }
+ }
+
+ /* Ulmo provides water breath and, while praying can
+ provide poison resistance and magic breath. */
+ if (p_ptr->pgod == GOD_ULMO)
+ {
+ p_ptr->water_breath = TRUE;
+
+ if ((p_ptr->grace > 1000) &&
+ (p_ptr->praying == TRUE))
+ {
+ p_ptr->resist_pois = TRUE;
+ }
+
+ if ((p_ptr->grace > 15000) &&
+ (p_ptr->praying == TRUE))
+ {
+ p_ptr->magical_breath = TRUE;
+ }
+ }
+}
+
+/* Apply spell schools */
+static void calc_schools()
+{
+ if (get_skill(SKILL_AIR) >= 50)
+ {
+ p_ptr->magical_breath = TRUE;
+ }
+
+ if (get_skill(SKILL_WATER) >= 30)
+ {
+ p_ptr->water_breath = TRUE;
+ }
+}
+
+/* Apply corruptions */
+static void calc_corruptions()
+{
+ if (player_has_corruption(CORRUPT_BALROG_AURA))
+ {
+ p_ptr->xtra_f3 |= TR3_SH_FIRE;
+ p_ptr->xtra_f3 |= TR3_LITE1;
+ }
+
+ if (player_has_corruption(CORRUPT_BALROG_WINGS))
+ {
+ p_ptr->xtra_f4 |= TR4_FLY;
+ p_ptr->stat_add[A_CHR] -= 4;
+ p_ptr->stat_add[A_DEX] -= 2;
+ }
+
+ if (player_has_corruption(CORRUPT_BALROG_STRENGTH))
+ {
+ p_ptr->stat_add[A_STR] += 3;
+ p_ptr->stat_add[A_CON] += 1;
+ p_ptr->stat_add[A_DEX] -= 3;
+ p_ptr->stat_add[A_CHR] -= 1;
+ }
+
+ if (player_has_corruption(CORRUPT_DEMON_SPIRIT))
+ {
+ p_ptr->stat_add[A_INT] += 1;
+ p_ptr->stat_add[A_CHR] -= 2;
+ }
+
+ if (player_has_corruption(CORRUPT_DEMON_HIDE))
+ {
+ p_ptr->to_a = p_ptr->to_a + p_ptr->lev;
+ p_ptr->dis_to_a = p_ptr->dis_to_a + p_ptr->lev;
+ p_ptr->pspeed = p_ptr->pspeed - (p_ptr->lev / 7);
+ if (p_ptr->lev >= 40)
+ {
+ p_ptr->xtra_f2 |= TR2_IM_FIRE;
+ }
+ }
+
+ if (player_has_corruption(CORRUPT_DEMON_REALM))
+ {
+ /* 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].mod == 0)
+ {
+ s_info[SKILL_DAEMON].mod = 1500;
+ }
+ s_info[SKILL_DAEMON].hidden = FALSE;
+ }
+
+ if (player_has_corruption(CORRUPT_RANDOM_TELEPORT))
+ {
+ p_ptr->xtra_f3 |= TR3_TELEPORT;
+ }
+
+ if (player_has_corruption(CORRUPT_ANTI_TELEPORT))
+ {
+ if (p_ptr->corrupt_anti_teleport_stopped == FALSE)
+ {
+ p_ptr->resist_continuum = TRUE;
+ }
+ }
+
+ if (player_has_corruption(CORRUPT_TROLL_BLOOD))
+ {
+ p_ptr->xtra_f3 |= (TR3_REGEN | TR3_AGGRAVATE);
+ p_ptr->xtra_esp |= ESP_TROLL;
+ }
+}
+
+/* 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_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;
+ }
+}
+
+
+
+/**
+ * Are barehand fighter's hands empty?
+ */
+static 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;
+}
+
+
+
+/*
+ * 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)
+{
+ static bool_ monk_notify_aux = FALSE;
+ 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;
+ bool_ monk_armour_aux;
+
+
+ /* 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 "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();
+ }
+
+ /* Take care of spell schools */
+ calc_schools();
+
+ /* Take care of corruptions */
+ calc_corruptions();
+
+ /* 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 (race_flags1_p(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);
+
+ /* 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 (race_flags1_p(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_FRAME);
+
+ /* 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_FRAME);
+
+ /* 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 */
+ if (p_ptr->pgod == 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;
+ }
+
+ /* Temporary precognition */
+ if (p_ptr->tim_precognition > 0)
+ {
+ apply_flags(0, 0, 0, TR4_PRECOGNITION, 0, 0, 0, 0, 0, 0, 0);
+ }
+
+ /* 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 "Reflection" */
+ if (p_ptr->tim_reflect)
+ {
+ p_ptr->reflect = TRUE;
+ }
+
+ /* Temporary "Levitation" and "Flying" */
+ if (p_ptr->tim_ffall)
+ {
+ p_ptr->ffall = TRUE;
+ }
+ if (p_ptr->tim_fly)
+ {
+ p_ptr->fly = 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;
+ }
+
+ /* 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;
+
+ /* Display the speed (if needed) */
+ if (p_ptr->pspeed != old_speed) p_ptr->redraw |= (PR_FRAME);
+
+
+ /* 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_FRAME);
+
+ /* 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 (race_flags1_p(PR1_XTRA_MIGHT_BOW) && p_ptr->tval_ammo == TV_ARROW)
+ p_ptr->xtra_might += 1;
+
+ if (race_flags1_p(PR1_XTRA_MIGHT_SLING) && p_ptr->tval_ammo == TV_SHOT)
+ p_ptr->xtra_might += 1;
+
+ if (race_flags1_p(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 num = 0;
+ int wgt = 0;
+ int mul = 0;
+ analyze_blow(&num, &wgt, &mul);
+
+ /* Access the strength vs weight */
+ int 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 */
+ int 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 */
+ auto r_ptr = race_info_idx(p_ptr->body_monster, 0);
+ 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;
+}
+
+
+
+/*
+ * 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);
+ }
+
+ 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);
+ 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;
+
+
+ /* 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_FRAME))
+ {
+ p_ptr->redraw &= ~(PR_FRAME);
+ prt_frame();
+ }
+}
+
+
+/*
+ * 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_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);
+}
+
+bool race_flags1_p(u32b flags1_mask)
+{
+ return (rp_ptr->flags1 | rmp_ptr->flags1 | cp_ptr->flags1 | spp_ptr->flags1) & flags1_mask;
+}
+
+bool race_flags2_p(u32b flags2_mask)
+{
+ return (rp_ptr->flags2 | rmp_ptr->flags2 | cp_ptr->flags2 | spp_ptr->flags2) & flags2_mask;
+}
diff --git a/src/xtra1.hpp b/src/xtra1.hpp
new file mode 100644
index 00000000..df2592ac
--- /dev/null
+++ b/src/xtra1.hpp
@@ -0,0 +1,24 @@
+#pragma once
+
+#include "h-basic.h"
+
+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_heavy_armor(void);
+extern void calc_bonuses(bool_ silent);
+extern void gain_fate(byte fate);
+extern void fate_desc(char *desc, int fate);
+extern void dump_fates(FILE *OutFile);
+extern bool race_flags1_p(u32b flags1_mask);
+extern bool race_flags2_p(u32b flags2_mask);
diff --git a/src/xtra2.c b/src/xtra2.c
deleted file mode 100644
index 70978e47..00000000
--- a/src/xtra2.c
+++ /dev/null
@@ -1,6158 +0,0 @@
-/* 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/xtra2.cc b/src/xtra2.cc
new file mode 100644
index 00000000..096f8966
--- /dev/null
+++ b/src/xtra2.cc
@@ -0,0 +1,5626 @@
+/*
+ * 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 "xtra2.hpp"
+
+#include "artifact_type.hpp"
+#include "cave.hpp"
+#include "cave_type.hpp"
+#include "corrupt.hpp"
+#include "dungeon_info_type.hpp"
+#include "ego_item_type.hpp"
+#include "feature_type.hpp"
+#include "files.hpp"
+#include "gods.hpp"
+#include "hook_player_level_in.hpp"
+#include "hook_monster_death_in.hpp"
+#include "hooks.hpp"
+#include "melee2.hpp"
+#include "mimic.hpp"
+#include "monster1.hpp"
+#include "monster2.hpp"
+#include "monster3.hpp"
+#include "monster_ego.hpp"
+#include "monster_race.hpp"
+#include "monster_type.hpp"
+#include "notes.hpp"
+#include "object1.hpp"
+#include "object2.hpp"
+#include "object_kind.hpp"
+#include "options.hpp"
+#include "player_class.hpp"
+#include "player_race.hpp"
+#include "player_race_mod.hpp"
+#include "player_type.hpp"
+#include "quark.hpp"
+#include "randart.hpp"
+#include "skill_type.hpp"
+#include "skills.hpp"
+#include "spells1.hpp"
+#include "spells2.hpp"
+#include "stats.hpp"
+#include "store_info_type.hpp"
+#include "tables.hpp"
+#include "trap_type.hpp"
+#include "util.hpp"
+#include "util.h"
+#include "variable.h"
+#include "variable.hpp"
+#include "wilderness_map.hpp"
+#include "wilderness_type_info.hpp"
+#include "wizard2.hpp"
+#include "xtra1.hpp"
+#include "z-rand.hpp"
+
+#include <type_traits>
+#include <cassert>
+
+#include <boost/algorithm/string/predicate.hpp>
+
+using boost::algorithm::iequals;
+
+static void corrupt_corrupted(void);
+
+/*
+ * 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);
+
+ /* 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);
+
+ /* 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 timered precognition
+ */
+bool_ set_tim_precognition(int v)
+{
+ return set_simple_field(
+ &p_ptr->tim_precognition, v,
+ TERM_WHITE, "You feel able to predict the future.",
+ TERM_WHITE, "You feel less able to predict the future.");
+}
+
+/*
+ * 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->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->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);
+
+ /* Redraw title */
+ p_ptr->redraw |= (PR_FRAME);
+
+ /* 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_FRAME);
+
+ /* 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_FRAME);
+
+ /* 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_FRAME);
+
+ /* 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_FRAME);
+
+ /* Handle stuff */
+ handle_stuff();
+ }
+
+ /* Result */
+ return notice;
+}
+
+
+/*
+ * Mechanics for setting the "paralyzed" field.
+ */
+static bool_ set_paralyzed_aux(int v)
+{
+ bool_ notice;
+
+ /* Normal processing */
+ 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_FRAME);
+
+ /* Handle stuff */
+ handle_stuff();
+ }
+
+ /* Result */
+ return notice;
+}
+
+/*
+ * Set "p_ptr->paralyzed", notice observable changes
+ */
+bool_ set_paralyzed(int v)
+{
+ /* Paralysis effects do not accumulate -- this is to
+ prevent the uninteresting insta-death effect, but
+ still leave paralyzers highly dangerous if they're
+ faster than the player. */
+
+ if (p_ptr->paralyzed > 0) {
+ return FALSE;
+ }
+
+ /* Normal processing */
+ return set_paralyzed_aux(v);
+}
+
+/*
+ * Decrement "p_ptr->paralyzed", notice observable changes
+ */
+void dec_paralyzed()
+{
+ set_paralyzed_aux(p_ptr->paralyzed - 1);
+}
+
+
+/*
+ * 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);
+
+ /* 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->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);
+
+ /* 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->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);
+
+ /* 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 (race_flags1_p(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);
+ break;
+ }
+
+ /* Notice */
+ notice = TRUE;
+ }
+
+ /* Use the value */
+ p_ptr->stun = v;
+
+ /* No change */
+ if (!notice) return (FALSE);
+
+ /* Disturb */
+ if (disturb_state) disturb(0);
+
+ /* Recalculate bonuses */
+ p_ptr->update |= (PU_BONUS);
+
+ /* Redraw the "stun" */
+ p_ptr->redraw |= (PR_FRAME);
+
+ /* 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 (race_flags1_p(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);
+ break;
+ }
+
+ /* Notice */
+ notice = TRUE;
+ }
+
+ /* Use the value */
+ p_ptr->cut = v;
+
+ /* No change */
+ if (!notice) return (FALSE);
+
+ /* Disturb */
+ if (disturb_state) disturb(0);
+
+ /* Recalculate bonuses */
+ p_ptr->update |= (PU_BONUS);
+
+ /* Redraw the "cut" */
+ p_ptr->redraw |= (PR_FRAME);
+
+ /* 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);
+
+ /* Recalculate bonuses */
+ p_ptr->update |= (PU_BONUS);
+
+ /* Redraw hunger */
+ p_ptr->redraw |= (PR_FRAME);
+
+ /* Handle stuff */
+ handle_stuff();
+
+ /* Result */
+ return (TRUE);
+}
+
+
+/*
+ * Advance experience levels and print experience
+ */
+void check_experience(void)
+{
+ int gained = 0;
+ 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_FRAME);
+
+ /* 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_FRAME);
+
+ /* 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 ((race_flags1_p(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)
+ {
+ p_ptr->skill_last_level = p_ptr->lev;
+ p_ptr->skill_points += modules[game_module_idx].skills.skill_per_level;
+ cmsg_format(TERM_L_GREEN, "You can increase %d more skills.", p_ptr->skill_points);
+ p_ptr->redraw |= PR_FRAME;
+ }
+
+ /* Gain this level's abilities */
+ apply_level_abilities(p_ptr->lev);
+
+ /* Note level gain */
+ {
+ 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_FRAME);
+
+ /* Window stuff */
+ p_ptr->window |= (PW_PLAYER);
+
+ /* Handle stuff */
+ handle_stuff();
+
+ if (level_corruption)
+ {
+ msg_print("You feel different...");
+ corrupt_corrupted();
+ level_corruption = FALSE;
+ }
+ }
+
+ /* Hook it! */
+ {
+ hook_player_level_in in = { gained };
+ process_hooks_new(HOOK_PLAYER_LEVEL, &in, NULL);
+ }
+}
+
+/*
+ * 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
+ */
+void gain_exp(s32b amount)
+{
+ if ((p_ptr->max_exp > 0) && (race_flags1_p(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;
+
+ /* 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;
+
+ /* 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(std::shared_ptr<monster_race const> r_ptr)
+{
+ cptr 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)
+{
+ const int x = m_ptr->fx;
+ const int y = m_ptr->fy;
+
+ /* Get local object */
+ object_type object_type_body;
+ object_type *i_ptr = &object_type_body;
+
+ /* Get the race information */
+ auto const r_ptr = m_ptr->race();
+
+ /* 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);
+ }
+
+}
+
+
+/*
+ * Check if monster race is in a given list. The list
+ * must be NULL-terminated.
+ */
+static bool_ monster_race_in_list_p(monster_type *m_ptr, cptr races[])
+{
+ int i=0;
+ for (i=0; races[i] != NULL; i++)
+ {
+ if (m_ptr->r_idx == test_monster_name(races[i])) {
+ return TRUE;
+ }
+ }
+ /* Not found */
+ return FALSE;
+}
+
+/*
+ * Handle the "death" of a monster (Gods)
+ */
+static void monster_death_gods(int m_idx, monster_type *m_ptr)
+{
+ if (p_ptr->pgod == GOD_AULE)
+ {
+ /* TODO: This should really be a racial flag
+ which can be added to the r_info file. */
+ cptr DWARVES[] = {
+ "Petty-dwarf",
+ "Petty-dwarf mage",
+ "Dark dwarven warrior",
+ "Dark dwarven smith",
+ "Dark dwarven lord",
+ "Dark dwarven priest",
+ "Dwarven warrior",
+ NULL,
+ };
+ cptr UNIQUE_DWARVES[] = {
+ "Nar, the Dwarf",
+ "Naugladur, Lord of Nogrod",
+ "Telchar the Smith",
+ "Fundin Bluecloak",
+ "Khim, Son of Mim",
+ "Ibun, Son of Mim",
+ "Mim, Betrayer of Turin",
+ NULL,
+ };
+
+ /* Aule dislikes the killing of dwarves */
+ if (monster_race_in_list_p(m_ptr, DWARVES))
+ {
+ inc_piety(GOD_ALL, -20);
+ }
+
+ /* ... and UNIQUE dwarves */
+ if (monster_race_in_list_p(m_ptr, UNIQUE_DWARVES))
+ {
+ inc_piety(GOD_ALL, -500);
+ }
+ }
+
+ if (p_ptr->pgod == GOD_ULMO)
+ {
+ /* He doesn't like it if you kill these monsters */
+ cptr MINOR_RACES[] = {
+ "Swordfish",
+ "Barracuda",
+ "Globefish",
+ "Aquatic bear",
+ "Pike",
+ "Electric eel",
+ "Giant crayfish",
+ "Mermaid",
+ "Leviathan",
+ "Box jellyfish",
+ "Giant piranha",
+ "Piranha",
+ "Ocean naga",
+ "Whale",
+ "Octopus",
+ "Giant octopus",
+ "Drowned soul",
+ "Tiger shark",
+ "Hammerhead shark",
+ "Great white shark",
+ "White shark",
+ "Stargazer",
+ "Flounder",
+ "Giant turtle",
+ "Killer whale",
+ "Water naga",
+ "Behemoth",
+ NULL,
+ };
+ /* These monsters earn higher penalties */
+ cptr MAJOR_RACES[] = {
+ "Seahorse",
+ "Aquatic elven warrior",
+ "Aquatic elven mage",
+ "Wavelord",
+ "The Watcher in the Water",
+ NULL,
+ };
+
+ if (monster_race_in_list_p(m_ptr, MINOR_RACES))
+ {
+ inc_piety(GOD_ALL, -20);
+ }
+
+ if (monster_race_in_list_p(m_ptr, MAJOR_RACES))
+ {
+ inc_piety(GOD_ALL, -500);
+ }
+ }
+
+ if (p_ptr->pgod == GOD_MANDOS)
+ {
+ cptr MINOR_BONUS_RACES[] = {
+ "Vampire",
+ "Master vampire",
+ "Oriental vampire",
+ "Vampire lord",
+ "Vampire orc",
+ "Vampire yeek",
+ "Vampire ogre",
+ "Vampire troll",
+ "Vampire dwarf",
+ "Vampire gnome",
+ "Elder vampire",
+ NULL,
+ };
+ cptr MAJOR_BONUS_RACES[] = {
+ "Vampire elf",
+ "Thuringwethil, the Vampire Messenger",
+ NULL,
+ };
+ cptr MINOR_PENALTY[] = {
+ "Dark elf",
+ "Dark elven druid",
+ "Eol, the Dark Elf",
+ "Maeglin, the Traitor of Gondolin",
+ "Dark elven mage",
+ "Dark elven warrior",
+ "Dark elven priest",
+ "Dark elven lord",
+ "Dark elven warlock",
+ "Dark elven sorcerer",
+ NULL,
+ };
+ cptr MEDIUM_PENALTY[] = {
+ "Glorfindel of Rivendell",
+ "Finrod Felagund",
+ "Thranduil, King of the Wood Elves",
+ "Aquatic elven warrior",
+ "Aquatic elven mage",
+ "High-elven ranger",
+ "Elven archer",
+ NULL,
+ };
+ cptr MAJOR_PENALTY[] = {
+ "Child spirit",
+ "Young spirit",
+ "Mature spirit",
+ "Experienced spirit",
+ "Wise spirit",
+ NULL,
+ };
+
+ if (monster_race_in_list_p(m_ptr, MINOR_BONUS_RACES))
+ {
+ /* He really likes it if you kill Vampires
+ * (but not the adventurer kind :P) */
+ inc_piety(GOD_ALL, 50);
+ }
+
+ if (monster_race_in_list_p(m_ptr, MAJOR_BONUS_RACES))
+ {
+ /* He *loves* it if you kill vampire Elves. He
+ * will also thank you extra kindly if you
+ * kill Thuringwethil */
+ inc_piety(GOD_ALL, 200);
+ }
+
+ if (monster_race_in_list_p(m_ptr, MINOR_PENALTY))
+ {
+ /* He doesn't like it if you kill normal Elves
+ * (means more work for him :P) */
+ inc_piety(GOD_ALL, -20);
+ }
+
+ if (monster_race_in_list_p(m_ptr, MEDIUM_PENALTY))
+ {
+ /* He hates it if you kill coaligned Elves */
+ inc_piety(GOD_ALL, -200);
+ }
+
+ if (monster_race_in_list_p(m_ptr, MAJOR_PENALTY))
+ {
+ /* He *hates* it if you kill the coaligned Spirits */
+ inc_piety(GOD_ALL, -1000);
+ }
+ }
+}
+
+/*
+ * 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 dump_item = 0;
+ int dump_gold = 0;
+
+ monster_type *m_ptr = &m_list[m_idx];
+
+ auto const r_ptr = m_ptr->race();
+
+ 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 */
+ int y = m_ptr->fy;
+ int x = m_ptr->fx;
+
+ /* Process the appropriate hooks */
+ {
+ struct hook_monster_death_in in = { m_idx };
+ process_hooks_new(HOOK_MONSTER_DEATH, &in, NULL);
+ }
+
+ /* Per-god processing */
+ monster_death_gods(m_idx, m_ptr);
+
+ /* 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_FRAME);
+
+ /* 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");
+ }
+ }
+
+ /* If the doppleganger die, the variable must be set accordingly */
+ if (r_ptr->flags9 & RF9_DOPPLEGANGER) doppleganger = 0;
+
+ /* Need copy of object list since we're going to mutate it */
+ auto const object_idxs(m_ptr->hold_o_idxs);
+
+ /* Drop objects being carried */
+ for (auto const this_o_idx: object_idxs)
+ {
+ /* Acquire object */
+ object_type * o_ptr = &o_list[this_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_idxs.clear();
+
+ /* 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_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_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_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_ptr->name, "ink horror"))
+ {
+ for (int 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_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_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_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_ptr->name, "Marda, rider of the Gold Laronth"))
+ {
+ a_idx = ART_MARDA;
+ chance = 50;
+ }
+ else if (strstr(r_ptr->name, "Saruman of Many Colours"))
+ {
+ a_idx = ART_PALANTIR;
+ chance = 30;
+ }
+ else if (strstr(r_ptr->name, "Hagen, son of Alberich"))
+ {
+ a_idx = ART_NIMLOTH;
+ chance = 66;
+ }
+ else if (strstr(r_ptr->name, "Durin's Bane"))
+ {
+ a_idx = ART_CALRIS;
+ chance = 60;
+ }
+ else if (strstr(r_ptr->name, "Gothmog, the High Captain of Balrogs"))
+ {
+ a_idx = ART_GOTHMOG;
+ chance = 50;
+ }
+ else if (strstr(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 (int 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);
+ }
+
+ /* Create a magical staircase */
+ if (create_stairs && (dun_level < d_info[dungeon_type].maxdepth))
+ {
+ for (int i = -1; i <= 1; i++)
+ {
+ for (int 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))
+ {
+ /* Pick a location */
+ int ny, nx;
+ scatter(&ny, &nx, y, x, 1);
+
+ /* 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];
+ auto const r_idx = m_ptr->r_idx;
+ auto const r_ptr = m_ptr->race();
+
+ /* Redraw (later) if needed */
+ if (health_who == m_idx) p_ptr->redraw |= (PR_FRAME);
+
+ /* 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 (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 */
+ const s32b div = p_ptr->max_plv;
+
+ if (m_ptr->status < MSTATUS_FRIEND)
+ {
+ /* Give some experience for the kill */
+ int new_exp = ((long)r_ptr->mexp * m_ptr->level) / div;
+
+ /* Handle fractional experience */
+ const s32b 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 */
+ const int 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 = std::max(1, m_ptr->level / 2);
+
+ if (praying_to(GOD_MANWE))
+ {
+ inc_piety(GOD_MANWE, inc);
+ }
+
+ inc = std::max(2, inc);
+
+ inc_piety(GOD_TULKAS, inc / 2);
+
+ if (praying_to(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 = std::max(1, m_ptr->level / 2);
+ inc_piety(GOD_YAVANNA, inc);
+ }
+
+ /* Yavanna doesnt like any killing in her name */
+ if (praying_to(GOD_YAVANNA))
+ {
+ int inc = std::max(1, m_ptr->level / 2);
+ 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_idx == q_ptr->r_idx)
+ {
+ /* Invalidate it */
+ q_ptr->type = 0;
+ }
+ }
+ }
+
+ /* Make note of unique kills */
+ if (r_ptr->flags1 & RF1_UNIQUE)
+ {
+ char note[80];
+
+ /* Write note */
+ sprintf(note, "Killed %s", r_ptr->name);
+
+ 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);
+ }
+
+ /* Apply fear */
+ mon_handle_fear(m_ptr, dam, fear);
+
+ /* 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;
+}
+
+/*
+ * 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);
+
+ /* 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_FRAME | 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
+ */
+static cptr look_mon_desc(int m_idx)
+{
+ bool_ living = TRUE;
+
+ /* Determine if the monster is "living" (vs "undead") */
+ monster_type *m_ptr = &m_list[m_idx];
+ auto const r_ptr = m_ptr->race();
+ 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" */
+ const int 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");
+}
+
+
+
+/*
+ * Current "comp" function for ang_sort()
+ */
+static bool_ (*ang_sort_comp)(vptr u, vptr v, int a, int b) = nullptr;
+
+/*
+ * Current "swap" function for ang_sort()
+ */
+static void (*ang_sort_swap)(vptr u, vptr v, int a, int b) = nullptr;
+
+
+
+/*
+ * 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.
+ */
+static 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.
+ */
+static 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.
+ */
+static 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)
+{
+ /* 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 */
+ cave_type *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 (auto const this_o_idx: c_ptr->o_idxs)
+ {
+ /* Acquire object */
+ object_type *o_ptr = &o_list[this_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 "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];
+
+ 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];
+ auto const r_ptr = m_ptr->race();
+
+ /* Mimics special treatment -- looks like an object */
+ if ((r_ptr->flags9 & RF9_MIMIC) && (m_ptr->csleep))
+ {
+ /* Acquire object */
+ object_type *o_ptr = &o_list[m_ptr->mimic_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%s[r,%s]",
+ s1, s2, s3, m_name,
+ m_ptr->level, look_mon_desc(c_ptr->m_idx),
+ (m_ptr->csleep) ? ", asleep" : "",
+ (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 */
+ std::size_t i = 0;
+ for (; i < m_ptr->hold_o_idxs.size(); i++)
+ {
+ /* Acquire object */
+ auto this_o_idx = m_ptr->hold_o_idxs.at(i);
+ object_type *o_ptr = &o_list[this_o_idx];
+
+ /* Obtain an object description */
+ char o_name[80];
+ 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 (i != m_ptr->hold_o_idxs.size())
+ {
+ break;
+ }
+
+ /* Use a preposition */
+ s2 = "on ";
+ }
+ }
+ }
+
+ /* Scan all objects in the grid */
+ {
+ std::size_t i = 0;
+ for (; i < c_ptr->o_idxs.size(); i++)
+ {
+ /* Acquire object */
+ auto this_o_idx = c_ptr->o_idxs.at(i);
+ object_type *o_ptr = &o_list[this_o_idx];
+
+ /* Describe it */
+ if (o_ptr->marked && target_object(y, x, mode, info, &boring, o_ptr, out_val, &s1, &s2, &s3, &query))
+ {
+ break;
+ }
+ }
+
+ /* Double break? */
+ if (i != c_ptr->o_idxs.size())
+ {
+ 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_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_info[c_ptr->special].name;
+ }
+ else
+ {
+ 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_info[c_ptr->special].text;
+ }
+
+ if (p_ptr->wild_mode && (feat == FEAT_TOWN))
+ {
+ s3 = "";
+ name = format("%s(%s)",
+ wf_info[wild_map[y][x].feat].name,
+ wf_info[wild_map[y][x].feat].text);
+ }
+
+ if ((feat == FEAT_FOUNTAIN) && (c_ptr->info & CAVE_IDNT))
+ {
+ 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;
+ }
+
+ info = k_info[lookup_kind(tv, sv)].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;
+ }
+ break;
+ }
+
+ case '-':
+ {
+ if (m-- == 0)
+ {
+ m = temp_n - 1;
+ }
+ 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);
+}
+
+
+/*
+ * 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;
+}
+
+/*
+ * 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_FRAME);
+ handle_stuff();
+}
+
+static bool_ test_object_wish(char *name, object_type *o_ptr, object_type *forge, const 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 (iequals(buf, name))
+ {
+ /* Don't search any more */
+ return TRUE;
+ }
+ else
+ {
+ /* Restore again the aware status */
+ k_ptr->aware = save_aware;
+ }
+ }
+ }
+ }
+ }
+ return FALSE;
+}
+
+static 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);
+ 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(r_ptr, j)) continue;
+
+ if (j)
+ {
+ if (re_ptr->before)
+ {
+ sprintf(buf, "%s %s", re_ptr->name, r_ptr->name);
+ }
+ else
+ {
+ sprintf(buf, "%s %s", r_ptr->name, re_ptr->name);
+ }
+ }
+ else
+ {
+ sprintf(buf, "%s", r_ptr->name);
+ }
+ strlower(buf);
+
+ if (iequals(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
+ */
+static void corrupt_corrupted(void)
+{
+ if (magik(45))
+ {
+ lose_corruption();
+ }
+ else
+ {
+ gain_random_corruption();
+ }
+
+ /* We are done. */
+ return;
+}
+
+/*
+ * 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))
+ {
+ // This code is very reliant on the race_mod_info
+ // elements being simple PODs, in particular the
+ // text pointers being *unmanaged* owned pointers.
+ static_assert(std::is_pod<player_race_mod>::value,
+ "This code needs reworking");
+ // Keep references to owned pointers.
+ auto old_title = race_mod_info[SUBRACE_SAVE].title;
+ auto old_desc = race_mod_info[SUBRACE_SAVE].desc;
+ // Copy everything
+ race_mod_info[SUBRACE_SAVE] = race_mod_info[p_ptr->pracem];
+ // "Undo" copy of title and description (since they're *owned* pointers)
+ race_mod_info[SUBRACE_SAVE].title = old_title;
+ race_mod_info[SUBRACE_SAVE].desc = old_desc;
+ // Replace subrace title with the title currently held by player.
+ set_subrace_title(&race_mod_info[SUBRACE_SAVE], race_mod_info[p_ptr->pracem].title);
+ }
+
+ p_ptr->pracem = racem;
+ rmp_ptr = &race_mod_info[p_ptr->pracem];
+}
+
+void set_subrace_title(player_race_mod *rmp_ptr, cptr name)
+{
+ // Free old title.
+ free(rmp_ptr->title);
+ // Allocate copy of new title.
+ rmp_ptr->title = strdup(name);
+ if (!rmp_ptr->title) {
+ abort();
+ }
+}
+
+void set_subrace_description(player_race_mod *rmp_ptr, cptr desc)
+{
+ // Free old description
+ free(rmp_ptr->desc);
+ // Allocate copy of new description.
+ rmp_ptr->desc = strdup(desc);
+ if (!rmp_ptr->desc) {
+ abort();
+ }
+}
+
+/*
+ * 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_FRAME);
+ p_ptr->update |= (PU_BONUS);
+ handle_stuff();
+
+ lite_spot(p_ptr->py, p_ptr->px);
+}
diff --git a/src/xtra2.hpp b/src/xtra2.hpp
new file mode 100644
index 00000000..10d752a2
--- /dev/null
+++ b/src/xtra2.hpp
@@ -0,0 +1,96 @@
+#pragma once
+
+#include "h-basic.h"
+#include "monster_race_fwd.hpp"
+#include "object_type_fwd.hpp"
+#include "player_race_mod_fwd.hpp"
+
+#include <memory>
+
+extern void do_rebirth(void);
+extern void set_subrace_title(player_race_mod *rmp_ptr, cptr name);
+extern void set_subrace_description(player_race_mod *rmp_ptr, cptr desc);
+extern void switch_subrace(int racem, bool_ copy_old);
+extern void drop_from_wild(void);
+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_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_precognition(int v);
+extern bool_ set_tim_deadly(int v);
+extern bool_ set_tim_reflect(int v);
+extern bool_ set_tim_thunder(int v, int p1, int p2);
+extern bool_ set_strike(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_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 void dec_paralyzed();
+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(std::shared_ptr<monster_race const> 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 bool_ target_okay(void);
+extern bool_ target_set(int mode);
+extern bool_ get_aim_dir(int *dp);
+extern bool_ get_rep_dir(int *dp);
+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 void do_poly_self(void);
+extern bool_ curse_weapon(void);
+extern bool_ curse_armor(void);
+extern void make_wish(void);
+extern void create_between_gate(int dist, int y, int x);
+
+extern "C" {
+ extern void resize_map(void);
+ extern void resize_window(void);
+}
diff --git a/src/z-form.c b/src/z-form.c
index b3d5d005..90d71294 100644
--- a/src/z-form.c
+++ b/src/z-form.c
@@ -5,8 +5,8 @@
#include "z-form.h"
#include "z-util.h"
-#include "z-virt.h"
+#include <stdlib.h>
/*
* Here is some information about the routines in this file.
@@ -17,10 +17,10 @@
* (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".
+ * 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
+ * "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
@@ -99,13 +99,6 @@
*
* 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];",
@@ -126,12 +119,6 @@
* 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.
@@ -140,40 +127,6 @@
-
-/*
- * 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.
*
@@ -316,19 +269,6 @@ uint vstrnfmt(char *buf, uint max, cptr fmt, va_list vp)
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;
@@ -576,23 +516,6 @@ uint vstrnfmt(char *buf, uint max, cptr fmt, va_list vp)
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:
{
@@ -608,19 +531,7 @@ uint vstrnfmt(char *buf, uint max, cptr fmt, va_list vp)
/* 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;
- }
- }
+ capitalize(tmp);
}
/* Now append "tmp" to "buf" */
@@ -647,16 +558,20 @@ uint vstrnfmt(char *buf, uint max, cptr fmt, va_list vp)
* 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 *vformat(cptr fmt, va_list vp)
{
static char *format_buf = NULL;
- static huge format_len = 0;
+ static size_t format_len = 0;
/* Initial allocation */
if (!format_buf)
{
format_len = 1024;
- C_MAKE(format_buf, format_len, char);
+ format_buf = calloc(format_len, sizeof(char));
+ if (format_buf == NULL)
+ {
+ abort(); // Nothing sensible we can do
+ }
}
/* Null format yields last result */
@@ -674,9 +589,13 @@ char *vformat(cptr fmt, va_list vp)
if (len < format_len - 1) break;
/* Grow the buffer */
- C_KILL(format_buf, format_len, char);
+ free(format_buf);
format_len = format_len * 2;
- C_MAKE(format_buf, format_len, char);
+ format_buf = calloc(format_len, sizeof(char));
+ if (format_buf == NULL)
+ {
+ abort(); // Nothing sensible we can do
+ }
}
/* Return the new buffer */
@@ -708,30 +627,6 @@ uint strnfmt(char *buf, uint max, cptr fmt, ...)
}
-/*
- * 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);
-}
-
-
/*
@@ -762,29 +657,6 @@ char *format(cptr fmt, ...)
/*
- * 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, ...)
@@ -804,28 +676,3 @@ void quit_fmt(cptr fmt, ...)
/* 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
index 2dcfa96c..ac49c658 100644
--- a/src/z-form.h
+++ b/src/z-form.h
@@ -1,7 +1,4 @@
-/* File z-form.h */
-
-#ifndef INCLUDED_Z_FORM_H
-#define INCLUDED_Z_FORM_H
+#pragma once
#ifdef __cplusplus
extern "C" {
@@ -17,7 +14,7 @@ extern "C" {
* 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"
+ * This file makes use "z-util.c"
*/
@@ -29,26 +26,12 @@ 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
deleted file mode 100644
index ca5b49ae..00000000
--- a/src/z-rand.c
+++ /dev/null
@@ -1,355 +0,0 @@
-/* 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.cc b/src/z-rand.cc
new file mode 100644
index 00000000..c06b7893
--- /dev/null
+++ b/src/z-rand.cc
@@ -0,0 +1,376 @@
+/* File: z-rand.c */
+
+/* Purpose: a simple random number generator -BEN- */
+
+#include "z-rand.hpp"
+
+
+
+
+/*
+ * 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.
+ */
+static 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);
+}
+
+bool magik(int p) {
+ return rand_int(100) < p;
+}
+
+s32b rand_int(s32b m)
+{
+ return Rand_div(m);
+}
+
+s32b randint(s32b m)
+{
+ return rand_int(m) + 1;
+}
+
+s32b rand_range(s32b a, s32b b)
+{
+ return a + rand_int(1 + b - a);
+}
+
+s32b rand_spread(s32b a, s32b d)
+{
+ return a + rand_int(1 + d + d) - d;
+}
diff --git a/src/z-rand.h b/src/z-rand.h
deleted file mode 100644
index 39cc958c..00000000
--- a/src/z-rand.h
+++ /dev/null
@@ -1,96 +0,0 @@
-/* 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-rand.hpp b/src/z-rand.hpp
new file mode 100644
index 00000000..f2e3ce5c
--- /dev/null
+++ b/src/z-rand.hpp
@@ -0,0 +1,67 @@
+#pragma once
+
+#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 Variables ****/
+
+
+extern bool_ Rand_quick;
+extern u32b Rand_value;
+extern u16b Rand_place;
+extern u32b Rand_state[RAND_DEG];
+
+
+/**** Available Functions ****/
+
+
+void Rand_state_init(u32b seed);
+s32b Rand_mod(s32b m);
+s16b randnor(int mean, int stand);
+s32b damroll(s16b num, s16b sides);
+s32b maxroll(s16b num, s16b sides);
+
+/**
+ * Evaluate to "true" p percent of the time.
+ */
+bool magik(s32b p);
+
+/*
+ * 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"
+ */
+s32b rand_int(s32b m);
+
+/*
+ * Generate a random long integer X where 1<=X<=M
+ * Also, "correctly" handle the case of M<=1
+ */
+s32b randint(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)
+ */
+s32b 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)
+ */
+s32b rand_spread(s32b a, s32b d);
diff --git a/src/z-term.c b/src/z-term.c
index 4e89ffb7..53b23c02 100644
--- a/src/z-term.c
+++ b/src/z-term.c
@@ -1,5 +1,3 @@
-/* File: z-term.c */
-
/*
* Copyright (c) 1997 Ben Harrison
*
@@ -10,11 +8,8 @@
/* Purpose: a generic, efficient, terminal window package -BEN- */
-#include "angband.h"
-
#include "z-term.h"
-#include "z-virt.h"
/*
@@ -86,13 +81,9 @@
*
* 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.
+ * about the meaning of any attr/char values. We assume that "attr 0" is
+ * "black", with the semantics that "black" text should be
+ * sent to "Term_wipe()" instead of "Term_text()".
*
* 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"
@@ -160,8 +151,7 @@
* 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.
+ * (mem) which is used to save and restore screen images.
*
*
* Several "flags" are available in each "term" to allow the underlying
@@ -184,16 +174,9 @@
*
* 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
@@ -208,29 +191,11 @@
* 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 contents of "cp" are null-terminated.
*
* The game "Angband" uses a set of files called "main-xxx.c", for
* various "xxx" suffixes. Most of these contain a function called
@@ -254,12 +219,6 @@
* 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.
*/
@@ -271,50 +230,40 @@
*/
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 ***/
/*
+ * Calloc wrapper which aborts if NULL is returned by calloc
+ */
+static void *safe_calloc(size_t nmemb, size_t size)
+{
+ void *p = calloc(nmemb, size);
+ if ((nmemb > 0) && (p == NULL))
+ {
+ abort();
+ }
+ return p;
+}
+
+/*
* 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(s->a);
+ s->a = NULL;
- /* Free the terrain content arrays */
- C_KILL(s->vta, h * w, byte);
- C_KILL(s->vtc, h * w, char);
+ free(s->c);
+ s->c = NULL;
- /* Free the ego graphics access arrays */
- C_KILL(s->ea, h, byte*);
- C_KILL(s->ec, h, char*);
+ /* Free the window content arrays */
+ free(s->va);
+ s->va = NULL;
- /* Free the ego graphics content arrays */
- C_KILL(s->vea, h * w, byte);
- C_KILL(s->vec, h * w, char);
+ free(s->vc);
+ s->vc = NULL;
/* Success */
return (0);
@@ -329,42 +278,18 @@ 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*);
+ s->a = safe_calloc(h, sizeof(byte*));
+ s->c = safe_calloc(h, sizeof(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);
-
+ s->va = safe_calloc(h * w, sizeof(byte));
+ s->vc = safe_calloc(h * w, sizeof(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 */
@@ -388,28 +313,10 @@ static errr term_win_copy(term_win *s, term_win *f, int w, int h)
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++;
}
}
@@ -429,25 +336,9 @@ static errr term_win_copy(term_win *s, term_win *f, int w, int h)
/*
- * 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 */
@@ -475,18 +366,6 @@ static errr Term_curs_hack(int x, int y)
}
/*
- * 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)
@@ -498,18 +377,6 @@ static errr Term_text_hack(int x, int y, int n, byte a, const char *cp)
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 ***/
@@ -520,34 +387,20 @@ static errr Term_pict_hack(int x, int y, int n, const byte *ap, const char *cp,
*
* 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)
+void Term_queue_char(int x, int y, byte a, char c)
{
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;
+ if ((*scr_aa == a) && (*scr_cc == c)) 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;
@@ -558,89 +411,6 @@ void Term_queue_char(int x, int y, byte a, char c, byte ta, char tc, byte ea, ch
}
-/*
- * 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
@@ -657,40 +427,19 @@ void Term_queue_chars(int x, int y, int n, byte a, cptr s)
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;
-
+ if ((oa == a) && (oc == *s)) 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;
@@ -710,321 +459,11 @@ void Term_queue_chars(int x, int y, int n, byte a, cptr s)
}
-
-/*** Refresh routines ***/
-
-
/*
- * Flush a row of the current window (see "Term_fresh")
- *
- * Display text using "Term_pict()"
+ * Blank attribute/character
*/
-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));
- }
- }
-}
-
+static const byte ATTR_BLANK = TERM_WHITE;
+static const char CHAR_BLANK = ' ';
/*
* Flush a row of the current window (see "Term_fresh")
@@ -1041,9 +480,6 @@ static void Term_fresh_row_text(int y, int x1, int x2)
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;
@@ -1051,7 +487,7 @@ static void Term_fresh_row_text(int y, int x1, int x2)
int fx = 0;
/* Pending attr */
- byte fa = Term->attr_blank;
+ byte fa = ATTR_BLANK;
byte oa;
char oc;
@@ -1076,17 +512,7 @@ static void Term_fresh_row_text(int y, int x1, int x2)
/* 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));
- }
+ (void)((*Term->text_hook)(fx, y, fn, fa, &scr_cc[fx]));
/* Forget */
fn = 0;
@@ -1107,16 +533,7 @@ static void Term_fresh_row_text(int y, int x1, int x2)
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));
- }
+ (void)((*Term->text_hook)(fx, y, fn, fa, &scr_cc[fx]));
/* Forget */
fn = 0;
@@ -1133,17 +550,7 @@ static void Term_fresh_row_text(int y, int x1, int x2)
/* 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));
- }
+ (void)((*Term->text_hook)(fx, y, fn, fa, &scr_cc[fx]));
}
}
@@ -1172,21 +579,9 @@ static void Term_fresh_row_text(int y, int x1, int x2)
* 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
+ * Note that "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,
@@ -1209,18 +604,6 @@ static void Term_fresh_row_text(int y, int x1, int x2)
* 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
@@ -1228,18 +611,8 @@ static void Term_fresh_row_text(int y, int x1, int x2)
* 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.
+ * not "zero", then the "Term_wipe" hook will never be used.
*
* This function does nothing unless the "Term" is "mapped", which allows
* certain systems to optimize the handling of "closed" windows.
@@ -1296,26 +669,14 @@ errr Term_fresh(void)
/* 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;
- }
+ byte na = ATTR_BLANK;
+ char nc = CHAR_BLANK;
/* Physically erase the entire window */
Term_xtra(TERM_XTRA_CLEAR, 0);
@@ -1329,25 +690,12 @@ errr Term_fresh(void)
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;
}
}
@@ -1382,41 +730,8 @@ errr Term_fresh(void)
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));
- }
+ (void)((*Term->text_hook)(tx, ty, 1, oa, &oc));
}
}
@@ -1460,40 +775,12 @@ errr Term_fresh(void)
/* 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);
- }
+ /* 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);
}
}
@@ -1629,7 +916,7 @@ errr Term_draw(int x, int y, byte a, char c)
if (!c) return ( -2);
/* Queue it for later */
- Term_queue_char(x, y, a, c, 0, 0, 0, 0);
+ Term_queue_char(x, y, a, c);
/* Success */
return (0);
@@ -1663,7 +950,7 @@ errr Term_addch(byte a, char c)
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);
+ Term_queue_char(Term->scr->cx, Term->scr->cy, a, c);
/* Advance the cursor */
Term->scr->cx++;
@@ -1782,18 +1069,12 @@ errr Term_erase(int x, int y, int n)
int x1 = -1;
int x2 = -1;
- int na = Term->attr_blank;
- int nc = Term->char_blank;
+ int na = ATTR_BLANK;
+ int nc = 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);
@@ -1804,12 +1085,6 @@ errr Term_erase(int x, int y, int n)
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--;
@@ -1829,12 +1104,6 @@ errr Term_erase(int x, int y, int n)
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;
@@ -1871,8 +1140,8 @@ errr Term_clear(void)
int w = Term->wid;
int h = Term->hgt;
- byte na = Term->attr_blank;
- char nc = Term->char_blank;
+ byte na = ATTR_BLANK;
+ char nc = CHAR_BLANK;
/* Cursor usable */
Term->scr->cu = 0;
@@ -1886,23 +1155,11 @@ errr Term_clear(void)
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 */
@@ -1930,17 +1187,6 @@ errr Term_clear(void)
*/
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;
@@ -1995,6 +1241,10 @@ errr Term_redraw_section(int x1, int y1, int x2, int y2)
}
+void Term_bell()
+{
+ Term_xtra(TERM_XTRA_NOISE, 0);
+}
/*** Access routines ***/
@@ -2018,8 +1268,15 @@ errr Term_get_cursor(int *v)
errr Term_get_size(int *w, int *h)
{
/* Access the cursor */
- (*w) = Term->wid;
- (*h) = Term->hgt;
+ if (w)
+ {
+ (*w) = Term->wid;
+ }
+
+ if (h)
+ {
+ (*h) = Term->hgt;
+ }
/* Success */
return (0);
@@ -2149,20 +1406,8 @@ 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 */
+ /* Process queued UI events */
+ Term_xtra(TERM_XTRA_BORED, 0);
/* Wait */
if (wait)
@@ -2218,7 +1463,7 @@ errr Term_save(void)
if (!Term->mem)
{
/* Allocate window */
- MAKE(Term->mem, term_win);
+ Term->mem = safe_calloc(1, sizeof(struct term_win));
/* Initialize window */
term_win_init(Term->mem, w, h);
@@ -2241,7 +1486,7 @@ term_win* Term_save_to(void)
term_win *save;
/* Allocate window */
- MAKE(save, term_win);
+ save = safe_calloc(1, sizeof(struct term_win));
/* Initialize window */
term_win_init(save, w, h);
@@ -2269,7 +1514,7 @@ errr Term_load(void)
if (!Term->mem)
{
/* Allocate window */
- MAKE(Term->mem, term_win);
+ Term->mem = safe_calloc(1, sizeof(struct term_win));
/* Initialize window */
term_win_init(Term->mem, w, h);
@@ -2297,7 +1542,7 @@ errr Term_load(void)
/*
* Same as previous but allow to save more than one
*/
-errr Term_load_from(term_win *save, bool_ final)
+errr Term_load_from(term_win *save)
{
int y;
@@ -2326,52 +1571,7 @@ errr Term_load_from(term_win *save, bool_ final)
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;
+ free(save);
/* Success */
return (0);
@@ -2392,18 +1592,13 @@ errr Term_resize(int w, int h)
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;
+ if ((Term->wid == w) && (Term->hgt == h)) return (1);
/* Minimum dimensions */
wid = MIN(Term->wid, w);
@@ -2422,15 +1617,12 @@ errr Term_resize(int w, int h)
/* 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);
+ Term->x1 = safe_calloc(h, sizeof(byte));
+ Term->x2 = safe_calloc(h, sizeof(byte));
/* Create new window */
- MAKE(Term->old, term_win);
+ Term->old = safe_calloc(1, sizeof(struct term_win));
/* Initialize new window */
term_win_init(Term->old, w, h);
@@ -2439,7 +1631,7 @@ errr Term_resize(int w, int h)
term_win_copy(Term->old, hold_old, wid, hgt);
/* Create new window */
- MAKE(Term->scr, term_win);
+ Term->scr = safe_calloc(1, sizeof(struct term_win));
/* Initialize new window */
term_win_init(Term->scr, w, h);
@@ -2451,7 +1643,7 @@ errr Term_resize(int w, int h)
if (hold_mem)
{
/* Create new window */
- MAKE(Term->mem, term_win);
+ Term->mem = safe_calloc(1, sizeof(struct term_win));
/* Initialize new window */
term_win_init(Term->mem, w, h);
@@ -2460,28 +1652,18 @@ errr Term_resize(int w, int h)
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);
+ free(hold_x1);
+ hold_x1 = NULL;
+ free(hold_x2);
+ hold_x2 = NULL;
/* Nuke */
term_win_nuke(hold_old, Term->wid, Term->hgt);
/* Kill */
- KILL(hold_old, term_win);
+ free(hold_old);
+ hold_old = NULL;
/* Illegal cursor */
if (Term->old->cx >= w) Term->old->cu = 1;
@@ -2491,7 +1673,8 @@ errr Term_resize(int w, int h)
term_win_nuke(hold_scr, Term->wid, Term->hgt);
/* Kill */
- KILL(hold_scr, term_win);
+ free(hold_scr);
+ hold_scr = NULL;
/* Illegal cursor */
if (Term->scr->cx >= w) Term->scr->cu = 1;
@@ -2504,27 +1687,14 @@ errr Term_resize(int w, int h)
term_win_nuke(hold_mem, Term->wid, Term->hgt);
/* Kill */
- KILL(hold_mem, term_win);
+ free(hold_mem);
+ hold_mem = NULL;
/* 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;
@@ -2624,13 +1794,15 @@ errr term_nuke(term *t)
term_win_nuke(t->old, w, h);
/* Kill "displayed" */
- KILL(t->old, term_win);
+ free(t->old);
+ t->old = NULL;
/* Nuke "requested" */
term_win_nuke(t->scr, w, h);
/* Kill "requested" */
- KILL(t->scr, term_win);
+ free(t->scr);
+ t->scr = NULL;
/* If needed */
if (t->mem)
@@ -2639,25 +1811,19 @@ errr term_nuke(term *t)
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(t->mem);
+ t->mem = NULL;
}
/* Free some arrays */
- C_KILL(t->x1, h, byte);
- C_KILL(t->x2, h, byte);
+ free(t->x1);
+ t->x1 = NULL;
+ free(t->x2);
+ t->x2 = NULL;
/* Free the input queue */
- C_KILL(t->key_queue, t->key_size, char);
+ free(t->key_queue);
+ t->key_queue = NULL;
/* Success */
return (0);
@@ -2675,7 +1841,7 @@ errr term_init(term *t, int w, int h, int k)
int y;
/* Wipe it */
- (void)WIPE(t, term);
+ memset(t, 0, sizeof(term));
/* Prepare the input queue */
@@ -2685,7 +1851,7 @@ errr term_init(term *t, int w, int h, int k)
t->key_size = k;
/* Allocate the input queue */
- C_MAKE(t->key_queue, t->key_size, char);
+ t->key_queue = safe_calloc(t->key_size, sizeof(char));
/* Save the size */
@@ -2693,19 +1859,19 @@ errr term_init(term *t, int w, int h, int k)
t->hgt = h;
/* Allocate change arrays */
- C_MAKE(t->x1, h, byte);
- C_MAKE(t->x2, h, byte);
+ t->x1 = safe_calloc(h, sizeof(byte));
+ t->x2 = safe_calloc(h, sizeof(byte));
/* Allocate "displayed" */
- MAKE(t->old, term_win);
+ t->old = safe_calloc(1, sizeof(struct term_win));
/* Initialize "displayed" */
term_win_init(t->old, w, h);
/* Allocate "requested" */
- MAKE(t->scr, term_win);
+ t->scr = safe_calloc(1, sizeof(struct term_win));
/* Initialize "requested" */
term_win_init(t->scr, w, h);
@@ -2727,50 +1893,6 @@ errr term_init(term *t, int w, int h, int k)
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
index 31e5b308..01795629 100644
--- a/src/z-term.h
+++ b/src/z-term.h
@@ -17,8 +17,6 @@ extern "C" {
#include "h-basic.h"
-#define IN_MAINWINDOW (Term == term_screen)
-
/*
* A term_win is a "window" for a Term
*
@@ -48,18 +46,6 @@ struct term_win
byte *va;
char *vc;
- byte **ta;
- char **tc;
-
- byte *vta;
- char *vtc;
-
- byte **ea;
- char **ec;
-
- byte *vea;
- char *vec;
-
};
@@ -67,19 +53,9 @@ struct term_win
/*
* 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"
*
@@ -89,39 +65,13 @@ struct term_win
* - 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
@@ -151,14 +101,10 @@ struct term_win
* - 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
@@ -168,35 +114,17 @@ 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;
@@ -211,32 +139,49 @@ struct term
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);
-
};
+/*** 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 */
+
/**** Available Constants ****/
@@ -251,11 +196,8 @@ struct term
*
* 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.
*/
@@ -263,39 +205,24 @@ struct term
#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_char(int x, int y, byte a, char c);
extern void Term_queue_chars(int x, int y, int n, byte a, cptr s);
extern errr Term_fresh(void);
@@ -310,6 +237,7 @@ 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 void Term_bell();
extern errr Term_get_cursor(int *v);
extern errr Term_get_size(int *w, int *h);
@@ -324,9 +252,7 @@ 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_load_from(term_win *save);
extern errr Term_resize(int w, int h);
diff --git a/src/z-util.c b/src/z-util.c
index 7c5374f3..0304a1da 100644
--- a/src/z-util.c
+++ b/src/z-util.c
@@ -4,122 +4,7 @@
#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);
-}
-
-
+#include <assert.h>
/*
@@ -150,6 +35,27 @@ bool_ suffix(cptr s, cptr t)
}
+/**
+ * Captialize letter
+ */
+void capitalize(char *s)
+{
+ char *p = s;
+ assert(s != NULL);
+
+ for (; *p; p++)
+ {
+ if (!isspace(*p))
+ {
+ if (islower(*p))
+ {
+ *p = toupper(*p);
+ }
+ /* Done */
+ break;
+ }
+ }
+}
/*
@@ -167,7 +73,7 @@ void plog(cptr str)
if (plog_aux) (*plog_aux)(str);
/* Just do a labeled fprintf to stderr */
- else (void)(fprintf(stderr, "%s: %s\n", argv0 ? argv0 : "???", str));
+ else (void)(fprintf(stderr, "%s\n", str));
}
@@ -200,35 +106,3 @@ void quit(cptr 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
index 11dbdb4e..914a64e7 100644
--- a/src/z-util.h
+++ b/src/z-util.h
@@ -1,7 +1,4 @@
-/* File z-util.h */
-
-#ifndef INCLUDED_Z_UTIL_H
-#define INCLUDED_Z_UTIL_H
+#pragma once
#ifdef __cplusplus
extern "C" {
@@ -11,61 +8,17 @@ extern "C" {
/*
- * 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".
+ * Extremely basic stuff, like "streq()".
*/
-/**** 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);
@@ -73,19 +26,16 @@ extern bool_ prefix(cptr s, cptr t);
extern bool_ suffix(cptr s, cptr t);
+/* Capitalize the first letter of string. Ignores whitespace at the start of string. */
+extern void capitalize(char *s);
+
/* 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
deleted file mode 100644
index c9277166..00000000
--- a/src/z-virt.c
+++ /dev/null
@@ -1,187 +0,0 @@
-/* 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
deleted file mode 100644
index a7880f2f..00000000
--- a/src/z-virt.h
+++ /dev/null
@@ -1,168 +0,0 @@
-/* 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
deleted file mode 100644
index 5a46b3b2..00000000
--- a/src/z_pack.pkg
+++ /dev/null
@@ -1,398 +0,0 @@
-/* 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/tests/get_level_device.cc b/tests/get_level_device.cc
new file mode 100644
index 00000000..43dce624
--- /dev/null
+++ b/tests/get_level_device.cc
@@ -0,0 +1,184 @@
+#include "lua_bind.hpp"
+#include "spell_type.hpp"
+#include <bandit/bandit.h>
+using namespace bandit;
+
+//
+// Declarations for testing purposes:
+//
+
+s32b get_level_device(spell_type *spell, s32b max, s32b min, s32b device_skill, std::function<s32b(spell_type *, s32b, s32b, s32b, s32b)> lua_get_level_ = lua_get_level);
+
+//
+// Tests
+//
+
+go_bandit([]() {
+
+ describe("get_level_device", []() {
+
+ s32b passed_in_max;
+ s32b passed_in_min;
+
+ // Fake get_level function we can use to detect what's being passed to the real one.
+ auto fake_get_level = [&](struct spell_type *spell, s32b lvl, s32b max, s32b min, s32b bonus) -> s32b {
+ // Store the passed input values for verification purposes
+ passed_in_max = max;
+ passed_in_min = min;
+ // Return the input "lvl" unmodified.
+ return lvl;
+ };
+
+ before_each([&]() {
+ // Reset saved state
+ passed_in_max = -1;
+ passed_in_min = -1;
+ });
+
+ // Magic-Device skill levels that we've tested at.
+ const std::vector<s32b> device_skill_values {
+ 15300, // @15.3
+ 35300, // @35.3
+ 45300, // @45.3
+ 50000 // @50.0
+ };
+
+ // "Remove Curses" spell and expected result levels.
+ auto remove_curses_spell = spell_type_new("TEST: Remove Curses");
+ spell_type_set_difficulty(remove_curses_spell, 10, 42 /* notused */);
+
+ const std::map<s32b, s32b> remove_curses_expected_levels {
+ { 15300, 7 },
+ { 35300, 15 },
+ { 45300, 15 },
+ { 50000, 15 }
+ };
+
+ // "Wish" spell and expected result levels.
+ auto wish_spell = spell_type_new("TEST: Wish");
+ spell_type_set_difficulty(wish_spell, 50, 42 /* notused */);
+
+ const std::map<s32b, s32b> wish_expected_levels {
+ { 15300, 1 },
+ { 35300, 1 },
+ { 45300, 1 },
+ { 50000, 2 }
+ };
+
+ // "Heal Monster" spell and expected result levels.
+ auto heal_monster_spell = spell_type_new("TEST: Heal Monster");
+ spell_type_set_difficulty(heal_monster_spell, 3, 42 /* notused */);
+
+ const std::map<s32b, s32b> heal_monster_expected_levels {
+ { 15300, 108 },
+ { 35300, 152 },
+ { 45300, 152 },
+ { 50000, 152 }
+ };
+
+ // "Teleport Away" spell and expected result levels.
+ auto teleport_away_spell = spell_type_new("TEST: Teleport Away");
+ spell_type_set_difficulty(teleport_away_spell, 23, 42 /* notused */);
+
+ const std::map<s32b, s32b> teleport_away_expected_levels {
+ { 15300, 1 },
+ { 35300, 16 },
+ { 45300, 20 },
+ { 50000, 20 }
+ };
+
+ //
+ // Basic tests for "min <= 0" and "max <= 0".
+ //
+
+ it("should clamp 'min' parameter to 1", [&]() {
+ // Setup
+ s32b device_skill = 100; /* doesn't matter for this test */
+ get_level_max_stick = 1; /* doesn't matter for this test */
+ get_level_use_stick = 1; /* doesn't matter for this test */
+ auto spell = remove_curses_spell; /* doesn't matter for this test */
+ s32b max = 100; /* doesn't matter for this test */
+ s32b min = 0;
+ // Exercise
+ get_level_device(spell, max, min, device_skill, fake_get_level);
+ // Verify
+ AssertThat(passed_in_min, Equals(1));
+ });
+
+ it("should use 50 as default for 'max' parameter if zero or less", [&]() {
+ // Setup
+ s32b device_skill = 100; /* doesn't matter for this test */
+ get_level_max_stick = 1; /* doesn't matter for this test */
+ get_level_use_stick = 1; /* doesn't matter for this test */
+ auto spell = remove_curses_spell; /* doesn't matter for this test */
+ s32b max = 0;
+ s32b min = 25; /* doesn't matter for this test */
+ // Exercise
+ get_level_device(spell, max, min, device_skill, fake_get_level);
+ // Verify
+ AssertThat(passed_in_max, Equals(50));
+ });
+
+ //
+ // Table-driven tests derived from empirical testing
+ // using printf.
+ //
+
+ for (auto device_skill: device_skill_values)
+ {
+ it("calculates 'Remove Curses' staff level correctly for different magic device levels" , [&] {
+ // Setup: Device values for Remove Curses staff
+ get_level_use_stick = 1;
+ get_level_max_stick = 15;
+ // Setup: Max and min
+ s32b max = 50;
+ s32b min = 1;
+ // Exercise
+ s32b actualLevel = get_level_device(remove_curses_spell, max, min, device_skill);
+ // Verify: Check expected levels.
+ AssertThat(actualLevel, Equals(remove_curses_expected_levels.at(device_skill)));
+ });
+
+ it("calculates 'Wish' staff level correctly for different magic device levels", [&] {
+ // Setup: Device values for Wish staff
+ get_level_use_stick = 1;
+ get_level_max_stick = 1;
+ // Setup: Max and min
+ s32b max = 50;
+ s32b min = 1;
+ // Exercise
+ s32b actualLevel = get_level_device(wish_spell, max, min, device_skill);
+ // Verify: Check expected levels.
+ AssertThat(actualLevel, Equals(wish_expected_levels.at(device_skill)));
+ });
+
+ it("calculates 'Heal Monster' wand level correctly for different magic device levels", [&] {
+ // Setup: Device values for Heal Monster wand
+ get_level_use_stick = 1;
+ get_level_max_stick = 20;
+ // Setup: Max and min
+ s32b max = 380;
+ s32b min = 1;
+ // Exercise
+ s32b actualLevel = get_level_device(heal_monster_spell, max, min, device_skill);
+ // Verify: Check expected levels.
+ AssertThat(actualLevel, Equals(heal_monster_expected_levels.at(device_skill)));
+ });
+
+ it("calculates 'Teleport Away' wand level correctly for different magic device levels", [&] {
+ // Setup: Device values for Teleport Away wand
+ get_level_use_stick = 3;
+ get_level_max_stick = 20;
+ // Setup: Max and min
+ s32b max = 50;
+ s32b min = 1;
+ // Exercise
+ s32b actualLevel = get_level_device(teleport_away_spell, max, min, device_skill);
+ // Verify: Check expected levels.
+ AssertThat(actualLevel, Equals(teleport_away_expected_levels.at(device_skill)));
+ });
+ }
+
+ });
+
+});
diff --git a/tests/harness.cc b/tests/harness.cc
new file mode 100644
index 00000000..3a66ad55
--- /dev/null
+++ b/tests/harness.cc
@@ -0,0 +1,7 @@
+#include <bandit/bandit.h>
+using namespace bandit;
+
+int main(int argc, char** argv)
+{
+ return bandit::run(argc, argv);
+}
diff --git a/tests/lua_get_level.cc b/tests/lua_get_level.cc
new file mode 100644
index 00000000..a434903e
--- /dev/null
+++ b/tests/lua_get_level.cc
@@ -0,0 +1,135 @@
+#include "lua_bind.hpp"
+#include "spell_type.hpp"
+#include <bandit/bandit.h>
+using namespace bandit;
+
+go_bandit([]() {
+ describe("lua_get_level", []() {
+
+ auto createEntsPotion = ([]() {
+ auto my_spell = spell_type_new("TEST: Ent's Potion");
+ spell_type_set_difficulty(my_spell, 6, 35); // Copied from standard Ent's Potion spell.
+ return my_spell;
+ });
+
+ auto createSenseHidden = ([]() {
+ auto my_spell = spell_type_new("TEST: Sense Hidden");
+ spell_type_set_difficulty(my_spell, 5, 25); // Copied from standard Sense Hidden spell.
+ return my_spell;
+ });
+
+ //
+ // Test cases derived from empirical testing of the code before refactoring.
+ //
+
+ it("calculates \"Ent's Potion\" level appropriately for Sorcery@1.0", [&](){
+ // Setup
+ auto my_spell = createEntsPotion();
+ // Exercise
+ auto actualResult = lua_get_level(my_spell, 100, 50, -50, 0);
+ // Verify
+ AssertThat(actualResult, Equals(-4));
+ });
+
+ it("calculates \"Ent's Potion\" cost appropriately for Sorcery@1.0", [&](){
+ // Setup
+ auto my_spell = createEntsPotion();
+ // Exercise
+ auto actualResult = lua_get_level(my_spell, 100, 15, 7, 0);
+ // Verify
+ AssertThat(actualResult, Equals(7));
+ });
+
+ it("calculates \"Ent's Potion\" level appropriately for Sorcery@25.0", [&](){
+ // Setup
+ auto my_spell = createEntsPotion();
+ // Exercise
+ auto actualResult = lua_get_level(my_spell, 2500, 50, 1, 0);
+ // Verify
+ AssertThat(actualResult, Equals(20));
+ });
+
+ it("calculates \"Ent's Potion\" cost appropriately for Sorcery@25.0", [&](){
+ // Setup
+ auto my_spell = createEntsPotion();
+ // Exercise
+ auto actualResult = lua_get_level(my_spell, 2500, 15, 7, 0);
+ // Verify
+ AssertThat(actualResult, Equals(7));
+ });
+
+ it("calculates \"Ent's Potion\" level appropriately for Sorcery@25.0 with +3 equipment SP bonus", [&](){
+ // Setup
+ auto my_spell = createEntsPotion();
+ // Exercise
+ auto actualResult = lua_get_level(my_spell, 2500, 50, 1, 300);
+ // Verify
+ AssertThat(actualResult, Equals(23));
+ });
+
+ it("calculates \"Ent's Potion\" cost appropriately for Sorcery@25.0 with +3 equipment SP bonus", [&](){
+ // Setup
+ auto my_spell = createEntsPotion();
+ // Exercise
+ auto actualResult = lua_get_level(my_spell, 2500, 15, 7, 300);
+ // Verify
+ AssertThat(actualResult, Equals(7));
+
+ });
+
+ it("calculates \"Sense Hidden\" level appropriately for Sorcery@1.0", [&](){
+ // Setup
+ auto my_spell = createSenseHidden();
+ // Exercise
+ auto actualResult = lua_get_level(my_spell, 100, 50, -50, 0);
+ // Verify
+ AssertThat(actualResult, Equals(-3));
+ });
+
+ it("calculates \"Sense Hidden\" cost appropriately for Sorcery@1.0", [&](){
+ // Setup
+ auto my_spell = createSenseHidden();
+ // Exercise
+ auto actualResult = lua_get_level(my_spell, 100, 10, 2, 0);
+ // Verify
+ AssertThat(actualResult, Equals(2));
+ });
+
+ it("calculates \"Sense Hidden\" level appropriately for Sorcery@25.0", [&](){
+ // Setup
+ auto my_spell = createSenseHidden();
+ // Exercise
+ auto actualResult = lua_get_level(my_spell, 2500, 50, 1, 0);
+ // Verify
+ AssertThat(actualResult, Equals(21));
+ });
+
+ it("calculates \"Sense Hidden\" cost appropriately for Sorcery@25.0", [&](){
+ // Setup
+ auto my_spell = createSenseHidden();
+ // Exercise
+ auto actualResult = lua_get_level(my_spell, 2500, 10, 2, 0);
+ // Verify
+ AssertThat(actualResult, Equals(4));
+ });
+
+ it("calculates \"Sense Hidden\" level appropriately for Sorcery@25.0 with +3 equipment SP bonus", [&](){
+ // Setup
+ auto my_spell = createSenseHidden();
+ // Exercise
+ auto actualResult = lua_get_level(my_spell, 2500, 50, 1, 300);
+ // Verify
+ AssertThat(actualResult, Equals(24));
+ });
+
+ it("calculates \"Sense Hidden\" cost appropriately for Sorcery@25.0 with +3 equipment SP bonus", [&](){
+ // Setup
+ auto my_spell = createSenseHidden();
+ // Exercise
+ auto actualResult = lua_get_level(my_spell, 2500, 10, 2, 300);
+ // Verify
+ AssertThat(actualResult, Equals(4));
+ });
+
+ });
+});
diff --git a/vendor/bandit/.travis.yml b/vendor/bandit/.travis.yml
new file mode 100644
index 00000000..f6f5b222
--- /dev/null
+++ b/vendor/bandit/.travis.yml
@@ -0,0 +1,17 @@
+language: cpp
+sudo: true
+compiler:
+ - gcc
+ - clang
+before_install:
+ - sudo add-apt-repository ppa:kubuntu-ppa/backports -y
+ - sudo apt-get update -qq
+ - sudo apt-get install -qq cmake=2.8.12.2-0ubuntu1~ubuntu12.04.1~ppa2
+before_script:
+ - BUILD_DIR=`pwd`/builds
+ - mkdir -p ${BUILD_DIR}
+ - cd ${BUILD_DIR}
+ - cmake ..
+script:
+ - cd ${BUILD_DIR}
+ - make
diff --git a/vendor/bandit/.vimrc b/vendor/bandit/.vimrc
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/vendor/bandit/.vimrc
diff --git a/vendor/bandit/CMakeLists.txt b/vendor/bandit/CMakeLists.txt
new file mode 100644
index 00000000..a777e73b
--- /dev/null
+++ b/vendor/bandit/CMakeLists.txt
@@ -0,0 +1,60 @@
+cmake_minimum_required(VERSION 2.8)
+project(bandit)
+
+option(BANDIT_BUILD_SPECS "Build the Bandit specs" ON)
+option(BANDIT_RUN_SPECS "Run the Bandit specs" ON)
+option(SNOWHOUSE_IS_CPP11 "Build Snowhouse with C++11 settings" ON)
+
+set (CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake")
+include(cotire/CMake/cotire)
+
+include_directories("${PROJECT_SOURCE_DIR}")
+
+set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ./bin)
+
+if (MSVC)
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /W4 /MP ")
+else()
+ # Assume GCC-style arguments
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wdeprecated -Wdeprecated-declarations -Wshadow -Wall -W -Werror -Wfloat-equal -Wundef -Wendif-labels")
+
+ if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
+ if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS "4.7")
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x")
+ else()
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
+ endif()
+ endif()
+
+ if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
+ endif()
+endif()
+
+#
+# If we're on Mac OS we assume we have libc++, otherwise we assume
+# we don't need it. (TODO: make this check more sofisticated)
+#
+if (CMAKE_HOST_APPLE AND (CMAKE_CXX_COMPILER_ID STREQUAL "Clang"))
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libc++")
+endif()
+
+if (BANDIT_BUILD_SPECS)
+ FILE(GLOB BanditSpecSourceFiles specs/*.cpp specs/**/*.cpp)
+ add_executable(bandit-specs ${BanditSpecSourceFiles} )
+ set_target_properties(bandit-specs PROPERTIES COTIRE_CXX_PREFIX_HEADER_INIT "specs/specs.h")
+ set_target_properties(bandit-specs PROPERTIES COTIRE_ADD_UNIT_BUILD FALSE)
+ cotire(bandit-specs)
+endif()
+
+add_subdirectory(bandit/assertion_frameworks/snowhouse)
+
+if (BANDIT_BUILD_SPECS AND BANDIT_RUN_SPECS)
+ add_custom_command(TARGET bandit-specs
+ POST_BUILD
+ COMMAND bandit-specs --no-color --reporter=dots
+ WORKING_DIRECTORY ./bin)
+elseif (BANDIT_RUN_SPECS)
+ message(WARNING "Unable to run Bandit specs - set:\n option(BANDIT_BUILD_SPECS, \"Build the Bandit specs\" ON)\nand clear your CMake cache")
+endif()
+
diff --git a/vendor/bandit/LICENSE.md b/vendor/bandit/LICENSE.md
new file mode 100644
index 00000000..9d61348c
--- /dev/null
+++ b/vendor/bandit/LICENSE.md
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) 2013 Joakim Karlsson
+
+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
+AUTHORS OR COPYRIGHT HOLDERS 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.
diff --git a/vendor/bandit/README.md b/vendor/bandit/README.md
new file mode 100644
index 00000000..0c95d420
--- /dev/null
+++ b/vendor/bandit/README.md
@@ -0,0 +1,63 @@
+bandit
+======
+[![Build Status](https://travis-ci.org/joakimkarlsson/bandit.png)](https://travis-ci.org/joakimkarlsson/bandit)
+
+Human friendly unit testing for C++11
+
+Bandit is a framework for C++11 that wants to make working with unit tests a pleasant
+experience.
+
+For more information, go to [the bandit website](http://banditcpp.org).
+
+Bandit is released under the [MIT license](LICENSE.md)
+
+#An example
+
+This is a complete test application written in bandit:
+
+```cpp
+#include <bandit/bandit.h>
+using namespace bandit;
+
+// Tell bandit there are tests here.
+go_bandit([](){
+
+ // We're describing how a fuzzbox works.
+ describe("fuzzbox:", [](){
+ guitar_ptr guitar;
+ fuzzbox_ptr fuzzbox;
+
+ // Make sure each test has a fresh setup with
+ // a guitar with a fuzzbox connected to it.
+ before_each([&](){
+ guitar = guitar_ptr(new struct guitar());
+ fuzzbox = fuzzbox_ptr(new struct fuzzbox());
+ guitar->add_effect(*fuzzbox);
+ });
+
+ it("starts in clean mode", [&](){
+ AssertThat(guitar->sound(), Equals(sounds::clean));
+ });
+
+ // Describe what happens when we turn on the fuzzbox.
+ describe("in distorted mode", [&](){
+
+ // Turn on the fuzzbox.
+ before_each([&](){
+ fuzzbox->flip();
+ });
+
+ it("sounds distorted", [&](){
+ AssertThat(guitar->sound(), Equals(sounds::distorted));
+ });
+ });
+ });
+
+});
+
+int main(int argc, char* argv[])
+{
+ // Run the tests.
+ return bandit::run(argc, argv);
+}
+```
diff --git a/vendor/bandit/bandit/adapters/adapter.h b/vendor/bandit/bandit/adapters/adapter.h
new file mode 100644
index 00000000..809212a1
--- /dev/null
+++ b/vendor/bandit/bandit/adapters/adapter.h
@@ -0,0 +1,12 @@
+#ifndef BANDIT_ADAPTER_H
+#define BANDIT_ADAPTER_H
+
+namespace bandit { namespace adapters {
+
+ struct assertion_adapter
+ {
+ virtual void adapt_exceptions(detail::voidfunc_t) = 0;
+ };
+}}
+
+#endif
diff --git a/vendor/bandit/bandit/adapters/adapters.h b/vendor/bandit/bandit/adapters/adapters.h
new file mode 100644
index 00000000..fbfddaea
--- /dev/null
+++ b/vendor/bandit/bandit/adapters/adapters.h
@@ -0,0 +1,16 @@
+#ifndef BANDIT_ADAPTERS_H
+#define BANDIT_ADAPTERS_H
+
+#include <bandit/adapters/adapter.h>
+#include <bandit/adapters/snowhouse.h>
+
+namespace bandit { namespace detail {
+
+ inline bandit::adapters::assertion_adapter& registered_adapter()
+ {
+ static bandit::adapters::snowhouse_adapter adapter;
+ return adapter;
+ }
+}}
+
+#endif
diff --git a/vendor/bandit/bandit/adapters/snowhouse.h b/vendor/bandit/bandit/adapters/snowhouse.h
new file mode 100644
index 00000000..f0776662
--- /dev/null
+++ b/vendor/bandit/bandit/adapters/snowhouse.h
@@ -0,0 +1,22 @@
+#ifndef BANDIT_ADAPTERS_SNOWHOUSE_H
+#define BANDIT_ADAPTERS_SNOWHOUSE_H
+
+namespace bandit { namespace adapters {
+
+ struct snowhouse_adapter : public assertion_adapter
+ {
+ void adapt_exceptions(detail::voidfunc_t func)
+ {
+ try
+ {
+ func();
+ }
+ catch(const snowhouse::AssertionException& ex)
+ {
+ throw bandit::detail::assertion_exception(ex.GetMessage(), ex.GetFilename(), ex.GetLineNumber());
+ }
+ }
+ };
+
+}}
+#endif
diff --git a/vendor/bandit/bandit/assertion_exception.h b/vendor/bandit/bandit/assertion_exception.h
new file mode 100644
index 00000000..9abc9867
--- /dev/null
+++ b/vendor/bandit/bandit/assertion_exception.h
@@ -0,0 +1,41 @@
+#ifndef BANDIT_ASSERTION_EXCEPTION_H
+#define BANDIT_ASSERTION_EXCEPTION_H
+
+namespace bandit { namespace detail {
+
+ struct assertion_exception : public std::runtime_error
+ {
+ assertion_exception(const std::string& message,
+ const std::string& filename, const unsigned int linenumber)
+ : std::runtime_error(message), file_name_(filename), line_number_(linenumber)
+ {}
+
+ assertion_exception(const std::string& message)
+ : std::runtime_error(message), line_number_(0)
+ {}
+
+ //
+ // To make gcc < 4.7 happy.
+ //
+ assertion_exception(const assertion_exception&) = default;
+ assertion_exception(assertion_exception&&) = default;
+ virtual ~assertion_exception() noexcept
+ {}
+
+ const std::string& file_name() const
+ {
+ return file_name_;
+ }
+
+ unsigned int line_number() const
+ {
+ return line_number_;
+ }
+
+ private:
+ std::string file_name_;
+ unsigned int line_number_;
+ };
+}}
+
+#endif
diff --git a/vendor/bandit/bandit/assertion_frameworks/matchers/BeCloseTo.h b/vendor/bandit/bandit/assertion_frameworks/matchers/BeCloseTo.h
new file mode 100644
index 00000000..e4507c4c
--- /dev/null
+++ b/vendor/bandit/bandit/assertion_frameworks/matchers/BeCloseTo.h
@@ -0,0 +1,55 @@
+#ifndef BANDIT_BECLOSETO_H
+#define BANDIT_BECLOSETO_H
+
+#include "Matcher.h"
+
+namespace bandit { namespace Matchers {
+
+ template<typename T>
+ class BeCloseTo : public Matcher
+ {
+ public:
+ explicit BeCloseTo(const T& expectedValue): Matcher(), _expectedValue(expectedValue), _threshold(0.01) {}
+
+ BeCloseTo<T>& within(float threshold)
+ {
+ _threshold = threshold;
+ return *this;
+ }
+
+ template<typename U>
+ bool matches(const U& actualValue) const
+ {
+ return this->subtractable_types_match(actualValue, _expectedValue);
+ }
+
+
+ protected:
+ virtual std::string failure_message_end() const
+ {
+ std::ostringstream ss;
+ ss << "be close to <" << _expectedValue << ">" << " (within " << _threshold << ")";
+ return ss.str();
+ }
+
+ private:
+ template<typename U, typename V>
+ bool subtractable_types_match(const U& actualValue, const V& expectedValue) const
+ {
+ return (actualValue > (expectedValue - _threshold)) && (actualValue < (expectedValue + _threshold));
+ }
+
+
+ private:
+ const T& _expectedValue;
+ float _threshold;
+ };
+
+ template<typename T>
+ BeCloseTo<T> be_close_to(const T& expectedValue)
+ {
+ return BeCloseTo<T>(expectedValue);
+ }
+}}
+
+#endif // BANDIT_BECLOSETO_H
diff --git a/vendor/bandit/bandit/assertion_frameworks/matchers/BeEmpty.h b/vendor/bandit/bandit/assertion_frameworks/matchers/BeEmpty.h
new file mode 100644
index 00000000..a83ef994
--- /dev/null
+++ b/vendor/bandit/bandit/assertion_frameworks/matchers/BeEmpty.h
@@ -0,0 +1,32 @@
+#ifndef BANDIT_BEEMPTY_H
+#define BANDIT_BEEMPTY_H
+
+#include "Matcher.h"
+
+namespace bandit { namespace Matchers {
+
+ class BeEmpty : public Matcher
+ {
+ private:
+ // BeEmpty & operator=(const BeEmpty &);
+
+ public:
+ explicit BeEmpty() : Matcher() {}
+
+ template<typename U>
+ bool matches(const U& container) const
+ {
+ return container.empty();
+ }
+
+ protected:
+ std::string failure_message_end() const
+ {
+ return std::string("be empty");
+ }
+ };
+
+ static const BeEmpty be_empty = BeEmpty();
+}}
+
+#endif // BANDIT_BEEMPTY_H
diff --git a/vendor/bandit/bandit/assertion_frameworks/matchers/BeFalsy.h b/vendor/bandit/bandit/assertion_frameworks/matchers/BeFalsy.h
new file mode 100644
index 00000000..718c6366
--- /dev/null
+++ b/vendor/bandit/bandit/assertion_frameworks/matchers/BeFalsy.h
@@ -0,0 +1,39 @@
+#ifndef BANDIT_BEFALSY_H
+#define BANDIT_BEFALSY_H
+
+#include "Matcher.h"
+
+namespace bandit { namespace Matchers {
+
+ class BeFalsy : public Matcher
+ {
+ private:
+ // BeFalsy& operator=(const BeFalsy&);
+
+ public:
+ explicit BeFalsy() : Matcher() {}
+ // ~BeFalsy() {}
+
+ template<typename U>
+ bool matches(const U& actualValue) const
+ {
+ return !actualValue;
+ }
+
+ bool matches(const std::nullptr_t&) const
+ {
+ return true;
+ }
+
+
+ protected:
+ virtual std::string failure_message_end() const
+ {
+ return std::string("evaluate to false");
+ }
+ };
+
+ static const BeFalsy be_falsy = BeFalsy();
+}}
+
+#endif // BANDIT_BEFALSY_H
diff --git a/vendor/bandit/bandit/assertion_frameworks/matchers/BeGTE.h b/vendor/bandit/bandit/assertion_frameworks/matchers/BeGTE.h
new file mode 100644
index 00000000..072b2caf
--- /dev/null
+++ b/vendor/bandit/bandit/assertion_frameworks/matchers/BeGTE.h
@@ -0,0 +1,45 @@
+#ifndef BANDIT_BEGREATERTHANOREQUAL_H
+#define BANDIT_BEGREATERTHANOREQUAL_H
+
+#include "Matcher.h"
+
+namespace bandit { namespace Matchers {
+
+ template<typename T>
+ class BeGTE : public Matcher
+ {
+ public:
+ explicit BeGTE(const T& expectedValue) : Matcher(), _expectedValue(expectedValue) {}
+
+ template<typename U>
+ bool matches(const U& actualValue) const
+ {
+ return actualValue >= _expectedValue;
+ }
+
+ protected:
+ virtual std::string failure_message_end() const
+ {
+ std::ostringstream ss;
+ ss << "be greater than or equal to <" << _expectedValue << ">";
+ return ss.str();
+ }
+
+ private:
+ const T& _expectedValue;
+ };
+
+ template<typename T>
+ BeGTE<T> be_gte(const T& expectedValue)
+ {
+ return BeGTE<T>(expectedValue);
+ }
+
+ template<typename T>
+ BeGTE<T> be_greater_than_or_equal_to(const T& expectedValue)
+ {
+ return be_gte(expectedValue);
+ }
+}}
+
+#endif // BANDIT_BEGREATERTHANOREQUAL_H
diff --git a/vendor/bandit/bandit/assertion_frameworks/matchers/BeGreaterThan.h b/vendor/bandit/bandit/assertion_frameworks/matchers/BeGreaterThan.h
new file mode 100644
index 00000000..95d93d1e
--- /dev/null
+++ b/vendor/bandit/bandit/assertion_frameworks/matchers/BeGreaterThan.h
@@ -0,0 +1,39 @@
+#ifndef BANDIT_BEGREATERTHAN_H
+#define BANDIT_BEGREATERTHAN_H
+
+#include "Matcher.h"
+
+namespace bandit { namespace Matchers {
+
+ template<typename T>
+ class BeGreaterThan : public Matcher
+ {
+ public:
+ explicit BeGreaterThan(const T& expectedValue) : Matcher(), _expectedValue(expectedValue) {}
+
+ template<typename U>
+ bool matches(const U& actualValue) const
+ {
+ return actualValue > _expectedValue;
+ }
+
+ protected:
+ virtual std::string failure_message_end() const
+ {
+ std::ostringstream ss;
+ ss << "be greater than <" << _expectedValue << ">";
+ return ss.str();
+ }
+
+ private:
+ const T& _expectedValue;
+ };
+
+ template<typename T>
+ BeGreaterThan<T> be_greater_than(const T& expectedValue)
+ {
+ return BeGreaterThan<T>(expectedValue);
+ }
+}}
+
+#endif // BANDIT_BEGREATERTHAN_H
diff --git a/vendor/bandit/bandit/assertion_frameworks/matchers/BeLTE.h b/vendor/bandit/bandit/assertion_frameworks/matchers/BeLTE.h
new file mode 100644
index 00000000..83463f75
--- /dev/null
+++ b/vendor/bandit/bandit/assertion_frameworks/matchers/BeLTE.h
@@ -0,0 +1,45 @@
+#ifndef BANDIT_BELESSTHANOREQUAL_H
+#define BANDIT_BELESSTHANOREQUAL_H
+
+#include "Matcher.h"
+
+namespace bandit { namespace Matchers {
+
+ template<typename T>
+ class BeLTE : public Matcher
+ {
+ public:
+ explicit BeLTE(const T& expectedValue) : Matcher(), _expectedValue(expectedValue) {}
+
+ template<typename U>
+ bool matches(const U& actualValue) const
+ {
+ return actualValue <= _expectedValue;
+ }
+
+ protected:
+ virtual std::string failure_message_end() const
+ {
+ std::ostringstream ss;
+ ss << "be less than or equal to <" << _expectedValue << ">";
+ return ss.str();
+ }
+
+ private:
+ const T& _expectedValue;
+ };
+
+ template<typename T>
+ BeLTE<T> be_lte(const T& expectedValue)
+ {
+ return BeLTE<T>(expectedValue);
+ }
+
+ template<typename T>
+ BeLTE<T> be_less_than_or_equal_to(const T& expectedValue)
+ {
+ return be_lte(expectedValue);
+ }
+}}
+
+#endif // BANDIT_BELESSTHANOREQUAL_H
diff --git a/vendor/bandit/bandit/assertion_frameworks/matchers/BeLessThan.h b/vendor/bandit/bandit/assertion_frameworks/matchers/BeLessThan.h
new file mode 100644
index 00000000..87a2dc5e
--- /dev/null
+++ b/vendor/bandit/bandit/assertion_frameworks/matchers/BeLessThan.h
@@ -0,0 +1,39 @@
+#ifndef BANDIT_BELESSTHAN_H
+#define BANDIT_BELESSTHAN_H
+
+#include "Matcher.h"
+
+namespace bandit { namespace Matchers {
+
+ template<typename T>
+ class BeLessThan : public Matcher
+ {
+ public:
+ explicit BeLessThan(const T& expectedValue) : Matcher(), _expectedValue(expectedValue) {}
+
+ template<typename U>
+ bool matches(const U& actualValue) const
+ {
+ return actualValue < _expectedValue;
+ }
+
+ protected:
+ virtual std::string failure_message_end() const
+ {
+ std::ostringstream ss;
+ ss << "be less than <" << _expectedValue << ">";
+ return ss.str();
+ }
+
+ private:
+ const T& _expectedValue;
+ };
+
+ template<typename T>
+ BeLessThan<T> be_less_than(const T& expectedValue)
+ {
+ return BeLessThan<T>(expectedValue);
+ }
+}}
+
+#endif // BANDIT_BELESSTHAN_H
diff --git a/vendor/bandit/bandit/assertion_frameworks/matchers/BeNull.h b/vendor/bandit/bandit/assertion_frameworks/matchers/BeNull.h
new file mode 100644
index 00000000..6e034d10
--- /dev/null
+++ b/vendor/bandit/bandit/assertion_frameworks/matchers/BeNull.h
@@ -0,0 +1,29 @@
+#ifndef BANDIT_BENULL_H
+#define BANDIT_BENULL_H
+
+#include "Matcher.h"
+
+namespace bandit { namespace Matchers {
+
+ class BeNull : public Matcher
+ {
+ public:
+ BeNull() : Matcher() {}
+
+ template<typename U>
+ bool matches(U *const & actualValue) const
+ {
+ return !actualValue;
+ }
+
+ protected:
+ std::string failure_message_end() const
+ {
+ return std::string("be nil");
+ }
+ };
+
+ static const BeNull be_null = BeNull();
+}}
+
+#endif // BANDIT_BENULL_H
diff --git a/vendor/bandit/bandit/assertion_frameworks/matchers/BeTruthy.h b/vendor/bandit/bandit/assertion_frameworks/matchers/BeTruthy.h
new file mode 100644
index 00000000..c8652538
--- /dev/null
+++ b/vendor/bandit/bandit/assertion_frameworks/matchers/BeTruthy.h
@@ -0,0 +1,35 @@
+#ifndef BANDIT_BETRUTHY_H
+#define BANDIT_BETRUTHY_H
+
+#include "Matcher.h"
+
+namespace bandit { namespace Matchers {
+
+ class BeTruthy : public Matcher
+ {
+ public:
+ BeTruthy() : Matcher() {}
+
+ template<typename U>
+ bool matches(const U& actualValue) const
+ {
+ return !!actualValue;
+ }
+
+ bool matches(const std::nullptr_t&) const
+ {
+ return false;
+ }
+
+
+ protected:
+ virtual std::string failure_message_end() const
+ {
+ return std::string("evaluate to true");
+ }
+ };
+
+ static const BeTruthy be_truthy = BeTruthy();
+}}
+
+#endif // BANDIT_BETRUTHY_H
diff --git a/vendor/bandit/bandit/assertion_frameworks/matchers/Contain.h b/vendor/bandit/bandit/assertion_frameworks/matchers/Contain.h
new file mode 100644
index 00000000..f048e3a3
--- /dev/null
+++ b/vendor/bandit/bandit/assertion_frameworks/matchers/Contain.h
@@ -0,0 +1,58 @@
+#ifndef BANDIT_CONTAIN_H
+#define BANDIT_CONTAIN_H
+
+#include <cstring>
+#include <vector>
+
+#include "Matcher.h"
+
+namespace bandit { namespace Matchers {
+
+ template<typename T>
+ class Contain : public Matcher
+ {
+ public:
+ explicit Contain(const T& element) : Matcher(), _element(element) {}
+
+ template<typename U>
+ bool matches(const U& container) const
+ {
+ return container.find(_element) != container.end();
+ }
+
+ template<typename U>
+ bool matches(const std::vector<U>& container) const
+ {
+ return std::find(container.begin(), container.end(), _element) != container.end();
+ }
+
+ bool matches(const char *const container) const
+ {
+ return (_element != NULL) && (container != NULL) && (strstr(container, _element) != NULL);
+ }
+
+ bool matches(char *const container) const
+ {
+ return (_element != NULL) && (container != NULL) && (strstr(container, _element) != NULL);
+ }
+
+ protected:
+ std::string failure_message_end() const
+ {
+ std::ostringstream ss;
+ ss << "contain <" << _element << ">";
+ return ss.str();
+ }
+
+ private:
+ const T& _element;
+ };
+
+ template<typename T>
+ Contain<T> contain(const T& element)
+ {
+ return Contain<T>(element);
+ }
+}}
+
+#endif // BANDIT_CONTAIN_H
diff --git a/vendor/bandit/bandit/assertion_frameworks/matchers/Equal.h b/vendor/bandit/bandit/assertion_frameworks/matchers/Equal.h
new file mode 100644
index 00000000..521c6008
--- /dev/null
+++ b/vendor/bandit/bandit/assertion_frameworks/matchers/Equal.h
@@ -0,0 +1,90 @@
+#ifndef BANDIT_EQUAL_H
+#define BANDIT_EQUAL_H
+
+#include <cstring>
+#include <memory>
+
+#include "Matcher.h"
+
+namespace bandit { namespace Matchers {
+
+ template<typename T>
+ std::ostream& operator<<(std::ostream& os, const std::unique_ptr<T>& obj)
+ {
+ return os << *obj;
+ }
+
+ template<typename T>
+ class Equal : public Matcher
+ {
+ public:
+ explicit Equal(const T& expectedValue) : Matcher(), _expectedValue(expectedValue) {}
+
+ template<typename U>
+ bool matches(const U& actualValue) const
+ {
+ return actualValue == _expectedValue;
+ }
+
+ bool matches(char* actualValue) const
+ {
+ return strcmp(actualValue, &*_expectedValue) == 0;
+ }
+
+ bool matches(const char* actualValue) const
+ {
+ return strcmp(actualValue, &*_expectedValue) == 0;
+ }
+
+ template<typename U>
+ bool matches(const std::unique_ptr<U>& pointer) const
+ {
+ return matches(pointer.get());
+ }
+
+ protected:
+ virtual std::string failure_message_end() const
+ {
+ std::ostringstream ss;
+ ss << "equal <" << _expectedValue << ">";
+ return ss.str();
+ }
+
+ private:
+ const T& _expectedValue;
+ };
+
+ template<typename T>
+ Equal<T> equal(const T& expectedValue)
+ {
+ return Equal<T>(expectedValue);
+ }
+
+ template<typename T, typename U>
+ bool operator==(const ValueProxy<T>& actualValue, const U& expectedValue)
+ {
+ return actualValue.to == expectedValue;
+ }
+
+ template<typename T, typename U>
+ bool operator==(const MatchProxy<T>& matchProxy, const U& expectedValue)
+ {
+ matchProxy(equal(expectedValue));
+ return true;
+ }
+
+ template<typename T, typename U>
+ bool operator!=(const ValueProxy<T>& actualValue, const U& expectedValue)
+ {
+ return actualValue.to != expectedValue;
+ }
+
+ template<typename T, typename U>
+ bool operator!=(const MatchProxy<T>& matchProxy, const U& expectedValue)
+ {
+ matchProxy.negate()(equal(expectedValue));
+ return true;
+ }
+}}
+
+#endif // BANDIT_EQUAL_H
diff --git a/vendor/bandit/bandit/assertion_frameworks/matchers/MatchProxy.h b/vendor/bandit/bandit/assertion_frameworks/matchers/MatchProxy.h
new file mode 100644
index 00000000..b637ef0d
--- /dev/null
+++ b/vendor/bandit/bandit/assertion_frameworks/matchers/MatchProxy.h
@@ -0,0 +1,43 @@
+#ifndef BANDIT_MATCHPROXY_H
+#define BANDIT_MATCHPROXY_H
+
+#include "MatcherException.h"
+
+namespace bandit { namespace Matchers
+{
+ template<typename T> class ValueProxy;
+
+ template<typename T>
+ class MatchProxy
+ {
+ private:
+ template<typename U>
+ MatchProxy(const MatchProxy<U>&);
+
+ template<typename U>
+ MatchProxy& operator=(const MatchProxy<U>&);
+
+ public:
+ explicit MatchProxy(const ValueProxy<T>& value, bool negate_ = false) : _value(value), _negate(negate_) {}
+
+ template<typename MatcherType>
+ void operator()(const MatcherType& matcher) const
+ {
+ if( matcher.matches(_value._value) == _negate )
+ {
+ throw MatcherException(_value._filename, _value._lineNumber, matcher.failure_message(_value._value, _negate));
+ }
+ }
+
+ MatchProxy<T> negate() const
+ {
+ return MatchProxy<T>(_value, !_negate);
+ }
+
+ private:
+ const ValueProxy<T>& _value;
+ bool _negate;
+ };
+}}
+
+#endif // BANDIT_MATCHPROXY_H
diff --git a/vendor/bandit/bandit/assertion_frameworks/matchers/Matcher.h b/vendor/bandit/bandit/assertion_frameworks/matchers/Matcher.h
new file mode 100644
index 00000000..ad48c0a5
--- /dev/null
+++ b/vendor/bandit/bandit/assertion_frameworks/matchers/Matcher.h
@@ -0,0 +1,74 @@
+#ifndef BANDIT_MATCHER_H
+#define BANDIT_MATCHER_H
+
+#include <sstream>
+
+//#import "CedarStringifiers.h"
+
+namespace bandit { namespace Matchers {
+ class Matcher
+ {
+ public:
+ Matcher() {}
+
+ template<typename U>
+ std::string failure_message(const U& value, bool negate) const
+ {
+ std::ostringstream ss;
+ ss << "Expected <" << value << "> " << (negate ? "to not " : "to ") << failure_message_end();
+ return ss.str();
+ }
+
+ std::string failure_message(char *const value, bool negate) const
+ {
+ return failure_message((value ? value : "NULL"), negate);
+ }
+
+ template<typename U>
+ std::string failure_message(const std::unique_ptr<U>& value, bool negate) const
+ {
+ return failure_message(value.get(), negate);
+ }
+
+ std::string failure_message(const std::nullptr_t pointer, bool negate) const
+ {
+ (void)pointer;
+ return failure_message("nullptr", negate);
+ }
+
+ template<typename U>
+ std::string failure_message(std::function<U>& value, bool negate) const
+ {
+ return failure_message(typeid(value).name(), negate);
+ }
+
+ template<typename U>
+ std::string failure_message(const std::function<U>& value, bool negate) const
+ {
+ return failure_message(typeid(value).name(), negate);
+ }
+
+ template<typename U, template <class T, class = std::allocator<T> > class container >
+ std::string failure_message(const container<U>& value, bool negate) const
+ {
+ return failure_message(typeid(value).name(), negate);
+ }
+
+ template<typename U, template <class T, class = std::less<T>, class = std::allocator<T> > class container >
+ std::string failure_message(const container<U>& value, bool negate) const
+ {
+ return failure_message(typeid(value).name(), negate);
+ }
+
+ template<typename U, typename V, template <class K, class T, class = std::less<K>, class = std::allocator<std::pair<const K,T>> > class container >
+ std::string failure_message(const container<U,V>& value, bool negate) const
+ {
+ return failure_message(typeid(value).name(), negate);
+ }
+
+ protected:
+ virtual std::string failure_message_end() const = 0;
+ };
+}}
+
+#endif // BANDIT_MATCHER_H
diff --git a/vendor/bandit/bandit/assertion_frameworks/matchers/MatcherException.h b/vendor/bandit/bandit/assertion_frameworks/matchers/MatcherException.h
new file mode 100644
index 00000000..5d657ed7
--- /dev/null
+++ b/vendor/bandit/bandit/assertion_frameworks/matchers/MatcherException.h
@@ -0,0 +1,16 @@
+#ifndef BANDIT_MATCHER_EXCEPTION_H
+#define BANDIT_MATCHER_EXCEPTION_H
+
+#include <bandit/assertion_exception.h>
+
+namespace bandit { namespace Matchers {
+ class MatcherException : public detail::assertion_exception
+ {
+ public:
+ MatcherException(const std::string& filename, const unsigned linenumber, const std::string& message) : detail::assertion_exception(message, filename, linenumber) {}
+ MatcherException(const MatcherException&) = default;
+ virtual ~MatcherException() noexcept {}
+ };
+}}
+
+#endif // BANDIT_MATCHER_EXCEPTION_H
diff --git a/vendor/bandit/bandit/assertion_frameworks/matchers/ThrowException.h b/vendor/bandit/bandit/assertion_frameworks/matchers/ThrowException.h
new file mode 100644
index 00000000..cd8bfc34
--- /dev/null
+++ b/vendor/bandit/bandit/assertion_frameworks/matchers/ThrowException.h
@@ -0,0 +1,60 @@
+#ifndef BANDIT_THROWEXCEPTION_H
+#define BANDIT_THROWEXCEPTION_H
+
+#include "Matcher.h"
+
+namespace bandit { namespace Matchers {
+
+ template <typename T>
+ class ThrowException : public Matcher
+ {
+ public:
+ ThrowException() : Matcher(), _allow_subclasses(false) {}
+ explicit ThrowException(bool allow_subclasses) : Matcher(), _allow_subclasses(allow_subclasses) {}
+
+ template <typename U = std::exception>
+ ThrowException<U> operator()() const
+ {
+ return ThrowException<U>();
+ }
+
+ ThrowException& or_subclass()
+ {
+ _allow_subclasses = true;
+ return *this;
+ }
+
+ template <typename U>
+ bool matches(const U& block) const
+ {
+ try
+ {
+ block();
+ }
+ catch(const T& e)
+ {
+ return true;
+ }
+ catch(...) // Wrong exception
+ {
+ _exception = std::current_exception();
+ }
+
+ return false;
+ }
+
+ protected:
+ std::string failure_message_end() const
+ {
+ return std::string("throw an exception");
+ }
+
+ private:
+ bool _allow_subclasses;
+ mutable std::exception_ptr _exception;
+ };
+
+ static const ThrowException<std::exception> throw_exception;
+}}
+
+#endif // BANDIT_THROWEXCEPTION_H
diff --git a/vendor/bandit/bandit/assertion_frameworks/matchers/ValueProxy.h b/vendor/bandit/bandit/assertion_frameworks/matchers/ValueProxy.h
new file mode 100644
index 00000000..0cd5d35c
--- /dev/null
+++ b/vendor/bandit/bandit/assertion_frameworks/matchers/ValueProxy.h
@@ -0,0 +1,26 @@
+#ifndef BANDIT_VALUEPROXY_H
+#define BANDIT_VALUEPROXY_H
+
+#include "MatchProxy.h"
+
+namespace bandit { namespace Matchers {
+
+ template<typename T>
+ class ValueProxy
+ {
+ public:
+ MatchProxy<T> to;
+ MatchProxy<T> to_not;
+
+ explicit ValueProxy(const char* filename, int lineNumber, const T& value) : to(*this), to_not(*this, true), _value(value), _filename(filename), _lineNumber(lineNumber) {}
+
+ private:
+ friend class MatchProxy<T>;
+
+ const T& _value;
+ std::string _filename;
+ int _lineNumber;
+ };
+}}
+
+#endif // BANDIT_VALUEPROXY_H
diff --git a/vendor/bandit/bandit/assertion_frameworks/matchers/matchers.h b/vendor/bandit/bandit/assertion_frameworks/matchers/matchers.h
new file mode 100644
index 00000000..033cefcd
--- /dev/null
+++ b/vendor/bandit/bandit/assertion_frameworks/matchers/matchers.h
@@ -0,0 +1,19 @@
+#ifndef BANDIT_MATCHERS_H
+#define BANDIT_MATCHERS_H
+
+#include "must.h"
+
+#include "BeCloseTo.h"
+#include "BeEmpty.h"
+#include "BeFalsy.h"
+#include "BeGreaterThan.h"
+#include "BeGTE.h"
+#include "BeLessThan.h"
+#include "BeLTE.h"
+#include "BeNull.h"
+#include "BeTruthy.h"
+#include "Contain.h"
+#include "Equal.h"
+#include "ThrowException.h"
+
+#endif // BANDIT_MATCHERS_H
diff --git a/vendor/bandit/bandit/assertion_frameworks/matchers/must.h b/vendor/bandit/bandit/assertion_frameworks/matchers/must.h
new file mode 100644
index 00000000..54eedb7f
--- /dev/null
+++ b/vendor/bandit/bandit/assertion_frameworks/matchers/must.h
@@ -0,0 +1,36 @@
+#ifndef BANDIT_MUST_H
+#define BANDIT_MUST_H
+
+#include "ValueProxy.h"
+
+namespace bandit { namespace Matchers
+{
+ struct ValueMarker
+ {
+ const char* filename;
+ int lineNumber;
+ };
+
+ template<typename T>
+ const ValueProxy<T> operator,(const T& value, const ValueMarker& marker)
+ {
+ return ValueProxy<T>(marker.filename, marker.lineNumber, value);
+ }
+
+ template<typename T>
+ const MatchProxy<T> operator,(const ValueProxy<T>& value, bool negate)
+ {
+ return negate ? value.to_not : value.to;
+ }
+
+ template<typename T, typename MatcherType>
+ void operator,(const MatchProxy<T>& matchProxy, const MatcherType& matcher)
+ {
+ matchProxy(matcher);
+ }
+}}
+
+#define must ,(bandit::Matchers::ValueMarker){__FILE__, __LINE__},false,
+#define must_not ,(bandit::Matchers::ValueMarker){__FILE__, __LINE__},true,
+
+#endif //BANDIT_MUST_H
diff --git a/vendor/bandit/bandit/assertion_frameworks/snowhouse/CMakeLists.txt b/vendor/bandit/bandit/assertion_frameworks/snowhouse/CMakeLists.txt
new file mode 100644
index 00000000..ea43226b
--- /dev/null
+++ b/vendor/bandit/bandit/assertion_frameworks/snowhouse/CMakeLists.txt
@@ -0,0 +1,49 @@
+cmake_minimum_required(VERSION 2.8)
+
+project(snowhouse)
+
+option(SNOWHOUSE_BUILD_TESTS "Build the Snowhouse tests" ON)
+option(SNOWHOUSE_RUN_TESTS "Run the Snowhouse tests" ON)
+option(SNOWHOUSE_IS_CPP11 "Whether to build this as a C++11 project" OFF)
+
+include_directories("${PROJECT_SOURCE_DIR}")
+
+set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ./bin)
+
+set(CMAKE_CXX_FLAGS "-Wfatal-errors -Wall -W -Werror -Wfloat-equal -Wundef -Wendif-labels -Wshadow -pedantic-errors")
+
+if(SNOWHOUSE_IS_CPP11)
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wdeprecated")
+
+ if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
+ if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS "4.7")
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x")
+ else()
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
+ endif()
+ endif()
+
+ if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
+ endif()
+
+ if (CMAKE_HOST_APPLE AND (CMAKE_CXX_COMPILER_ID STREQUAL "Clang"))
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libc++")
+ endif()
+endif()
+
+message(${CMAKE_CXX_FLAGS})
+
+if (SNOWHOUSE_BUILD_TESTS)
+ FILE(GLOB SnowhouseSpecSourceFiles example/*.cpp)
+ add_executable(snowhouse-tests ${SnowhouseSpecSourceFiles})
+endif()
+
+if (SNOWHOUSE_BUILD_TESTS AND SNOWHOUSE_RUN_TESTS)
+ add_custom_command(TARGET snowhouse-tests
+ POST_BUILD
+ COMMAND snowhouse-tests
+ WORKING_DIRECTORY ./bin)
+elseif (SNOWHOUSE_RUN_TESTS)
+ message(WARNING "Unable to run snowhouse tests - set:\n option(SNOWHOUSE_BUILD_TESTS, \"Build the Snowhouse tests\" ON)\nand clear your CMakeCache.txt")
+endif()
diff --git a/vendor/bandit/bandit/assertion_frameworks/snowhouse/LICENSE_1_0.txt b/vendor/bandit/bandit/assertion_frameworks/snowhouse/LICENSE_1_0.txt
new file mode 100644
index 00000000..36b7cd93
--- /dev/null
+++ b/vendor/bandit/bandit/assertion_frameworks/snowhouse/LICENSE_1_0.txt
@@ -0,0 +1,23 @@
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
diff --git a/vendor/bandit/bandit/assertion_frameworks/snowhouse/README.md b/vendor/bandit/bandit/assertion_frameworks/snowhouse/README.md
new file mode 100644
index 00000000..ecd6e039
--- /dev/null
+++ b/vendor/bandit/bandit/assertion_frameworks/snowhouse/README.md
@@ -0,0 +1,419 @@
+snowhouse
+=========
+
+An assertion library for C++
+
+Snowhouse is a stand alone assertion framework for C++. It was originally
+developed as part of [Igloo](http://github.com/joakimkarlsson/igloo) and has
+been extracted to be usable in other contexts.
+
+## Usage
+
+```C++
+#include <snowhouse/snowhouse.h>
+using namespace snowhouse;
+
+int main()
+{
+ std::cout << "Testing that 23 is 23" << std::endl;
+ AssertThat(23, Is().EqualTo(23));
+
+ try
+ {
+ AssertThat(12, Is().LessThan(11).And().GreaterThan(99));
+ }
+ catch(const AssertionException& ex)
+ {
+ std::cout << "Apparently this failed:" << std::endl;
+ std::cout << ex.GetMessage() << std::endl;
+ }
+
+ return 0;
+}
+```
+
+### Assertions
+
+Snowhouse uses a constraint based assertion model that is heavily inspired by the
+model used in [NUnit](http://nunit.org/). An assertion in Snowhouse is written
+using the following format:
+
+```cpp
+AssertThat(actual_value, <constraint expression>);
+```
+
+where &lt;constraint expression&gt; is an expression that actual_value is evaluated against when the test is executed.
+
+Constraint expressions come in two basic forms: composite and fluent expressions
+
+#### Composite Expressions
+
+With composite expressions, you can create compact, powerful expressions that combine a set of predefined constraints with ones that you provide yourself.
+
+Example:
+
+```cpp
+AssertThat(length, IsGreaterThan(4) && !Equals(10));
+```
+
+Composite expressions can be any combination of constraints and the standard logical C++ operators.
+
+You can also add your own constraints to be used within composite expressions.
+
+####Fluent Expressions
+
+With fluent expressions, you can create assertions that better convey the intent of a test without exposing implementation-specific details. Fluent expressions aim to help you create tests that are not just by developers for developers, but rather can be read and understood by domain experts.
+
+Fluent expressions also has the ability to make assertions on the elements in a conteiner in a way you cannot achieve with composite expressions.
+
+Example:
+
+```cpp
+AssertThat(length, Is().GreaterThan(4).And().Not().EqualTo(10));
+```
+
+### Basic Constraints
+
+####Equality Constraint
+
+Used to verify equality between actual and expected.
+
+```cpp
+AssertThat(x, Equals(12));
+AssertThat(x, Is().EqualTo(12));
+```
+
+####EqualityWithDelta Constraint
+
+Used to verify equality between actual and expected, allowing the two to differ by a delta.
+
+```cpp
+AssertThat(2.49, EqualsWithDelta(2.5, 0.1));
+AssertThat(2.49, Is().EqualToWithDelta(2.5, 0.1));
+```
+
+####GreaterThan Constraint
+
+Used to verify that actual is greater than a value.
+
+```cpp
+AssertThat(x, IsGreaterThan(4));
+AssertThat(x, Is().GreaterThan(4));
+```
+
+
+####LessThan Constraint
+
+Used to verify that actual is less than a value.
+
+```cpp
+AssertThat(x, IsLessThan(3));
+AssertThat(x, Is().LessThan(3));
+```
+
+####GreaterThanOrEqualTo Constraint
+
+Used to verify that actual is greater than or equal to a value.
+
+```cpp
+AssertThat(x, IsGreaterThanOrEqualTo(5));
+AssertThat(x, Is().GreaterThanOrEqualTo(5));
+```
+
+####LessThanOrEqualTo Constraint
+
+Used to verify that actual is less than or equal to a value.
+
+```cpp
+AssertThat(x, IsLessThanOrEqualTo(6));
+AssertThat(x, Is().LessThanOrEqualTo(6));
+```
+
+### Pointer Constraints
+
+Used to check for `nullptr` equality.
+
+```cpp
+AssertThat(x, IsNull());
+AssertThat(x, Is().Null());
+```
+
+### String Constraints
+
+String assertions in Snowhouse are used to verify the values of STL strings (std::string).
+
+####Equality Constraints
+
+Used to verify that actual is equal to an expected value.
+
+```cpp
+AssertThat(actual_str, Equals("foo"));
+AssertThat(actual_str, Is().EqualTo("foo"));
+```
+
+####Contains Constraint
+
+Used to verify that a string contains a substring.
+
+```cpp
+AssertThat(actual_str, Contains("foo"));
+AssertThat(actual_str, Is().Containing("foo"));
+```
+
+####EndsWith Constraint
+
+Used to verify that a string ends with an expected substring.
+
+```cpp
+AssertThat(actual_str, EndsWith("foo"));
+AssertThat(actual_str, Is().EndingWith("foo"));
+```
+
+####StartsWith Constraint
+
+Used to verify that a string starts with an expected substring.
+
+```cpp
+AssertThat(actual_str, StartsWith("foo"));
+AssertThat(actual_str, Is().StartingWith("foo"));
+```
+
+####HasLength Constraint
+
+Used to verify that a string is of the expected length.
+
+```cpp
+AssertThat(actual_str, HasLength(5));
+AssertThat(actual_str, Is().OfLength(5));
+```
+
+###Constraints on Multi Line Strings
+
+If you have a string that contains multiple lines, you can use the collection constraints to make assertions on the content of that string. This may be handy if you have a string that, for instance, represents the resulting content of a file or a network transmission.
+
+Snowhouse can handle both windows (CR+LF) and unix (LF) line endings
+
+```cpp
+std::string lines = "First line\r\nSecond line\r\nThird line";
+AssertThat(lines, Has().Exactly(1).StartingWith("Second"));
+```
+
+###Container Constraints
+
+The following constraints can be applied to containers in the standard template library:
+
+####Contains Constraint
+
+Used to verify that a container contains an expected value.
+
+```cpp
+AssertThat(container, Contains(12));
+AssertThat(container, Is().Containing(12));
+```
+
+####HasLength Constraint
+
+Used to verify that a container has the expected length.
+
+```cpp
+AssertThat(container, HasLength(3));
+AssertThat(container, Is().OfLength(3));
+```
+
+####IsEmpty Constraint
+
+Used to verify that a container is empty.
+
+```cpp
+AssertThat(contatiner, IsEmpty());
+AssertThat(container, Is().Empty());
+```
+
+####All
+
+Used to verify that all elements of a STL sequence container matches an expectation.
+
+```cpp
+AssertThat(container, Has().All().LessThan(5).Or().EqualTo(66));
+```
+
+####AtLeast
+
+Used to verify that at least a specified amount of elements in a STL sequence container matches an expectation.
+
+```cpp
+AssertThat(container, Has().AtLeast(3).StartingWith("foo"));
+```
+
+####AtMost
+
+Used to verify that at most a specified amount of elements in a STL sequence container matches an expectation.
+
+```cpp
+Assert:That(container, Has().AtMost(2).Not().Containing("failed"));
+```
+
+####Exactly
+
+Used to verify that a STL sequence container has exactly a specified amount of elements that matches an expectation.
+
+```cpp
+AssertThat(container, Has().Exactly(3).GreaterThan(10).And().LessThan(20));
+```
+
+####EqualsContainer
+
+Used to verify that two STL sequence containers are equal.
+
+```cpp
+AssertThat(container1, EqualsContainer(container2));
+AssertThat(container1, Is().EqualToContainer(container2));
+```
+
+#####Predicate functions
+
+You can supply a predicate function or a functor to EqualsContainer to customize how to compare the elements in the two containers.
+
+With a predicate function:
+
+```cpp
+static bool are_my_types_equal(const my_type& lhs, const my_type& rhs)
+{
+ return lhs.my_val_ == rhs.my_val_;
+}
+
+AssertThat(container1, EqualsContainer(container2, are_my_types_equal));
+```
+
+With a functor as predicate:
+
+```cpp
+struct within_delta
+{
+ within_delta(int delta) : delta_(delta) {}
+
+ bool operator()(const my_type& lhs, const my_type& rhs) const
+ {
+ return abs(lhs.my_val_ - rhs.my_val_) <= delta_;
+ }
+
+private:
+ int delta_;
+};
+
+AssertThat(container1, Is().EqualToContainer(container1, within_delta(1));
+```
+
+###Exceptions
+
+Exception constraints can be used to verify that your code throws the correct exceptions.
+
+####AssertThrows
+
+AssertThrows succeeds if the exception thrown by the call is of the supplied type (or one of its subtypes).
+
+```cpp
+AssertThrows(std::logic_error, myObject.a_method(42));
+```
+
+####Making Assertions on the Thrown Exceptions
+
+If AssertThrows succeeds, it will store the thrown exception so that you can make more detailed assertions on it.
+
+```cpp
+AssertThrows(std::logic_error, myObject.a_method(42));
+AssertThat(LastException<std::logic_error>().what(), Is().Containing("logic failure"));
+```
+
+The LastException<> is available in the scope of the call to AssertThrows. An exception is not available between specs in order to avoid the result of one spec contaminating another.
+
+###Custom Constraints
+
+You can add your own constraints to Snowhouse to create more expressive specifications.
+
+####Fulfills Constraints
+
+By defining the following matcher
+
+```cpp
+struct IsEvenNumber
+{
+ bool Matches(const int actual) const
+ {
+ return (actual % 2) == 0;
+ }
+
+ friend std::ostream& operator<<(std::ostream& stm, const IsEvenNumber& );
+};
+
+std::ostream& operator<<(std::ostream& stm, const IsEvenNumber& )
+{
+ stm << "An even number";
+ return stm;
+}
+```
+
+You can create the following constraints in Snowhouse:
+
+```cpp
+AssertThat(42, Fulfills(IsEvenNumber()));
+AssertThat(42, Is().Fulfilling(IsEvenNumber()));
+```
+
+Your custom matcher should implement a method called Matches() that takes a parameter of the type you expect and returns true if the passed parameter fulfills the constraint.
+
+To get more expressive failure messages, you should also implement the streaming operator as in the example above.
+
+##Getting better output for your types
+
+Whenever Snowhouse prints an error message for a type, it will use the stream operator for that type, otherwise it will print "[unsupported type]"
+as a placeholder.
+
+```cpp
+struct MyType { /*...*/ };
+
+AssertThat(myType, Fulfills(MyConstraint());
+```
+
+Will output the following if the constraint fails:
+
+```bash
+Expected: To fulfill my constraint
+Actual: [unsupported type]
+```
+
+If we add a stream operator:
+
+```cpp
+std::ostream& operator<<(std::ostream& stream, const MyType& a)
+{
+ stream << "MyType( x = " << a.x << " )";
+ return stream;
+}
+```
+
+the output will be a bit more readable:
+
+```bash
+Expected: To fullfill my constraint
+Actual: MyType( x = 23 )
+```
+
+##Configurable Failure Handlers
+
+You can provide Snowhouse with custom failure handlers, for example to call `std::terminate` instead of throwing an exception. See `DefaultFailureHandler` for an example of a failure handler. You can derive your own macros with custom failure handlers using `SNOWHOUSE_ASSERT_THAT` and `SNOWHOUSE_ASSERT_THROWS`. See the definitions of `AssertThat` and `AssertThrows` for examples of these. Define `SNOWHOUSE_NO_MACROS` to disable the unprefixed macros `AssertThat` and `AssertThrows`.
+
+### Example Use Cases
+
+#### Assert Program State
+
+Log an error immediately as we may crash if we try to continue. Don't attempt to unwind the stack as we may be inside a destructor or `nothrow` function. We may want to call `std::terminate`, or attempt to muddle along with the rest of the program.
+
+#### Assert Program State in Safe Builds
+
+As above, but only in debug builds.
+
+#### Test Assert
+
+Assert that a test behaved as expected. Throw an exception and let our testing framework deal with the test failure.
+
diff --git a/vendor/bandit/bandit/assertion_frameworks/snowhouse/cross_compile.sh b/vendor/bandit/bandit/assertion_frameworks/snowhouse/cross_compile.sh
new file mode 100755
index 00000000..d3a73279
--- /dev/null
+++ b/vendor/bandit/bandit/assertion_frameworks/snowhouse/cross_compile.sh
@@ -0,0 +1,50 @@
+#!/bin/bash
+
+STATUS=""
+
+function build_for {
+ local CC=$1
+ local CXX=$2
+ local CXX_VERSION=$3
+
+ echo "Compiling for $CC, $CXX, $CXX_VERSION..."
+
+ if [[ "$CXX_VERSION" == "CXX" ]]; then
+ local SNOWHOUSE_IS_CPP11=OFF
+ else
+ local SNOWHOUSE_IS_CPP11=ON
+ fi
+
+ echo "SNOWHOUSE_IS_CPP11=$SNOWHOUSE_IS_CPP11"
+
+ BUILD_DIR=build-$CC-$CXX_VERSION
+ mkdir $BUILD_DIR
+ pushd $BUILD_DIR
+ CC=$CC CXX=$CXX cmake -DSNOWHOUSE_IS_CPP11=$SNOWHOUSE_IS_CPP11 ../..
+ make
+ STATUS="$STATUS\n$BUILD_DIR - Status: $?"
+ popd
+}
+
+if [[ -d builds ]]; then
+ rm -rf builds
+fi
+
+mkdir builds
+pushd builds
+
+build_for gcc-4.5 g++-4.5 CXX
+build_for gcc-4.6 g++-4.6 CXX
+build_for gcc-4.6 g++-4.6 CXX11
+build_for gcc-4.7 g++-4.7 CXX
+build_for gcc-4.7 g++-4.7 CXX11
+build_for gcc-4.8 g++-4.8 CXX
+build_for gcc-4.8 g++-4.8 CXX11
+build_for gcc-4.9 g++-4.9 CXX
+build_for gcc-4.9 g++-4.9 CXX11
+build_for clang clang++ CXX
+build_for clang clang++ CXX11
+popd
+
+echo "============================================"
+echo -e $STATUS
diff --git a/vendor/bandit/bandit/assertion_frameworks/snowhouse/example/basic_assertions.cpp b/vendor/bandit/bandit/assertion_frameworks/snowhouse/example/basic_assertions.cpp
new file mode 100644
index 00000000..2766ec0a
--- /dev/null
+++ b/vendor/bandit/bandit/assertion_frameworks/snowhouse/example/basic_assertions.cpp
@@ -0,0 +1,228 @@
+#include <stdexcept>
+#include <sstream>
+#include <snowhouse/snowhouse.h>
+using namespace snowhouse;
+#include "tests.h"
+
+void throwRuntimeError() {
+ throw std::runtime_error("This is expected");
+}
+
+struct IgnoreErrors {
+ template <class ExpectedType, class ActualType>
+ static void Handle(const ExpectedType&, const ActualType&, const char*, int)
+ {
+ }
+
+ static void Handle(const std::string&)
+ {
+ }
+};
+
+void BasicAssertions()
+{
+ std::cout << "================================================" << std::endl;
+ std::cout << " ASSERTIONS " << std::endl;
+ std::cout << "================================================" << std::endl;
+
+ std::cout << "ShouldHandleIntegerEquality" << std::endl;
+ {
+ Assert::That(5, Is().EqualTo(5));
+ }
+
+ std::cout << "ShouldDetectIntegerInequality" << std::endl;
+ {
+ AssertTestFails(Assert::That(5, Is().EqualTo(4)), "equal to 4");
+ }
+
+ std::cout << "ShouldDetectIfNotFails" << std::endl;
+ {
+ AssertTestFails(Assert::That(5, Is().Not().EqualTo(5)), "Expected: not equal to 5\nActual: 5\n");
+ }
+
+ std::cout << "ShouldHandleStrings" << std::endl;
+ {
+ Assert::That(std::string("joakim"), Is().EqualTo(std::string("joakim")));
+ }
+
+ std::cout << "ShouldHandleStringsWithoutExplicitTemplateSpecialization" << std::endl;
+ {
+ Assert::That("kim", Is().EqualTo("kim"));
+ }
+
+ std::cout << "ShouldHandleGreaterThan" << std::endl;
+ {
+ Assert::That(5, Is().GreaterThan(4));
+ }
+
+ std::cout << "ShouldDetectWhenGreaterThanFails" << std::endl;
+ {
+ AssertTestFails(Assert::That(5, Is().GreaterThan(5)),
+ "Expected: greater than 5\nActual: 5\n");
+ }
+
+ std::cout << "ShouldHandleLessThan" << std::endl;
+ {
+ Assert::That(5, Is().LessThan(6));
+ }
+
+ std::cout << "ShouldDetectWhenLessThanFails" << std::endl;
+ {
+ AssertTestFails(Assert::That(6, Is().LessThan(5)),
+ "Expected: less than 5\nActual: 6\n");
+ }
+
+ std::cout << "ShouldThrowExplicitFailureMessage" << std::endl;
+ {
+ AssertTestFails(Assert::Failure("foo"), "foo");
+ }
+
+ std::cout << "Should contain location information" << std::endl;
+ {
+ int line;
+ std::string file;
+
+ try
+ {
+ Assert::That(5, Equals(2), "filename", 32);
+ }
+ catch(const AssertionException& e)
+ {
+ line = e.GetLineNumber();
+ file = e.GetFilename();
+ }
+
+ Assert::That(line, Equals(32));
+ Assert::That(file, Equals("filename"));
+ }
+
+ std::cout << "ShouldEnsureExceptionIsThrown" << std::endl;
+ {
+
+ AssertThrows(std::runtime_error, throwRuntimeError());
+ }
+
+ std::cout << "ShouldIgnoreTheError" << std::endl;
+ {
+ ConfigurableAssert<IgnoreErrors>::That(1, Equals(2));
+ }
+
+ std::cout << "================================================" << std::endl;
+ std::cout << " ASSERTIONS EXPRESSION TEMPLATES" << std::endl;
+ std::cout << "================================================" << std::endl;
+
+ std::cout << "ShouldHandleIntegerEquality" << std::endl;
+ {
+ Assert::That(5, Equals(5));
+ }
+
+ std::cout << "ShouldDetectIntegerInequality" << std::endl;
+ {
+ AssertTestFails(Assert::That(5, Equals(4)), "equal to 4");
+ }
+
+ std::cout << "ShouldDetectIfNotFails" << std::endl;
+ {
+ AssertTestFails(Assert::That(5, !Equals(5)),
+ "Expected: not equal to 5\nActual: 5\n");
+ }
+
+ std::cout << "ShouldHandleStrings" << std::endl;
+ {
+ Assert::That(std::string("joakim"), Equals(std::string("joakim")));
+ }
+
+ std::cout << "ShouldHandleStringsWithoutExplicitTemplateSpecialization"
+ << std::endl;
+ {
+ Assert::That("kim", Equals("kim"));
+ }
+
+ std::cout << "ShouldHandleGreaterThan" << std::endl;
+ {
+ Assert::That(5, IsGreaterThan(4));
+ }
+
+ std::cout << "ShouldHandleGreaterThanOrEqualTo" << std::endl;
+ {
+ Assert::That(4, IsGreaterThanOrEqualTo(4));
+ Assert::That(5, IsGreaterThanOrEqualTo(4));
+ }
+
+ std::cout << "ShouldDetectWhenGreaterThanFails" << std::endl;
+ {
+ AssertTestFails(Assert::That(5, IsGreaterThan(5)),
+ "Expected: greater than 5\nActual: 5\n");
+ }
+
+ std::cout << "ShouldDetectWhenGreaterThanOrEqualToFails" << std::endl;
+ {
+ AssertTestFails(Assert::That(4, IsGreaterThanOrEqualTo(5)),
+ "Expected: greater than or equal to 5\nActual: 4\n");
+ }
+
+ std::cout << "ShouldHandleLessThan" << std::endl;
+ {
+ Assert::That(5, IsLessThan(6));
+ }
+
+ std::cout << "ShouldHandleLessThanOrEqualTo" << std::endl;
+ {
+ Assert::That(5, IsLessThanOrEqualTo(6));
+ Assert::That(6, IsLessThanOrEqualTo(6));
+ }
+
+ std::cout << "ShouldDetectWhenLessThanFails" << std::endl;
+ {
+ AssertTestFails(Assert::That(6, IsLessThan(5)),
+ "Expected: less than 5\nActual: 6\n");
+ }
+
+ std::cout << "ShouldDetectWhenLessThanOrEqualToFails" << std::endl;
+ {
+ AssertTestFails(Assert::That(6, IsLessThanOrEqualTo(5)),
+ "Expected: less than or equal to 5\nActual: 6\n");
+ }
+
+#if __cplusplus > 199711L
+ std::cout << "ShouldHandleNull" << std::endl;
+ {
+ Assert::That(nullptr, IsNull());
+ }
+
+ std::cout << "ShouldHandleNull" << std::endl;
+ {
+ Assert::That(nullptr, Is().Null());
+ }
+
+ std::cout << "ShouldHandleNotNull" << std::endl;
+ {
+ int anInt = 0;
+ Assert::That(&anInt, ! IsNull());
+ }
+
+ std::cout << "ShouldDetectWhenIsNullFails" << std::endl;
+ {
+ int anInt = 0;
+ std::ostringstream message;
+ message << "Expected: equal to nullptr\nActual: " << &anInt << "\n";
+ AssertTestFails(Assert::That(&anInt, IsNull()), message.str());
+ }
+
+ std::cout << "ShouldDetectWhenIsNullFails" << std::endl;
+ {
+ int anInt = 0;
+ std::ostringstream message;
+ message << "Expected: equal to nullptr\nActual: " << &anInt << "\n";
+ AssertTestFails(Assert::That(&anInt, Is().Null()), message.str());
+ }
+
+ std::cout << "ShouldDetectWhenIsNotNullFails" << std::endl;
+ {
+ std::ostringstream message;
+ message << "Expected: not equal to nullptr\nActual: nullptr\n";
+
+ AssertTestFails(Assert::That(nullptr, ! IsNull()), message.str());
+ }
+#endif
+}
diff --git a/vendor/bandit/bandit/assertion_frameworks/snowhouse/example/boolean_operators.cpp b/vendor/bandit/bandit/assertion_frameworks/snowhouse/example/boolean_operators.cpp
new file mode 100644
index 00000000..3e4577a5
--- /dev/null
+++ b/vendor/bandit/bandit/assertion_frameworks/snowhouse/example/boolean_operators.cpp
@@ -0,0 +1,48 @@
+#include <snowhouse/snowhouse.h>
+using namespace snowhouse;
+#include "tests.h"
+
+void BooleanOperators()
+{
+ std::cout << "================================================" << std::endl;
+ std::cout << " Boolean operators" << std::endl;
+ std::cout << "================================================" << std::endl;
+
+ std::cout << "ShouldHandleIsFalseOperator" << std::endl;
+ {
+ Assert::That(false, IsFalse());
+ }
+
+ std::cout << "ShouldHandleWhenIsFalseFails" << std::endl;
+ {
+ AssertTestFails(Assert::That(true, IsFalse()), "Expected: false");
+ }
+
+ std::cout << "ShouldHandleIsTrueOperator" << std::endl;
+ {
+ Assert::That(true, IsTrue());
+ }
+
+ std::cout << "ShouldHandleWhenIsTrueFails" << std::endl;
+ {
+ AssertTestFails(Assert::That(false, IsTrue()), "Expected: true");
+ }
+
+ std::cout << "ShouldHandleFluentIsTrue" << std::endl;
+ {
+ Assert::That(true, Is().True());
+ AssertTestFails(Assert::That(false, Is().True()), "Expected: true");
+ }
+
+ std::cout << "ShouldHandleFluentIsFalse" << std::endl;
+ {
+ Assert::That(false, Is().False());
+ AssertTestFails(Assert::That(true, Is().False()), "Expected: false");
+ }
+
+ std::cout << "ShouldTreatAssertWithoutConstraintAsBooleanConstrains" << std::endl;
+ {
+ Assert::That(true);
+ }
+}
+
diff --git a/vendor/bandit/bandit/assertion_frameworks/snowhouse/example/container_spec.cpp b/vendor/bandit/bandit/assertion_frameworks/snowhouse/example/container_spec.cpp
new file mode 100644
index 00000000..c668dffa
--- /dev/null
+++ b/vendor/bandit/bandit/assertion_frameworks/snowhouse/example/container_spec.cpp
@@ -0,0 +1,85 @@
+
+// Copyright Joakim Karlsson & Kim Gräsman 2010-2013.
+// Distributed under the Boost Software License, Version 1.0.
+// (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#include <snowhouse/snowhouse.h>
+using namespace snowhouse;
+#include "tests.h"
+
+struct my_type
+{
+ my_type(int my_val)
+ : my_val_(my_val)
+ {}
+
+ friend bool operator==(const my_type&, const my_type&);
+ friend bool operator!=(const my_type&, const my_type&);
+ friend std::ostream& operator<<(std::ostream&, const my_type&);
+
+ int my_val_;
+};
+
+bool operator==(const my_type& lhs, const my_type& rhs)
+{
+ return lhs.my_val_ == rhs.my_val_;
+}
+
+bool operator!=(const my_type& lhs, const my_type& rhs)
+{
+ return !(lhs == rhs);
+}
+
+std::ostream& operator<<(std::ostream& stream, const my_type& item)
+{
+ stream << "(my_type: my_val_=" << item.my_val_ << " )";
+ return stream;
+}
+
+static bool are_my_types_equal(const my_type& lhs, const my_type& rhs)
+{
+ return lhs.my_val_ == rhs.my_val_;
+}
+
+void ContainerConstraints()
+{
+ std::cout << "================================================" << std::endl;
+ std::cout << " ContainerContstraints" << std::endl;
+ std::cout << "================================================" << std::endl;
+
+ std::cout << "it_should_be_able_to_compare_containers_of_custom_types" << std::endl;
+ {
+ const my_type e[] = {my_type(1), my_type(3)};
+ const std::list<my_type> expected(e, e + sizeof(e) / sizeof(e[0]));
+ std::list<my_type> my_container_;
+ my_container_.push_back(my_type(1));
+ my_container_.push_back(my_type(3));
+
+ AssertThat(my_container_, EqualsContainer(expected));
+ }
+
+ std::cout << "it_should_handle_failing_comparisons" << std::endl;
+ {
+ const my_type e[] = {my_type(1), my_type(2)};
+ const std::list<my_type> expected(e, e + sizeof(e) / sizeof(e[0]));
+ std::list<my_type> my_container_;
+ my_container_.push_back(my_type(1));
+ my_container_.push_back(my_type(3));
+
+ AssertTestFails(Assert::That(my_container_, EqualsContainer(expected)),
+ "Expected: [ (my_type: my_val_=1 ), (my_type: my_val_=2 ) ]");
+ }
+
+ std::cout << "it_should_handle_comparison_with_a_predicate_function" << std::endl;
+ {
+ const my_type e[] = {my_type(1), my_type(3)};
+ const std::list<my_type> expected(e, e + sizeof(e) / sizeof(e[0]));
+ std::list<my_type> my_container_;
+ my_container_.push_back(my_type(1));
+ my_container_.push_back(my_type(3));
+
+ Assert::That(my_container_, EqualsContainer(expected, are_my_types_equal));
+ Assert::That(my_container_, Is().EqualToContainer(expected, are_my_types_equal));
+ }
+}
diff --git a/vendor/bandit/bandit/assertion_frameworks/snowhouse/example/custom_matchers_test.cpp b/vendor/bandit/bandit/assertion_frameworks/snowhouse/example/custom_matchers_test.cpp
new file mode 100644
index 00000000..c5437f9f
--- /dev/null
+++ b/vendor/bandit/bandit/assertion_frameworks/snowhouse/example/custom_matchers_test.cpp
@@ -0,0 +1,69 @@
+
+// Copyright Joakim Karlsson & Kim Gräsman 2010-2013.
+// Distributed under the Boost Software License, Version 1.0.
+// (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#include <snowhouse/snowhouse.h>
+using namespace snowhouse;
+#include "tests.h"
+
+struct IsEvenNumberNoStreamOperator
+{
+ bool Matches(const int actual) const
+ {
+ return (actual % 2) == 0;
+ }
+};
+
+struct IsEvenNumberWithStreamOperator
+{
+ bool Matches(const int actual) const
+ {
+ return (actual % 2) == 0;
+ }
+
+ friend std::ostream& operator<<(std::ostream& stm,
+ const IsEvenNumberWithStreamOperator& );
+};
+
+std::ostream& operator<<(std::ostream& stm,
+ const IsEvenNumberWithStreamOperator& )
+{
+ stm << "An even number";
+ return stm;
+}
+
+void CustomMatchers()
+{
+ std::cout << "================================================" << std::endl;
+ std::cout << " CustomMatchersNoStreamOperator" << std::endl;
+ std::cout << "================================================" << std::endl;
+
+ std::cout << "CanHandleCustomMatcher" << std::endl;
+ {
+ Assert::That(2, Fulfills(IsEvenNumberNoStreamOperator()));
+ }
+
+ std::cout << "CustomMatcherWithFluent" << std::endl;
+ {
+ Assert::That(2, Is().Fulfilling(IsEvenNumberNoStreamOperator()));
+ }
+
+ std::cout << "OutputsCorrectMessageWhenFails" << std::endl;
+ {
+ AssertTestFails(Assert::That(3, Fulfills(IsEvenNumberNoStreamOperator())),
+ "Expected: [unsupported type]\nActual: 3");
+ }
+
+
+ std::cout << "================================================" << std::endl;
+ std::cout << "CustomMatcherWithStreamOperator" << std::endl;
+ std::cout << "================================================" << std::endl;
+
+ std::cout << "ErrorMessageUsesCustomStreamOperatorIfAvailable" << std::endl;
+ {
+ AssertTestFails(Assert::That(3, Fulfills(IsEvenNumberWithStreamOperator())),
+ "Expected: An even number\nActual: 3");
+ }
+}
diff --git a/vendor/bandit/bandit/assertion_frameworks/snowhouse/example/exceptions_tests.cpp b/vendor/bandit/bandit/assertion_frameworks/snowhouse/example/exceptions_tests.cpp
new file mode 100644
index 00000000..0f1ac2ab
--- /dev/null
+++ b/vendor/bandit/bandit/assertion_frameworks/snowhouse/example/exceptions_tests.cpp
@@ -0,0 +1,97 @@
+
+// Copyright Joakim Karlsson & Kim Gräsman 2010-2013.
+// Distributed under the Boost Software License, Version 1.0.
+// (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#include <snowhouse/snowhouse.h>
+#include <stdexcept>
+using namespace snowhouse;
+
+#include "tests.h"
+
+class ClassWithExceptions
+{
+public:
+ int LogicError()
+ {
+ throw std::logic_error("not logical!");
+ }
+
+ double RangeError()
+ {
+ throw std::range_error("range error!");
+ }
+
+ void NoError()
+ {
+ }
+};
+
+void ExceptionTests()
+{
+ ClassWithExceptions objectUnderTest;
+
+ std::cout << "================================================" << std::endl;
+ std::cout << " ExceptionTests" << std::endl;
+ std::cout << "================================================" << std::endl;
+
+
+ std::cout << "CanDetectExceptions" << std::endl;
+ {
+ AssertThrows(std::exception, objectUnderTest.LogicError());
+ }
+
+ std::cout << "CanAssertOnLastException" << std::endl;
+ {
+ AssertThrows(std::logic_error, objectUnderTest.LogicError());
+ Assert::That(LastException<std::logic_error>().what(), Contains("not logical!"));
+ }
+
+ std::cout << "CanDetectWhenWrongExceptionIsThrown" << std::endl;
+ {
+ AssertTestFails(AssertThrows(std::logic_error, objectUnderTest.RangeError()), "Wrong exception");
+ }
+
+ std::cout << "CanPrintExpectedExceptionTypeWhenWrongExceptionIsThrown" << std::endl;
+ {
+ AssertTestFails(AssertThrows(std::logic_error, objectUnderTest.RangeError()), "Expected std::logic_error");
+ }
+
+ std::cout << "CanHaveSeveralExceptionAssertionsInSameSpec" << std::endl;
+ {
+ AssertThrows(std::logic_error, objectUnderTest.LogicError());
+ Assert::That(LastException<std::logic_error>().what(), Contains("not logical!"));
+
+ AssertThrows(std::range_error, objectUnderTest.RangeError());
+ Assert::That(LastException<std::range_error>().what(), Contains("range error!"));
+ }
+
+ std::cout << "CanHaveSeveralExceptionAssertionForTheSameExceptionInSameSpec" << std::endl;
+ {
+ AssertThrows(std::logic_error, objectUnderTest.LogicError());
+ Assert::That(LastException<std::logic_error>().what(), Contains("not logical!"));
+
+ AssertThrows(std::logic_error, objectUnderTest.LogicError());
+ Assert::That(LastException<std::logic_error>().what(), Contains("not logical!"));
+ }
+
+ std::cout << "CanDetectWhenNoExceptionIsThrown" << std::endl;
+ {
+ AssertTestFails(AssertThrows(std::logic_error, objectUnderTest.NoError()), "No exception");
+ }
+
+ std::cout << "CanPrintExpectedExceptionWhenNoExceptionIsThrown" << std::endl;
+ {
+ AssertTestFails(AssertThrows(std::logic_error, objectUnderTest.NoError()), "Expected std::logic_error");
+ }
+
+ std::cout << "ExceptionsAreDestoryedWhenWeExitScope" << std::endl;
+ {
+ {
+ AssertThrows(std::logic_error, objectUnderTest.LogicError());
+ }
+ AssertThrows(AssertionException, LastException<std::logic_error>());
+ Assert::That(LastException<AssertionException>().GetMessage(), Contains("No exception was stored"));
+ }
+}
diff --git a/vendor/bandit/bandit/assertion_frameworks/snowhouse/example/expression_error_handling.cpp b/vendor/bandit/bandit/assertion_frameworks/snowhouse/example/expression_error_handling.cpp
new file mode 100644
index 00000000..de96f038
--- /dev/null
+++ b/vendor/bandit/bandit/assertion_frameworks/snowhouse/example/expression_error_handling.cpp
@@ -0,0 +1,28 @@
+#include <snowhouse/snowhouse.h>
+using namespace snowhouse;
+#include "tests.h"
+
+void ExpressionErrorHandling()
+{
+ std::cout << "================================================" << std::endl;
+ std::cout << " ExpressionErrorHandling" << std::endl;
+ std::cout << "================================================" << std::endl;
+
+ std::vector<int> collection;
+ collection.push_back(1);
+ collection.push_back(2);
+ collection.push_back(3);
+
+ std::cout << "AnInvalidAllOperationShouldBeReportedProperly" << std::endl;
+ {
+ AssertTestFails(Assert::That(collection, Has().All()),
+ "The expression after \"all\" operator does not yield any result");
+ }
+
+ std::cout << "AnInvalidAtLeastOperationShouldBeReportedProperly" << std::endl;
+ {
+ AssertTestFails(Assert::That(collection, Has().AtLeast(2)),
+ "The expression after \"at least 2\" operator does not yield any result");
+ }
+
+}
diff --git a/vendor/bandit/bandit/assertion_frameworks/snowhouse/example/main.cpp b/vendor/bandit/bandit/assertion_frameworks/snowhouse/example/main.cpp
new file mode 100644
index 00000000..616b97ff
--- /dev/null
+++ b/vendor/bandit/bandit/assertion_frameworks/snowhouse/example/main.cpp
@@ -0,0 +1,43 @@
+#include <snowhouse/snowhouse.h>
+using namespace snowhouse;
+#include "tests.h"
+
+void BooleanOperators();
+void BasicAssertions();
+void ContainerConstraints();
+void CustomMatchers();
+void ExceptionTests();
+void ExpressionErrorHandling();
+void MapTests();
+void OperatorTests();
+void SequenceContainerTests();
+void StringLineTests();
+void StringTests();
+void StringizeTests();
+
+int main()
+{
+ try
+ {
+ BasicAssertions();
+ BooleanOperators();
+ ContainerConstraints();
+ CustomMatchers();
+ ExceptionTests();
+ ExpressionErrorHandling();
+ MapTests();
+ OperatorTests();
+ SequenceContainerTests();
+ StringLineTests();
+ StringTests();
+ StringizeTests();
+ }
+ catch(const AssertionException& e)
+ {
+ std::cout << "Tests failed!" << std::endl;
+ std::cout << e.GetMessage() << std::endl;
+ return 1;
+ }
+
+ return 0;
+}
diff --git a/vendor/bandit/bandit/assertion_frameworks/snowhouse/example/map_tests.cpp b/vendor/bandit/bandit/assertion_frameworks/snowhouse/example/map_tests.cpp
new file mode 100644
index 00000000..813b5011
--- /dev/null
+++ b/vendor/bandit/bandit/assertion_frameworks/snowhouse/example/map_tests.cpp
@@ -0,0 +1,38 @@
+#include <snowhouse/snowhouse.h>
+using namespace snowhouse;
+#include "tests.h"
+
+void MapTests()
+{
+ std::cout << "================================================" << std::endl;
+ std::cout << " MapTests" << std::endl;
+ std::cout << "================================================" << std::endl;
+
+ std::map<std::string, int> ages;
+ ages["joakim"] = 38;
+ ages["maria"] = 36;
+ ages["hanna"] = 6;
+ ages["moa"] = 4;
+
+ std::cout << "ContainingShouldDetermineIfKeyExists" << std::endl;
+ {
+ Assert::That(ages, Is().Containing("joakim"));
+ }
+
+ std::cout << "ShouldGiveAProperMessageWhenContainingFails" << std::endl;
+ {
+ AssertTestFails(Assert::That(ages, Is().Not().Containing("hanna")),
+ "Expected: not contains hanna");
+ }
+
+ std::cout << "ContainingShouldDetermineIfKeyExists" << std::endl;
+ {
+ Assert::That(ages, Contains("joakim"));
+ }
+
+ std::cout << "ShouldGiveAProperMessageWhenContainingFails" << std::endl;
+ {
+ AssertTestFails(Assert::That(ages, !Contains("hanna")),
+ "Expected: not contains hanna");
+ }
+}
diff --git a/vendor/bandit/bandit/assertion_frameworks/snowhouse/example/operator_tests.cpp b/vendor/bandit/bandit/assertion_frameworks/snowhouse/example/operator_tests.cpp
new file mode 100644
index 00000000..3d11ae07
--- /dev/null
+++ b/vendor/bandit/bandit/assertion_frameworks/snowhouse/example/operator_tests.cpp
@@ -0,0 +1,137 @@
+#include <snowhouse/snowhouse.h>
+using namespace snowhouse;
+#include "tests.h"
+
+void OperatorTests()
+{
+ std::cout << "================================================" << std::endl;
+ std::cout << " OperatorTests" << std::endl;
+ std::cout << "================================================" << std::endl;
+
+ std::cout << "ShouldHandleAndOperatorExpressionTemplates" << std::endl;
+ {
+ Assert::That(5, IsLessThan(6) && IsGreaterThan(4));
+ }
+
+ std::cout << "ShouldHandleAndOperator" << std::endl;
+ {
+ Assert::That(5, Is().LessThan(6).And().GreaterThan(4));
+ }
+
+ std::cout << "ShouldHandleAndOperatorFailExpressionTemplates" << std::endl;
+ {
+ AssertTestFails(Assert::That(5, IsLessThan(7) && IsGreaterThan(5)),
+ "less than 7 and greater than 5");
+ }
+
+ std::cout << "ShouldHandleAndOperatorFail" << std::endl;
+ {
+ AssertTestFails(Assert::That(5, Is().LessThan(7).And().GreaterThan(5)),
+ "less than 7 and greater than 5");
+ }
+
+ std::cout << "ShouldHandleOrOperator" << std::endl;
+ {
+ Assert::That(12, Is().LessThan(7).Or().GreaterThan(5));
+ }
+
+ std::cout << "ShouldHandleOrOperatorExpressionTemplates" << std::endl;
+ {
+ Assert::That(12, IsLessThan(7) || IsGreaterThan(5));
+ }
+
+ std::cout << "ShouldHandleOrOperatorFails" << std::endl;
+ {
+ AssertTestFails(Assert::That(67, Is().LessThan(12).Or().GreaterThan(99)),
+ "less than 12 or greater than 99");
+ }
+
+ std::cout << "ShouldHandleOrOperatorFailsExpressionTemplates" << std::endl;
+ {
+ AssertTestFails(Assert::That(67, IsLessThan(12) || IsGreaterThan(99)),
+ "less than 12 or greater than 99");
+ }
+
+ std::cout << "ShouldHandleNotOperators" << std::endl;
+ {
+ Assert::That(5, Is().Not().EqualTo(4));
+ }
+
+ std::cout << "ShouldHandleNotOperatorsExpressionTemplates" << std::endl;
+ {
+ Assert::That(5, !Equals(4));
+ }
+
+ std::cout << "ShouldHandleNotOperatorsFails" << std::endl;
+ {
+ AssertTestFails(Assert::That(12, Is().Not().EqualTo(12)), "not equal to 12");
+ }
+
+ std::cout << "ShouldHandleNotOperatorsFailsExpressionTemplates" << std::endl;
+ {
+ AssertTestFails(Assert::That(12, !Equals(12)), "not equal to 12");
+ }
+
+ std::cout << "ShouldHandleNotOperatorsForStrings" << std::endl;
+ {
+ Assert::That("joakim", Is().Not().EqualTo("harry"));
+ }
+
+ std::cout << "ShouldHandleNotOperatorsForStringsExpressionTemplates" << std::endl;
+ {
+ Assert::That("joakim", !Equals("harry"));
+ }
+
+ std::cout << "ShouldHandleBothLeftAndRightAssociativeOperators" << std::endl;
+ {
+ Assert::That(5, Is().GreaterThan(4).And().Not().LessThan(3));
+ }
+
+ std::cout << "ShouldHandleBothLeftAndRightAssociativeOperatorsExpressionTemplates" << std::endl;
+ {
+ Assert::That(5, IsGreaterThan(4)&& !IsLessThan(3));
+ }
+
+ std::cout << "MalformedExpressionYieldsError" << std::endl;
+ {
+ AssertTestFails(Assert::That(4, Is().Not()),
+ "The expression contains a not operator without any operand");
+ }
+
+ std::cout <<
+ "EqualsWithDeltaOperator_should_fail_for_actual_larger_than_delta"
+ << std::endl;
+ {
+ AssertTestFails(Assert::That(3.9, EqualsWithDelta(3, 0.5)),
+ "Expected: equal to 3 (+/- 0.5)");
+ }
+
+ std::cout << "EqualsWithDeltaOperator_should_fail_for_actual_less_than_delta" << std::endl;
+ {
+ AssertTestFails(Assert::That(2.49, EqualsWithDelta(3, 0.5)),
+ "Expected: equal to 3 (+/- 0.5)");
+ }
+
+ std::cout << "EqualsWithDeltaOperator_should_succeed" << std::endl;
+ {
+ Assert::That(2, EqualsWithDelta(1.9, 0.1));
+ }
+
+ std::cout << "Fluent_equals_with_delta_should_fail_for_actual_larger_than_delta" << std::endl;
+ {
+ AssertTestFails(Assert::That(3.9, Is().EqualToWithDelta(3, 0.5)),
+ "Expected: equal to 3 (+/- 0.5)");
+ }
+
+ std::cout << "Fluent_EqualsWithDeltaOperator_should_fail_for_actual_less_than_delta" << std::endl;
+ {
+ AssertTestFails(Assert::That(2.49, Is().EqualToWithDelta(3, 0.5)),
+ "Expected: equal to 3 (+/- 0.5)");
+ }
+
+ std::cout << "Fluent_EqualsWithDeltaOperator_should_succeed" << std::endl;
+ {
+ Assert::That(2, Is().EqualToWithDelta(1.9, 0.1));
+ }
+
+}
diff --git a/vendor/bandit/bandit/assertion_frameworks/snowhouse/example/sequence_container_tests.cpp b/vendor/bandit/bandit/assertion_frameworks/snowhouse/example/sequence_container_tests.cpp
new file mode 100644
index 00000000..c090cc58
--- /dev/null
+++ b/vendor/bandit/bandit/assertion_frameworks/snowhouse/example/sequence_container_tests.cpp
@@ -0,0 +1,192 @@
+#include <snowhouse/snowhouse.h>
+using namespace snowhouse;
+#include "tests.h"
+
+
+template <typename T>
+void SequenceContainerActual()
+{
+ const char* ExpectedActual = "\nActual: [ 1, 2, 3, 5, 8 ]";
+
+ T container;
+ container.clear();
+ container.push_back(1);
+ container.push_back(2);
+ container.push_back(3);
+ container.push_back(5);
+ container.push_back(8);
+
+ std::cout << "ShouldHandleAllOperator" << std::endl;
+ {
+ Assert::That(container, Has().All().GreaterThan(1).Or().LessThan(4));
+ }
+
+ std::cout << "ShouldHandleFailingAllOperator" << std::endl;
+ {
+ AssertTestFails(Assert::That(container, Has().All().GreaterThan(4)), std::string("Expected: all greater than 4") + ExpectedActual);
+ }
+
+ std::cout << "SHouldHandleInvalidExpressionAfterAllOperator" << std::endl;
+ {
+ AssertTestFails(Assert::That(container, Has().All().Not()), "The expression contains a not operator without any operand");
+ }
+
+ std::cout << "ShouldHandleNoExpressionAfterAllOperator" << std::endl;
+ {
+ AssertTestFails(Assert::That(container, Has().All()), "The expression after \"all\" operator does not yield any result");
+ }
+
+ std::cout << "ShouldHandleAtLeastOperator" << std::endl;
+ {
+ Assert::That(container, Has().AtLeast(1).LessThan(5));
+ }
+
+ std::cout << "ShouldHandleFailingAtLeastOperator" << std::endl;
+ {
+ AssertTestFails(Assert::That(container, Has().AtLeast(2).LessThan(2)), std::string("Expected: at least 2 less than 2") + ExpectedActual);
+ }
+
+ std::cout << "ShouldHandleExactlyOperator" << std::endl;
+ {
+ Assert::That(container, Has().Exactly(1).EqualTo(3));
+ }
+
+ std::cout << "ShouldHandleFailingExactlyOperator" << std::endl;
+ {
+ AssertTestFails(Assert::That(container, Has().Exactly(2).EqualTo(3)), std::string("Expected: exactly 2 equal to 3") + ExpectedActual);
+ }
+
+ std::cout << "ShouldHandleAtMostOperator" << std::endl;
+ {
+ Assert::That(container, Has().AtMost(1).EqualTo(5));
+ }
+
+ std::cout << "ShouldHandleFailingAtMostOperator" << std::endl;
+ {
+ AssertTestFails(Assert::That(container, Has().AtMost(1).EqualTo(3).Or().EqualTo(5)), std::string("Expected: at most 1 equal to 3 or equal to 5") + ExpectedActual);
+ }
+
+ std::cout << "ShouldHandleNoneOperator" << std::endl;
+ {
+ Assert::That(container, Has().None().EqualTo(666));
+ }
+
+ std::cout << "ShouldHandleFailingNoneOperator" << std::endl;
+ {
+ AssertTestFails(Assert::That(container, Has().None().EqualTo(5)), std::string("Expected: none equal to 5") + ExpectedActual);
+ }
+
+ std::cout << "ShouldHandleContaining" << std::endl;
+ {
+ Assert::That(container, Contains(3));
+ }
+
+ std::cout << "ShouldDetectFailingContains" << std::endl;
+ {
+ AssertTestFails(Assert::That(container, Contains(99)), std::string("contains 99") + ExpectedActual);
+ }
+
+ std::cout << "ShouldHandleOfLength" << std::endl;
+ {
+ Assert::That(container, HasLength(5));
+ }
+
+ std::cout << "ShouldHandleFailingOfLength" << std::endl;
+ {
+ AssertTestFails(Assert::That(container, HasLength(7)), std::string("of length 7") + ExpectedActual);
+ }
+
+ std::cout << "ShouldHandleContaining_ExpressionTemplates" << std::endl;
+ {
+ Assert::That(container, Contains(3));
+ }
+
+ std::cout << "ShouldDetectFailingContains_ExpressionTemplates" << std::endl;
+ {
+ AssertTestFails(Assert::That(container, Contains(99)), std::string("contains 99") + ExpectedActual);
+ }
+
+ std::cout << "ShouldHandleOfLength_ExpressionTemplates" << std::endl;
+ {
+ Assert::That(container, HasLength(5));
+ }
+
+ std::cout << "ShouldHandleFailingOfLengthForVectors" << std::endl;
+ {
+ AssertTestFails(Assert::That(container, HasLength(7)), std::string("of length 7") + ExpectedActual);
+ }
+
+ std::cout << "ShouldHandleIsEmpty" << std::endl;
+ {
+ T is_empty;
+
+ Assert::That(is_empty, IsEmpty());
+ }
+
+ std::cout << "ShouldHandleFailingIsEmpty" << std::endl;
+ {
+ AssertTestFails(Assert::That(container, IsEmpty()), "of length 0");
+ }
+
+ std::cout << "ShouldHandleFluentIsEmpty" << std::endl;
+ {
+ T is_empty;
+
+ Assert::That(is_empty, Is().Empty());
+ }
+
+ std::cout << "ShouldHandleFailingFluentIsEmpty" << std::endl;
+ {
+ AssertTestFails(Assert::That(container, Is().Empty()), "of length 0");
+ }
+
+ std::cout << "ShouldHandlerEqualsContainer" << std::endl;
+ {
+ std::list<int> expected;
+ expected.assign(container.begin(), container.end());
+
+ AssertThat(container, EqualsContainer(expected));
+ }
+
+ std::cout << "ShouldHandleEqualsContainer_Fluent" << std::endl;
+ {
+ std::list<int> expected;
+ expected.assign(container.begin(), container.end());
+
+ AssertThat(container, Is().EqualToContainer(expected));
+ }
+
+ std::cout << "ShouldHandleFailingEqualsContainer" << std::endl;
+ {
+ const int e[] = {4, 2, 4};
+ std::list<int> expected(e, e + sizeof(e) / sizeof(e[0]));
+
+ AssertTestFails(Assert::That(container, EqualsContainer(expected)), "Expected: [ 4, 2, 4 ]");
+ }
+
+ std::cout << "ShouldHandleFailingEqualsContainer_Fluent" << std::endl;
+ {
+ const int e[] = {4, 2, 4};
+ std::list<int> expected(e, e + sizeof(e) / sizeof(e[0]));
+
+ AssertTestFails(Assert::That(container, Is().EqualToContainer(expected)), "Expected: [ 4, 2, 4 ]");
+ }
+}
+
+void SequenceContainerTests()
+{
+ std::cout << "================================================" << std::endl;
+ std::cout << " SequenceContainerTests(vector)" << std::endl;
+ std::cout << "================================================" << std::endl;
+ SequenceContainerActual<std::vector<int> >();
+
+ std::cout << "================================================" << std::endl;
+ std::cout << " SequenceContainerTests(list)" << std::endl;
+ std::cout << "================================================" << std::endl;
+ SequenceContainerActual<std::list<int> >();
+
+ std::cout << "================================================" << std::endl;
+ std::cout << " SequenceContainerTests(deque)" << std::endl;
+ std::cout << "================================================" << std::endl;
+ SequenceContainerActual<std::deque<int> >();
+}
diff --git a/vendor/bandit/bandit/assertion_frameworks/snowhouse/example/string_line_tests.cpp b/vendor/bandit/bandit/assertion_frameworks/snowhouse/example/string_line_tests.cpp
new file mode 100644
index 00000000..8cf90cfb
--- /dev/null
+++ b/vendor/bandit/bandit/assertion_frameworks/snowhouse/example/string_line_tests.cpp
@@ -0,0 +1,179 @@
+#include <snowhouse/snowhouse.h>
+using namespace snowhouse;
+#include "tests.h"
+
+void StringLineTests()
+{
+ std::cout << "================================================" << std::endl;
+ std::cout << " StringLineTests" << std::endl;
+ std::cout << "================================================" << std::endl;
+
+ std::cout << "CanAssertThatAtLeastOneLineInAStreamMatches" << std::endl;
+ {
+ Assert::That("First line\n", Has().AtLeast(1).EqualTo("First line"));
+ }
+
+ std::cout << "CanDetectWhenAssertionFails" << std::endl;
+ {
+ AssertTestFails(Assert::That("First line\n", Has().AtLeast(1).EqualTo("Second line")), "Expected: at least 1 equal to Second line");
+ }
+
+ std::cout << "CanHandleLineMissingNewline" << std::endl;
+ {
+ Assert::That("First line", Has().AtLeast(1).EqualTo("First line"));
+ }
+
+ std::cout << "CanHandleSeveralLines" << std::endl;
+ {
+ std::string lines = "First line\nSecond line";
+ Assert::That(lines, Has().Exactly(2).EndingWith("line"));
+ }
+
+ std::cout << "CanHandleWindowsLineEndings" << std::endl;
+ {
+ std::string lines = "First line\r\nSecond line\r\nThird line";
+ Assert::That(lines, Has().Exactly(3).EndingWith("line"));
+ }
+
+ std::cout << "CanMatchBeginningOfLinesWithWindowsLineEndings" << std::endl;
+ {
+ std::string lines = "First line\nSecond line\r\nThird line";
+ Assert::That(lines, Has().Exactly(1).StartingWith("Second"));
+ }
+
+ std::cout << "CanHandleEmptyLinesWhenUsingWindowsLineEndings" << std::endl;
+ {
+ std::string lines = "\r\nSecond line\r\n\r\n";
+ Assert::That(lines, Has().Exactly(2).OfLength(0));
+ }
+
+ std::cout << "CanHandleLastLineMissingNewlineForWindowsLineEndings" << std::endl;
+ {
+ std::string lines = "First line\r\nSecond line";
+ Assert::That(lines, Has().Exactly(2).EndingWith("line"));
+ }
+
+ std::cout << "CanHandleAllEmptyLines" << std::endl;
+ {
+ Assert::That("\n\n\n\n\n\n", Has().Exactly(6).OfLength(0));
+ }
+
+ std::cout << "CanHandleAllEmptyLinesWithWindowsLineEndings" << std::endl;
+ {
+ Assert::That("\r\n\r\n\r\n", Has().Exactly(3).OfLength(0));
+ }
+
+
+ std::cout << "================================================" << std::endl;
+ std::cout << " StringLineParserTests" << std::endl;
+ std::cout << "================================================" << std::endl;
+
+
+ std::cout << "CanParseEmptyString" << std::endl;
+ {
+ std::vector<std::string> res;
+
+ StringLineParser::Parse("", res);
+
+ Assert::That(res, HasLength(0));
+ }
+
+ std::cout << "CanParseSingleLine" << std::endl;
+ {
+ std::vector<std::string> res;
+
+ StringLineParser::Parse("Simple line", res);
+
+ Assert::That(res, HasLength(1));
+ Assert::That(res, Has().Exactly(1).EqualTo("Simple line"));
+ }
+
+ std::cout << "CanParseTwoLines" << std::endl;
+ {
+ std::vector<std::string> res;
+
+ StringLineParser::Parse("One line\nTwo lines", res);
+
+ Assert::That(res, HasLength(2));
+ Assert::That(res, Has().Exactly(1).EqualTo("One line"));
+ Assert::That(res, Has().Exactly(1).EqualTo("Two lines"));
+ }
+
+ std::cout << "CanParseThreeLines" << std::endl;
+ {
+ std::vector<std::string> res;
+
+ StringLineParser::Parse("One line\nTwo lines\nThree lines", res);
+
+ Assert::That(res, HasLength(3));
+ Assert::That(res, Has().Exactly(1).EqualTo("One line"));
+ Assert::That(res, Has().Exactly(1).EqualTo("Two lines"));
+ Assert::That(res, Has().Exactly(1).EqualTo("Three lines"));
+ }
+
+ std::cout << "CanHandleStringEndingWithNewline" << std::endl;
+ {
+ std::vector<std::string> res;
+ StringLineParser::Parse("One line\n", res);
+ Assert::That(res, HasLength(1));
+ Assert::That(res, Has().Exactly(1).EqualTo("One line"));
+ }
+
+ std::cout << "CanHandleSingleLineWithWindowsLineEnding" << std::endl;
+ {
+ std::vector<std::string> res;
+ StringLineParser::Parse("One line\r\n", res);
+ Assert::That(res, HasLength(1));
+ Assert::That(res, Has().Exactly(1).EqualTo("One line"));
+ }
+
+ std::cout << "CanHandleTwoLinesWithWindowsLineEndings" << std::endl;
+ {
+ std::vector<std::string> res;
+ StringLineParser::Parse("One line\r\nTwo lines", res);
+ Assert::That(res, HasLength(2));
+ Assert::That(res, Has().Exactly(1).EqualTo("One line"));
+ Assert::That(res, Has().Exactly(1).EqualTo("Two lines"));
+ }
+
+ std::cout << "CanHandleEmptyLineWithNewline" << std::endl;
+ {
+ std::vector<std::string> res;
+ StringLineParser::Parse("\n", res);
+ Assert::That(res, Is().OfLength(1).And().Exactly(1).OfLength(0));
+ }
+
+ std::cout << "CanHandleTwoEmptyLines" << std::endl;
+ {
+ std::vector<std::string> res;
+ StringLineParser::Parse("\n\n", res);
+ Assert::That(res, HasLength(2));
+ Assert::That(res, Has().Exactly(2).OfLength(0));
+ }
+
+ std::cout << "CanHandleTwoEmptyLinesWithWindowsLineEndings" << std::endl;
+ {
+ std::vector<std::string> res;
+ StringLineParser::Parse("\r\n\r\n", res);
+ Assert::That(res, HasLength(2));
+ Assert::That(res, Has().Exactly(2).OfLength(0));
+ }
+
+ std::cout << "CanHandleCarriageReturnOnly" << std::endl;
+ {
+ std::vector<std::string> res;
+ StringLineParser::Parse("One line\rTwo lines", res);
+ Assert::That(res, HasLength(2));
+ Assert::That(res, Has().Exactly(1).EqualTo("One line"));
+ Assert::That(res, Has().Exactly(1).EqualTo("Two lines"));
+ }
+
+ std::cout << "CanHandleCarriageReturnOnlyAtEndOfString" << std::endl;
+ {
+ std::vector<std::string> res;
+ StringLineParser::Parse("One line\r\nTwo lines\r", res);
+ Assert::That(res, HasLength(2));
+ Assert::That(res, Has().Exactly(1).EqualTo("One line"));
+ Assert::That(res, Has().Exactly(1).EqualTo("Two lines"));
+ }
+}
diff --git a/vendor/bandit/bandit/assertion_frameworks/snowhouse/example/string_tests.cpp b/vendor/bandit/bandit/assertion_frameworks/snowhouse/example/string_tests.cpp
new file mode 100644
index 00000000..989ad42b
--- /dev/null
+++ b/vendor/bandit/bandit/assertion_frameworks/snowhouse/example/string_tests.cpp
@@ -0,0 +1,65 @@
+#include <snowhouse/snowhouse.h>
+using namespace snowhouse;
+#include "tests.h"
+
+void StringTests()
+{
+ std::cout << "================================================" << std::endl;
+ std::cout << " StringTests" << std::endl;
+ std::cout << "================================================" << std::endl;
+
+ std::cout << "ShouldHandleStringContainsConstraint" << std::endl;
+ {
+ Assert::That("abcdef", Contains("bcde"));
+ }
+
+ std::cout << "StringConstraintShouldHandleMatchAtBeginningOfString" << std::endl;
+ {
+ Assert::That("abcdef", Contains("a"));
+ }
+
+ std::cout << "ShouldDetectFailingContains" << std::endl;
+ {
+ AssertTestFails(Assert::That("abcdef", Contains("hello")), "contains hello");
+ }
+
+ std::cout << "ShouldHandleStringStartingWithConstraint" << std::endl;
+ {
+ Assert::That("abcdef", StartsWith("abc"));
+ }
+
+ std::cout << "ShouldHandleStringEndingWithConstraint" << std::endl;
+ {
+ Assert::That("abcdef", EndsWith("def"));
+ }
+
+ std::cout << "ShouldHandleOperatorsForStrings" << std::endl;
+ {
+ Assert::That("abcdef", StartsWith("ab") && EndsWith("ef"));
+ }
+
+ std::cout << "ShouldHandleStringsWithMultipleOperators" << std::endl;
+ {
+ Assert::That("abcdef", StartsWith("ab") && !EndsWith("qwqw"));
+ }
+
+ std::cout << "ShouldHandleOfLength" << std::endl;
+ {
+ Assert::That("12345", HasLength(5));
+ }
+
+ std::cout << "ShouldHandleWeirdLongExpressions" << std::endl;
+ {
+ Assert::That("12345", HasLength(5) && StartsWith("123") && !EndsWith("zyxxy"));
+ }
+
+ std::cout << "ShouldHandleStdStrings" << std::endl;
+ {
+ Assert::That("12345", Contains(std::string("23")));
+ }
+
+ std::cout << "ShouldHandleSimpleChar" << std::endl;
+ {
+ Assert::That("12345", StartsWith('1'));
+ }
+}
diff --git a/vendor/bandit/bandit/assertion_frameworks/snowhouse/example/stringize_tests.cpp b/vendor/bandit/bandit/assertion_frameworks/snowhouse/example/stringize_tests.cpp
new file mode 100644
index 00000000..a0971274
--- /dev/null
+++ b/vendor/bandit/bandit/assertion_frameworks/snowhouse/example/stringize_tests.cpp
@@ -0,0 +1,111 @@
+#include <snowhouse/snowhouse.h>
+using namespace snowhouse;
+#include "tests.h"
+
+namespace
+{
+ // No overload for operator<<(std::ostream&) or specialization of igloo::Stringizer
+ struct WithoutStreamOperator
+ {
+ WithoutStreamOperator(int id)
+ : m_id(id)
+ {
+ }
+
+ bool operator==(const WithoutStreamOperator& rhs) const
+ {
+ return m_id == rhs.m_id;
+ }
+
+ int m_id;
+ };
+
+ // Has operator<<(std::ostream&)
+ struct WithStreamOperator : public WithoutStreamOperator
+ {
+ WithStreamOperator(int id)
+ : WithoutStreamOperator(id)
+ {
+ }
+ };
+
+ std::ostream& operator<<(std::ostream& stream, const WithStreamOperator& a)
+ {
+ stream << a.m_id;
+ return stream;
+ }
+
+ // Has no operator<<(std::ostream&), but a specialization of igloo::Stringizer
+ struct WithoutStreamOperatorButWithStringizer : public WithoutStreamOperator
+ {
+ WithoutStreamOperatorButWithStringizer(int id)
+ : WithoutStreamOperator(id)
+ {
+ }
+ };
+}
+
+namespace snowhouse {
+
+ template<>
+ struct Stringizer< WithoutStreamOperatorButWithStringizer >
+ {
+ static std::string ToString(const WithoutStreamOperatorButWithStringizer& value)
+ {
+ return snowhouse::Stringize(value.m_id);
+ }
+ };
+}
+
+void StringizeTests()
+{
+ std::cout << "================================================" << std::endl;
+ std::cout << " StringizeTests" << std::endl;
+ std::cout << "================================================" << std::endl;
+
+ std::cout << "ShouldHandleTypesWithStreamOperators" << std::endl;
+ {
+ WithStreamOperator a(12);
+ WithStreamOperator b(13);
+ AssertTestFails(Assert::That(a, Is().EqualTo(b)), "Expected: equal to 13\nActual: 12");
+ }
+
+ std::cout << "ShouldHandleTypesWithoutStreamOperators" << std::endl;
+ {
+ WithoutStreamOperator a(12);
+ WithoutStreamOperator b(13);
+ AssertTestFails(Assert::That(a, Is().EqualTo(b)), "Expected: equal to [unsupported type]\nActual: [unsupported type]");
+ }
+
+ std::cout << "ShouldHandleTypesWithTraits" << std::endl;
+ {
+ WithoutStreamOperatorButWithStringizer a(12);
+ WithoutStreamOperatorButWithStringizer b(13);
+ AssertTestFails(Assert::That(a, Is().EqualTo(b)), "Expected: equal to 13\nActual: 12");
+ }
+
+ std::cout << "================================================" << std::endl;
+ std::cout << " StringizeTestsExpressionTemplates" << std::endl;
+ std::cout << "================================================" << std::endl;
+
+ std::cout << "ShouldHandleTypesWithStreamOperators" << std::endl;
+ {
+ WithStreamOperator a(12);
+ WithStreamOperator b(13);
+ AssertTestFails(Assert::That(a, Equals(b)), "Expected: equal to 13\nActual: 12");
+ }
+
+ std::cout << "ShouldHandleTypesWithoutStreamOperators" << std::endl;
+ {
+ WithoutStreamOperator a(12);
+ WithoutStreamOperator b(13);
+ AssertTestFails(Assert::That(a, Equals(b)), "Expected: equal to [unsupported type]\nActual: [unsupported type]");
+ }
+
+ std::cout << "ShouldHandleTypesWithTraits" << std::endl;
+ {
+ WithoutStreamOperatorButWithStringizer a(12);
+ WithoutStreamOperatorButWithStringizer b(13);
+ AssertTestFails(Assert::That(a, Is().EqualTo(b)), "Expected: equal to 13\nActual: 12");
+ }
+}
diff --git a/vendor/bandit/bandit/assertion_frameworks/snowhouse/example/tests.h b/vendor/bandit/bandit/assertion_frameworks/snowhouse/example/tests.h
new file mode 100644
index 00000000..9dd1d28c
--- /dev/null
+++ b/vendor/bandit/bandit/assertion_frameworks/snowhouse/example/tests.h
@@ -0,0 +1,16 @@
+#ifndef SNOWHOUSE_EXAMPLES_TEST_H
+#define SNOWHOUSE_EXAMPLES_TEST_H
+
+#define AssertTestFails(assertion, expected_error_text) \
+ std::string IGLOO_INTERNAL_expected_error = "Test did not fail"; \
+ try \
+ { \
+ assertion; \
+ } \
+ catch(const AssertionException& exception_from_igloo_assertion) \
+ { \
+ IGLOO_INTERNAL_expected_error = exception_from_igloo_assertion.GetMessage(); \
+ } \
+ Assert::That(IGLOO_INTERNAL_expected_error, Is().Containing(expected_error_text));
+
+#endif
diff --git a/vendor/bandit/bandit/assertion_frameworks/snowhouse/snowhouse/assert.h b/vendor/bandit/bandit/assertion_frameworks/snowhouse/snowhouse/assert.h
new file mode 100644
index 00000000..64981094
--- /dev/null
+++ b/vendor/bandit/bandit/assertion_frameworks/snowhouse/snowhouse/assert.h
@@ -0,0 +1,126 @@
+
+// Copyright Joakim Karlsson & Kim Gräsman 2010-2012.
+// Distributed under the Boost Software License, Version 1.0.
+// (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef IGLOO_ASSERT_H
+#define IGLOO_ASSERT_H
+
+#include "stringize.h"
+#include "stringizers.h"
+
+namespace snowhouse {
+
+ struct DefaultFailureHandler
+ {
+ template <class ExpectedType, class ActualType>
+ static void Handle(const ExpectedType& expected, const ActualType& actual, const char* file_name, int line_number)
+ {
+ std::ostringstream str;
+
+ str << "Expected: " << snowhouse::Stringize(expected) << std::endl;
+ str << "Actual: " << snowhouse::Stringize(actual) << std::endl;
+
+ throw AssertionException(str.str(), file_name, line_number);
+ }
+
+ static void Handle(const std::string& message)
+ {
+ throw AssertionException(message);
+ }
+ };
+
+ template<typename FailureHandler>
+ class ConfigurableAssert
+ {
+ public:
+
+ template <typename ActualType, typename ConstraintListType>
+ static void That(const ActualType& actual, ExpressionBuilder<ConstraintListType> expression)
+ {
+ const char* no_file = "";
+ int line_number = 0;
+
+ ConfigurableAssert<FailureHandler>::That(actual, expression, no_file, line_number);
+ }
+
+ template <typename ActualType, typename ConstraintListType>
+ static void That(const ActualType& actual, ExpressionBuilder<ConstraintListType> expression, const char* file_name, int line_number)
+ {
+ try
+ {
+ ResultStack result;
+ OperatorStack operators;
+ expression.Evaluate(result, operators, actual);
+
+ while (!operators.empty())
+ {
+ ConstraintOperator* op = operators.top();
+ op->PerformOperation(result);
+ operators.pop();
+ }
+
+ if (result.empty())
+ {
+ throw InvalidExpressionException("The expression did not yield any result");
+ }
+
+ if (!result.top())
+ {
+ FailureHandler::Handle(expression, actual, file_name, line_number);
+ }
+ }
+ catch (const InvalidExpressionException& e)
+ {
+ FailureHandler::Handle("Malformed expression: \"" + snowhouse::Stringize(expression) + "\"\n" + e.Message());
+ }
+ }
+
+ template <typename ConstraintListType>
+ static void That(const char* actual, ExpressionBuilder<ConstraintListType> expression)
+ {
+ return That(std::string(actual), expression);
+ }
+
+ template <typename ActualType, typename ExpressionType>
+ static void That(const ActualType& actual, const ExpressionType& expression)
+ {
+ const char* no_file = "";
+ int no_line = 0;
+ That(actual, expression, no_file, no_line);
+ }
+
+ template <typename ActualType, typename ExpressionType>
+ static void That(const ActualType& actual, const ExpressionType& expression, const char* file_name, int line_number)
+ {
+ if (!expression(actual))
+ {
+ FailureHandler::Handle(expression, actual, file_name, line_number);
+ }
+ }
+
+ template <typename ExpressionType>
+ static void That(const char* actual, const ExpressionType& expression)
+ {
+ return That(std::string(actual), expression);
+ }
+
+ static void That(bool actual)
+ {
+ if (!actual)
+ {
+ FailureHandler::Handle("Expected: true\nActual: false");
+ }
+ }
+
+ static void Failure(const std::string& message)
+ {
+ FailureHandler::Handle(message);
+ }
+ };
+
+ typedef ConfigurableAssert<DefaultFailureHandler> Assert;
+}
+
+#endif // IGLOO_ASSERT_H
diff --git a/vendor/bandit/bandit/assertion_frameworks/snowhouse/snowhouse/assertionexception.h b/vendor/bandit/bandit/assertion_frameworks/snowhouse/snowhouse/assertionexception.h
new file mode 100644
index 00000000..d0747742
--- /dev/null
+++ b/vendor/bandit/bandit/assertion_frameworks/snowhouse/snowhouse/assertionexception.h
@@ -0,0 +1,58 @@
+
+// Copyright Joakim Karlsson & Kim Gräsman 2010-2012.
+// Distributed under the Boost Software License, Version 1.0.
+// (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef IGLOO_ASSERTIONEXCEPTION_H
+#define IGLOO_ASSERTIONEXCEPTION_H
+
+namespace snowhouse {
+ class AssertionException : public std::exception
+ {
+ public:
+ AssertionException(const std::string& message)
+ : m_message(message), m_fileName(""), m_line(0)
+ {}
+
+ AssertionException(const std::string& message, const std::string& fileName, unsigned int line)
+ : m_message(message), m_fileName(fileName), m_line(line)
+ {}
+
+#if __cplusplus > 199711L
+ AssertionException(const AssertionException&) = default;
+#endif
+
+#if __cplusplus > 199711L
+ virtual ~AssertionException() noexcept
+ {
+ }
+#else
+ virtual ~AssertionException() throw()
+ {
+ }
+#endif
+
+ std::string GetMessage() const
+ {
+ return m_message;
+ }
+
+ std::string GetFilename() const
+ {
+ return m_fileName;
+ }
+
+ unsigned int GetLineNumber() const
+ {
+ return m_line;
+ }
+
+ private:
+ std::string m_message;
+ std::string m_fileName;
+ unsigned int m_line;
+ };
+}
+
+#endif // IGLOO_ASSERTIONEXCEPTION_H
diff --git a/vendor/bandit/bandit/assertion_frameworks/snowhouse/snowhouse/assertmacro.h b/vendor/bandit/bandit/assertion_frameworks/snowhouse/snowhouse/assertmacro.h
new file mode 100644
index 00000000..df5b4b34
--- /dev/null
+++ b/vendor/bandit/bandit/assertion_frameworks/snowhouse/snowhouse/assertmacro.h
@@ -0,0 +1,22 @@
+
+// Copyright Joakim Karlsson & Kim Gräsman 2010-2012.
+// Distributed under the Boost Software License, Version 1.0.
+// (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef IGLOO_ASSERTMACRO_H
+#define IGLOO_ASSERTMACRO_H
+
+#include "assert.h"
+
+#define SNOWHOUSE_ASSERT_THAT(p1,p2,FAILURE_HANDLER)\
+ ::snowhouse::ConfigurableAssert<FAILURE_HANDLER>::That((p1), (p2), __FILE__, __LINE__);\
+
+#ifndef SNOWHOUSE_NO_MACROS
+
+#define AssertThat(p1,p2)\
+ SNOWHOUSE_ASSERT_THAT((p1), (p2), ::snowhouse::DefaultFailureHandler);\
+
+#endif // SNOWHOUSE_NO_MACROS
+
+#endif // IGLOO_ASSERTMACRO_H
diff --git a/vendor/bandit/bandit/assertion_frameworks/snowhouse/snowhouse/constraints/constraints.h b/vendor/bandit/bandit/assertion_frameworks/snowhouse/snowhouse/constraints/constraints.h
new file mode 100644
index 00000000..a12433d1
--- /dev/null
+++ b/vendor/bandit/bandit/assertion_frameworks/snowhouse/snowhouse/constraints/constraints.h
@@ -0,0 +1,23 @@
+
+// Copyright Joakim Karlsson & Kim Gräsman 2010-2012.
+// Distributed under the Boost Software License, Version 1.0.
+// (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef IGLOO_CONSTRAINTS_H
+#define IGLOO_CONSTRAINTS_H
+
+#include "containsconstraint.h"
+#include "endswithconstraint.h"
+#include "equalsconstraint.h"
+#include "haslengthconstraint.h"
+#include "isgreaterthanconstraint.h"
+#include "isgreaterthanorequaltoconstraint.h"
+#include "islessthanconstraint.h"
+#include "islessthanorequaltoconstraint.h"
+#include "startswithconstraint.h"
+#include "fulfillsconstraint.h"
+#include "equalswithdeltaconstraint.h"
+#include "equalscontainerconstraint.h"
+
+#endif
diff --git a/vendor/bandit/bandit/assertion_frameworks/snowhouse/snowhouse/constraints/containsconstraint.h b/vendor/bandit/bandit/assertion_frameworks/snowhouse/snowhouse/constraints/containsconstraint.h
new file mode 100644
index 00000000..f20d6800
--- /dev/null
+++ b/vendor/bandit/bandit/assertion_frameworks/snowhouse/snowhouse/constraints/containsconstraint.h
@@ -0,0 +1,80 @@
+
+// Copyright Joakim Karlsson & Kim Gräsman 2010-2012.
+// Distributed under the Boost Software License, Version 1.0.
+// (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef IGLOO_CONTAINSCONSTRAINT_H
+#define IGLOO_CONTAINSCONSTRAINT_H
+
+#include <algorithm>
+
+#include "./expressions/expression.h"
+
+namespace snowhouse {
+
+ template <typename ContainerType>
+ struct find_in_container_traits
+ {
+ template <typename ExpectedType>
+ static bool find(const ContainerType& container, const ExpectedType& expected)
+ {
+ return std::find(container.begin(), container.end(), expected) != container.end();
+ }
+ };
+
+ template <typename KeyType, typename ValueType>
+ struct find_in_container_traits<std::map<KeyType, ValueType> >
+ {
+ template <typename ExpectedType>
+ static bool find(const std::map<KeyType, ValueType>& container, const ExpectedType& expected)
+ {
+ return container.find(expected) != container.end();
+ }
+ };
+
+ template <typename ExpectedType>
+ struct ContainsConstraint : Expression< ContainsConstraint<ExpectedType> >
+ {
+ ContainsConstraint(const ExpectedType& expected)
+ : m_expected(expected) {}
+
+ template <typename ActualType>
+ bool operator()(const ActualType& actual) const
+ {
+ return find_in_container_traits<ActualType>::find(actual, m_expected);
+ }
+
+ bool operator()(const std::string& actual) const
+ {
+ return actual.find(m_expected) != actual.npos;
+ }
+
+ ExpectedType m_expected;
+ };
+
+ template< typename ExpectedType >
+ inline ContainsConstraint<ExpectedType> Contains(const ExpectedType& expected)
+ {
+ return ContainsConstraint<ExpectedType>(expected);
+ }
+
+ inline ContainsConstraint<std::string> Contains(const char* expected)
+ {
+ return ContainsConstraint<std::string>(expected);
+ }
+
+ template< typename ExpectedType >
+ struct Stringizer< ContainsConstraint< ExpectedType > >
+ {
+ static std::string ToString(const ContainsConstraint<ExpectedType>& constraint)
+ {
+ std::ostringstream builder;
+ builder << "contains " << snowhouse::Stringize(constraint.m_expected);
+
+ return builder.str();
+ }
+ };
+}
+
+#endif
diff --git a/vendor/bandit/bandit/assertion_frameworks/snowhouse/snowhouse/constraints/endswithconstraint.h b/vendor/bandit/bandit/assertion_frameworks/snowhouse/snowhouse/constraints/endswithconstraint.h
new file mode 100644
index 00000000..c867e203
--- /dev/null
+++ b/vendor/bandit/bandit/assertion_frameworks/snowhouse/snowhouse/constraints/endswithconstraint.h
@@ -0,0 +1,53 @@
+
+// Copyright Joakim Karlsson & Kim Gräsman 2010-2012.
+// Distributed under the Boost Software License, Version 1.0.
+// (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef IGLOO_ENDSWITHCONSTRAINT_H
+#define IGLOO_ENDSWITHCONSTRAINT_H
+
+#include "./expressions/expression.h"
+
+namespace snowhouse {
+
+ template <typename ExpectedType>
+ struct EndsWithConstraint : Expression< EndsWithConstraint<ExpectedType> >
+ {
+ EndsWithConstraint(const ExpectedType& expected)
+ : m_expected(expected) {}
+
+ bool operator()(const std::string& actual) const
+ {
+ size_t expectedPos = actual.length() - m_expected.length();
+ return actual.find(m_expected) == expectedPos;
+ }
+
+ ExpectedType m_expected;
+ };
+
+ template< typename ExpectedType >
+ inline EndsWithConstraint<ExpectedType> EndsWith(const ExpectedType& expected)
+ {
+ return EndsWithConstraint<ExpectedType>(expected);
+ }
+
+ inline EndsWithConstraint<std::string> EndsWith(const char* expected)
+ {
+ return EndsWithConstraint<std::string>(expected);
+ }
+
+ template< typename ExpectedType >
+ struct Stringizer< EndsWithConstraint< ExpectedType > >
+ {
+ static std::string ToString(const EndsWithConstraint<ExpectedType>& constraint)
+ {
+ std::ostringstream builder;
+ builder << "ends with " << snowhouse::Stringize(constraint.m_expected);
+
+ return builder.str();
+ }
+ };
+}
+
+#endif
diff --git a/vendor/bandit/bandit/assertion_frameworks/snowhouse/snowhouse/constraints/equalsconstraint.h b/vendor/bandit/bandit/assertion_frameworks/snowhouse/snowhouse/constraints/equalsconstraint.h
new file mode 100644
index 00000000..a47f6bf4
--- /dev/null
+++ b/vendor/bandit/bandit/assertion_frameworks/snowhouse/snowhouse/constraints/equalsconstraint.h
@@ -0,0 +1,83 @@
+
+// Copyright Joakim Karlsson & Kim Gräsman 2010-2012.
+// Distributed under the Boost Software License, Version 1.0.
+// (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef IGLOO_EQUALSCONSTRAINT_H
+#define IGLOO_EQUALSCONSTRAINT_H
+
+#include <cstddef>
+
+#include "./expressions/expression.h"
+
+namespace snowhouse {
+
+ template< typename ExpectedType >
+ struct EqualsConstraint : Expression< EqualsConstraint<ExpectedType> >
+ {
+ EqualsConstraint(const ExpectedType& expected)
+ : m_expected(expected)
+ {
+ }
+
+ template<typename ActualType>
+ bool operator()(const ActualType& actual) const
+ {
+ return (m_expected == actual);
+ }
+
+ ExpectedType m_expected;
+ };
+
+ template< typename ExpectedType >
+ inline EqualsConstraint<ExpectedType> Equals(const ExpectedType& expected)
+ {
+ return EqualsConstraint<ExpectedType>(expected);
+ }
+
+ inline EqualsConstraint<std::string> Equals(const char* expected)
+ {
+ return EqualsConstraint<std::string>(expected);
+ }
+
+ inline EqualsConstraint<bool> IsFalse()
+ {
+ return EqualsConstraint<bool>(false);
+ }
+
+ inline EqualsConstraint<bool> IsTrue()
+ {
+ return EqualsConstraint<bool>(true);
+ }
+
+#if __cplusplus > 199711L
+ inline EqualsConstraint<std::nullptr_t> IsNull()
+ {
+ return EqualsConstraint<std::nullptr_t>(nullptr);
+ }
+#endif
+
+ template <>
+ struct Stringizer< EqualsConstraint< bool > >
+ {
+ static std::string ToString(const EqualsConstraint<bool>& constraint)
+ {
+ return constraint.m_expected ? "true" : "false";
+ }
+ };
+
+ template< typename ExpectedType >
+ struct Stringizer< EqualsConstraint< ExpectedType > >
+ {
+ static std::string ToString(const EqualsConstraint<ExpectedType>& constraint)
+ {
+ std::ostringstream builder;
+ builder << "equal to " << snowhouse::Stringize(constraint.m_expected);
+
+ return builder.str();
+ }
+ };
+}
+
+#endif
diff --git a/vendor/bandit/bandit/assertion_frameworks/snowhouse/snowhouse/constraints/equalscontainerconstraint.h b/vendor/bandit/bandit/assertion_frameworks/snowhouse/snowhouse/constraints/equalscontainerconstraint.h
new file mode 100644
index 00000000..f8650952
--- /dev/null
+++ b/vendor/bandit/bandit/assertion_frameworks/snowhouse/snowhouse/constraints/equalscontainerconstraint.h
@@ -0,0 +1,80 @@
+
+// Copyright Joakim Karlsson & Kim Gräsman 2010-2012.
+// Distributed under the Boost Software License, Version 1.0.
+// (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef IGLOO_EQUALSCONTAINERCONSTRAINT_H
+#define IGLOO_EQUALSCONTAINERCONSTRAINT_H
+
+namespace snowhouse {
+
+ namespace constraint_internal {
+ template<typename T>
+ inline bool default_comparer(const T& lhs, const T& rhs)
+ {
+ return lhs == rhs;
+ }
+ }
+
+ template< typename ExpectedType, typename BinaryPredicate>
+ struct EqualsContainerConstraint : Expression< EqualsContainerConstraint<ExpectedType, BinaryPredicate> >
+ {
+ EqualsContainerConstraint(const ExpectedType& expected, const BinaryPredicate predicate)
+ : expected_(expected), predicate_(predicate)
+ {}
+
+ template<typename ActualType>
+ bool operator()(const ActualType& actual) const
+ {
+ typename ActualType::const_iterator actual_it;
+ typename ExpectedType::const_iterator expected_it;
+
+ for(actual_it = actual.begin(), expected_it = expected_.begin(); actual_it != actual.end() && expected_it != expected_.end(); actual_it++, expected_it++)
+ {
+ if(!predicate_(*actual_it, *expected_it))
+ {
+ return false;
+ }
+ }
+
+ return actual.size() == expected_.size();
+ }
+
+ const ExpectedType expected_;
+ const BinaryPredicate predicate_;
+
+ private:
+
+#if __cplusplus > 199711L
+#else
+ EqualsContainerConstraint& operator=(const EqualsContainerConstraint&) { return *this; }
+#endif
+
+ };
+
+ template< typename ExpectedType>
+ inline EqualsContainerConstraint<ExpectedType, bool (*)(const typename ExpectedType::value_type&, const typename ExpectedType::value_type&)> EqualsContainer(const ExpectedType& expected)
+ {
+ return EqualsContainerConstraint<ExpectedType, bool (*)(const typename ExpectedType::value_type&, const typename ExpectedType::value_type&)>(expected, constraint_internal::default_comparer);
+ }
+
+ template< typename ExpectedType, typename BinaryPredicate >
+ inline EqualsContainerConstraint<ExpectedType, BinaryPredicate> EqualsContainer(const ExpectedType& expected, const BinaryPredicate predicate)
+ {
+ return EqualsContainerConstraint<ExpectedType, BinaryPredicate>(expected, predicate);
+ }
+
+ template< typename ExpectedType, typename BinaryPredicate >
+ struct Stringizer< EqualsContainerConstraint<ExpectedType, BinaryPredicate> >
+ {
+ static std::string ToString(const EqualsContainerConstraint<ExpectedType, BinaryPredicate>& constraint)
+ {
+ std::ostringstream builder;
+ builder << snowhouse::Stringize(constraint.expected_);
+ return builder.str();
+ }
+ };
+}
+
+#endif
diff --git a/vendor/bandit/bandit/assertion_frameworks/snowhouse/snowhouse/constraints/equalswithdeltaconstraint.h b/vendor/bandit/bandit/assertion_frameworks/snowhouse/snowhouse/constraints/equalswithdeltaconstraint.h
new file mode 100644
index 00000000..b54fb74e
--- /dev/null
+++ b/vendor/bandit/bandit/assertion_frameworks/snowhouse/snowhouse/constraints/equalswithdeltaconstraint.h
@@ -0,0 +1,51 @@
+
+// Copyright Joakim Karlsson & Kim Gräsman 2010-2012.
+// Distributed under the Boost Software License, Version 1.0.
+// (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef IGLOO_EQUALSWITHDELTACONSTRAINT_H
+#define IGLOO_EQUALSWITHDELTACONSTRAINT_H
+
+#include "./expressions/expression.h"
+
+namespace snowhouse {
+
+ template< typename ExpectedType, typename DeltaType >
+ struct EqualsWithDeltaConstraint : Expression< EqualsWithDeltaConstraint<ExpectedType, DeltaType> >
+ {
+ EqualsWithDeltaConstraint(const ExpectedType& expected, const DeltaType& delta)
+ : m_expected(expected), m_delta(delta)
+ {
+ }
+
+ template<typename ActualType>
+ bool operator()(const ActualType& actual) const
+ {
+ return ((m_expected <= (actual + m_delta)) && (m_expected >= (actual - m_delta)));
+ }
+
+ ExpectedType m_expected;
+ DeltaType m_delta;
+ };
+
+ template< typename ExpectedType, typename DeltaType >
+ inline EqualsWithDeltaConstraint<ExpectedType, DeltaType> EqualsWithDelta(const ExpectedType& expected, const DeltaType& delta)
+ {
+ return EqualsWithDeltaConstraint<ExpectedType, DeltaType>(expected, delta);
+ }
+
+ template< typename ExpectedType, typename DeltaType >
+ struct Stringizer< EqualsWithDeltaConstraint< ExpectedType, DeltaType > >
+ {
+ static std::string ToString(const EqualsWithDeltaConstraint<ExpectedType, DeltaType>& constraint)
+ {
+ std::ostringstream builder;
+ builder << "equal to " << snowhouse::Stringize(constraint.m_expected) << " (+/- " << snowhouse::Stringize(constraint.m_delta) << ")";
+
+ return builder.str();
+ }
+ };
+}
+
+#endif
diff --git a/vendor/bandit/bandit/assertion_frameworks/snowhouse/snowhouse/constraints/expressions/andexpression.h b/vendor/bandit/bandit/assertion_frameworks/snowhouse/snowhouse/constraints/expressions/andexpression.h
new file mode 100644
index 00000000..8b6b7d12
--- /dev/null
+++ b/vendor/bandit/bandit/assertion_frameworks/snowhouse/snowhouse/constraints/expressions/andexpression.h
@@ -0,0 +1,46 @@
+
+// Copyright Joakim Karlsson & Kim Gräsman 2010-2012.
+// Distributed under the Boost Software License, Version 1.0.
+// (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef IGLOO_ANDEXPRESSION_H
+#define IGLOO_ANDEXPRESSION_H
+
+#include "./expression_fwd.h"
+
+namespace snowhouse {
+
+ template< typename LeftExpression, typename RightExpression >
+ struct AndExpression : Expression< AndExpression<LeftExpression, RightExpression> >
+ {
+ AndExpression(const LeftExpression& left, const RightExpression& right)
+ : m_left(left)
+ , m_right(right)
+ {
+ }
+
+ template< typename ActualType >
+ bool operator()(const ActualType& actual) const
+ {
+ return (m_left(actual) && m_right(actual));
+ }
+
+ LeftExpression m_left;
+ RightExpression m_right;
+ };
+
+ template< typename LeftExpression, typename RightExpression >
+ struct Stringizer< AndExpression<LeftExpression, RightExpression> >
+ {
+ static std::string ToString(const AndExpression<LeftExpression, RightExpression>& expression)
+ {
+ std::ostringstream builder;
+ builder << Stringize(expression.m_left) << " and " << Stringize(expression.m_right);
+
+ return builder.str();
+ }
+ };
+}
+
+#endif
diff --git a/vendor/bandit/bandit/assertion_frameworks/snowhouse/snowhouse/constraints/expressions/expression.h b/vendor/bandit/bandit/assertion_frameworks/snowhouse/snowhouse/constraints/expressions/expression.h
new file mode 100644
index 00000000..fa894818
--- /dev/null
+++ b/vendor/bandit/bandit/assertion_frameworks/snowhouse/snowhouse/constraints/expressions/expression.h
@@ -0,0 +1,38 @@
+
+// Copyright Joakim Karlsson & Kim Gräsman 2010-2012.
+// Distributed under the Boost Software License, Version 1.0.
+// (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef IGLOO_EXPRESSION_H
+#define IGLOO_EXPRESSION_H
+
+#include "./notexpression.h"
+#include "./andexpression.h"
+#include "./orexpression.h"
+
+namespace snowhouse {
+
+ template<typename T>
+ struct Expression
+ {
+ NotExpression<T> operator!() const
+ {
+ return NotExpression<T>(static_cast<const T&>(*this));
+ }
+
+ template< typename Right >
+ AndExpression<T, Right> operator&&(const Right& right) const
+ {
+ return AndExpression<T, Right>(static_cast<const T&>(*this), right);
+ }
+
+ template< typename Right >
+ OrExpression<T, Right> operator||(const Right& right) const
+ {
+ return OrExpression<T, Right>(static_cast<const T&>(*this), right);
+ }
+ };
+}
+
+#endif
diff --git a/vendor/bandit/bandit/assertion_frameworks/snowhouse/snowhouse/constraints/expressions/expression_fwd.h b/vendor/bandit/bandit/assertion_frameworks/snowhouse/snowhouse/constraints/expressions/expression_fwd.h
new file mode 100644
index 00000000..c0e3706e
--- /dev/null
+++ b/vendor/bandit/bandit/assertion_frameworks/snowhouse/snowhouse/constraints/expressions/expression_fwd.h
@@ -0,0 +1,15 @@
+
+// Copyright Joakim Karlsson & Kim Gräsman 2010-2012.
+// Distributed under the Boost Software License, Version 1.0.
+// (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef IGLOO_EXPRESSION_FWD_H
+#define IGLOO_EXPRESSION_FWD_H
+
+namespace snowhouse {
+ template<typename T>
+ struct Expression;
+}
+
+#endif
diff --git a/vendor/bandit/bandit/assertion_frameworks/snowhouse/snowhouse/constraints/expressions/notexpression.h b/vendor/bandit/bandit/assertion_frameworks/snowhouse/snowhouse/constraints/expressions/notexpression.h
new file mode 100644
index 00000000..4785f07b
--- /dev/null
+++ b/vendor/bandit/bandit/assertion_frameworks/snowhouse/snowhouse/constraints/expressions/notexpression.h
@@ -0,0 +1,44 @@
+
+// Copyright Joakim Karlsson & Kim Gräsman 2010-2012.
+// Distributed under the Boost Software License, Version 1.0.
+// (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef IGLOO_NOTEXPRESSION_H
+#define IGLOO_NOTEXPRESSION_H
+
+#include "./expression_fwd.h"
+
+namespace snowhouse {
+
+ template< typename ExpressionType >
+ struct NotExpression : Expression< NotExpression<ExpressionType> >
+ {
+ NotExpression(const ExpressionType& expression)
+ : m_expression(expression)
+ {
+ }
+
+ template<typename ActualType>
+ bool operator()(const ActualType& actual) const
+ {
+ return !m_expression(actual);
+ }
+
+ ExpressionType m_expression;
+ };
+
+ template< typename ExpressionType >
+ struct Stringizer< NotExpression<ExpressionType> >
+ {
+ static std::string ToString(const NotExpression<ExpressionType>& expression)
+ {
+ std::ostringstream builder;
+ builder << "not " << snowhouse::Stringize(expression.m_expression);
+
+ return builder.str();
+ }
+ };
+}
+
+#endif
diff --git a/vendor/bandit/bandit/assertion_frameworks/snowhouse/snowhouse/constraints/expressions/orexpression.h b/vendor/bandit/bandit/assertion_frameworks/snowhouse/snowhouse/constraints/expressions/orexpression.h
new file mode 100644
index 00000000..c1b6c12b
--- /dev/null
+++ b/vendor/bandit/bandit/assertion_frameworks/snowhouse/snowhouse/constraints/expressions/orexpression.h
@@ -0,0 +1,46 @@
+
+// Copyright Joakim Karlsson & Kim Gräsman 2010-2012.
+// Distributed under the Boost Software License, Version 1.0.
+// (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef IGLOO_OREXPRESSION_H
+#define IGLOO_OREXPRESSION_H
+
+#include "./expression_fwd.h"
+
+namespace snowhouse {
+
+ template< typename LeftExpression, typename RightExpression >
+ struct OrExpression : Expression< OrExpression<LeftExpression, RightExpression> >
+ {
+ OrExpression(const LeftExpression& left, const RightExpression& right)
+ : m_left(left)
+ , m_right(right)
+ {
+ }
+
+ template< typename ActualType >
+ bool operator()(const ActualType& actual) const
+ {
+ return (m_left(actual) || m_right(actual));
+ }
+
+ LeftExpression m_left;
+ RightExpression m_right;
+ };
+
+ template< typename LeftExpression, typename RightExpression >
+ struct Stringizer< OrExpression<LeftExpression, RightExpression> >
+ {
+ static std::string ToString(const OrExpression<LeftExpression, RightExpression>& expression)
+ {
+ std::ostringstream builder;
+ builder << snowhouse::Stringize(expression.m_left) << " or " << snowhouse::Stringize(expression.m_right);
+
+ return builder.str();
+ }
+ };
+}
+
+#endif
diff --git a/vendor/bandit/bandit/assertion_frameworks/snowhouse/snowhouse/constraints/fulfillsconstraint.h b/vendor/bandit/bandit/assertion_frameworks/snowhouse/snowhouse/constraints/fulfillsconstraint.h
new file mode 100644
index 00000000..577056c1
--- /dev/null
+++ b/vendor/bandit/bandit/assertion_frameworks/snowhouse/snowhouse/constraints/fulfillsconstraint.h
@@ -0,0 +1,51 @@
+
+// Copyright Joakim Karlsson & Kim Gräsman 2010-2012.
+// Distributed under the Boost Software License, Version 1.0.
+// (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef FULFILLSCONSTRAINT_H
+#define FULFILLSCONSTRAINT_H
+
+#include "./expressions/expression.h"
+
+namespace snowhouse {
+
+ template< typename MatcherType >
+ struct FulfillsConstraint : Expression< FulfillsConstraint<MatcherType> >
+ {
+ FulfillsConstraint(const MatcherType& matcher)
+ : m_matcher(matcher)
+ {
+ }
+
+ template<typename ActualType>
+ bool operator()(const ActualType& actual) const
+ {
+ return m_matcher.Matches(actual);
+ }
+
+ MatcherType m_matcher;
+ };
+
+ template< typename MatcherType >
+ inline FulfillsConstraint<MatcherType> Fulfills(const MatcherType& matcher)
+ {
+ return FulfillsConstraint<MatcherType>(matcher);
+ }
+
+ template< typename MatcherType >
+ struct Stringizer< FulfillsConstraint< MatcherType > >
+ {
+ static std::string ToString(const FulfillsConstraint<MatcherType>& constraint)
+ {
+ std::ostringstream builder;
+ builder << snowhouse::Stringize(constraint.m_matcher);
+
+ return builder.str();
+ }
+ };
+
+}
+
+#endif
diff --git a/vendor/bandit/bandit/assertion_frameworks/snowhouse/snowhouse/constraints/haslengthconstraint.h b/vendor/bandit/bandit/assertion_frameworks/snowhouse/snowhouse/constraints/haslengthconstraint.h
new file mode 100644
index 00000000..fb6e7cc9
--- /dev/null
+++ b/vendor/bandit/bandit/assertion_frameworks/snowhouse/snowhouse/constraints/haslengthconstraint.h
@@ -0,0 +1,60 @@
+
+// Copyright Joakim Karlsson & Kim Gräsman 2010-2012.
+// Distributed under the Boost Software License, Version 1.0.
+// (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef IGLOO_HASLENGTHCONSTRAINT_H
+#define IGLOO_HASLENGTHCONSTRAINT_H
+
+#include "./expressions/expression.h"
+
+namespace snowhouse {
+
+ template <typename ExpectedType>
+ struct HasLengthConstraint : Expression< HasLengthConstraint<ExpectedType> >
+ {
+ HasLengthConstraint(const ExpectedType& expected)
+ : m_expected(expected) {}
+
+ template <typename ActualType>
+ bool operator()(const ActualType& actual) const
+ {
+ typedef typename ActualType::size_type SizeType;
+ SizeType expectedSize = static_cast<SizeType>(m_expected);
+ return (actual.size() == expectedSize);
+ }
+
+ ExpectedType m_expected;
+ };
+
+ template< typename ExpectedType >
+ inline HasLengthConstraint<ExpectedType> HasLength(const ExpectedType& expected)
+ {
+ return HasLengthConstraint<ExpectedType>(expected);
+ }
+
+ inline HasLengthConstraint<int> IsEmpty()
+ {
+ return HasLength<int>(0);
+ }
+
+ inline HasLengthConstraint<std::string> HasLength(const char* expected)
+ {
+ return HasLengthConstraint<std::string>(expected);
+ }
+
+ template< typename ExpectedType >
+ struct Stringizer< HasLengthConstraint< ExpectedType > >
+ {
+ static std::string ToString(const HasLengthConstraint<ExpectedType>& constraint)
+ {
+ std::ostringstream builder;
+ builder << "of length " << snowhouse::Stringize(constraint.m_expected);
+
+ return builder.str();
+ }
+ };
+}
+
+#endif
diff --git a/vendor/bandit/bandit/assertion_frameworks/snowhouse/snowhouse/constraints/isgreaterthanconstraint.h b/vendor/bandit/bandit/assertion_frameworks/snowhouse/snowhouse/constraints/isgreaterthanconstraint.h
new file mode 100644
index 00000000..e7ef01f8
--- /dev/null
+++ b/vendor/bandit/bandit/assertion_frameworks/snowhouse/snowhouse/constraints/isgreaterthanconstraint.h
@@ -0,0 +1,55 @@
+
+// Copyright Joakim Karlsson & Kim Gräsman 2010-2012.
+// Distributed under the Boost Software License, Version 1.0.
+// (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef IGLOO_ISGREATERTHANCONSTRAINT_H
+#define IGLOO_ISGREATERTHANCONSTRAINT_H
+
+#include "./expressions/expression.h"
+
+namespace snowhouse {
+
+ template< typename ExpectedType >
+ struct IsGreaterThanConstraint : Expression< IsGreaterThanConstraint<ExpectedType> >
+ {
+ IsGreaterThanConstraint(const ExpectedType& expected)
+ : m_expected(expected)
+ {
+ }
+
+ template<typename ActualType>
+ bool operator()(const ActualType& actual) const
+ {
+ return (actual > m_expected);
+ }
+
+ ExpectedType m_expected;
+ };
+
+ template< typename ExpectedType >
+ inline IsGreaterThanConstraint<ExpectedType> IsGreaterThan(const ExpectedType& expected)
+ {
+ return IsGreaterThanConstraint<ExpectedType>(expected);
+ }
+
+ inline IsGreaterThanConstraint<std::string> IsGreaterThan(const char* expected)
+ {
+ return IsGreaterThanConstraint<std::string>(expected);
+ }
+
+ template< typename ExpectedType >
+ struct Stringizer< IsGreaterThanConstraint< ExpectedType > >
+ {
+ static std::string ToString(const IsGreaterThanConstraint<ExpectedType>& constraint)
+ {
+ std::ostringstream builder;
+ builder << "greater than " << snowhouse::Stringize(constraint.m_expected);
+
+ return builder.str();
+ }
+ };
+}
+
+#endif
diff --git a/vendor/bandit/bandit/assertion_frameworks/snowhouse/snowhouse/constraints/isgreaterthanorequaltoconstraint.h b/vendor/bandit/bandit/assertion_frameworks/snowhouse/snowhouse/constraints/isgreaterthanorequaltoconstraint.h
new file mode 100644
index 00000000..3752887b
--- /dev/null
+++ b/vendor/bandit/bandit/assertion_frameworks/snowhouse/snowhouse/constraints/isgreaterthanorequaltoconstraint.h
@@ -0,0 +1,55 @@
+
+// Copyright Joakim Karlsson & Kim Gräsman 2010-2012.
+// Distributed under the Boost Software License, Version 1.0.
+// (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef IGLOO_ISGREATERTHANOREQUALTOCONSTRAINT_H
+#define IGLOO_ISGREATERTHANOREQUALTOCONSTRAINT_H
+
+#include "./expressions/expression.h"
+
+namespace snowhouse {
+
+ template< typename ExpectedType >
+ struct IsGreaterThanOrEqualToConstraint : Expression < IsGreaterThanOrEqualToConstraint<ExpectedType> >
+ {
+ IsGreaterThanOrEqualToConstraint(const ExpectedType& expected)
+ : m_expected(expected)
+ {
+ }
+
+ template<typename ActualType>
+ bool operator()(const ActualType& actual) const
+ {
+ return (actual >= m_expected);
+ }
+
+ ExpectedType m_expected;
+ };
+
+ template< typename ExpectedType >
+ inline IsGreaterThanOrEqualToConstraint<ExpectedType> IsGreaterThanOrEqualTo(const ExpectedType& expected)
+ {
+ return IsGreaterThanOrEqualToConstraint<ExpectedType>(expected);
+ }
+
+ inline IsGreaterThanOrEqualToConstraint<std::string> IsGreaterThanOrEqualTo(const char* expected)
+ {
+ return IsGreaterThanOrEqualToConstraint<std::string>(expected);
+ }
+
+ template< typename ExpectedType >
+ struct Stringizer < IsGreaterThanOrEqualToConstraint< ExpectedType > >
+ {
+ static std::string ToString(const IsGreaterThanOrEqualToConstraint<ExpectedType>& constraint)
+ {
+ std::ostringstream builder;
+ builder << "greater than or equal to " << snowhouse::Stringize(constraint.m_expected);
+
+ return builder.str();
+ }
+ };
+}
+
+#endif
diff --git a/vendor/bandit/bandit/assertion_frameworks/snowhouse/snowhouse/constraints/islessthanconstraint.h b/vendor/bandit/bandit/assertion_frameworks/snowhouse/snowhouse/constraints/islessthanconstraint.h
new file mode 100644
index 00000000..7379dcf7
--- /dev/null
+++ b/vendor/bandit/bandit/assertion_frameworks/snowhouse/snowhouse/constraints/islessthanconstraint.h
@@ -0,0 +1,54 @@
+
+// Copyright Joakim Karlsson & Kim Gräsman 2010-2012.
+// Distributed under the Boost Software License, Version 1.0.
+// (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef IGLOO_ISLESSTHANCONSTRAINT_H
+#define IGLOO_ISLESSTHANCONSTRAINT_H
+
+#include "./expressions/expression.h"
+
+namespace snowhouse {
+
+ template< typename ExpectedType >
+ struct IsLessThanConstraint : Expression< IsLessThanConstraint<ExpectedType> >
+ {
+ IsLessThanConstraint(const ExpectedType& expected)
+ : m_expected(expected)
+ {
+ }
+
+ template<typename ActualType>
+ bool operator()(const ActualType& actual) const
+ {
+ return (actual < m_expected);
+ }
+
+ ExpectedType m_expected;
+ };
+
+ template< typename ExpectedType >
+ inline IsLessThanConstraint<ExpectedType> IsLessThan(const ExpectedType& expected)
+ {
+ return IsLessThanConstraint<ExpectedType>(expected);
+ }
+
+ inline IsLessThanConstraint<std::string> IsLessThan(const char* expected)
+ {
+ return IsLessThanConstraint<std::string>(expected);
+ }
+
+ template< typename ExpectedType >
+ struct Stringizer< IsLessThanConstraint< ExpectedType > >
+ {
+ static std::string ToString(const IsLessThanConstraint<ExpectedType>& constraint)
+ {
+ std::ostringstream builder;
+ builder << "less than " << snowhouse::Stringize(constraint.m_expected);
+
+ return builder.str();
+ }
+ };
+}
+#endif
diff --git a/vendor/bandit/bandit/assertion_frameworks/snowhouse/snowhouse/constraints/islessthanorequaltoconstraint.h b/vendor/bandit/bandit/assertion_frameworks/snowhouse/snowhouse/constraints/islessthanorequaltoconstraint.h
new file mode 100644
index 00000000..36e02ab4
--- /dev/null
+++ b/vendor/bandit/bandit/assertion_frameworks/snowhouse/snowhouse/constraints/islessthanorequaltoconstraint.h
@@ -0,0 +1,55 @@
+
+// Copyright Joakim Karlsson & Kim Gräsman 2010-2012.
+// Distributed under the Boost Software License, Version 1.0.
+// (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef IGLOO_ISLESSTHANOREQUALTOCONSTRAINT_H
+#define IGLOO_ISLESSTHANOREQUALTOCONSTRAINT_H
+
+#include "./expressions/expression.h"
+
+namespace snowhouse {
+
+ template< typename ExpectedType >
+ struct IsLessThanOrEqualToConstraint : Expression < IsLessThanOrEqualToConstraint<ExpectedType> >
+ {
+ IsLessThanOrEqualToConstraint(const ExpectedType& expected)
+ : m_expected(expected)
+ {
+ }
+
+ template<typename ActualType>
+ bool operator()(const ActualType& actual) const
+ {
+ return (actual <= m_expected);
+ }
+
+ ExpectedType m_expected;
+ };
+
+ template< typename ExpectedType >
+ inline IsLessThanOrEqualToConstraint<ExpectedType> IsLessThanOrEqualTo(const ExpectedType& expected)
+ {
+ return IsLessThanOrEqualToConstraint<ExpectedType>(expected);
+ }
+
+ inline IsLessThanOrEqualToConstraint<std::string> IsLessThanOrEqualTo(const char* expected)
+ {
+ return IsLessThanOrEqualToConstraint<std::string>(expected);
+ }
+
+ template< typename ExpectedType >
+ struct Stringizer < IsLessThanOrEqualToConstraint< ExpectedType > >
+ {
+ static std::string ToString(const IsLessThanOrEqualToConstraint<ExpectedType>& constraint)
+ {
+ std::ostringstream builder;
+ builder << "less than or equal to " << snowhouse::Stringize(constraint.m_expected);
+
+ return builder.str();
+ }
+ };
+}
+
+#endif
diff --git a/vendor/bandit/bandit/assertion_frameworks/snowhouse/snowhouse/constraints/startswithconstraint.h b/vendor/bandit/bandit/assertion_frameworks/snowhouse/snowhouse/constraints/startswithconstraint.h
new file mode 100644
index 00000000..ffdd1696
--- /dev/null
+++ b/vendor/bandit/bandit/assertion_frameworks/snowhouse/snowhouse/constraints/startswithconstraint.h
@@ -0,0 +1,52 @@
+
+// Copyright Joakim Karlsson & Kim Gräsman 2010-2012.
+// Distributed under the Boost Software License, Version 1.0.
+// (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef IGLOO_STARTSWITHCONSTRAINT_H
+#define IGLOO_STARTSWITHCONSTRAINT_H
+
+#include "./expressions/expression.h"
+
+namespace snowhouse {
+
+ template <typename ExpectedType>
+ struct StartsWithConstraint : Expression< StartsWithConstraint<ExpectedType> >
+ {
+ StartsWithConstraint(const ExpectedType& expected)
+ : m_expected(expected) {}
+
+ bool operator()(const std::string& actual) const
+ {
+ return actual.find(m_expected) == 0;
+ }
+
+ ExpectedType m_expected;
+ };
+
+ template< typename ExpectedType >
+ inline StartsWithConstraint<ExpectedType> StartsWith(const ExpectedType& expected)
+ {
+ return StartsWithConstraint<ExpectedType>(expected);
+ }
+
+ inline StartsWithConstraint<std::string> StartsWith(const char* expected)
+ {
+ return StartsWithConstraint<std::string>(expected);
+ }
+
+ template< typename ExpectedType >
+ struct Stringizer< StartsWithConstraint< ExpectedType > >
+ {
+ static std::string ToString(const StartsWithConstraint<ExpectedType>& constraint)
+ {
+ std::ostringstream builder;
+ builder << "starts with " << snowhouse::Stringize(constraint.m_expected);
+
+ return builder.str();
+ }
+ };
+}
+
+#endif
diff --git a/vendor/bandit/bandit/assertion_frameworks/snowhouse/snowhouse/exceptions.h b/vendor/bandit/bandit/assertion_frameworks/snowhouse/snowhouse/exceptions.h
new file mode 100644
index 00000000..22ad11ef
--- /dev/null
+++ b/vendor/bandit/bandit/assertion_frameworks/snowhouse/snowhouse/exceptions.h
@@ -0,0 +1,120 @@
+
+// Copyright Joakim Karlsson & Kim Gräsman 2010-2012.
+// Distributed under the Boost Software License, Version 1.0.
+// (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef IGLOO_EXCEPTIONS_H
+#define IGLOO_EXCEPTIONS_H
+
+#include "assert.h"
+
+namespace snowhouse {
+
+ template <typename ExceptionType>
+ class ExceptionStorage
+ {
+ public:
+ static void last_exception(ExceptionType*** e, bool clear=false)
+ {
+ static ExceptionType* last = NULL;
+ if(clear && last)
+ {
+ delete last;
+ return;
+ }
+
+ *e = &last;
+ silly_warning_about_unused_arg(e);
+ }
+
+ static ExceptionType*** silly_warning_about_unused_arg(ExceptionType*** e)
+ {
+ return e;
+ }
+
+ static void store(const ExceptionType& e)
+ {
+ ExceptionType** last = NULL;
+ last_exception(&last);
+ if(*last)
+ {
+ delete *last;
+ *last = NULL;
+ }
+
+ *last = new ExceptionType(e);
+ }
+
+ void compiler_thinks_i_am_unused() {}
+
+ ~ExceptionStorage()
+ {
+ ExceptionType** e = NULL;
+ last_exception(&e);
+ if(*e)
+ {
+ delete *e;
+ *e = NULL;
+ }
+ }
+ };
+
+ template <typename ExceptionType>
+ inline ExceptionType& LastException()
+ {
+ ExceptionType** e = NULL;
+ ExceptionStorage<ExceptionType>::last_exception(&e);
+ if(*e == NULL)
+ {
+ Assert::Failure("No exception was stored");
+ }
+
+ return **e;
+ }
+}
+
+#define IGLOO_CONCAT2(a, b) a##b
+#define IGLOO_CONCAT(a, b) IGLOO_CONCAT2(a, b)
+
+#define SNOWHOUSE_ASSERT_THROWS(EXCEPTION_TYPE, METHOD, FAILURE_HANDLER_TYPE) \
+::snowhouse::ExceptionStorage<EXCEPTION_TYPE> IGLOO_CONCAT(IGLOO_storage_, __LINE__); IGLOO_CONCAT(IGLOO_storage_, __LINE__).compiler_thinks_i_am_unused(); \
+{ \
+ bool wrong_exception = false; \
+ bool no_exception = false; \
+ try \
+ { \
+ METHOD; \
+ no_exception = true; \
+ } \
+ catch (const EXCEPTION_TYPE& e) \
+ { \
+ ::snowhouse::ExceptionStorage<EXCEPTION_TYPE>::store(e); \
+ } \
+ catch(...) \
+ { \
+ wrong_exception = true; \
+ } \
+ if(no_exception) \
+ { \
+ std::ostringstream stm; \
+ stm << "Expected " << #EXCEPTION_TYPE << ". No exception was thrown."; \
+ ::snowhouse::ConfigurableAssert<FAILURE_HANDLER_TYPE>::Failure(stm.str()); \
+ } \
+ if(wrong_exception) \
+ { \
+ std::ostringstream stm; \
+ stm << "Expected " << #EXCEPTION_TYPE << ". Wrong exception was thrown."; \
+ ::snowhouse::ConfigurableAssert<FAILURE_HANDLER_TYPE>::Failure(stm.str()); \
+ } \
+}
+
+#ifndef SNOWHOUSE_NO_MACROS
+
+#define AssertThrows(EXCEPTION_TYPE, METHOD) SNOWHOUSE_ASSERT_THROWS(EXCEPTION_TYPE, (METHOD), ::snowhouse::DefaultFailureHandler)
+
+#endif // SNOWHOUSE_NO_MACROS
+
+#endif
+
+
diff --git a/vendor/bandit/bandit/assertion_frameworks/snowhouse/snowhouse/fluent/constraintadapter.h b/vendor/bandit/bandit/assertion_frameworks/snowhouse/snowhouse/fluent/constraintadapter.h
new file mode 100644
index 00000000..b1719288
--- /dev/null
+++ b/vendor/bandit/bandit/assertion_frameworks/snowhouse/snowhouse/fluent/constraintadapter.h
@@ -0,0 +1,39 @@
+
+// Copyright Joakim Karlsson & Kim Gräsman 2010-2012.
+// Distributed under the Boost Software License, Version 1.0.
+// (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef IGLOO_CONSTRAINTADAPTER_H
+#define IGLOO_CONSTRAINTADAPTER_H
+
+namespace snowhouse {
+
+ template <typename ConstraintType>
+ struct ConstraintAdapter
+ {
+ ConstraintAdapter(const ConstraintType& constraint) : m_constraint(constraint)
+ {
+ }
+
+ template <typename ConstraintListType, typename ActualType>
+ void Evaluate(ConstraintListType& list, ResultStack& result, OperatorStack& operators, const ActualType& actual)
+ {
+ result.push(m_constraint(actual));
+ EvaluateConstraintList(list.m_tail, result, operators, actual);
+ }
+
+ ConstraintType m_constraint;
+ };
+
+ template<typename ConstraintType>
+ struct Stringizer< ConstraintAdapter<ConstraintType> >
+ {
+ static std::string ToString(const ConstraintAdapter<ConstraintType>& constraintAdapter)
+ {
+ return snowhouse::Stringize(constraintAdapter.m_constraint);
+ }
+ };
+}
+
+#endif
diff --git a/vendor/bandit/bandit/assertion_frameworks/snowhouse/snowhouse/fluent/constraintlist.h b/vendor/bandit/bandit/assertion_frameworks/snowhouse/snowhouse/fluent/constraintlist.h
new file mode 100644
index 00000000..1a62a60e
--- /dev/null
+++ b/vendor/bandit/bandit/assertion_frameworks/snowhouse/snowhouse/fluent/constraintlist.h
@@ -0,0 +1,91 @@
+
+// Copyright Joakim Karlsson & Kim Gräsman 2010-2012.
+// Distributed under the Boost Software License, Version 1.0.
+// (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef IGLOO_CONSTRAINT_H
+#define IGLOO_CONSTRAINT_H
+
+namespace snowhouse {
+
+ struct ConstraintOperator;
+ typedef std::stack<bool> ResultStack;
+ typedef std::stack<ConstraintOperator*> OperatorStack;
+
+ template <typename HT, typename TT>
+ struct ConstraintList
+ {
+ typedef HT HeadType;
+ typedef TT TailType;
+
+ ConstraintList(const HeadType& head, const TailType& tail)
+ : m_head(head), m_tail(tail)
+ {
+ }
+
+ HeadType m_head;
+ TailType m_tail;
+ };
+
+ struct Nil
+ {
+ Nil() {}
+ Nil(const Nil&) {}
+ };
+
+
+ // ---- These structs defines the resulting types of list concatenation operations
+ template <typename L1, typename L2>
+ struct type_concat
+ {
+ typedef ConstraintList<typename L1::HeadType, typename type_concat<typename L1::TailType, L2>::t> t;
+ };
+
+ template <typename L2> struct type_concat<Nil, L2> { typedef L2 t; };
+
+ template <typename L3> inline L3 tr_concat(const Nil&, const Nil&) { return Nil(); }
+
+
+ // ---- These structs define the concatenation operations.
+
+ template <typename LeftList, typename RightList, typename ResultList>
+ struct ListConcat
+ {
+ static ResultList Concatenate(const LeftList& left, const RightList& right)
+ {
+ return ResultList(left.m_head, ListConcat<typename LeftList::TailType, RightList, typename type_concat< typename LeftList::TailType, RightList>::t>::Concatenate(left.m_tail, right));
+ }
+ };
+
+ // Concatenating an empty list with a second list yields the second list
+ template <typename RightList, typename ResultList>
+ struct ListConcat<Nil, RightList, ResultList>
+ {
+ static ResultList Concatenate(const Nil&, const RightList& right)
+ {
+ return right;
+ }
+
+ };
+
+ // Concatenating two empty lists yields an empty list
+ template <typename ResultList>
+ struct ListConcat<Nil, Nil, ResultList>
+ {
+ static ResultList Concatenate(const Nil&, const Nil&)
+ {
+ return Nil();
+ }
+ };
+
+ // ---- The concatenation operation
+
+ template <typename L1, typename L2>
+ inline typename type_concat<L1, L2>::t Concatenate(const L1& list1, const L2& list2)
+ {
+ return ListConcat<L1, L2, typename type_concat<L1, L2>::t>::Concatenate(list1, list2);
+ }
+}
+
+#endif
diff --git a/vendor/bandit/bandit/assertion_frameworks/snowhouse/snowhouse/fluent/expressionbuilder.h b/vendor/bandit/bandit/assertion_frameworks/snowhouse/snowhouse/fluent/expressionbuilder.h
new file mode 100644
index 00000000..f0889f1d
--- /dev/null
+++ b/vendor/bandit/bandit/assertion_frameworks/snowhouse/snowhouse/fluent/expressionbuilder.h
@@ -0,0 +1,357 @@
+
+// Copyright Joakim Karlsson & Kim Gräsman 2010-2012.
+// Distributed under the Boost Software License, Version 1.0.
+// (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef IGLOO_EXPRESSIONBUILDER_H
+#define IGLOO_EXPRESSIONBUILDER_H
+
+#include <cstddef>
+
+namespace snowhouse {
+
+ // ---- Evaluation of list of constraints
+
+ template <typename ConstraintListType, typename ActualType>
+ inline void EvaluateConstraintList(ConstraintListType& constraint_list, ResultStack& result, OperatorStack& operators, const ActualType& actual)
+ {
+ constraint_list.m_head.Evaluate(constraint_list, result, operators, actual);
+ }
+
+ template <typename ActualType>
+ inline void EvaluateConstraintList(Nil&, ResultStack&, OperatorStack&, const ActualType&) {}
+
+
+ template <typename ConstraintListType>
+ struct ExpressionBuilder
+ {
+ ExpressionBuilder(const ConstraintListType& list) : m_constraint_list(list)
+ {
+ }
+
+ template <typename ExpectedType>
+ ExpressionBuilder<typename type_concat<ConstraintListType, ConstraintList<ConstraintAdapter<EqualsConstraint<ExpectedType> >, Nil> >::t>
+ EqualTo(const ExpectedType& expected)
+ {
+ typedef ConstraintAdapter<EqualsConstraint<ExpectedType> > ConstraintAdapterType;
+ typedef ExpressionBuilder< typename type_concat<ConstraintListType, ConstraintList<ConstraintAdapterType, Nil> >::t > BuilderType;
+
+ ConstraintAdapterType constraint(expected);
+ ConstraintList<ConstraintAdapterType, Nil> node(constraint, Nil());
+
+ return BuilderType(Concatenate(m_constraint_list, node));
+ }
+
+ template <typename ExpectedType, typename DeltaType>
+ ExpressionBuilder<typename type_concat<ConstraintListType, ConstraintList<ConstraintAdapter<EqualsWithDeltaConstraint<ExpectedType, DeltaType> >, Nil> >::t>
+ EqualToWithDelta(const ExpectedType& expected, const DeltaType& delta)
+ {
+ typedef ConstraintAdapter<EqualsWithDeltaConstraint<ExpectedType, DeltaType> > ConstraintAdapterType;
+ typedef ExpressionBuilder< typename type_concat<ConstraintListType, ConstraintList<ConstraintAdapterType, Nil> >::t > BuilderType;
+
+ ConstraintAdapterType constraint(EqualsWithDeltaConstraint<ExpectedType, DeltaType>(expected, delta));
+ ConstraintList<ConstraintAdapterType, Nil> node(constraint, Nil());
+
+ return BuilderType(Concatenate(m_constraint_list, node));
+ }
+
+ template <typename MatcherType>
+ ExpressionBuilder<typename type_concat<ConstraintListType, ConstraintList<ConstraintAdapter<FulfillsConstraint<MatcherType> >, Nil> >::t>
+ Fulfilling(const MatcherType& matcher)
+ {
+ typedef ConstraintAdapter<FulfillsConstraint<MatcherType> > ConstraintAdapterType;
+ typedef ExpressionBuilder< typename type_concat<ConstraintListType, ConstraintList<ConstraintAdapterType, Nil> >::t > BuilderType;
+
+ ConstraintAdapterType constraint(matcher);
+ ConstraintList<ConstraintAdapterType, Nil> node(constraint, Nil());
+
+ return BuilderType(Concatenate(m_constraint_list, node));
+ }
+
+ ExpressionBuilder<typename type_concat<ConstraintListType, ConstraintList<ConstraintAdapter<EqualsConstraint<bool> >, Nil> >::t>
+ False()
+ {
+ return EqualTo<bool>(false);
+ }
+
+ ExpressionBuilder<typename type_concat<ConstraintListType, ConstraintList<ConstraintAdapter<EqualsConstraint<bool> >, Nil> >::t>
+ True()
+ {
+ return EqualTo<bool>(true);
+ }
+
+#if __cplusplus > 199711L
+ ExpressionBuilder<typename type_concat<ConstraintListType, ConstraintList<ConstraintAdapter<EqualsConstraint<std::nullptr_t> >, Nil> >::t>
+ Null()
+ {
+ return EqualTo<std::nullptr_t>(nullptr);
+ }
+#endif
+
+ ExpressionBuilder<typename type_concat<ConstraintListType, ConstraintList<ConstraintAdapter<EqualsConstraint<std::string> >, Nil> >::t>
+ EqualTo(const char* expected)
+ {
+ return EqualTo<std::string>(std::string(expected));
+ }
+
+ template <typename ExpectedType>
+ ExpressionBuilder<typename type_concat<ConstraintListType, ConstraintList<ConstraintAdapter<IsGreaterThanConstraint<ExpectedType> >, Nil> >::t>
+ GreaterThan(const ExpectedType& expected)
+ {
+ typedef ConstraintAdapter<IsGreaterThanConstraint<ExpectedType> > ConstraintAdapterType;
+
+ typedef ExpressionBuilder< typename type_concat<ConstraintListType, ConstraintList<ConstraintAdapterType, Nil> >::t > BuilderType;
+ ConstraintAdapterType constraint(expected);
+ ConstraintList<ConstraintAdapterType, Nil> node(constraint, Nil());
+ return BuilderType(Concatenate(m_constraint_list, node));
+ }
+
+ template <typename ExpectedType>
+ ExpressionBuilder<typename type_concat<ConstraintListType, ConstraintList<ConstraintAdapter<IsGreaterThanOrEqualToConstraint<ExpectedType> >, Nil> >::t>
+ GreaterThanOrEqualTo(const ExpectedType& expected)
+ {
+ typedef ConstraintAdapter<IsGreaterThanOrEqualToConstraint<ExpectedType> > ConstraintAdapterType;
+
+ typedef ExpressionBuilder< typename type_concat<ConstraintListType, ConstraintList<ConstraintAdapterType, Nil> >::t > BuilderType;
+ ConstraintAdapterType constraint(expected);
+ ConstraintList<ConstraintAdapterType, Nil> node(constraint, Nil());
+ return BuilderType(Concatenate(m_constraint_list, node));
+ }
+
+ template <typename ExpectedType>
+ ExpressionBuilder<typename type_concat<ConstraintListType, ConstraintList<ConstraintAdapter<IsLessThanConstraint<ExpectedType> >, Nil> >::t>
+ LessThan(const ExpectedType& expected)
+ {
+ typedef ConstraintAdapter<IsLessThanConstraint<ExpectedType> > ConstraintAdapterType;
+
+ typedef ExpressionBuilder< typename type_concat<ConstraintListType, ConstraintList<ConstraintAdapterType, Nil> >::t > BuilderType;
+ ConstraintAdapterType constraint(expected);
+ ConstraintList<ConstraintAdapterType, Nil> node(constraint, Nil());
+ return BuilderType(Concatenate(m_constraint_list, node));
+ }
+
+ template <typename ExpectedType>
+ ExpressionBuilder<typename type_concat<ConstraintListType, ConstraintList<ConstraintAdapter<IsLessThanOrEqualToConstraint<ExpectedType> >, Nil> >::t>
+ LessThanOrEqualTo(const ExpectedType& expected)
+ {
+ typedef ConstraintAdapter<IsLessThanOrEqualToConstraint<ExpectedType> > ConstraintAdapterType;
+
+ typedef ExpressionBuilder< typename type_concat<ConstraintListType, ConstraintList<ConstraintAdapterType, Nil> >::t > BuilderType;
+ ConstraintAdapterType constraint(expected);
+ ConstraintList<ConstraintAdapterType, Nil> node(constraint, Nil());
+ return BuilderType(Concatenate(m_constraint_list, node));
+ }
+
+ template <typename ExpectedType>
+ ExpressionBuilder<typename type_concat<ConstraintListType, ConstraintList<ConstraintAdapter<ContainsConstraint<ExpectedType> >, Nil> >::t>
+ Containing(const ExpectedType& expected)
+ {
+ typedef ConstraintAdapter<ContainsConstraint<ExpectedType> > ConstraintAdapterType;
+
+ typedef ExpressionBuilder< typename type_concat<ConstraintListType, ConstraintList<ConstraintAdapterType, Nil> >::t > BuilderType;
+ ConstraintAdapterType constraint(expected);
+ ConstraintList<ConstraintAdapterType, Nil> node(constraint, Nil());
+ return BuilderType(Concatenate(m_constraint_list, node));
+ }
+
+ ExpressionBuilder<typename type_concat<ConstraintListType, ConstraintList<ConstraintAdapter<ContainsConstraint<std::string> >, Nil> >::t>
+ Containing(const char* expected)
+ {
+ return Containing<std::string>(std::string(expected));
+ }
+
+ template <typename ExpectedType>
+ ExpressionBuilder<typename type_concat<ConstraintListType, ConstraintList<ConstraintAdapter<EndsWithConstraint<ExpectedType> >, Nil> >::t>
+ EndingWith(const ExpectedType& expected)
+ {
+ typedef ConstraintAdapter<EndsWithConstraint<ExpectedType> > ConstraintAdapterType;
+ typedef ExpressionBuilder< typename type_concat<ConstraintListType, ConstraintList<ConstraintAdapterType, Nil> >::t > BuilderType;
+
+ ConstraintAdapterType constraint(expected);
+ ConstraintList<ConstraintAdapterType, Nil> node(constraint, Nil());
+ return BuilderType(Concatenate(m_constraint_list, node));
+ }
+
+ ExpressionBuilder<typename type_concat<ConstraintListType, ConstraintList<ConstraintAdapter<EndsWithConstraint<std::string> >, Nil> >::t>
+ EndingWith(const char* expected)
+ {
+ return EndingWith(std::string(expected));
+ }
+
+ template <typename ExpectedType>
+ ExpressionBuilder<typename type_concat<ConstraintListType, ConstraintList<ConstraintAdapter<StartsWithConstraint<ExpectedType> >, Nil> >::t>
+ StartingWith(const ExpectedType& expected)
+ {
+ typedef ConstraintAdapter<StartsWithConstraint<ExpectedType> > ConstraintAdapterType;
+
+ typedef ExpressionBuilder< typename type_concat<ConstraintListType, ConstraintList<ConstraintAdapterType, Nil> >::t > BuilderType;
+ ConstraintAdapterType constraint(expected);
+ ConstraintList<ConstraintAdapterType, Nil> node(constraint, Nil());
+ return BuilderType(Concatenate(m_constraint_list, node));
+ }
+
+ ExpressionBuilder<typename type_concat<ConstraintListType, ConstraintList<ConstraintAdapter<StartsWithConstraint<std::string> >, Nil> >::t>
+ StartingWith(const char* expected)
+ {
+ return StartingWith(std::string(expected));
+ }
+
+ template <typename ExpectedType>
+ ExpressionBuilder<typename type_concat<ConstraintListType, ConstraintList<ConstraintAdapter<HasLengthConstraint<ExpectedType> >, Nil> >::t>
+ OfLength(const ExpectedType& expected)
+ {
+ typedef ConstraintAdapter<HasLengthConstraint<ExpectedType> > ConstraintAdapterType;
+
+ typedef ExpressionBuilder< typename type_concat<ConstraintListType, ConstraintList<ConstraintAdapterType, Nil> >::t > BuilderType;
+ ConstraintAdapterType constraint(expected);
+ ConstraintList<ConstraintAdapterType, Nil> node(constraint, Nil());
+ return BuilderType(Concatenate(m_constraint_list, node));
+ }
+
+ ExpressionBuilder<typename type_concat<ConstraintListType, ConstraintList<ConstraintAdapter<HasLengthConstraint<int> >, Nil> >::t>
+ Empty()
+ {
+ typedef ConstraintAdapter<HasLengthConstraint<int> > ConstraintAdapterType;
+
+ typedef ExpressionBuilder< typename type_concat<ConstraintListType, ConstraintList<ConstraintAdapterType, Nil> >::t > BuilderType;
+ ConstraintAdapterType constraint(0);
+ ConstraintList<ConstraintAdapterType, Nil> node(constraint, Nil());
+ return BuilderType(Concatenate(m_constraint_list, node));
+ }
+
+ template <typename ExpectedType>
+ ExpressionBuilder<typename type_concat<ConstraintListType, ConstraintList<ConstraintAdapter<EqualsContainerConstraint<ExpectedType, bool (*)(const typename ExpectedType::value_type&, const typename ExpectedType::value_type&)> >, Nil> >::t>
+ EqualToContainer(const ExpectedType& expected)
+ {
+ typedef bool (*DefaultBinaryPredivateType)(const typename ExpectedType::value_type&, const typename ExpectedType::value_type&);
+ typedef ConstraintAdapter<EqualsContainerConstraint<ExpectedType, DefaultBinaryPredivateType> > ConstraintAdapterType;
+
+ typedef ExpressionBuilder< typename type_concat<ConstraintListType, ConstraintList<ConstraintAdapterType, Nil> >::t > BuilderType;
+ ConstraintAdapterType constraint(EqualsContainerConstraint<ExpectedType, DefaultBinaryPredivateType>(expected, constraint_internal::default_comparer<typename ExpectedType::value_type>));
+ ConstraintList<ConstraintAdapterType, Nil> node(constraint, Nil());
+ return BuilderType(Concatenate(m_constraint_list, node));
+ }
+
+ template <typename ExpectedType, typename BinaryPredicate>
+ ExpressionBuilder<typename type_concat<ConstraintListType, ConstraintList<ConstraintAdapter<EqualsContainerConstraint<ExpectedType, BinaryPredicate> >, Nil> >::t>
+ EqualToContainer(const ExpectedType& expected, const BinaryPredicate predicate)
+ {
+ typedef ConstraintAdapter<EqualsContainerConstraint<ExpectedType, BinaryPredicate> > ConstraintAdapterType;
+
+ typedef ExpressionBuilder< typename type_concat<ConstraintListType, ConstraintList<ConstraintAdapterType, Nil> >::t > BuilderType;
+ ConstraintAdapterType constraint(EqualsContainerConstraint<ExpectedType, BinaryPredicate>(expected, predicate));
+ ConstraintList<ConstraintAdapterType, Nil> node(constraint, Nil());
+ return BuilderType(Concatenate(m_constraint_list, node));
+ }
+
+ typedef ConstraintList<AndOperator, Nil> AndOperatorNode;
+ typedef ConstraintList<OrOperator, Nil> OrOperatorNode;
+ typedef ConstraintList<NotOperator, Nil> NotOperatorNode;
+ typedef ConstraintList<AllOperator, Nil> AllOperatorNode;
+ typedef ConstraintList<AtLeastOperator, Nil> AtLeastOperatorNode;
+ typedef ConstraintList<ExactlyOperator, Nil> ExactlyOperatorNode;
+ typedef ConstraintList<AtMostOperator, Nil> AtMostOperatorNode;
+ typedef ConstraintList<NoneOperator, Nil> NoneOperatorNode;
+
+ ExpressionBuilder<typename type_concat<ConstraintListType, AllOperatorNode>::t> All()
+ {
+ typedef ExpressionBuilder<typename type_concat<ConstraintListType, AllOperatorNode>::t> BuilderType;
+ AllOperator op;
+ AllOperatorNode node(op, Nil());
+ return BuilderType(Concatenate(m_constraint_list, node));
+ }
+
+ ExpressionBuilder<typename type_concat<ConstraintListType, AtLeastOperatorNode>::t> AtLeast(unsigned int expected)
+ {
+ typedef ExpressionBuilder<typename type_concat<ConstraintListType, AtLeastOperatorNode>::t> BuilderType;
+ AtLeastOperator op(expected);
+ AtLeastOperatorNode node(op, Nil());
+ return BuilderType(Concatenate(m_constraint_list, node));
+ }
+
+ ExpressionBuilder<typename type_concat<ConstraintListType, ExactlyOperatorNode>::t> Exactly(unsigned int expected)
+ {
+ typedef ExpressionBuilder<typename type_concat<ConstraintListType, ExactlyOperatorNode>::t> BuilderType;
+ ExactlyOperator op(expected);
+ ExactlyOperatorNode node(op, Nil());
+ return BuilderType(Concatenate(m_constraint_list, node));
+ }
+
+ ExpressionBuilder<typename type_concat<ConstraintListType, AtMostOperatorNode>::t> AtMost(unsigned int expected)
+ {
+ typedef ExpressionBuilder<typename type_concat<ConstraintListType, AtMostOperatorNode>::t> BuilderType;
+ AtMostOperator op(expected);
+ AtMostOperatorNode node(op, Nil());
+ return BuilderType(Concatenate(m_constraint_list, node));
+ }
+
+ ExpressionBuilder<typename type_concat<ConstraintListType, NoneOperatorNode>::t> None()
+ {
+ typedef ExpressionBuilder<typename type_concat<ConstraintListType, NoneOperatorNode>::t> BuilderType;
+ NoneOperator op;
+ NoneOperatorNode node(op, Nil());
+ return BuilderType(Concatenate(m_constraint_list, node));
+ }
+
+ ExpressionBuilder<typename type_concat<ConstraintListType, AndOperatorNode>::t> And()
+ {
+ typedef ExpressionBuilder<typename type_concat<ConstraintListType, AndOperatorNode>::t> BuilderType;
+ AndOperator op;
+ AndOperatorNode node(op, Nil());
+ return BuilderType(Concatenate(m_constraint_list, node));
+ }
+
+ ExpressionBuilder<typename type_concat<ConstraintListType, OrOperatorNode>::t> Or()
+ {
+ typedef ExpressionBuilder<typename type_concat<ConstraintListType, OrOperatorNode>::t> BuilderType;
+ OrOperator op;
+ OrOperatorNode node(op, Nil());
+ return BuilderType(Concatenate(m_constraint_list, node));
+ }
+
+ ExpressionBuilder<typename type_concat<ConstraintListType, NotOperatorNode>::t> Not()
+ {
+ typedef ExpressionBuilder<typename type_concat<ConstraintListType, NotOperatorNode>::t> BuilderType;
+ NotOperator op;
+ NotOperatorNode node(op, Nil());
+ return BuilderType(Concatenate(m_constraint_list, node));
+ }
+
+ template <typename ActualType>
+ void Evaluate(ResultStack& result, OperatorStack& operators, const ActualType& actual)
+ {
+ EvaluateConstraintList(m_constraint_list, result, operators, actual);
+ }
+
+ ConstraintListType m_constraint_list;
+ };
+
+ template <typename T>
+ inline void StringizeConstraintList(const T& list, std::ostringstream& stm)
+ {
+ if (stm.tellp() > 0)
+ stm << " ";
+
+ stm << snowhouse::Stringize(list.m_head);
+ StringizeConstraintList(list.m_tail, stm);
+ }
+
+ inline void StringizeConstraintList(const Nil&, std::ostringstream&)
+ {
+ }
+
+ template<typename ConstraintListType>
+ struct Stringizer< ExpressionBuilder<ConstraintListType> >
+ {
+ static std::string ToString(const ExpressionBuilder<ConstraintListType>& builder)
+ {
+ std::ostringstream stm;
+ StringizeConstraintList(builder.m_constraint_list, stm);
+
+ return stm.str();
+ }
+ };
+}
+
+#endif
diff --git a/vendor/bandit/bandit/assertion_frameworks/snowhouse/snowhouse/fluent/fluent.h b/vendor/bandit/bandit/assertion_frameworks/snowhouse/snowhouse/fluent/fluent.h
new file mode 100644
index 00000000..6bbd4b81
--- /dev/null
+++ b/vendor/bandit/bandit/assertion_frameworks/snowhouse/snowhouse/fluent/fluent.h
@@ -0,0 +1,38 @@
+
+// Copyright Joakim Karlsson & Kim Gräsman 2010-2012.
+// Distributed under the Boost Software License, Version 1.0.
+// (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef IGLOO_FLUENT_H
+#define IGLOO_FLUENT_H
+
+#include "constraintlist.h"
+#include "constraintadapter.h"
+#include "operators/constraintoperator.h"
+#include "operators/andoperator.h"
+#include "operators/oroperator.h"
+#include "operators/collections/collectionconstraintevaluator.h"
+#include "operators/collections/alloperator.h"
+#include "operators/collections/noneoperator.h"
+#include "operators/collections/atleastoperator.h"
+#include "operators/collections/exactlyoperator.h"
+#include "operators/collections/atmostoperator.h"
+#include "operators/notoperator.h"
+#include "expressionbuilder.h"
+
+namespace snowhouse {
+
+ inline ExpressionBuilder<Nil> Is()
+ {
+ return ExpressionBuilder<Nil>(Nil());
+ }
+
+ inline ExpressionBuilder<Nil> Has()
+ {
+ return ExpressionBuilder<Nil>(Nil());
+ }
+
+}
+
+#endif
diff --git a/vendor/bandit/bandit/assertion_frameworks/snowhouse/snowhouse/fluent/operators/andoperator.h b/vendor/bandit/bandit/assertion_frameworks/snowhouse/snowhouse/fluent/operators/andoperator.h
new file mode 100644
index 00000000..39670632
--- /dev/null
+++ b/vendor/bandit/bandit/assertion_frameworks/snowhouse/snowhouse/fluent/operators/andoperator.h
@@ -0,0 +1,54 @@
+
+// Copyright Joakim Karlsson & Kim Gräsman 2010-2012.
+// Distributed under the Boost Software License, Version 1.0.
+// (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef IGLOO_ANDOPERATOR_H
+#define IGLOO_ANDOPERATOR_H
+
+namespace snowhouse {
+
+ struct AndOperator : public ConstraintOperator
+ {
+ template <typename ConstraintListType, typename ActualType>
+ void Evaluate(ConstraintListType& list, ResultStack& result, OperatorStack& operators, const ActualType& actual)
+ {
+ EvaluateOperatorsWithLessOrEqualPrecedence(*this, operators, result);
+
+ operators.push(this);
+
+ EvaluateConstraintList(list.m_tail, result, operators, actual);
+ }
+
+ void PerformOperation(ResultStack& result)
+ {
+ if(result.size() < 2)
+ {
+ throw InvalidExpressionException("The expression contains an and operator with too few operands");
+ }
+
+ bool right = result.top();
+ result.pop();
+ bool left = result.top();
+ result.pop();
+
+ result.push(left && right);
+ }
+
+ int Precedence() const
+ {
+ return 3;
+ }
+ };
+
+ template<>
+ struct Stringizer<AndOperator>
+ {
+ static std::string ToString(const AndOperator&)
+ {
+ return "and";
+ }
+ };
+}
+#endif
diff --git a/vendor/bandit/bandit/assertion_frameworks/snowhouse/snowhouse/fluent/operators/collections/alloperator.h b/vendor/bandit/bandit/assertion_frameworks/snowhouse/snowhouse/fluent/operators/collections/alloperator.h
new file mode 100644
index 00000000..4157faf9
--- /dev/null
+++ b/vendor/bandit/bandit/assertion_frameworks/snowhouse/snowhouse/fluent/operators/collections/alloperator.h
@@ -0,0 +1,35 @@
+
+// Copyright Joakim Karlsson & Kim Gräsman 2010-2012.
+// Distributed under the Boost Software License, Version 1.0.
+// (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef IGLOO_ALLOPERATOR_H
+#define IGLOO_ALLOPERATOR_H
+
+#include "collectionoperator.h"
+
+namespace snowhouse {
+
+ struct AllOperator : public CollectionOperator
+ {
+ template <typename ConstraintListType, typename ActualType>
+ void Evaluate(ConstraintListType& list, ResultStack& result, OperatorStack& operators, const ActualType& actual)
+ {
+ unsigned int passed_elements = CollectionConstraintEvaluator<ConstraintListType, ActualType>::Evaluate(*this, list, result, operators, actual);
+
+ result.push(passed_elements == actual.size());
+ }
+ };
+
+ template<>
+ struct Stringizer<AllOperator>
+ {
+ static std::string ToString(const AllOperator&)
+ {
+ return "all";
+ }
+ };
+}
+
+#endif
diff --git a/vendor/bandit/bandit/assertion_frameworks/snowhouse/snowhouse/fluent/operators/collections/atleastoperator.h b/vendor/bandit/bandit/assertion_frameworks/snowhouse/snowhouse/fluent/operators/collections/atleastoperator.h
new file mode 100644
index 00000000..d46e697f
--- /dev/null
+++ b/vendor/bandit/bandit/assertion_frameworks/snowhouse/snowhouse/fluent/operators/collections/atleastoperator.h
@@ -0,0 +1,41 @@
+
+// Copyright Joakim Karlsson & Kim Gräsman 2010-2012.
+// Distributed under the Boost Software License, Version 1.0.
+// (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef IGLOO_ATLEASTOPERATOR_H
+#define IGLOO_ATLEASTOPERATOR_H
+
+#include "collectionoperator.h"
+
+namespace snowhouse {
+
+ struct AtLeastOperator : public CollectionOperator
+ {
+ AtLeastOperator(unsigned int expected) : m_expected(expected) {}
+
+ template <typename ConstraintListType, typename ActualType>
+ void Evaluate(ConstraintListType& list, ResultStack& result, OperatorStack& operators, const ActualType& actual)
+ {
+ unsigned int passed_elements = CollectionConstraintEvaluator<ConstraintListType, ActualType>::Evaluate(*this, list, result, operators, actual);
+
+ result.push(passed_elements >= m_expected);
+ }
+
+ unsigned int m_expected;
+ };
+
+ template<>
+ struct Stringizer<AtLeastOperator>
+ {
+ static std::string ToString(const AtLeastOperator& op)
+ {
+ std::ostringstream stm;
+ stm << "at least " << op.m_expected;
+ return stm.str();
+ }
+ };
+}
+
+#endif
diff --git a/vendor/bandit/bandit/assertion_frameworks/snowhouse/snowhouse/fluent/operators/collections/atmostoperator.h b/vendor/bandit/bandit/assertion_frameworks/snowhouse/snowhouse/fluent/operators/collections/atmostoperator.h
new file mode 100644
index 00000000..53debbc8
--- /dev/null
+++ b/vendor/bandit/bandit/assertion_frameworks/snowhouse/snowhouse/fluent/operators/collections/atmostoperator.h
@@ -0,0 +1,39 @@
+
+// Copyright Joakim Karlsson & Kim Gräsman 2010-2012.
+// Distributed under the Boost Software License, Version 1.0.
+// (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef IGLOO_ATMOSTOPERATOR_H
+#define IGLOO_ATMOSTOPERATOR_H
+
+namespace snowhouse {
+
+ struct AtMostOperator : public CollectionOperator
+ {
+ AtMostOperator(unsigned int expected) : m_expected(expected) {}
+
+ template <typename ConstraintListType, typename ActualType>
+ void Evaluate(ConstraintListType& list, ResultStack& result, OperatorStack& operators, const ActualType& actual)
+ {
+ unsigned int passed_elements = CollectionConstraintEvaluator<ConstraintListType, ActualType>::Evaluate(*this, list, result, operators, actual);
+
+ result.push(passed_elements <= m_expected);
+ }
+
+ unsigned int m_expected;
+ };
+
+ template<>
+ struct Stringizer<AtMostOperator>
+ {
+ static std::string ToString(const AtMostOperator& op)
+ {
+ std::ostringstream stm;
+ stm << "at most " << op.m_expected;
+ return stm.str();
+ }
+ };
+}
+
+#endif
diff --git a/vendor/bandit/bandit/assertion_frameworks/snowhouse/snowhouse/fluent/operators/collections/collectionconstraintevaluator.h b/vendor/bandit/bandit/assertion_frameworks/snowhouse/snowhouse/fluent/operators/collections/collectionconstraintevaluator.h
new file mode 100644
index 00000000..3fa30f2c
--- /dev/null
+++ b/vendor/bandit/bandit/assertion_frameworks/snowhouse/snowhouse/fluent/operators/collections/collectionconstraintevaluator.h
@@ -0,0 +1,113 @@
+
+// Copyright Joakim Karlsson & Kim Gräsman 2010-2012.
+// Distributed under the Boost Software License, Version 1.0.
+// (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef IGLOO_COLLECTIONCONSTRAINTEVALUATOR_H
+#define IGLOO_COLLECTIONCONSTRAINTEVALUATOR_H
+
+#include <string>
+#include "../invalidexpressionexception.h"
+
+namespace snowhouse
+{
+
+template<typename ConstraintListType, typename ActualType>
+struct CollectionConstraintEvaluator
+{
+ static unsigned int Evaluate(const ConstraintOperator& op,
+ ConstraintListType& expression, ResultStack& result,
+ OperatorStack& operators, const ActualType& actual)
+ {
+ ConstraintOperator::EvaluateOperatorsWithLessOrEqualPrecedence(op,
+ operators, result);
+
+ unsigned int passed_elements = 0;
+ typename ActualType::const_iterator it;
+ for(it = actual.begin(); it != actual.end(); it++)
+ {
+ if(ConstraintOperator::EvaluateElementAgainstRestOfExpression(expression,
+ *it))
+ {
+ passed_elements++;
+ }
+ }
+
+ return passed_elements;
+ }
+};
+
+struct StringLineParser
+{
+ static void Parse(const std::string& str, std::vector<std::string>& res)
+ {
+ size_t start = 0;
+ size_t newline = FindNewline(str, start);
+
+ while(newline != std::string::npos)
+ {
+ StoreLine(str, start, newline, res);
+ start = MoveToNextLine(str, newline);
+ newline = FindNewline(str, start);
+ }
+
+ if(start < str.size())
+ {
+ StoreLine(str, start, std::string::npos, res);
+ }
+ }
+
+private:
+ static size_t FindNewline(const std::string& str, size_t start)
+ {
+ return str.find_first_of("\r\n", start);
+ }
+
+ static void StoreLine(const std::string& str, size_t start, size_t end,
+ std::vector<std::string>& res)
+ {
+ std::string line = str.substr(start, end - start);
+ res.push_back(line);
+ }
+
+ static size_t MoveToNextLine(const std::string& str, size_t newline)
+ {
+ if(str.find("\r\n", newline) == newline)
+ {
+ return newline + 2;
+ }
+
+ if(str.find("\n", newline) == newline)
+ {
+ return newline + 1;
+ }
+
+ if(str.find("\r", newline) == newline)
+ {
+ return newline + 1;
+ }
+
+ std::ostringstream stm;
+ stm << "This string seems to contain an invalid line ending at position "
+ << newline << ":\n" << str << std::endl;
+ throw InvalidExpressionException(stm.str());
+ }
+};
+
+template<typename ConstraintListType>
+struct CollectionConstraintEvaluator<ConstraintListType, std::string>
+{
+ static unsigned int Evaluate(const ConstraintOperator& op,
+ ConstraintListType& expression, ResultStack& result,
+ OperatorStack& operators, const std::string& actual)
+ {
+ std::vector<std::string> lines;
+ StringLineParser::Parse(actual, lines);
+ return CollectionConstraintEvaluator<ConstraintListType, std::vector<std::string> >::Evaluate(op, expression, result, operators, lines);
+ }
+};
+
+}
+
+#endif
diff --git a/vendor/bandit/bandit/assertion_frameworks/snowhouse/snowhouse/fluent/operators/collections/collectionoperator.h b/vendor/bandit/bandit/assertion_frameworks/snowhouse/snowhouse/fluent/operators/collections/collectionoperator.h
new file mode 100644
index 00000000..c1bb8bec
--- /dev/null
+++ b/vendor/bandit/bandit/assertion_frameworks/snowhouse/snowhouse/fluent/operators/collections/collectionoperator.h
@@ -0,0 +1,24 @@
+
+// Copyright Joakim Karlsson & Kim Gräsman 2010-2012.
+// Distributed under the Boost Software License, Version 1.0.
+// (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef IGLOO_COLLECTIONOPERATOR_H
+#define IGLOO_COLLECTIONOPERATOR_H
+
+namespace snowhouse {
+ struct CollectionOperator : public ConstraintOperator
+ {
+ void PerformOperation(ResultStack&)
+ {
+ }
+
+ int Precedence() const
+ {
+ return 1;
+ }
+ };
+}
+
+#endif
diff --git a/vendor/bandit/bandit/assertion_frameworks/snowhouse/snowhouse/fluent/operators/collections/exactlyoperator.h b/vendor/bandit/bandit/assertion_frameworks/snowhouse/snowhouse/fluent/operators/collections/exactlyoperator.h
new file mode 100644
index 00000000..81c2dcaa
--- /dev/null
+++ b/vendor/bandit/bandit/assertion_frameworks/snowhouse/snowhouse/fluent/operators/collections/exactlyoperator.h
@@ -0,0 +1,39 @@
+
+// Copyright Joakim Karlsson & Kim Gräsman 2010-2012.
+// Distributed under the Boost Software License, Version 1.0.
+// (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef IGLOO_EXACTLYOPERATOR_H
+#define IGLOO_EXACTLYOPERATOR_H
+
+namespace snowhouse {
+
+ struct ExactlyOperator : public CollectionOperator
+ {
+ ExactlyOperator(unsigned int expected) : m_expected(expected) {}
+
+ template <typename ConstraintListType, typename ActualType>
+ void Evaluate(ConstraintListType& list, ResultStack& result, OperatorStack& operators, const ActualType& actual)
+ {
+ unsigned int passed_elements = CollectionConstraintEvaluator<ConstraintListType, ActualType>::Evaluate(*this, list, result, operators, actual);
+
+ result.push(passed_elements == m_expected);
+ }
+
+ unsigned int m_expected;
+ };
+
+ template<>
+ struct Stringizer< ExactlyOperator >
+ {
+ static std::string ToString(const ExactlyOperator& op)
+ {
+ std::ostringstream stm;
+ stm << "exactly " << op.m_expected;
+ return stm.str();
+ }
+ };
+}
+
+#endif
diff --git a/vendor/bandit/bandit/assertion_frameworks/snowhouse/snowhouse/fluent/operators/collections/noneoperator.h b/vendor/bandit/bandit/assertion_frameworks/snowhouse/snowhouse/fluent/operators/collections/noneoperator.h
new file mode 100644
index 00000000..c4570915
--- /dev/null
+++ b/vendor/bandit/bandit/assertion_frameworks/snowhouse/snowhouse/fluent/operators/collections/noneoperator.h
@@ -0,0 +1,33 @@
+
+// Copyright Joakim Karlsson & Kim Gräsman 2010-2012.
+// Distributed under the Boost Software License, Version 1.0.
+// (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef IGLOO_NONEOPERATOR_H
+#define IGLOO_NONEOPERATOR_H
+
+namespace snowhouse {
+
+ struct NoneOperator : public CollectionOperator
+ {
+ template <typename ConstraintListType, typename ActualType>
+ void Evaluate(ConstraintListType& list, ResultStack& result, OperatorStack& operators, const ActualType& actual)
+ {
+ unsigned int passed_elements = CollectionConstraintEvaluator<ConstraintListType, ActualType>::Evaluate(*this, list, result, operators, actual);
+ result.push(passed_elements == 0);
+ }
+ };
+
+ template<>
+ struct Stringizer<NoneOperator>
+ {
+ static std::string ToString(const NoneOperator&)
+ {
+ return "none";
+ }
+ };
+
+}
+
+#endif
diff --git a/vendor/bandit/bandit/assertion_frameworks/snowhouse/snowhouse/fluent/operators/constraintoperator.h b/vendor/bandit/bandit/assertion_frameworks/snowhouse/snowhouse/fluent/operators/constraintoperator.h
new file mode 100644
index 00000000..eafe6c51
--- /dev/null
+++ b/vendor/bandit/bandit/assertion_frameworks/snowhouse/snowhouse/fluent/operators/constraintoperator.h
@@ -0,0 +1,70 @@
+
+// Copyright Joakim Karlsson & Kim Gräsman 2010-2012.
+// Distributed under the Boost Software License, Version 1.0.
+// (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef IGLOO_CONTRAINTOPERATOR_H
+#define IGLOO_CONTRAINTOPERATOR_H
+
+#include "invalidexpressionexception.h"
+
+namespace snowhouse {
+
+ struct ConstraintOperator
+ {
+#if __cplusplus > 199711L
+#else
+ virtual ~ConstraintOperator() {}
+#endif
+
+ virtual void PerformOperation(ResultStack& result) = 0;
+ virtual int Precedence() const = 0;
+
+ template <typename ConstraintListType, typename ActualType>
+ static bool EvaluateElementAgainstRestOfExpression(ConstraintListType& list, const ActualType& actual)
+ {
+ ResultStack innerResult;
+ OperatorStack innerOperators;
+
+ EvaluateConstraintList(list.m_tail, innerResult, innerOperators, actual);
+ EvaluateAllOperatorsOnStack(innerOperators, innerResult);
+
+ if(innerResult.empty())
+ {
+ throw InvalidExpressionException("The expression after \"" + snowhouse::Stringize(list.m_head) + "\" operator does not yield any result");
+ }
+
+ return innerResult.top();
+ }
+
+ static void EvaluateOperatorsWithLessOrEqualPrecedence(const ConstraintOperator& op, OperatorStack& operators, ResultStack& result)
+ {
+ while(!operators.empty())
+ {
+ ConstraintOperator* op_from_stack = operators.top();
+
+ if(op_from_stack->Precedence() > op.Precedence())
+ {
+ break;
+ }
+
+ op_from_stack->PerformOperation(result);
+ operators.pop();
+ }
+ }
+
+ static void EvaluateAllOperatorsOnStack(OperatorStack& operators, ResultStack& result)
+ {
+ while(!operators.empty())
+ {
+ ConstraintOperator* op = operators.top();
+ op->PerformOperation(result);
+ operators.pop();
+ }
+ }
+ };
+
+}
+
+#endif
diff --git a/vendor/bandit/bandit/assertion_frameworks/snowhouse/snowhouse/fluent/operators/invalidexpressionexception.h b/vendor/bandit/bandit/assertion_frameworks/snowhouse/snowhouse/fluent/operators/invalidexpressionexception.h
new file mode 100644
index 00000000..404341f1
--- /dev/null
+++ b/vendor/bandit/bandit/assertion_frameworks/snowhouse/snowhouse/fluent/operators/invalidexpressionexception.h
@@ -0,0 +1,28 @@
+
+// Copyright Joakim Karlsson & Kim Gräsman 2010-2012.
+// Distributed under the Boost Software License, Version 1.0.
+// (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef IGLOO_INVALUDEXPRESSIONEXCEPTION_H
+#define IGLOO_INVALUDEXPRESSIONEXCEPTION_H
+
+namespace snowhouse {
+
+ struct InvalidExpressionException
+ {
+ InvalidExpressionException(const std::string& message) : m_message(message)
+ {
+ }
+
+ const std::string& Message() const
+ {
+ return m_message;
+ }
+
+ std::string m_message;
+ };
+
+}
+
+#endif // IGLOO_INVALUDEXPRESSIONEXCEPTION_H
diff --git a/vendor/bandit/bandit/assertion_frameworks/snowhouse/snowhouse/fluent/operators/notoperator.h b/vendor/bandit/bandit/assertion_frameworks/snowhouse/snowhouse/fluent/operators/notoperator.h
new file mode 100644
index 00000000..709c8413
--- /dev/null
+++ b/vendor/bandit/bandit/assertion_frameworks/snowhouse/snowhouse/fluent/operators/notoperator.h
@@ -0,0 +1,53 @@
+
+// Copyright Joakim Karlsson & Kim Gräsman 2010-2012.
+// Distributed under the Boost Software License, Version 1.0.
+// (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef IGLOO_NOTOPERATOR_H
+#define IGLOO_NOTOPERATOR_H
+
+namespace snowhouse {
+
+ struct NotOperator : public ConstraintOperator
+ {
+ template <typename ConstraintListType, typename ActualType>
+ void Evaluate(ConstraintListType& list, ResultStack& result, OperatorStack& operators, const ActualType& actual)
+ {
+ EvaluateOperatorsWithLessOrEqualPrecedence(*this, operators, result);
+
+ operators.push(this);
+
+ EvaluateConstraintList(list.m_tail, result, operators, actual);
+ }
+
+ void PerformOperation(ResultStack& result)
+ {
+ if(result.size() < 1)
+ {
+ throw InvalidExpressionException("The expression contains a not operator without any operand");
+ }
+
+ bool right = result.top();
+ result.pop();
+
+ result.push(!right);
+ }
+
+ int Precedence() const
+ {
+ return 2;
+ }
+ };
+
+ template<>
+ struct Stringizer<NotOperator>
+ {
+ static std::string ToString(const NotOperator&)
+ {
+ return "not";
+ }
+ };
+}
+
+#endif
diff --git a/vendor/bandit/bandit/assertion_frameworks/snowhouse/snowhouse/fluent/operators/oroperator.h b/vendor/bandit/bandit/assertion_frameworks/snowhouse/snowhouse/fluent/operators/oroperator.h
new file mode 100644
index 00000000..5a307ff6
--- /dev/null
+++ b/vendor/bandit/bandit/assertion_frameworks/snowhouse/snowhouse/fluent/operators/oroperator.h
@@ -0,0 +1,55 @@
+
+// Copyright Joakim Karlsson & Kim Gräsman 2010-2012.
+// Distributed under the Boost Software License, Version 1.0.
+// (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef IGLOO_OROPERATOR_H
+#define IGLOO_OROPERATOR_H
+
+namespace snowhouse {
+
+ struct OrOperator : public ConstraintOperator
+ {
+ template <typename ConstraintListType, typename ActualType>
+ void Evaluate(ConstraintListType& list, ResultStack& result, OperatorStack& operators, const ActualType& actual)
+ {
+ EvaluateOperatorsWithLessOrEqualPrecedence(*this, operators, result);
+
+ operators.push(this);
+
+ EvaluateConstraintList(list.m_tail, result, operators, actual);
+ }
+
+ void PerformOperation(ResultStack& result)
+ {
+ if(result.size() < 2)
+ {
+ throw InvalidExpressionException("The expression contains an or operator with too few operands");
+ }
+
+ bool right = result.top();
+ result.pop();
+ bool left = result.top();
+ result.pop();
+
+ result.push(left || right);
+ }
+
+ int Precedence() const
+ {
+ return 4;
+ }
+ };
+
+ template<>
+ struct Stringizer<OrOperator>
+ {
+ static std::string ToString(const OrOperator&)
+ {
+ return "or";
+ }
+ };
+}
+
+#endif
diff --git a/vendor/bandit/bandit/assertion_frameworks/snowhouse/snowhouse/snowhouse.h b/vendor/bandit/bandit/assertion_frameworks/snowhouse/snowhouse/snowhouse.h
new file mode 100644
index 00000000..38214aa7
--- /dev/null
+++ b/vendor/bandit/bandit/assertion_frameworks/snowhouse/snowhouse/snowhouse.h
@@ -0,0 +1,33 @@
+#ifndef _SNOWHOUSE_H_JK_2013_06_28
+#define _SNOWHOUSE_H_JK_2013_06_28
+
+#define SNOWHOUSE_VERSION "2.1.0"
+
+#if __cplusplus > 199711L
+#ifdef _MSC_VER
+// Visual Studio (including 2013) does not support the noexcept keyword
+#define _ALLOW_KEYWORD_MACROS
+#define noexcept
+#endif
+#endif
+
+
+#include <iostream>
+#include <map>
+#include <vector>
+#include <sstream>
+#include <stack>
+#include <list>
+#include <memory>
+#include <algorithm>
+
+#include "stringize.h"
+#include "constraints/constraints.h"
+#include "fluent/fluent.h"
+#include "assertionexception.h"
+#include "assert.h"
+#include "assertmacro.h"
+#include "exceptions.h"
+
+#endif
+
diff --git a/vendor/bandit/bandit/assertion_frameworks/snowhouse/snowhouse/stringize.h b/vendor/bandit/bandit/assertion_frameworks/snowhouse/snowhouse/stringize.h
new file mode 100644
index 00000000..42249f57
--- /dev/null
+++ b/vendor/bandit/bandit/assertion_frameworks/snowhouse/snowhouse/stringize.h
@@ -0,0 +1,104 @@
+
+// Copyright Joakim Karlsson & Kim Gräsman 2010-2012.
+// Distributed under the Boost Software License, Version 1.0.
+// (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef IGLOO_STRINGIZE_H
+#define IGLOO_STRINGIZE_H
+
+#include <cstddef>
+
+namespace snowhouse {
+ namespace detail {
+
+ // This type soaks up any implicit conversions and makes the following operator<<
+ // less preferred than any other such operator found via ADL.
+ struct any
+ {
+ // Conversion constructor for any type.
+ template <class T>
+ any(T const&);
+ };
+
+ // A tag type returned by operator<< for the any struct in this namespace
+ // when T does not support <<.
+ struct tag {};
+
+ // Fallback operator<< for types T that don't support <<.
+ tag operator<<(std::ostream&, any const&);
+
+ // Two overloads to distinguish whether T supports a certain operator expression.
+ // The first overload returns a reference to a two-element character array and is chosen if
+ // T does not support the expression, such as <<, whereas the second overload returns a char
+ // directly and is chosen if T supports the expression. So using sizeof(check(<expression>))
+ // returns 2 for the first overload and 1 for the second overload.
+ typedef char yes;
+ typedef char (&no)[2];
+
+ no check(tag);
+
+ template <class T>
+ yes check(T const&);
+
+ template <class T>
+ struct is_output_streamable
+ {
+ static const T& x;
+ static const bool value = sizeof(check(std::cout << x)) == sizeof(yes);
+ };
+
+ template<typename T, bool type_is_streamable>
+ struct DefaultStringizer
+ {
+ static std::string ToString(const T& value)
+ {
+ std::ostringstream buf;
+ buf << value;
+ return buf.str();
+ }
+ };
+
+ template<typename T>
+ struct DefaultStringizer<T, false>
+ {
+ static std::string ToString(const T&)
+ {
+ return "[unsupported type]";
+ }
+ };
+ }
+
+ template<typename T>
+ struct Stringizer;
+
+ template<typename T>
+ std::string Stringize(const T& value)
+ {
+ return Stringizer<T>::ToString(value);
+ }
+
+ // NOTE: Specialize snowhouse::Stringizer to customize assertion messages
+ template<typename T>
+ struct Stringizer
+ {
+ static std::string ToString(const T& value)
+ {
+ return detail::DefaultStringizer< T, detail::is_output_streamable<T>::value >::ToString(value);
+ }
+ };
+
+#if __cplusplus > 199711L
+ // We need this because nullptr_t has ambiguous overloads of operator<< in the standard library.
+ template<>
+ struct Stringizer<std::nullptr_t>
+ {
+ static std::string ToString(std::nullptr_t)
+ {
+ return "nullptr";
+ }
+ };
+#endif
+}
+
+#endif
diff --git a/vendor/bandit/bandit/assertion_frameworks/snowhouse/snowhouse/stringizers.h b/vendor/bandit/bandit/assertion_frameworks/snowhouse/snowhouse/stringizers.h
new file mode 100644
index 00000000..79a416de
--- /dev/null
+++ b/vendor/bandit/bandit/assertion_frameworks/snowhouse/snowhouse/stringizers.h
@@ -0,0 +1,60 @@
+
+// Copyright Joakim Karlsson & Kim Gräsman 2010-2012.
+// Distributed under the Boost Software License, Version 1.0.
+// (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef IGLOO_STRINGIZERS_H
+#define IGLOO_STRINGIZERS_H
+
+namespace snowhouse
+{
+
+ namespace detail
+ {
+
+ template<typename Container>
+ struct SequentialContainerStringizer
+ {
+ static std::string
+ ToString(const Container& cont)
+ {
+ std::ostringstream stm;
+ typedef typename Container::const_iterator Iterator;
+
+ stm << "[ ";
+ for (Iterator it = cont.begin(); it != cont.end();)
+ {
+ stm << snowhouse::Stringize(*it);
+
+ if (++it != cont.end())
+ {
+ stm << ", ";
+ }
+ }
+ stm << " ]";
+ return stm.str();
+ }
+ };
+ }
+
+ template<typename T>
+ struct Stringizer<std::vector<T> > : detail::SequentialContainerStringizer<
+ std::vector<T> >
+ {
+ };
+
+ template<typename T>
+ struct Stringizer<std::deque<T> > : detail::SequentialContainerStringizer<
+ std::deque<T> >
+ {
+ };
+
+ template<typename T>
+ struct Stringizer<std::list<T> > : detail::SequentialContainerStringizer<
+ std::list<T> >
+ {
+ };
+}
+
+#endif
diff --git a/vendor/bandit/bandit/bandit.h b/vendor/bandit/bandit/bandit.h
new file mode 100644
index 00000000..c9caeda9
--- /dev/null
+++ b/vendor/bandit/bandit/bandit.h
@@ -0,0 +1,42 @@
+#ifndef BANDIT_BANDIT_H
+#define BANDIT_BANDIT_H
+
+#ifdef _MSC_VER
+// Visual Studio (including 2013) does not support the noexcept keyword
+#define _ALLOW_KEYWORD_MACROS
+#define noexcept
+#endif
+
+#include <cassert>
+#include <functional>
+#include <iostream>
+#include <list>
+#include <deque>
+#include <stdexcept>
+
+#define BANDIT_VERSION "2.0.0"
+
+namespace bandit { namespace detail {
+ typedef std::function<void ()> voidfunc_t;
+}}
+
+#include <bandit/assertion_frameworks/snowhouse/snowhouse/snowhouse.h>
+using namespace snowhouse;
+
+#include <bandit/assertion_frameworks/matchers/matchers.h>
+
+#include <bandit/external/optionparser.h>
+#include <bandit/options.h>
+#include <bandit/test_run_error.h>
+#include <bandit/registration/registration.h>
+#include <bandit/assertion_exception.h>
+#include <bandit/failure_formatters/failure_formatters.h>
+#include <bandit/adapters/adapters.h>
+#include <bandit/listener.h>
+#include <bandit/reporters/reporters.h>
+#include <bandit/context.h>
+#include <bandit/run_policies/run_policies.h>
+#include <bandit/grammar.h>
+#include <bandit/runner.h>
+
+#endif
diff --git a/vendor/bandit/bandit/context.h b/vendor/bandit/bandit/context.h
new file mode 100644
index 00000000..71194253
--- /dev/null
+++ b/vendor/bandit/bandit/context.h
@@ -0,0 +1,97 @@
+#ifndef BANDIT_CONTEXT_H
+#define BANDIT_CONTEXT_H
+
+namespace bandit {
+ namespace detail {
+
+ class context
+ {
+ public:
+ virtual ~context() {}
+ virtual const std::string& name() = 0;
+ virtual void execution_is_starting() = 0;
+ virtual void register_before_each(voidfunc_t func) = 0;
+ virtual void register_after_each(voidfunc_t func) = 0;
+ virtual void run_before_eaches() = 0;
+ virtual void run_after_eaches() = 0;
+ virtual bool hard_skip() = 0;
+ };
+
+ class bandit_context : public context
+ {
+ public:
+ bandit_context(const char* desc, bool hard_skip_a)
+ : desc_(desc), hard_skip_(hard_skip_a), is_executing_(false)
+ {}
+
+ const std::string& name()
+ {
+ return desc_;
+ }
+
+ void execution_is_starting()
+ {
+ is_executing_ = true;
+ }
+
+ void register_before_each(voidfunc_t func)
+ {
+ if(is_executing_)
+ {
+ throw test_run_error("before_each was called after 'describe' or 'it'");
+ }
+
+ before_eaches_.push_back(func);
+ }
+
+ void register_after_each(voidfunc_t func)
+ {
+ if(is_executing_)
+ {
+ throw test_run_error("after_each was called after 'describe' or 'it'");
+ }
+
+ after_eaches_.push_back(func);
+ }
+
+ void run_before_eaches()
+ {
+ run_all(before_eaches_);
+ }
+
+ void run_after_eaches()
+ {
+ run_all(after_eaches_);
+ }
+
+ bool hard_skip()
+ {
+ return hard_skip_;
+ }
+
+ private:
+ void run_all(const std::list<voidfunc_t>& funcs)
+ {
+ auto call_func = [](voidfunc_t f){ f(); };
+
+ for_each(funcs.begin(), funcs.end(), call_func);
+ }
+
+ private:
+ std::string desc_;
+ bool hard_skip_;
+ bool is_executing_;
+ std::list<voidfunc_t> before_eaches_;
+ std::list<voidfunc_t> after_eaches_;
+ };
+ typedef std::deque<context*> contextstack_t;
+
+ inline contextstack_t& context_stack()
+ {
+ static contextstack_t contexts;
+ return contexts;
+ }
+ }
+}
+
+#endif
diff --git a/vendor/bandit/bandit/external/optionparser.h b/vendor/bandit/bandit/external/optionparser.h
new file mode 100644
index 00000000..ffeaac66
--- /dev/null
+++ b/vendor/bandit/bandit/external/optionparser.h
@@ -0,0 +1,2825 @@
+/*
+ * The Lean Mean C++ Option Parser
+ *
+ * Copyright (C) 2012 Matthias S. Benkmann
+ *
+ * The "Software" in the following 2 paragraphs refers to this file containing
+ * the code to The Lean Mean C++ Option Parser.
+ * The "Software" does NOT refer to any other files which you
+ * may have received alongside this file (e.g. as part of a larger project that
+ * incorporates The Lean Mean C++ Option Parser).
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this 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
+ * AUTHORS OR COPYRIGHT HOLDERS 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.
+ */
+
+/*
+ * NOTE: It is recommended that you read the processed HTML doxygen documentation
+ * rather than this source. If you don't know doxygen, it's like javadoc for C++.
+ * If you don't want to install doxygen you can find a copy of the processed
+ * documentation at
+ *
+ * http://optionparser.sourceforge.net/
+ *
+ */
+
+/**
+ * @file
+ *
+ * @brief This is the only file required to use The Lean Mean C++ Option Parser.
+ * Just \#include it and you're set.
+ *
+ * The Lean Mean C++ Option Parser handles the program's command line arguments
+ * (argc, argv).
+ * It supports the short and long option formats of getopt(), getopt_long()
+ * and getopt_long_only() but has a more convenient interface.
+ * The following features set it apart from other option parsers:
+ *
+ * @par Highlights:
+ * <ul style="padding-left:1em;margin-left:0">
+ * <li> It is a header-only library. Just <code>\#include "optionparser.h"</code> and you're set.
+ * <li> It is freestanding. There are no dependencies whatsoever, not even the
+ * C or C++ standard library.
+ * <li> It has a usage message formatter that supports column alignment and
+ * line wrapping. This aids localization because it adapts to
+ * translated strings that are shorter or longer (even if they contain
+ * Asian wide characters).
+ * <li> Unlike getopt() and derivatives it doesn't force you to loop through
+ * options sequentially. Instead you can access options directly like this:
+ * <ul style="margin-top:.5em">
+ * <li> Test for presence of a switch in the argument vector:
+ * @code if ( options[QUIET] ) ... @endcode
+ * <li> Evaluate --enable-foo/--disable-foo pair where the last one used wins:
+ * @code if ( options[FOO].last()->type() == DISABLE ) ... @endcode
+ * <li> Cumulative option (-v verbose, -vv more verbose, -vvv even more verbose):
+ * @code int verbosity = options[VERBOSE].count(); @endcode
+ * <li> Iterate over all --file=&lt;fname> arguments:
+ * @code for (Option* opt = options[FILE]; opt; opt = opt->next())
+ * fname = opt->arg; ... @endcode
+ * <li> If you really want to, you can still process all arguments in order:
+ * @code
+ * for (int i = 0; i < p.optionsCount(); ++i) {
+ * Option& opt = buffer[i];
+ * switch(opt.index()) {
+ * case HELP: ...
+ * case VERBOSE: ...
+ * case FILE: fname = opt.arg; ...
+ * case UNKNOWN: ...
+ * @endcode
+ * </ul>
+ * </ul> @n
+ * Despite these features the code size remains tiny.
+ * It is smaller than <a href="http://uclibc.org">uClibc</a>'s GNU getopt() and just a
+ * couple 100 bytes larger than uClibc's SUSv3 getopt(). @n
+ * (This does not include the usage formatter, of course. But you don't have to use that.)
+ *
+ * @par Download:
+ * Tarball with examples and test programs:
+ * <a style="font-size:larger;font-weight:bold" href="http://sourceforge.net/projects/optionparser/files/optionparser-1.3.tar.gz/download">optionparser-1.3.tar.gz</a> @n
+ * Just the header (this is all you really need):
+ * <a style="font-size:larger;font-weight:bold" href="http://optionparser.sourceforge.net/optionparser.h">optionparser.h</a>
+ *
+ * @par Changelog:
+ * <b>Version 1.3:</b> Compatible with Microsoft Visual C++. @n
+ * <b>Version 1.2:</b> Added @ref option::Option::namelen "Option::namelen" and removed the extraction
+ * of short option characters into a special buffer. @n
+ * Changed @ref option::Arg::Optional "Arg::Optional" to accept arguments if they are attached
+ * rather than separate. This is what GNU getopt() does and how POSIX recommends
+ * utilities should interpret their arguments.@n
+ * <b>Version 1.1:</b> Optional mode with argument reordering as done by GNU getopt(), so that
+ * options and non-options can be mixed. See
+ * @ref option::Parser::parse() "Parser::parse()".
+ *
+ * @par Feedback:
+ * Send questions, bug reports, feature requests etc. to: <tt><b>optionparser-feedback<span id="antispam">&nbsp;(a)&nbsp;</span>lists.sourceforge.net</b></tt>
+ * @htmlonly <script type="text/javascript">document.getElementById("antispam").innerHTML="@"</script> @endhtmlonly
+ *
+ *
+ * @par Example program:
+ * (Note: @c option::* identifiers are links that take you to their documentation.)
+ * @code
+ * #include <iostream>
+ * #include "optionparser.h"
+ *
+ * enum optionIndex { UNKNOWN, HELP, PLUS };
+ * const option::Descriptor usage[] =
+ * {
+ * {UNKNOWN, 0,"" , "" ,option::Arg::None, "USAGE: example [options]\n\n"
+ * "Options:" },
+ * {HELP, 0,"" , "help",option::Arg::None, " --help \tPrint usage and exit." },
+ * {PLUS, 0,"p", "plus",option::Arg::None, " --plus, -p \tIncrement count." },
+ * {UNKNOWN, 0,"" , "" ,option::Arg::None, "\nExamples:\n"
+ * " example --unknown -- --this_is_no_option\n"
+ * " example -unk --plus -ppp file1 file2\n" },
+ * {0,0,0,0,0,0}
+ * };
+ *
+ * int main(int argc, char* argv[])
+ * {
+ * argc-=(argc>0); argv+=(argc>0); // skip program name argv[0] if present
+ * option::Stats stats(usage, argc, argv);
+ * option::Option options[stats.options_max], buffer[stats.buffer_max];
+ * option::Parser parse(usage, argc, argv, options, buffer);
+ *
+ * if (parse.error())
+ * return 1;
+ *
+ * if (options[HELP] || argc == 0) {
+ * option::printUsage(std::cout, usage);
+ * return 0;
+ * }
+ *
+ * std::cout << "--plus count: " <<
+ * options[PLUS].count() << "\n";
+ *
+ * for (option::Option* opt = options[UNKNOWN]; opt; opt = opt->next())
+ * std::cout << "Unknown option: " << opt->name << "\n";
+ *
+ * for (int i = 0; i < parse.nonOptionsCount(); ++i)
+ * std::cout << "Non-option #" << i << ": " << parse.nonOption(i) << "\n";
+ * }
+ * @endcode
+ *
+ * @par Option syntax:
+ * @li The Lean Mean C++ Option Parser follows POSIX <code>getopt()</code> conventions and supports
+ * GNU-style <code>getopt_long()</code> long options as well as Perl-style single-minus
+ * long options (<code>getopt_long_only()</code>).
+ * @li short options have the format @c -X where @c X is any character that fits in a char.
+ * @li short options can be grouped, i.e. <code>-X -Y</code> is equivalent to @c -XY.
+ * @li a short option may take an argument either separate (<code>-X foo</code>) or
+ * attached (@c -Xfoo). You can make the parser accept the additional format @c -X=foo by
+ * registering @c X as a long option (in addition to being a short option) and
+ * enabling single-minus long options.
+ * @li an argument-taking short option may be grouped if it is the last in the group, e.g.
+ * @c -ABCXfoo or <code> -ABCX foo </code> (@c foo is the argument to the @c -X option).
+ * @li a lone minus character @c '-' is not treated as an option. It is customarily used where
+ * a file name is expected to refer to stdin or stdout.
+ * @li long options have the format @c --option-name.
+ * @li the option-name of a long option can be anything and include any characters.
+ * Even @c = characters will work, but don't do that.
+ * @li [optional] long options may be abbreviated as long as the abbreviation is unambiguous.
+ * You can set a minimum length for abbreviations.
+ * @li [optional] long options may begin with a single minus. The double minus form is always
+ * accepted, too.
+ * @li a long option may take an argument either separate (<code> --option arg </code>) or
+ * attached (<code> --option=arg </code>). In the attached form the equals sign is mandatory.
+ * @li an empty string can be passed as an attached long option argument: <code> --option-name= </code>.
+ * Note the distinction between an empty string as argument and no argument at all.
+ * @li an empty string is permitted as separate argument to both long and short options.
+ * @li Arguments to both short and long options may start with a @c '-' character. E.g.
+ * <code> -X-X </code>, <code>-X -X</code> or <code> --long-X=-X </code>. If @c -X
+ * and @c --long-X take an argument, that argument will be @c "-X" in all 3 cases.
+ * @li If using the built-in @ref option::Arg::Optional "Arg::Optional", optional arguments must
+ * be attached.
+ * @li the special option @c -- (i.e. without a name) terminates the list of
+ * options. Everything that follows is a non-option argument, even if it starts with
+ * a @c '-' character. The @c -- itself will not appear in the parse results.
+ * @li the first argument that doesn't start with @c '-' or @c '--' and does not belong to
+ * a preceding argument-taking option, will terminate the option list and is the
+ * first non-option argument. All following command line arguments are treated as
+ * non-option arguments, even if they start with @c '-' . @n
+ * NOTE: This behaviour is mandated by POSIX, but GNU getopt() only honours this if it is
+ * explicitly requested (e.g. by setting POSIXLY_CORRECT). @n
+ * You can enable the GNU behaviour by passing @c true as first argument to
+ * e.g. @ref option::Parser::parse() "Parser::parse()".
+ * @li Arguments that look like options (i.e. @c '-' followed by at least 1 character) but
+ * aren't, are NOT treated as non-option arguments. They are treated as unknown options and
+ * are collected into a list of unknown options for error reporting. @n
+ * This means that in order to pass a first non-option
+ * argument beginning with the minus character it is required to use the
+ * @c -- special option, e.g.
+ * @code
+ * program -x -- --strange-filename
+ * @endcode
+ * In this example, @c --strange-filename is a non-option argument. If the @c --
+ * were omitted, it would be treated as an unknown option. @n
+ * See @ref option::Descriptor::longopt for information on how to collect unknown options.
+ *
+ */
+
+#ifndef OPTIONPARSER_H_
+#define OPTIONPARSER_H_
+
+/** @brief The namespace of The Lean Mean C++ Option Parser. */
+namespace option
+{
+
+#ifdef _MSC_VER
+#include <intrin.h>
+#pragma intrinsic(_BitScanReverse)
+struct MSC_Builtin_CLZ
+{
+ static int builtin_clz(unsigned x)
+ {
+ unsigned long index;
+ _BitScanReverse(&index, x);
+ return 32-index; // int is always 32bit on Windows, even for target x64
+ }
+};
+#define __builtin_clz(x) MSC_Builtin_CLZ::builtin_clz(x)
+
+#pragma warning( push )
+#pragma warning( disable: 4510 )
+#pragma warning( disable: 4512 )
+#pragma warning( disable: 4610 )
+#pragma warning( disable: 4127 )
+#endif
+
+class Option;
+
+/**
+ * @brief Possible results when checking if an argument is valid for a certain option.
+ *
+ * In the case that no argument is provided for an option that takes an
+ * optional argument, return codes @c ARG_OK and @c ARG_IGNORE are equivalent.
+ */
+enum ArgStatus
+{
+ //! The option does not take an argument.
+ ARG_NONE,
+ //! The argument is acceptable for the option.
+ ARG_OK,
+ //! The argument is not acceptable but that's non-fatal because the option's argument is optional.
+ ARG_IGNORE,
+ //! The argument is not acceptable and that's fatal.
+ ARG_ILLEGAL
+};
+
+/**
+ * @brief Signature of functions that check if an argument is valid for a certain type of option.
+ *
+ * Every Option has such a function assigned in its Descriptor.
+ * @code
+ * Descriptor usage[] = { {UNKNOWN, 0, "", "", Arg::None, ""}, ... };
+ * @endcode
+ *
+ * A CheckArg function has the following signature:
+ * @code ArgStatus CheckArg(const Option& option, bool msg); @endcode
+ *
+ * It is used to check if a potential argument would be acceptable for the option.
+ * It will even be called if there is no argument. In that case @c option.arg will be @c NULL.
+ *
+ * If @c msg is @c true and the function determines that an argument is not acceptable and
+ * that this is a fatal error, it should output a message to the user before
+ * returning @ref ARG_ILLEGAL. If @c msg is @c false the function should remain silent (or you
+ * will get duplicate messages).
+ *
+ * See @ref ArgStatus for the meaning of the return values.
+ *
+ * While you can provide your own functions,
+ * often the following pre-defined checks (which never return @ref ARG_ILLEGAL) will suffice:
+ *
+ * @li @c Arg::None @copybrief Arg::None
+ * @li @c Arg::Optional @copybrief Arg::Optional
+ *
+ */
+typedef ArgStatus (*CheckArg)(const Option& option, bool msg);
+
+/**
+ * @brief Describes an option, its help text (usage) and how it should be parsed.
+ *
+ * The main input when constructing an option::Parser is an array of Descriptors.
+
+ * @par Example:
+ * @code
+ * enum OptionIndex {CREATE, ...};
+ * enum OptionType {DISABLE, ENABLE, OTHER};
+ *
+ * const option::Descriptor usage[] = {
+ * { CREATE, // index
+ * OTHER, // type
+ * "c", // shortopt
+ * "create", // longopt
+ * Arg::None, // check_arg
+ * "--create Tells the program to create something." // help
+ * }
+ * , ...
+ * };
+ * @endcode
+ */
+struct Descriptor
+{
+ /**
+ * @brief Index of this option's linked list in the array filled in by the parser.
+ *
+ * Command line options whose Descriptors have the same index will end up in the same
+ * linked list in the order in which they appear on the command line. If you have
+ * multiple long option aliases that refer to the same option, give their descriptors
+ * the same @c index.
+ *
+ * If you have options that mean exactly opposite things
+ * (e.g. @c --enable-foo and @c --disable-foo ), you should also give them the same
+ * @c index, but distinguish them through different values for @ref type.
+ * That way they end up in the same list and you can just take the last element of the
+ * list and use its type. This way you get the usual behaviour where switches later
+ * on the command line override earlier ones without having to code it manually.
+ *
+ * @par Tip:
+ * Use an enum rather than plain ints for better readability, as shown in the example
+ * at Descriptor.
+ */
+ const unsigned index;
+
+ /**
+ * @brief Used to distinguish between options with the same @ref index.
+ * See @ref index for details.
+ *
+ * It is recommended that you use an enum rather than a plain int to make your
+ * code more readable.
+ */
+ const int type;
+
+ /**
+ * @brief Each char in this string will be accepted as a short option character.
+ *
+ * The string must not include the minus character @c '-' or you'll get undefined
+ * behaviour.
+ *
+ * If this Descriptor should not have short option characters, use the empty
+ * string "". NULL is not permitted here!
+ *
+ * See @ref longopt for more information.
+ */
+ const char* const shortopt;
+
+ /**
+ * @brief The long option name (without the leading @c -- ).
+ *
+ * If this Descriptor should not have a long option name, use the empty
+ * string "". NULL is not permitted here!
+ *
+ * While @ref shortopt allows multiple short option characters, each
+ * Descriptor can have only a single long option name. If you have multiple
+ * long option names referring to the same option use separate Descriptors
+ * that have the same @ref index and @ref type. You may repeat
+ * short option characters in such an alias Descriptor but there's no need to.
+ *
+ * @par Dummy Descriptors:
+ * You can use dummy Descriptors with an
+ * empty string for both @ref shortopt and @ref longopt to add text to
+ * the usage that is not related to a specific option. See @ref help.
+ * The first dummy Descriptor will be used for unknown options (see below).
+ *
+ * @par Unknown Option Descriptor:
+ * The first dummy Descriptor in the list of Descriptors,
+ * whose @ref shortopt and @ref longopt are both the empty string, will be used
+ * as the Descriptor for unknown options. An unknown option is a string in
+ * the argument vector that is not a lone minus @c '-' but starts with a minus
+ * character and does not match any Descriptor's @ref shortopt or @ref longopt. @n
+ * Note that the dummy descriptor's @ref check_arg function @e will be called and
+ * its return value will be evaluated as usual. I.e. if it returns @ref ARG_ILLEGAL
+ * the parsing will be aborted with <code>Parser::error()==true</code>. @n
+ * if @c check_arg does not return @ref ARG_ILLEGAL the descriptor's
+ * @ref index @e will be used to pick the linked list into which
+ * to put the unknown option. @n
+ * If there is no dummy descriptor, unknown options will be dropped silently.
+ *
+ */
+ const char* const longopt;
+
+ /**
+ * @brief For each option that matches @ref shortopt or @ref longopt this function
+ * will be called to check a potential argument to the option.
+ *
+ * This function will be called even if there is no potential argument. In that case
+ * it will be passed @c NULL as @c arg parameter. Do not confuse this with the empty
+ * string.
+ *
+ * See @ref CheckArg for more information.
+ */
+ const CheckArg check_arg;
+
+ /**
+ * @brief The usage text associated with the options in this Descriptor.
+ *
+ * You can use option::printUsage() to format your usage message based on
+ * the @c help texts. You can use dummy Descriptors where
+ * @ref shortopt and @ref longopt are both the empty string to add text to
+ * the usage that is not related to a specific option.
+ *
+ * See option::printUsage() for special formatting characters you can use in
+ * @c help to get a column layout.
+ *
+ * @attention
+ * Must be UTF-8-encoded. If your compiler supports C++11 you can use the "u8"
+ * prefix to make sure string literals are properly encoded.
+ */
+ const char* help;
+};
+
+/**
+ * @brief A parsed option from the command line together with its argument if it has one.
+ *
+ * The Parser chains all parsed options with the same Descriptor::index together
+ * to form a linked list. This allows you to easily implement all of the common ways
+ * of handling repeated options and enable/disable pairs.
+ *
+ * @li Test for presence of a switch in the argument vector:
+ * @code if ( options[QUIET] ) ... @endcode
+ * @li Evaluate --enable-foo/--disable-foo pair where the last one used wins:
+ * @code if ( options[FOO].last()->type() == DISABLE ) ... @endcode
+ * @li Cumulative option (-v verbose, -vv more verbose, -vvv even more verbose):
+ * @code int verbosity = options[VERBOSE].count(); @endcode
+ * @li Iterate over all --file=&lt;fname> arguments:
+ * @code for (Option* opt = options[FILE]; opt; opt = opt->next())
+ * fname = opt->arg; ... @endcode
+ */
+class Option
+{
+ Option* next_;
+ Option* prev_;
+public:
+ /**
+ * @brief Pointer to this Option's Descriptor.
+ *
+ * Remember that the first dummy descriptor (see @ref Descriptor::longopt) is used
+ * for unknown options.
+ *
+ * @attention
+ * @c desc==NULL signals that this Option is unused. This is the default state of
+ * elements in the result array. You don't need to test @c desc explicitly. You
+ * can simply write something like this:
+ * @code
+ * if (options[CREATE])
+ * {
+ * ...
+ * }
+ * @endcode
+ * This works because of <code> operator const Option*() </code>.
+ */
+ const Descriptor* desc;
+
+ /**
+ * @brief The name of the option as used on the command line.
+ *
+ * The main purpose of this string is to be presented to the user in messages.
+ *
+ * In the case of a long option, this is the actual @c argv pointer, i.e. the first
+ * character is a '-'. In the case of a short option this points to the option
+ * character within the @c argv string.
+ *
+ * Note that in the case of a short option group or an attached option argument, this
+ * string will contain additional characters following the actual name. Use @ref namelen
+ * to filter out the actual option name only.
+ *
+ */
+ const char* name;
+
+ /**
+ * @brief Pointer to this Option's argument (if any).
+ *
+ * NULL if this option has no argument. Do not confuse this with the empty string which
+ * is a valid argument.
+ */
+ const char* arg;
+
+ /**
+ * @brief The length of the option @ref name.
+ *
+ * Because @ref name points into the actual @c argv string, the option name may be
+ * followed by more characters (e.g. other short options in the same short option group).
+ * This value is the number of bytes (not characters!) that are part of the actual name.
+ *
+ * For a short option, this length is always 1. For a long option this length is always
+ * at least 2 if single minus long options are permitted and at least 3 if they are disabled.
+ *
+ * @note
+ * In the pathological case of a minus within a short option group (e.g. @c -xf-z), this
+ * length is incorrect, because this case will be misinterpreted as a long option and the
+ * name will therefore extend to the string's 0-terminator or a following '=" character
+ * if there is one. This is irrelevant for most uses of @ref name and @c namelen. If you
+ * really need to distinguish the case of a long and a short option, compare @ref name to
+ * the @c argv pointers. A long option's @c name is always identical to one of them,
+ * whereas a short option's is never.
+ */
+ int namelen;
+
+ /**
+ * @brief Returns Descriptor::type of this Option's Descriptor, or 0 if this Option
+ * is invalid (unused).
+ *
+ * Because this method (and last(), too) can be used even on unused Options with desc==0, you can (provided
+ * you arrange your types properly) switch on type() without testing validity first.
+ * @code
+ * enum OptionType { UNUSED=0, DISABLED=0, ENABLED=1 };
+ * enum OptionIndex { FOO };
+ * const Descriptor usage[] = {
+ * { FOO, ENABLED, "", "enable-foo", Arg::None, 0 },
+ * { FOO, DISABLED, "", "disable-foo", Arg::None, 0 },
+ * { 0, 0, 0, 0, 0, 0 } };
+ * ...
+ * switch(options[FOO].last()->type()) // no validity check required!
+ * {
+ * case ENABLED: ...
+ * case DISABLED: ... // UNUSED==DISABLED !
+ * }
+ * @endcode
+ */
+ int type() const
+ {
+ return desc == 0 ? 0 : desc->type;
+ }
+
+ /**
+ * @brief Returns Descriptor::index of this Option's Descriptor, or -1 if this Option
+ * is invalid (unused).
+ */
+ int index() const
+ {
+ return desc == 0 ? -1 : desc->index;
+ }
+
+ /**
+ * @brief Returns the number of times this Option (or others with the same Descriptor::index)
+ * occurs in the argument vector.
+ *
+ * This corresponds to the number of elements in the linked list this Option is part of.
+ * It doesn't matter on which element you call count(). The return value is always the same.
+ *
+ * Use this to implement cumulative options, such as -v, -vv, -vvv for
+ * different verbosity levels.
+ *
+ * Returns 0 when called for an unused/invalid option.
+ */
+ int count()
+ {
+ int c = (desc == 0 ? 0 : 1);
+ Option* p = first();
+ while (!p->isLast())
+ {
+ ++c;
+ p = p->next_;
+ };
+ return c;
+ }
+
+ /**
+ * @brief Returns true iff this is the first element of the linked list.
+ *
+ * The first element in the linked list is the first option on the command line
+ * that has the respective Descriptor::index value.
+ *
+ * Returns true for an unused/invalid option.
+ */
+ bool isFirst() const
+ {
+ return isTagged(prev_);
+ }
+
+ /**
+ * @brief Returns true iff this is the last element of the linked list.
+ *
+ * The last element in the linked list is the last option on the command line
+ * that has the respective Descriptor::index value.
+ *
+ * Returns true for an unused/invalid option.
+ */
+ bool isLast() const
+ {
+ return isTagged(next_);
+ }
+
+ /**
+ * @brief Returns a pointer to the first element of the linked list.
+ *
+ * Use this when you want the first occurrence of an option on the command line to
+ * take precedence. Note that this is not the way most programs handle options.
+ * You should probably be using last() instead.
+ *
+ * @note
+ * This method may be called on an unused/invalid option and will return a pointer to the
+ * option itself.
+ */
+ Option* first()
+ {
+ Option* p = this;
+ while (!p->isFirst())
+ p = p->prev_;
+ return p;
+ }
+
+ /**
+ * @brief Returns a pointer to the last element of the linked list.
+ *
+ * Use this when you want the last occurrence of an option on the command line to
+ * take precedence. This is the most common way of handling conflicting options.
+ *
+ * @note
+ * This method may be called on an unused/invalid option and will return a pointer to the
+ * option itself.
+ *
+ * @par Tip:
+ * If you have options with opposite meanings (e.g. @c --enable-foo and @c --disable-foo), you
+ * can assign them the same Descriptor::index to get them into the same list. Distinguish them by
+ * Descriptor::type and all you have to do is check <code> last()->type() </code> to get
+ * the state listed last on the command line.
+ */
+ Option* last()
+ {
+ return first()->prevwrap();
+ }
+
+ /**
+ * @brief Returns a pointer to the previous element of the linked list or NULL if
+ * called on first().
+ *
+ * If called on first() this method returns NULL. Otherwise it will return the
+ * option with the same Descriptor::index that precedes this option on the command
+ * line.
+ */
+ Option* prev()
+ {
+ return isFirst() ? 0 : prev_;
+ }
+
+ /**
+ * @brief Returns a pointer to the previous element of the linked list with wrap-around from
+ * first() to last().
+ *
+ * If called on first() this method returns last(). Otherwise it will return the
+ * option with the same Descriptor::index that precedes this option on the command
+ * line.
+ */
+ Option* prevwrap()
+ {
+ return untag(prev_);
+ }
+
+ /**
+ * @brief Returns a pointer to the next element of the linked list or NULL if called
+ * on last().
+ *
+ * If called on last() this method returns NULL. Otherwise it will return the
+ * option with the same Descriptor::index that follows this option on the command
+ * line.
+ */
+ Option* next()
+ {
+ return isLast() ? 0 : next_;
+ }
+
+ /**
+ * @brief Returns a pointer to the next element of the linked list with wrap-around from
+ * last() to first().
+ *
+ * If called on last() this method returns first(). Otherwise it will return the
+ * option with the same Descriptor::index that follows this option on the command
+ * line.
+ */
+ Option* nextwrap()
+ {
+ return untag(next_);
+ }
+
+ /**
+ * @brief Makes @c new_last the new last() by chaining it into the list after last().
+ *
+ * It doesn't matter which element you call append() on. The new element will always
+ * be appended to last().
+ *
+ * @attention
+ * @c new_last must not yet be part of a list, or that list will become corrupted, because
+ * this method does not unchain @c new_last from an existing list.
+ */
+ void append(Option* new_last)
+ {
+ Option* p = last();
+ Option* f = first();
+ p->next_ = new_last;
+ new_last->prev_ = p;
+ new_last->next_ = tag(f);
+ f->prev_ = tag(new_last);
+ }
+
+ /**
+ * @brief Casts from Option to const Option* but only if this Option is valid.
+ *
+ * If this Option is valid (i.e. @c desc!=NULL), returns this.
+ * Otherwise returns NULL. This allows testing an Option directly
+ * in an if-clause to see if it is used:
+ * @code
+ * if (options[CREATE])
+ * {
+ * ...
+ * }
+ * @endcode
+ * It also allows you to write loops like this:
+ * @code for (Option* opt = options[FILE]; opt; opt = opt->next())
+ * fname = opt->arg; ... @endcode
+ */
+ operator const Option*() const
+ {
+ return desc ? this : 0;
+ }
+
+ /**
+ * @brief Casts from Option to Option* but only if this Option is valid.
+ *
+ * If this Option is valid (i.e. @c desc!=NULL), returns this.
+ * Otherwise returns NULL. This allows testing an Option directly
+ * in an if-clause to see if it is used:
+ * @code
+ * if (options[CREATE])
+ * {
+ * ...
+ * }
+ * @endcode
+ * It also allows you to write loops like this:
+ * @code for (Option* opt = options[FILE]; opt; opt = opt->next())
+ * fname = opt->arg; ... @endcode
+ */
+ operator Option*()
+ {
+ return desc ? this : 0;
+ }
+
+ /**
+ * @brief Creates a new Option that is a one-element linked list and has NULL
+ * @ref desc, @ref name, @ref arg and @ref namelen.
+ */
+ Option() :
+ desc(0), name(0), arg(0), namelen(0)
+ {
+ prev_ = tag(this);
+ next_ = tag(this);
+ }
+
+ /**
+ * @brief Creates a new Option that is a one-element linked list and has the given
+ * values for @ref desc, @ref name and @ref arg.
+ *
+ * If @c name_ points at a character other than '-' it will be assumed to refer to a
+ * short option and @ref namelen will be set to 1. Otherwise the length will extend to
+ * the first '=' character or the string's 0-terminator.
+ */
+ Option(const Descriptor* desc_, const char* name_, const char* arg_)
+ {
+ init(desc_, name_, arg_);
+ }
+
+ /**
+ * @brief Makes @c *this a copy of @c orig except for the linked list pointers.
+ *
+ * After this operation @c *this will be a one-element linked list.
+ */
+ void operator=(const Option& orig)
+ {
+ init(orig.desc, orig.name, orig.arg);
+ }
+
+ /**
+ * @brief Makes @c *this a copy of @c orig except for the linked list pointers.
+ *
+ * After this operation @c *this will be a one-element linked list.
+ */
+ Option(const Option& orig)
+ {
+ init(orig.desc, orig.name, orig.arg);
+ }
+
+private:
+ /**
+ * @internal
+ * @brief Sets the fields of this Option to the given values (extracting @c name if necessary).
+ *
+ * If @c name_ points at a character other than '-' it will be assumed to refer to a
+ * short option and @ref namelen will be set to 1. Otherwise the length will extend to
+ * the first '=' character or the string's 0-terminator.
+ */
+ void init(const Descriptor* desc_, const char* name_, const char* arg_)
+ {
+ desc = desc_;
+ name = name_;
+ arg = arg_;
+ prev_ = tag(this);
+ next_ = tag(this);
+ namelen = 0;
+ if (name == 0)
+ return;
+ namelen = 1;
+ if (name[0] != '-')
+ return;
+ while (name[namelen] != 0 && name[namelen] != '=')
+ ++namelen;
+ }
+
+ static Option* tag(Option* ptr)
+ {
+ return (Option*) ((unsigned long long) ptr | 1);
+ }
+
+ static Option* untag(Option* ptr)
+ {
+ return (Option*) ((unsigned long long) ptr & ~1ull);
+ }
+
+ static bool isTagged(Option* ptr)
+ {
+ return ((unsigned long long) ptr & 1);
+ }
+};
+
+/**
+ * @brief Functions for checking the validity of option arguments.
+ *
+ * @copydetails CheckArg
+ *
+ * The following example code
+ * can serve as starting place for writing your own more complex CheckArg functions:
+ * @code
+ * struct Arg: public option::Arg
+ * {
+ * static void printError(const char* msg1, const option::Option& opt, const char* msg2)
+ * {
+ * fprintf(stderr, "ERROR: %s", msg1);
+ * fwrite(opt.name, opt.namelen, 1, stderr);
+ * fprintf(stderr, "%s", msg2);
+ * }
+ *
+ * static option::ArgStatus Unknown(const option::Option& option, bool msg)
+ * {
+ * if (msg) printError("Unknown option '", option, "'\n");
+ * return option::ARG_ILLEGAL;
+ * }
+ *
+ * static option::ArgStatus Required(const option::Option& option, bool msg)
+ * {
+ * if (option.arg != 0)
+ * return option::ARG_OK;
+ *
+ * if (msg) printError("Option '", option, "' requires an argument\n");
+ * return option::ARG_ILLEGAL;
+ * }
+ *
+ * static option::ArgStatus NonEmpty(const option::Option& option, bool msg)
+ * {
+ * if (option.arg != 0 && option.arg[0] != 0)
+ * return option::ARG_OK;
+ *
+ * if (msg) printError("Option '", option, "' requires a non-empty argument\n");
+ * return option::ARG_ILLEGAL;
+ * }
+ *
+ * static option::ArgStatus Numeric(const option::Option& option, bool msg)
+ * {
+ * char* endptr = 0;
+ * if (option.arg != 0 && strtol(option.arg, &endptr, 10)){};
+ * if (endptr != option.arg && *endptr == 0)
+ * return option::ARG_OK;
+ *
+ * if (msg) printError("Option '", option, "' requires a numeric argument\n");
+ * return option::ARG_ILLEGAL;
+ * }
+ * };
+ * @endcode
+ */
+struct Arg
+{
+ //! @brief For options that don't take an argument: Returns ARG_NONE.
+ static ArgStatus None(const Option&, bool)
+ {
+ return ARG_NONE;
+ }
+
+ //! @brief Returns ARG_OK if the argument is attached and ARG_IGNORE otherwise.
+ static ArgStatus Optional(const Option& option, bool)
+ {
+ if (option.arg && option.name[option.namelen] != 0)
+ return ARG_OK;
+ else
+ return ARG_IGNORE;
+ }
+};
+
+/**
+ * @brief Determines the minimum lengths of the buffer and options arrays used for Parser.
+ *
+ * Because Parser doesn't use dynamic memory its output arrays have to be pre-allocated.
+ * If you don't want to use fixed size arrays (which may turn out too small, causing
+ * command line arguments to be dropped), you can use Stats to determine the correct sizes.
+ * Stats work cumulative. You can first pass in your default options and then the real
+ * options and afterwards the counts will reflect the union.
+ */
+struct Stats
+{
+ /**
+ * @brief Number of elements needed for a @c buffer[] array to be used for
+ * @ref Parser::parse() "parsing" the same argument vectors that were fed
+ * into this Stats object.
+ *
+ * @note
+ * This number is always 1 greater than the actual number needed, to give
+ * you a sentinel element.
+ */
+ unsigned buffer_max;
+
+ /**
+ * @brief Number of elements needed for an @c options[] array to be used for
+ * @ref Parser::parse() "parsing" the same argument vectors that were fed
+ * into this Stats object.
+ *
+ * @note
+ * @li This number is always 1 greater than the actual number needed, to give
+ * you a sentinel element.
+ * @li This number depends only on the @c usage, not the argument vectors, because
+ * the @c options array needs exactly one slot for each possible Descriptor::index.
+ */
+ unsigned options_max;
+
+ /**
+ * @brief Creates a Stats object with counts set to 1 (for the sentinel element).
+ */
+ Stats() :
+ buffer_max(1), options_max(1) // 1 more than necessary as sentinel
+ {
+ }
+
+ /**
+ * @brief Creates a new Stats object and immediately updates it for the
+ * given @c usage and argument vector. You may pass 0 for @c argc and/or @c argv,
+ * if you just want to update @ref options_max.
+ *
+ * @note
+ * The calls to Stats methods must match the later calls to Parser methods.
+ * See Parser::parse() for the meaning of the arguments.
+ */
+ Stats(bool gnu, const Descriptor usage[], int argc, const char** argv, int min_abbr_len = 0, //
+ bool single_minus_longopt = false) :
+ buffer_max(1), options_max(1) // 1 more than necessary as sentinel
+ {
+ add(gnu, usage, argc, argv, min_abbr_len, single_minus_longopt);
+ }
+
+ //! @brief Stats(...) with non-const argv.
+ Stats(bool gnu, const Descriptor usage[], int argc, char** argv, int min_abbr_len = 0, //
+ bool single_minus_longopt = false) :
+ buffer_max(1), options_max(1) // 1 more than necessary as sentinel
+ {
+ add(gnu, usage, argc, (const char**) argv, min_abbr_len, single_minus_longopt);
+ }
+
+ //! @brief POSIX Stats(...) (gnu==false).
+ Stats(const Descriptor usage[], int argc, const char** argv, int min_abbr_len = 0, //
+ bool single_minus_longopt = false) :
+ buffer_max(1), options_max(1) // 1 more than necessary as sentinel
+ {
+ add(false, usage, argc, argv, min_abbr_len, single_minus_longopt);
+ }
+
+ //! @brief POSIX Stats(...) (gnu==false) with non-const argv.
+ Stats(const Descriptor usage[], int argc, char** argv, int min_abbr_len = 0, //
+ bool single_minus_longopt = false) :
+ buffer_max(1), options_max(1) // 1 more than necessary as sentinel
+ {
+ add(false, usage, argc, (const char**) argv, min_abbr_len, single_minus_longopt);
+ }
+
+ /**
+ * @brief Updates this Stats object for the
+ * given @c usage and argument vector. You may pass 0 for @c argc and/or @c argv,
+ * if you just want to update @ref options_max.
+ *
+ * @note
+ * The calls to Stats methods must match the later calls to Parser methods.
+ * See Parser::parse() for the meaning of the arguments.
+ */
+ void add(bool gnu, const Descriptor usage[], int argc, const char** argv, int min_abbr_len = 0, //
+ bool single_minus_longopt = false);
+
+ //! @brief add() with non-const argv.
+ void add(bool gnu, const Descriptor usage[], int argc, char** argv, int min_abbr_len = 0, //
+ bool single_minus_longopt = false)
+ {
+ add(gnu, usage, argc, (const char**) argv, min_abbr_len, single_minus_longopt);
+ }
+
+ //! @brief POSIX add() (gnu==false).
+ void add(const Descriptor usage[], int argc, const char** argv, int min_abbr_len = 0, //
+ bool single_minus_longopt = false)
+ {
+ add(false, usage, argc, argv, min_abbr_len, single_minus_longopt);
+ }
+
+ //! @brief POSIX add() (gnu==false) with non-const argv.
+ void add(const Descriptor usage[], int argc, char** argv, int min_abbr_len = 0, //
+ bool single_minus_longopt = false)
+ {
+ add(false, usage, argc, (const char**) argv, min_abbr_len, single_minus_longopt);
+ }
+private:
+ class CountOptionsAction;
+};
+
+/**
+ * @brief Checks argument vectors for validity and parses them into data
+ * structures that are easier to work with.
+ *
+ * @par Example:
+ * @code
+ * int main(int argc, char* argv[])
+ * {
+ * argc-=(argc>0); argv+=(argc>0); // skip program name argv[0] if present
+ * option::Stats stats(usage, argc, argv);
+ * option::Option options[stats.options_max], buffer[stats.buffer_max];
+ * option::Parser parse(usage, argc, argv, options, buffer);
+ *
+ * if (parse.error())
+ * return 1;
+ *
+ * if (options[HELP])
+ * ...
+ * @endcode
+ */
+class Parser
+{
+ int op_count; //!< @internal @brief see optionsCount()
+ int nonop_count; //!< @internal @brief see nonOptionsCount()
+ const char** nonop_args; //!< @internal @brief see nonOptions()
+ bool err; //!< @internal @brief see error()
+public:
+
+ /**
+ * @brief Creates a new Parser.
+ */
+ Parser() :
+ op_count(0), nonop_count(0), nonop_args(0), err(false)
+ {
+ }
+
+ /**
+ * @brief Creates a new Parser and immediately parses the given argument vector.
+ * @copydetails parse()
+ */
+ Parser(bool gnu, const Descriptor usage[], int argc, const char** argv, Option options[], Option buffer[],
+ int min_abbr_len = 0, bool single_minus_longopt = false, int bufmax = -1) :
+ op_count(0), nonop_count(0), nonop_args(0), err(false)
+ {
+ parse(gnu, usage, argc, argv, options, buffer, min_abbr_len, single_minus_longopt, bufmax);
+ }
+
+ //! @brief Parser(...) with non-const argv.
+ Parser(bool gnu, const Descriptor usage[], int argc, char** argv, Option options[], Option buffer[],
+ int min_abbr_len = 0, bool single_minus_longopt = false, int bufmax = -1) :
+ op_count(0), nonop_count(0), nonop_args(0), err(false)
+ {
+ parse(gnu, usage, argc, (const char**) argv, options, buffer, min_abbr_len, single_minus_longopt, bufmax);
+ }
+
+ //! @brief POSIX Parser(...) (gnu==false).
+ Parser(const Descriptor usage[], int argc, const char** argv, Option options[], Option buffer[], int min_abbr_len = 0,
+ bool single_minus_longopt = false, int bufmax = -1) :
+ op_count(0), nonop_count(0), nonop_args(0), err(false)
+ {
+ parse(false, usage, argc, argv, options, buffer, min_abbr_len, single_minus_longopt, bufmax);
+ }
+
+ //! @brief POSIX Parser(...) (gnu==false) with non-const argv.
+ Parser(const Descriptor usage[], int argc, char** argv, Option options[], Option buffer[], int min_abbr_len = 0,
+ bool single_minus_longopt = false, int bufmax = -1) :
+ op_count(0), nonop_count(0), nonop_args(0), err(false)
+ {
+ parse(false, usage, argc, (const char**) argv, options, buffer, min_abbr_len, single_minus_longopt, bufmax);
+ }
+
+ /**
+ * @brief Parses the given argument vector.
+ *
+ * @param gnu if true, parse() will not stop at the first non-option argument. Instead it will
+ * reorder arguments so that all non-options are at the end. This is the default behaviour
+ * of GNU getopt() but is not conforming to POSIX. @n
+ * Note, that once the argument vector has been reordered, the @c gnu flag will have
+ * no further effect on this argument vector. So it is enough to pass @c gnu==true when
+ * creating Stats.
+ * @param usage Array of Descriptor objects that describe the options to support. The last entry
+ * of this array must have 0 in all fields.
+ * @param argc The number of elements from @c argv that are to be parsed. If you pass -1, the number
+ * will be determined automatically. In that case the @c argv list must end with a NULL
+ * pointer.
+ * @param argv The arguments to be parsed. If you pass -1 as @c argc the last pointer in the @c argv
+ * list must be NULL to mark the end.
+ * @param options Each entry is the first element of a linked list of Options. Each new option
+ * that is parsed will be appended to the list specified by that Option's
+ * Descriptor::index. If an entry is not yet used (i.e. the Option is invalid),
+ * it will be replaced rather than appended to. @n
+ * The minimum length of this array is the greatest Descriptor::index value that
+ * occurs in @c usage @e PLUS ONE.
+ * @param buffer Each argument that is successfully parsed (including unknown arguments, if they
+ * have a Descriptor whose CheckArg does not return @ref ARG_ILLEGAL) will be stored in this
+ * array. parse() scans the array for the first invalid entry and begins writing at that
+ * index. You can pass @c bufmax to limit the number of options stored.
+ * @param min_abbr_len Passing a value <code> min_abbr_len > 0 </code> enables abbreviated long
+ * options. The parser will match a prefix of a long option as if it was
+ * the full long option (e.g. @c --foob=10 will be interpreted as if it was
+ * @c --foobar=10 ), as long as the prefix has at least @c min_abbr_len characters
+ * (not counting the @c -- ) and is unambiguous.
+ * @n Be careful if combining @c min_abbr_len=1 with @c single_minus_longopt=true
+ * because the ambiguity check does not consider short options and abbreviated
+ * single minus long options will take precedence over short options.
+ * @param single_minus_longopt Passing @c true for this option allows long options to begin with
+ * a single minus. The double minus form will still be recognized. Note that
+ * single minus long options take precedence over short options and short option
+ * groups. E.g. @c -file would be interpreted as @c --file and not as
+ * <code> -f -i -l -e </code> (assuming a long option named @c "file" exists).
+ * @param bufmax The greatest index in the @c buffer[] array that parse() will write to is
+ * @c bufmax-1. If there are more options, they will be processed (in particular
+ * their CheckArg will be called) but not stored. @n
+ * If you used Stats::buffer_max to dimension this array, you can pass
+ * -1 (or not pass @c bufmax at all) which tells parse() that the buffer is
+ * "large enough".
+ * @attention
+ * Remember that @c options and @c buffer store Option @e objects, not pointers. Therefore it
+ * is not possible for the same object to be in both arrays. For those options that are found in
+ * both @c buffer[] and @c options[] the respective objects are independent copies. And only the
+ * objects in @c options[] are properly linked via Option::next() and Option::prev().
+ * You can iterate over @c buffer[] to
+ * process all options in the order they appear in the argument vector, but if you want access to
+ * the other Options with the same Descriptor::index, then you @e must access the linked list via
+ * @c options[]. You can get the linked list in options from a buffer object via something like
+ * @c options[buffer[i].index()].
+ */
+ void parse(bool gnu, const Descriptor usage[], int argc, const char** argv, Option options[], Option buffer[],
+ int min_abbr_len = 0, bool single_minus_longopt = false, int bufmax = -1);
+
+ //! @brief parse() with non-const argv.
+ void parse(bool gnu, const Descriptor usage[], int argc, char** argv, Option options[], Option buffer[],
+ int min_abbr_len = 0, bool single_minus_longopt = false, int bufmax = -1)
+ {
+ parse(gnu, usage, argc, (const char**) argv, options, buffer, min_abbr_len, single_minus_longopt, bufmax);
+ }
+
+ //! @brief POSIX parse() (gnu==false).
+ void parse(const Descriptor usage[], int argc, const char** argv, Option options[], Option buffer[],
+ int min_abbr_len = 0, bool single_minus_longopt = false, int bufmax = -1)
+ {
+ parse(false, usage, argc, argv, options, buffer, min_abbr_len, single_minus_longopt, bufmax);
+ }
+
+ //! @brief POSIX parse() (gnu==false) with non-const argv.
+ void parse(const Descriptor usage[], int argc, char** argv, Option options[], Option buffer[], int min_abbr_len = 0,
+ bool single_minus_longopt = false, int bufmax = -1)
+ {
+ parse(false, usage, argc, (const char**) argv, options, buffer, min_abbr_len, single_minus_longopt, bufmax);
+ }
+
+ /**
+ * @brief Returns the number of valid Option objects in @c buffer[].
+ *
+ * @note
+ * @li The returned value always reflects the number of Options in the buffer[] array used for
+ * the most recent call to parse().
+ * @li The count (and the buffer[]) includes unknown options if they are collected
+ * (see Descriptor::longopt).
+ */
+ int optionsCount()
+ {
+ return op_count;
+ }
+
+ /**
+ * @brief Returns the number of non-option arguments that remained at the end of the
+ * most recent parse() that actually encountered non-option arguments.
+ *
+ * @note
+ * A parse() that does not encounter non-option arguments will leave this value
+ * as well as nonOptions() undisturbed. This means you can feed the Parser a
+ * default argument vector that contains non-option arguments (e.g. a default filename).
+ * Then you feed it the actual arguments from the user. If the user has supplied at
+ * least one non-option argument, all of the non-option arguments from the default
+ * disappear and are replaced by the user's non-option arguments. However, if the
+ * user does not supply any non-option arguments the defaults will still be in
+ * effect.
+ */
+ int nonOptionsCount()
+ {
+ return nonop_count;
+ }
+
+ /**
+ * @brief Returns a pointer to an array of non-option arguments (only valid
+ * if <code>nonOptionsCount() >0 </code>).
+ *
+ * @note
+ * @li parse() does not copy arguments, so this pointer points into the actual argument
+ * vector as passed to parse().
+ * @li As explained at nonOptionsCount() this pointer is only changed by parse() calls
+ * that actually encounter non-option arguments. A parse() call that encounters only
+ * options, will not change nonOptions().
+ */
+ const char** nonOptions()
+ {
+ return nonop_args;
+ }
+
+ /**
+ * @brief Returns <b><code>nonOptions()[i]</code></b> (@e without checking if i is in range!).
+ */
+ const char* nonOption(int i)
+ {
+ return nonOptions()[i];
+ }
+
+ /**
+ * @brief Returns @c true if an unrecoverable error occurred while parsing options.
+ *
+ * An illegal argument to an option (i.e. CheckArg returns @ref ARG_ILLEGAL) is an
+ * unrecoverable error that aborts the parse. Unknown options are only an error if
+ * their CheckArg function returns @ref ARG_ILLEGAL. Otherwise they are collected.
+ * In that case if you want to exit the program if either an illegal argument
+ * or an unknown option has been passed, use code like this
+ *
+ * @code
+ * if (parser.error() || options[UNKNOWN])
+ * exit(1);
+ * @endcode
+ *
+ */
+ bool error()
+ {
+ return err;
+ }
+
+private:
+ friend struct Stats;
+ class StoreOptionAction;
+ struct Action;
+
+ /**
+ * @internal
+ * @brief This is the core function that does all the parsing.
+ * @retval false iff an unrecoverable error occurred.
+ */
+ static bool workhorse(bool gnu, const Descriptor usage[], int numargs, const char** args, Action& action,
+ bool single_minus_longopt, bool print_errors, int min_abbr_len);
+
+ /**
+ * @internal
+ * @brief Returns true iff @c st1 is a prefix of @c st2 and
+ * in case @c st2 is longer than @c st1, then
+ * the first additional character is '='.
+ *
+ * @par Examples:
+ * @code
+ * streq("foo", "foo=bar") == true
+ * streq("foo", "foobar") == false
+ * streq("foo", "foo") == true
+ * streq("foo=bar", "foo") == false
+ * @endcode
+ */
+ static bool streq(const char* st1, const char* st2)
+ {
+ while (*st1 != 0)
+ if (*st1++ != *st2++)
+ return false;
+ return (*st2 == 0 || *st2 == '=');
+ }
+
+ /**
+ * @internal
+ * @brief Like streq() but handles abbreviations.
+ *
+ * Returns true iff @c st1 and @c st2 have a common
+ * prefix with the following properties:
+ * @li (if min > 0) its length is at least @c min characters or the same length as @c st1 (whichever is smaller).
+ * @li (if min <= 0) its length is the same as that of @c st1
+ * @li within @c st2 the character following the common prefix is either '=' or end-of-string.
+ *
+ * Examples:
+ * @code
+ * streqabbr("foo", "foo=bar",<anything>) == true
+ * streqabbr("foo", "fo=bar" , 2) == true
+ * streqabbr("foo", "fo" , 2) == true
+ * streqabbr("foo", "fo" , 0) == false
+ * streqabbr("foo", "f=bar" , 2) == false
+ * streqabbr("foo", "f" , 2) == false
+ * streqabbr("fo" , "foo=bar",<anything>) == false
+ * streqabbr("foo", "foobar" ,<anything>) == false
+ * streqabbr("foo", "fobar" ,<anything>) == false
+ * streqabbr("foo", "foo" ,<anything>) == true
+ * @endcode
+ */
+ static bool streqabbr(const char* st1, const char* st2, long long min)
+ {
+ const char* st1start = st1;
+ while (*st1 != 0 && (*st1 == *st2))
+ {
+ ++st1;
+ ++st2;
+ }
+
+ return (*st1 == 0 || (min > 0 && (st1 - st1start) >= min)) && (*st2 == 0 || *st2 == '=');
+ }
+
+ /**
+ * @internal
+ * @brief Returns true iff character @c ch is contained in the string @c st.
+ *
+ * Returns @c true for @c ch==0 .
+ */
+ static bool instr(char ch, const char* st)
+ {
+ while (*st != 0 && *st != ch)
+ ++st;
+ return *st == ch;
+ }
+
+ /**
+ * @internal
+ * @brief Rotates <code>args[-count],...,args[-1],args[0]</code> to become
+ * <code>args[0],args[-count],...,args[-1]</code>.
+ */
+ static void shift(const char** args, int count)
+ {
+ for (int i = 0; i > -count; --i)
+ {
+ const char* temp = args[i];
+ args[i] = args[i - 1];
+ args[i - 1] = temp;
+ }
+ }
+};
+
+/**
+ * @internal
+ * @brief Interface for actions Parser::workhorse() should perform for each Option it
+ * parses.
+ */
+struct Parser::Action
+{
+ /**
+ * @brief Called by Parser::workhorse() for each Option that has been successfully
+ * parsed (including unknown
+ * options if they have a Descriptor whose Descriptor::check_arg does not return
+ * @ref ARG_ILLEGAL.
+ *
+ * Returns @c false iff a fatal error has occured and the parse should be aborted.
+ */
+ virtual bool perform(Option&)
+ {
+ return true;
+ }
+
+ /**
+ * @brief Called by Parser::workhorse() after finishing the parse.
+ * @param numargs the number of non-option arguments remaining
+ * @param args pointer to the first remaining non-option argument (if numargs > 0).
+ *
+ * @return
+ * @c false iff a fatal error has occurred.
+ */
+ virtual bool finished(int numargs, const char** args)
+ {
+ (void) numargs;
+ (void) args;
+ return true;
+ }
+};
+
+/**
+ * @internal
+ * @brief An Action to pass to Parser::workhorse() that will increment a counter for
+ * each parsed Option.
+ */
+class Stats::CountOptionsAction: public Parser::Action
+{
+ unsigned* buffer_max;
+public:
+ /**
+ * Creates a new CountOptionsAction that will increase @c *buffer_max_ for each
+ * parsed Option.
+ */
+ CountOptionsAction(unsigned* buffer_max_) :
+ buffer_max(buffer_max_)
+ {
+ }
+
+ bool perform(Option&)
+ {
+ if (*buffer_max == 0x7fffffff)
+ return false; // overflow protection: don't accept number of options that doesn't fit signed int
+ ++*buffer_max;
+ return true;
+ }
+};
+
+/**
+ * @internal
+ * @brief An Action to pass to Parser::workhorse() that will store each parsed Option in
+ * appropriate arrays (see Parser::parse()).
+ */
+class Parser::StoreOptionAction: public Parser::Action
+{
+ Parser& parser;
+ Option* options;
+ Option* buffer;
+ int bufmax; //! Number of slots in @c buffer. @c -1 means "large enough".
+public:
+ /**
+ * @brief Creates a new StoreOption action.
+ * @param parser_ the parser whose op_count should be updated.
+ * @param options_ each Option @c o is chained into the linked list @c options_[o.desc->index]
+ * @param buffer_ each Option is appended to this array as long as there's a free slot.
+ * @param bufmax_ number of slots in @c buffer_. @c -1 means "large enough".
+ */
+ StoreOptionAction(Parser& parser_, Option options_[], Option buffer_[], int bufmax_) :
+ parser(parser_), options(options_), buffer(buffer_), bufmax(bufmax_)
+ {
+ // find first empty slot in buffer (if any)
+ int bufidx = 0;
+ while ((bufmax < 0 || bufidx < bufmax) && buffer[bufidx])
+ ++bufidx;
+
+ // set parser's optionCount
+ parser.op_count = bufidx;
+ }
+
+ bool perform(Option& option)
+ {
+ if (bufmax < 0 || parser.op_count < bufmax)
+ {
+ if (parser.op_count == 0x7fffffff)
+ return false; // overflow protection: don't accept number of options that doesn't fit signed int
+
+ buffer[parser.op_count] = option;
+ int idx = buffer[parser.op_count].desc->index;
+ if (options[idx])
+ options[idx].append(buffer[parser.op_count]);
+ else
+ options[idx] = buffer[parser.op_count];
+ ++parser.op_count;
+ }
+ return true; // NOTE: an option that is discarded because of a full buffer is not fatal
+ }
+
+ bool finished(int numargs, const char** args)
+ {
+ // only overwrite non-option argument list if there's at least 1
+ // new non-option argument. Otherwise we keep the old list. This
+ // makes it easy to use default non-option arguments.
+ if (numargs > 0)
+ {
+ parser.nonop_count = numargs;
+ parser.nonop_args = args;
+ }
+
+ return true;
+ }
+};
+
+inline void Parser::parse(bool gnu, const Descriptor usage[], int argc, const char** argv, Option options[],
+ Option buffer[], int min_abbr_len, bool single_minus_longopt, int bufmax)
+{
+ StoreOptionAction action(*this, options, buffer, bufmax);
+ err = !workhorse(gnu, usage, argc, argv, action, single_minus_longopt, true, min_abbr_len);
+}
+
+inline void Stats::add(bool gnu, const Descriptor usage[], int argc, const char** argv, int min_abbr_len,
+ bool single_minus_longopt)
+{
+ // determine size of options array. This is the greatest index used in the usage + 1
+ int i = 0;
+ while (usage[i].shortopt != 0)
+ {
+ if (usage[i].index + 1 >= options_max)
+ options_max = (usage[i].index + 1) + 1; // 1 more than necessary as sentinel
+
+ ++i;
+ }
+
+ CountOptionsAction action(&buffer_max);
+ Parser::workhorse(gnu, usage, argc, argv, action, single_minus_longopt, false, min_abbr_len);
+}
+
+inline bool Parser::workhorse(bool gnu, const Descriptor usage[], int numargs, const char** args, Action& action,
+ bool single_minus_longopt, bool print_errors, int min_abbr_len)
+{
+ // protect against NULL pointer
+ if (args == 0)
+ numargs = 0;
+
+ int nonops = 0;
+
+ while (numargs != 0 && *args != 0)
+ {
+ const char* param = *args; // param can be --long-option, -srto or non-option argument
+
+ // in POSIX mode the first non-option argument terminates the option list
+ // a lone minus character is a non-option argument
+ if (param[0] != '-' || param[1] == 0)
+ {
+ if (gnu)
+ {
+ ++nonops;
+ ++args;
+ if (numargs > 0)
+ --numargs;
+ continue;
+ }
+ else
+ break;
+ }
+
+ // -- terminates the option list. The -- itself is skipped.
+ if (param[1] == '-' && param[2] == 0)
+ {
+ shift(args, nonops);
+ ++args;
+ if (numargs > 0)
+ --numargs;
+ break;
+ }
+
+ bool handle_short_options;
+ const char* longopt_name;
+ if (param[1] == '-') // if --long-option
+ {
+ handle_short_options = false;
+ longopt_name = param + 2;
+ }
+ else
+ {
+ handle_short_options = true;
+ longopt_name = param + 1; //for testing a potential -long-option
+ }
+
+ bool try_single_minus_longopt = single_minus_longopt;
+ bool have_more_args = (numargs > 1 || numargs < 0); // is referencing argv[1] valid?
+
+ do // loop over short options in group, for long options the body is executed only once
+ {
+ int idx = 0;
+
+ const char* optarg = 0;
+
+ /******************** long option **********************/
+ if (handle_short_options == false || try_single_minus_longopt)
+ {
+ idx = 0;
+ while (usage[idx].longopt != 0 && !streq(usage[idx].longopt, longopt_name))
+ ++idx;
+
+ if (usage[idx].longopt == 0 && min_abbr_len > 0) // if we should try to match abbreviated long options
+ {
+ int i1 = 0;
+ while (usage[i1].longopt != 0 && !streqabbr(usage[i1].longopt, longopt_name, min_abbr_len))
+ ++i1;
+ if (usage[i1].longopt != 0)
+ { // now test if the match is unambiguous by checking for another match
+ int i2 = i1 + 1;
+ while (usage[i2].longopt != 0 && !streqabbr(usage[i2].longopt, longopt_name, min_abbr_len))
+ ++i2;
+
+ if (usage[i2].longopt == 0) // if there was no second match it's unambiguous, so accept i1 as idx
+ idx = i1;
+ }
+ }
+
+ // if we found something, disable handle_short_options (only relevant if single_minus_longopt)
+ if (usage[idx].longopt != 0)
+ handle_short_options = false;
+
+ try_single_minus_longopt = false; // prevent looking for longopt in the middle of shortopt group
+
+ optarg = longopt_name;
+ while (*optarg != 0 && *optarg != '=')
+ ++optarg;
+ if (*optarg == '=') // attached argument
+ ++optarg;
+ else
+ // possibly detached argument
+ optarg = (have_more_args ? args[1] : 0);
+ }
+
+ /************************ short option ***********************************/
+ if (handle_short_options)
+ {
+ if (*++param == 0) // point at the 1st/next option character
+ break; // end of short option group
+
+ idx = 0;
+ while (usage[idx].shortopt != 0 && !instr(*param, usage[idx].shortopt))
+ ++idx;
+
+ if (param[1] == 0) // if the potential argument is separate
+ optarg = (have_more_args ? args[1] : 0);
+ else
+ // if the potential argument is attached
+ optarg = param + 1;
+ }
+
+ const Descriptor* descriptor = &usage[idx];
+
+ if (descriptor->shortopt == 0) /************** unknown option ********************/
+ {
+ // look for dummy entry (shortopt == "" and longopt == "") to use as Descriptor for unknown options
+ idx = 0;
+ while (usage[idx].shortopt != 0 && (usage[idx].shortopt[0] != 0 || usage[idx].longopt[0] != 0))
+ ++idx;
+ descriptor = (usage[idx].shortopt == 0 ? 0 : &usage[idx]);
+ }
+
+ if (descriptor != 0)
+ {
+ Option option(descriptor, param, optarg);
+ switch (descriptor->check_arg(option, print_errors))
+ {
+ case ARG_ILLEGAL:
+ return false; // fatal
+ case ARG_OK:
+ // skip one element of the argument vector, if it's a separated argument
+ if (optarg != 0 && have_more_args && optarg == args[1])
+ {
+ shift(args, nonops);
+ if (numargs > 0)
+ --numargs;
+ ++args;
+ }
+
+ // No further short options are possible after an argument
+ handle_short_options = false;
+
+ break;
+ case ARG_IGNORE:
+ case ARG_NONE:
+ option.arg = 0;
+ break;
+ }
+
+ if (!action.perform(option))
+ return false;
+ }
+
+ } while (handle_short_options);
+
+ shift(args, nonops);
+ ++args;
+ if (numargs > 0)
+ --numargs;
+
+ } // while
+
+ if (numargs > 0 && *args == 0) // It's a bug in the caller if numargs is greater than the actual number
+ numargs = 0; // of arguments, but as a service to the user we fix this if we spot it.
+
+ if (numargs < 0) // if we don't know the number of remaining non-option arguments
+ { // we need to count them
+ numargs = 0;
+ while (args[numargs] != 0)
+ ++numargs;
+ }
+
+ return action.finished(numargs + nonops, args - nonops);
+}
+
+/**
+ * @internal
+ * @brief The implementation of option::printUsage().
+ */
+struct PrintUsageImplementation
+{
+ /**
+ * @internal
+ * @brief Interface for Functors that write (part of) a string somewhere.
+ */
+ struct IStringWriter
+ {
+ /**
+ * @brief Writes the given number of chars beginning at the given pointer somewhere.
+ */
+ virtual void operator()(const char*, int)
+ {
+ }
+ };
+
+ /**
+ * @internal
+ * @brief Encapsulates a function with signature <code>func(string, size)</code> where
+ * string can be initialized with a const char* and size with an int.
+ */
+ template<typename Function>
+ struct FunctionWriter: public IStringWriter
+ {
+ Function* write;
+
+ virtual void operator()(const char* str, int size)
+ {
+ (*write)(str, size);
+ }
+
+ FunctionWriter(Function* w) :
+ write(w)
+ {
+ }
+ };
+
+ /**
+ * @internal
+ * @brief Encapsulates a reference to an object with a <code>write(string, size)</code>
+ * method like that of @c std::ostream.
+ */
+ template<typename OStream>
+ struct OStreamWriter: public IStringWriter
+ {
+ OStream& ostream;
+
+ virtual void operator()(const char* str, int size)
+ {
+ ostream.write(str, size);
+ }
+
+ OStreamWriter(OStream& o) :
+ ostream(o)
+ {
+ }
+ };
+
+ /**
+ * @internal
+ * @brief Like OStreamWriter but encapsulates a @c const reference, which is
+ * typically a temporary object of a user class.
+ */
+ template<typename Temporary>
+ struct TemporaryWriter: public IStringWriter
+ {
+ const Temporary& userstream;
+
+ virtual void operator()(const char* str, int size)
+ {
+ userstream.write(str, size);
+ }
+
+ TemporaryWriter(const Temporary& u) :
+ userstream(u)
+ {
+ }
+ };
+
+ /**
+ * @internal
+ * @brief Encapsulates a function with the signature <code>func(fd, string, size)</code> (the
+ * signature of the @c write() system call)
+ * where fd can be initialized from an int, string from a const char* and size from an int.
+ */
+ template<typename Syscall>
+ struct SyscallWriter: public IStringWriter
+ {
+ Syscall* write;
+ int fd;
+
+ virtual void operator()(const char* str, int size)
+ {
+ (*write)(fd, str, size);
+ }
+
+ SyscallWriter(Syscall* w, int f) :
+ write(w), fd(f)
+ {
+ }
+ };
+
+ /**
+ * @internal
+ * @brief Encapsulates a function with the same signature as @c std::fwrite().
+ */
+ template<typename Function, typename Stream>
+ struct StreamWriter: public IStringWriter
+ {
+ Function* fwrite;
+ Stream* stream;
+
+ virtual void operator()(const char* str, int size)
+ {
+ (*fwrite)(str, size, 1, stream);
+ }
+
+ StreamWriter(Function* w, Stream* s) :
+ fwrite(w), stream(s)
+ {
+ }
+ };
+
+ /**
+ * @internal
+ * @brief Sets <code> i1 = max(i1, i2) </code>
+ */
+ static void upmax(int& i1, int i2)
+ {
+ i1 = (i1 >= i2 ? i1 : i2);
+ }
+
+ /**
+ * @internal
+ * @brief Moves the "cursor" to column @c want_x assuming it is currently at column @c x
+ * and sets @c x=want_x .
+ * If <code> x > want_x </code>, a line break is output before indenting.
+ *
+ * @param write Spaces and possibly a line break are written via this functor to get
+ * the desired indentation @c want_x .
+ * @param[in,out] x the current indentation. Set to @c want_x by this method.
+ * @param want_x the desired indentation.
+ */
+ static void indent(IStringWriter& write, int& x, int want_x)
+ {
+ int indent = want_x - x;
+ if (indent < 0)
+ {
+ write("\n", 1);
+ indent = want_x;
+ }
+
+ if (indent > 0)
+ {
+ char space = ' ';
+ for (int i = 0; i < indent; ++i)
+ write(&space, 1);
+ x = want_x;
+ }
+ }
+
+ /**
+ * @brief Returns true if ch is the unicode code point of a wide character.
+ *
+ * @note
+ * The following character ranges are treated as wide
+ * @code
+ * 1100..115F
+ * 2329..232A (just 2 characters!)
+ * 2E80..A4C6 except for 303F
+ * A960..A97C
+ * AC00..D7FB
+ * F900..FAFF
+ * FE10..FE6B
+ * FF01..FF60
+ * FFE0..FFE6
+ * 1B000......
+ * @endcode
+ */
+ static bool isWideChar(unsigned ch)
+ {
+ if (ch == 0x303F)
+ return false;
+
+ return ((0x1100 <= ch && ch <= 0x115F) || (0x2329 <= ch && ch <= 0x232A) || (0x2E80 <= ch && ch <= 0xA4C6)
+ || (0xA960 <= ch && ch <= 0xA97C) || (0xAC00 <= ch && ch <= 0xD7FB) || (0xF900 <= ch && ch <= 0xFAFF)
+ || (0xFE10 <= ch && ch <= 0xFE6B) || (0xFF01 <= ch && ch <= 0xFF60) || (0xFFE0 <= ch && ch <= 0xFFE6)
+ || (0x1B000 <= ch));
+ }
+
+ /**
+ * @internal
+ * @brief Splits a @c Descriptor[] array into tables, rows, lines and columns and
+ * iterates over these components.
+ *
+ * The top-level organizational unit is the @e table.
+ * A table begins at a Descriptor with @c help!=NULL and extends up to
+ * a Descriptor with @c help==NULL.
+ *
+ * A table consists of @e rows. Due to line-wrapping and explicit breaks
+ * a row may take multiple lines on screen. Rows within the table are separated
+ * by \\n. They never cross Descriptor boundaries. This means a row ends either
+ * at \\n or the 0 at the end of the help string.
+ *
+ * A row consists of columns/cells. Columns/cells within a row are separated by \\t.
+ * Line breaks within a cell are marked by \\v.
+ *
+ * Rows in the same table need not have the same number of columns/cells. The
+ * extreme case are interjections, which are rows that contain neither \\t nor \\v.
+ * These are NOT treated specially by LinePartIterator, but they are treated
+ * specially by printUsage().
+ *
+ * LinePartIterator iterates through the usage at 3 levels: table, row and part.
+ * Tables and rows are as described above. A @e part is a line within a cell.
+ * LinePartIterator iterates through 1st parts of all cells, then through the 2nd
+ * parts of all cells (if any),... @n
+ * Example: The row <code> "1 \v 3 \t 2 \v 4" </code> has 2 cells/columns and 4 parts.
+ * The parts will be returned in the order 1, 2, 3, 4.
+ *
+ * It is possible that some cells have fewer parts than others. In this case
+ * LinePartIterator will "fill up" these cells with 0-length parts. IOW, LinePartIterator
+ * always returns the same number of parts for each column. Note that this is different
+ * from the way rows and columns are handled. LinePartIterator does @e not guarantee that
+ * the same number of columns will be returned for each row.
+ *
+ */
+ class LinePartIterator
+ {
+ const Descriptor* tablestart; //!< The 1st descriptor of the current table.
+ const Descriptor* rowdesc; //!< The Descriptor that contains the current row.
+ const char* rowstart; //!< Ptr to 1st character of current row within rowdesc->help.
+ const char* ptr; //!< Ptr to current part within the current row.
+ int col; //!< Index of current column.
+ int len; //!< Length of the current part (that ptr points at) in BYTES
+ int screenlen; //!< Length of the current part in screen columns (taking narrow/wide chars into account).
+ int max_line_in_block; //!< Greatest index of a line within the block. This is the number of \\v within the cell with the most \\vs.
+ int line_in_block; //!< Line index within the current cell of the current part.
+ int target_line_in_block; //!< Line index of the parts we should return to the user on this iteration.
+ bool hit_target_line; //!< Flag whether we encountered a part with line index target_line_in_block in the current cell.
+
+ /**
+ * @brief Determines the byte and character lengths of the part at @ref ptr and
+ * stores them in @ref len and @ref screenlen respectively.
+ */
+ void update_length()
+ {
+ screenlen = 0;
+ for (len = 0; ptr[len] != 0 && ptr[len] != '\v' && ptr[len] != '\t' && ptr[len] != '\n'; ++len)
+ {
+ ++screenlen;
+ unsigned ch = (unsigned char) ptr[len];
+ if (ch > 0xC1) // everything <= 0xC1 (yes, even 0xC1 itself) is not a valid UTF-8 start byte
+ {
+ // int __builtin_clz (unsigned int x)
+ // Returns the number of leading 0-bits in x, starting at the most significant bit
+ unsigned mask = (unsigned) -1 >> __builtin_clz(ch ^ 0xff);
+ ch = ch & mask; // mask out length bits, we don't verify their correctness
+ while (((unsigned char) ptr[len + 1] ^ 0x80) <= 0x3F) // while next byte is continuation byte
+ {
+ ch = (ch << 6) ^ (unsigned char) ptr[len + 1] ^ 0x80; // add continuation to char code
+ ++len;
+ }
+ // ch is the decoded unicode code point
+ if (ch >= 0x1100 && isWideChar(ch)) // the test for 0x1100 is here to avoid the function call in the Latin case
+ ++screenlen;
+ }
+ }
+ }
+
+ public:
+ //! @brief Creates an iterator for @c usage.
+ LinePartIterator(const Descriptor usage[]) :
+ tablestart(usage), rowdesc(0), rowstart(0), ptr(0), col(-1), len(0), max_line_in_block(0), line_in_block(0),
+ target_line_in_block(0), hit_target_line(true)
+ {
+ }
+
+ /**
+ * @brief Moves iteration to the next table (if any). Has to be called once on a new
+ * LinePartIterator to move to the 1st table.
+ * @retval false if moving to next table failed because no further table exists.
+ */
+ bool nextTable()
+ {
+ // If this is NOT the first time nextTable() is called after the constructor,
+ // then skip to the next table break (i.e. a Descriptor with help == 0)
+ if (rowdesc != 0)
+ {
+ while (tablestart->help != 0 && tablestart->shortopt != 0)
+ ++tablestart;
+ }
+
+ // Find the next table after the break (if any)
+ while (tablestart->help == 0 && tablestart->shortopt != 0)
+ ++tablestart;
+
+ restartTable();
+ return rowstart != 0;
+ }
+
+ /**
+ * @brief Reset iteration to the beginning of the current table.
+ */
+ void restartTable()
+ {
+ rowdesc = tablestart;
+ rowstart = tablestart->help;
+ ptr = 0;
+ }
+
+ /**
+ * @brief Moves iteration to the next row (if any). Has to be called once after each call to
+ * @ref nextTable() to move to the 1st row of the table.
+ * @retval false if moving to next row failed because no further row exists.
+ */
+ bool nextRow()
+ {
+ if (ptr == 0)
+ {
+ restartRow();
+ return rowstart != 0;
+ }
+
+ while (*ptr != 0 && *ptr != '\n')
+ ++ptr;
+
+ if (*ptr == 0)
+ {
+ if ((rowdesc + 1)->help == 0) // table break
+ return false;
+
+ ++rowdesc;
+ rowstart = rowdesc->help;
+ }
+ else // if (*ptr == '\n')
+ {
+ rowstart = ptr + 1;
+ }
+
+ restartRow();
+ return true;
+ }
+
+ /**
+ * @brief Reset iteration to the beginning of the current row.
+ */
+ void restartRow()
+ {
+ ptr = rowstart;
+ col = -1;
+ len = 0;
+ screenlen = 0;
+ max_line_in_block = 0;
+ line_in_block = 0;
+ target_line_in_block = 0;
+ hit_target_line = true;
+ }
+
+ /**
+ * @brief Moves iteration to the next part (if any). Has to be called once after each call to
+ * @ref nextRow() to move to the 1st part of the row.
+ * @retval false if moving to next part failed because no further part exists.
+ *
+ * See @ref LinePartIterator for details about the iteration.
+ */
+ bool next()
+ {
+ if (ptr == 0)
+ return false;
+
+ if (col == -1)
+ {
+ col = 0;
+ update_length();
+ return true;
+ }
+
+ ptr += len;
+ while (true)
+ {
+ switch (*ptr)
+ {
+ case '\v':
+ upmax(max_line_in_block, ++line_in_block);
+ ++ptr;
+ break;
+ case '\t':
+ if (!hit_target_line) // if previous column did not have the targetline
+ { // then "insert" a 0-length part
+ update_length();
+ hit_target_line = true;
+ return true;
+ }
+
+ hit_target_line = false;
+ line_in_block = 0;
+ ++col;
+ ++ptr;
+ break;
+ case 0:
+ case '\n':
+ if (!hit_target_line) // if previous column did not have the targetline
+ { // then "insert" a 0-length part
+ update_length();
+ hit_target_line = true;
+ return true;
+ }
+
+ if (++target_line_in_block > max_line_in_block)
+ {
+ update_length();
+ return false;
+ }
+
+ hit_target_line = false;
+ line_in_block = 0;
+ col = 0;
+ ptr = rowstart;
+ continue;
+ default:
+ ++ptr;
+ continue;
+ } // switch
+
+ if (line_in_block == target_line_in_block)
+ {
+ update_length();
+ hit_target_line = true;
+ return true;
+ }
+ } // while
+ }
+
+ /**
+ * @brief Returns the index (counting from 0) of the column in which
+ * the part pointed to by @ref data() is located.
+ */
+ int column()
+ {
+ return col;
+ }
+
+ /**
+ * @brief Returns the index (counting from 0) of the line within the current column
+ * this part belongs to.
+ */
+ int line()
+ {
+ return target_line_in_block; // NOT line_in_block !!! It would be wrong if !hit_target_line
+ }
+
+ /**
+ * @brief Returns the length of the part pointed to by @ref data() in raw chars (not UTF-8 characters).
+ */
+ int length()
+ {
+ return len;
+ }
+
+ /**
+ * @brief Returns the width in screen columns of the part pointed to by @ref data().
+ * Takes multi-byte UTF-8 sequences and wide characters into account.
+ */
+ int screenLength()
+ {
+ return screenlen;
+ }
+
+ /**
+ * @brief Returns the current part of the iteration.
+ */
+ const char* data()
+ {
+ return ptr;
+ }
+ };
+
+ /**
+ * @internal
+ * @brief Takes input and line wraps it, writing out one line at a time so that
+ * it can be interleaved with output from other columns.
+ *
+ * The LineWrapper is used to handle the last column of each table as well as interjections.
+ * The LineWrapper is called once for each line of output. If the data given to it fits
+ * into the designated width of the last column it is simply written out. If there
+ * is too much data, an appropriate split point is located and only the data up to this
+ * split point is written out. The rest of the data is queued for the next line.
+ * That way the last column can be line wrapped and interleaved with data from
+ * other columns. The following example makes this clearer:
+ * @code
+ * Column 1,1 Column 2,1 This is a long text
+ * Column 1,2 Column 2,2 that does not fit into
+ * a single line.
+ * @endcode
+ *
+ * The difficulty in producing this output is that the whole string
+ * "This is a long text that does not fit into a single line" is the
+ * 1st and only part of column 3. In order to produce the above
+ * output the string must be output piecemeal, interleaved with
+ * the data from the other columns.
+ */
+ class LineWrapper
+ {
+ static const int bufmask = 15; //!< Must be a power of 2 minus 1.
+ /**
+ * @brief Ring buffer for length component of pair (data, length).
+ */
+ int lenbuf[bufmask + 1];
+ /**
+ * @brief Ring buffer for data component of pair (data, length).
+ */
+ const char* datbuf[bufmask + 1];
+ /**
+ * @brief The indentation of the column to which the LineBuffer outputs. LineBuffer
+ * assumes that the indentation has already been written when @ref process()
+ * is called, so this value is only used when a buffer flush requires writing
+ * additional lines of output.
+ */
+ int x;
+ /**
+ * @brief The width of the column to line wrap.
+ */
+ int width;
+ int head; //!< @brief index for next write
+ int tail; //!< @brief index for next read - 1 (i.e. increment tail BEFORE read)
+
+ /**
+ * @brief Multiple methods of LineWrapper may decide to flush part of the buffer to
+ * free up space. The contract of process() says that only 1 line is output. So
+ * this variable is used to track whether something has output a line. It is
+ * reset at the beginning of process() and checked at the end to decide if
+ * output has already occurred or is still needed.
+ */
+ bool wrote_something;
+
+ bool buf_empty()
+ {
+ return ((tail + 1) & bufmask) == head;
+ }
+
+ bool buf_full()
+ {
+ return tail == head;
+ }
+
+ void buf_store(const char* data, int len)
+ {
+ lenbuf[head] = len;
+ datbuf[head] = data;
+ head = (head + 1) & bufmask;
+ }
+
+ //! @brief Call BEFORE reading ...buf[tail].
+ void buf_next()
+ {
+ tail = (tail + 1) & bufmask;
+ }
+
+ /**
+ * @brief Writes (data,len) into the ring buffer. If the buffer is full, a single line
+ * is flushed out of the buffer into @c write.
+ */
+ void output(IStringWriter& write, const char* data, int len)
+ {
+ if (buf_full())
+ write_one_line(write);
+
+ buf_store(data, len);
+ }
+
+ /**
+ * @brief Writes a single line of output from the buffer to @c write.
+ */
+ void write_one_line(IStringWriter& write)
+ {
+ if (wrote_something) // if we already wrote something, we need to start a new line
+ {
+ write("\n", 1);
+ int _ = 0;
+ indent(write, _, x);
+ }
+
+ if (!buf_empty())
+ {
+ buf_next();
+ write(datbuf[tail], lenbuf[tail]);
+ }
+
+ wrote_something = true;
+ }
+ public:
+
+ /**
+ * @brief Writes out all remaining data from the LineWrapper using @c write.
+ * Unlike @ref process() this method indents all lines including the first and
+ * will output a \\n at the end (but only if something has been written).
+ */
+ void flush(IStringWriter& write)
+ {
+ if (buf_empty())
+ return;
+ int _ = 0;
+ indent(write, _, x);
+ wrote_something = false;
+ while (!buf_empty())
+ write_one_line(write);
+ write("\n", 1);
+ }
+
+ /**
+ * @brief Process, wrap and output the next piece of data.
+ *
+ * process() will output at least one line of output. This is not necessarily
+ * the @c data passed in. It may be data queued from a prior call to process().
+ * If the internal buffer is full, more than 1 line will be output.
+ *
+ * process() assumes that the a proper amount of indentation has already been
+ * output. It won't write any further indentation before the 1st line. If
+ * more than 1 line is written due to buffer constraints, the lines following
+ * the first will be indented by this method, though.
+ *
+ * No \\n is written by this method after the last line that is written.
+ *
+ * @param write where to write the data.
+ * @param data the new chunk of data to write.
+ * @param len the length of the chunk of data to write.
+ */
+ void process(IStringWriter& write, const char* data, int len)
+ {
+ wrote_something = false;
+
+ while (len > 0)
+ {
+ if (len <= width) // quick test that works because utf8width <= len (all wide chars have at least 2 bytes)
+ {
+ output(write, data, len);
+ len = 0;
+ }
+ else // if (len > width) it's possible (but not guaranteed) that utf8len > width
+ {
+ int utf8width = 0;
+ int maxi = 0;
+ while (maxi < len && utf8width < width)
+ {
+ int charbytes = 1;
+ unsigned ch = (unsigned char) data[maxi];
+ if (ch > 0xC1) // everything <= 0xC1 (yes, even 0xC1 itself) is not a valid UTF-8 start byte
+ {
+ // int __builtin_clz (unsigned int x)
+ // Returns the number of leading 0-bits in x, starting at the most significant bit
+ unsigned mask = (unsigned) -1 >> __builtin_clz(ch ^ 0xff);
+ ch = ch & mask; // mask out length bits, we don't verify their correctness
+ while ((maxi + charbytes < len) && //
+ (((unsigned char) data[maxi + charbytes] ^ 0x80) <= 0x3F)) // while next byte is continuation byte
+ {
+ ch = (ch << 6) ^ (unsigned char) data[maxi + charbytes] ^ 0x80; // add continuation to char code
+ ++charbytes;
+ }
+ // ch is the decoded unicode code point
+ if (ch >= 0x1100 && isWideChar(ch)) // the test for 0x1100 is here to avoid the function call in the Latin case
+ {
+ if (utf8width + 2 > width)
+ break;
+ ++utf8width;
+ }
+ }
+ ++utf8width;
+ maxi += charbytes;
+ }
+
+ // data[maxi-1] is the last byte of the UTF-8 sequence of the last character that fits
+ // onto the 1st line. If maxi == len, all characters fit on the line.
+
+ if (maxi == len)
+ {
+ output(write, data, len);
+ len = 0;
+ }
+ else // if (maxi < len) at least 1 character (data[maxi] that is) doesn't fit on the line
+ {
+ int i;
+ for (i = maxi; i >= 0; --i)
+ if (data[i] == ' ')
+ break;
+
+ if (i >= 0)
+ {
+ output(write, data, i);
+ data += i + 1;
+ len -= i + 1;
+ }
+ else // did not find a space to split at => split before data[maxi]
+ { // data[maxi] is always the beginning of a character, never a continuation byte
+ output(write, data, maxi);
+ data += maxi;
+ len -= maxi;
+ }
+ }
+ }
+ }
+ if (!wrote_something) // if we didn't already write something to make space in the buffer
+ write_one_line(write); // write at most one line of actual output
+ }
+
+ /**
+ * @brief Constructs a LineWrapper that wraps its output to fit into
+ * screen columns @c x1 (incl.) to @c x2 (excl.).
+ *
+ * @c x1 gives the indentation LineWrapper uses if it needs to indent.
+ */
+ LineWrapper(int x1, int x2) :
+ x(x1), width(x2 - x1), head(0), tail(bufmask)
+ {
+ if (width < 2) // because of wide characters we need at least width 2 or the code breaks
+ width = 2;
+ }
+ };
+
+ /**
+ * @internal
+ * @brief This is the implementation that is shared between all printUsage() templates.
+ * Because all printUsage() templates share this implementation, there is no template bloat.
+ */
+ static void printUsage(IStringWriter& write, const Descriptor usage[], int width = 80, //
+ int last_column_min_percent = 50, int last_column_own_line_max_percent = 75)
+ {
+ if (width < 1) // protect against nonsense values
+ width = 80;
+
+ if (width > 10000) // protect against overflow in the following computation
+ width = 10000;
+
+ int last_column_min_width = ((width * last_column_min_percent) + 50) / 100;
+ int last_column_own_line_max_width = ((width * last_column_own_line_max_percent) + 50) / 100;
+ if (last_column_own_line_max_width == 0)
+ last_column_own_line_max_width = 1;
+
+ LinePartIterator part(usage);
+ while (part.nextTable())
+ {
+
+ /***************** Determine column widths *******************************/
+
+ const int maxcolumns = 8; // 8 columns are enough for everyone
+ int col_width[maxcolumns];
+ int lastcolumn;
+ int leftwidth;
+ int overlong_column_threshold = 10000;
+ do
+ {
+ lastcolumn = 0;
+ for (int i = 0; i < maxcolumns; ++i)
+ col_width[i] = 0;
+
+ part.restartTable();
+ while (part.nextRow())
+ {
+ while (part.next())
+ {
+ if (part.column() < maxcolumns)
+ {
+ upmax(lastcolumn, part.column());
+ if (part.screenLength() < overlong_column_threshold)
+ // We don't let rows that don't use table separators (\t or \v) influence
+ // the width of column 0. This allows the user to interject section headers
+ // or explanatory paragraphs that do not participate in the table layout.
+ if (part.column() > 0 || part.line() > 0 || part.data()[part.length()] == '\t'
+ || part.data()[part.length()] == '\v')
+ upmax(col_width[part.column()], part.screenLength());
+ }
+ }
+ }
+
+ /*
+ * If the last column doesn't fit on the same
+ * line as the other columns, we can fix that by starting it on its own line.
+ * However we can't do this for any of the columns 0..lastcolumn-1.
+ * If their sum exceeds the maximum width we try to fix this by iteratively
+ * ignoring the widest line parts in the width determination until
+ * we arrive at a series of column widths that fit into one line.
+ * The result is a layout where everything is nicely formatted
+ * except for a few overlong fragments.
+ * */
+
+ leftwidth = 0;
+ overlong_column_threshold = 0;
+ for (int i = 0; i < lastcolumn; ++i)
+ {
+ leftwidth += col_width[i];
+ upmax(overlong_column_threshold, col_width[i]);
+ }
+
+ } while (leftwidth > width);
+
+ /**************** Determine tab stops and last column handling **********************/
+
+ int tabstop[maxcolumns];
+ tabstop[0] = 0;
+ for (int i = 1; i < maxcolumns; ++i)
+ tabstop[i] = tabstop[i - 1] + col_width[i - 1];
+
+ int rightwidth = width - tabstop[lastcolumn];
+ bool print_last_column_on_own_line = false;
+ if (rightwidth < last_column_min_width && rightwidth < col_width[lastcolumn])
+ {
+ print_last_column_on_own_line = true;
+ rightwidth = last_column_own_line_max_width;
+ }
+
+ // If lastcolumn == 0 we must disable print_last_column_on_own_line because
+ // otherwise 2 copies of the last (and only) column would be output.
+ // Actually this is just defensive programming. It is currently not
+ // possible that lastcolumn==0 and print_last_column_on_own_line==true
+ // at the same time, because lastcolumn==0 => tabstop[lastcolumn] == 0 =>
+ // rightwidth==width => rightwidth>=last_column_min_width (unless someone passes
+ // a bullshit value >100 for last_column_min_percent) => the above if condition
+ // is false => print_last_column_on_own_line==false
+ if (lastcolumn == 0)
+ print_last_column_on_own_line = false;
+
+ LineWrapper lastColumnLineWrapper(width - rightwidth, width);
+ LineWrapper interjectionLineWrapper(0, width);
+
+ part.restartTable();
+
+ /***************** Print out all rows of the table *************************************/
+
+ while (part.nextRow())
+ {
+ int x = -1;
+ while (part.next())
+ {
+ if (part.column() > lastcolumn)
+ continue; // drop excess columns (can happen if lastcolumn == maxcolumns-1)
+
+ if (part.column() == 0)
+ {
+ if (x >= 0)
+ write("\n", 1);
+ x = 0;
+ }
+
+ indent(write, x, tabstop[part.column()]);
+
+ if ((part.column() < lastcolumn)
+ && (part.column() > 0 || part.line() > 0 || part.data()[part.length()] == '\t'
+ || part.data()[part.length()] == '\v'))
+ {
+ write(part.data(), part.length());
+ x += part.screenLength();
+ }
+ else // either part.column() == lastcolumn or we are in the special case of
+ // an interjection that doesn't contain \v or \t
+ {
+ // NOTE: This code block is not necessarily executed for
+ // each line, because some rows may have fewer columns.
+
+ LineWrapper& lineWrapper = (part.column() == 0) ? interjectionLineWrapper : lastColumnLineWrapper;
+
+ if (!print_last_column_on_own_line)
+ lineWrapper.process(write, part.data(), part.length());
+ }
+ } // while
+
+ if (print_last_column_on_own_line)
+ {
+ part.restartRow();
+ while (part.next())
+ {
+ if (part.column() == lastcolumn)
+ {
+ write("\n", 1);
+ int _ = 0;
+ indent(write, _, width - rightwidth);
+ lastColumnLineWrapper.process(write, part.data(), part.length());
+ }
+ }
+ }
+
+ write("\n", 1);
+ lastColumnLineWrapper.flush(write);
+ interjectionLineWrapper.flush(write);
+ }
+ }
+ }
+
+}
+;
+
+/**
+ * @brief Outputs a nicely formatted usage string with support for multi-column formatting
+ * and line-wrapping.
+ *
+ * printUsage() takes the @c help texts of a Descriptor[] array and formats them into
+ * a usage message, wrapping lines to achieve the desired output width.
+ *
+ * <b>Table formatting:</b>
+ *
+ * Aside from plain strings which are simply line-wrapped, the usage may contain tables. Tables
+ * are used to align elements in the output.
+ *
+ * @code
+ * // Without a table. The explanatory texts are not aligned.
+ * -c, --create |Creates something.
+ * -k, --kill |Destroys something.
+ *
+ * // With table formatting. The explanatory texts are aligned.
+ * -c, --create |Creates something.
+ * -k, --kill |Destroys something.
+ * @endcode
+ *
+ * Table formatting removes the need to pad help texts manually with spaces to achieve
+ * alignment. To create a table, simply insert \\t (tab) characters to separate the cells
+ * within a row.
+ *
+ * @code
+ * const option::Descriptor usage[] = {
+ * {..., "-c, --create \tCreates something." },
+ * {..., "-k, --kill \tDestroys something." }, ...
+ * @endcode
+ *
+ * Note that you must include the minimum amount of space desired between cells yourself.
+ * Table formatting will insert further spaces as needed to achieve alignment.
+ *
+ * You can insert line breaks within cells by using \\v (vertical tab).
+ *
+ * @code
+ * const option::Descriptor usage[] = {
+ * {..., "-c,\v--create \tCreates\vsomething." },
+ * {..., "-k,\v--kill \tDestroys\vsomething." }, ...
+ *
+ * // results in
+ *
+ * -c, Creates
+ * --create something.
+ * -k, Destroys
+ * --kill something.
+ * @endcode
+ *
+ * You can mix lines that do not use \\t or \\v with those that do. The plain
+ * lines will not mess up the table layout. Alignment of the table columns will
+ * be maintained even across these interjections.
+ *
+ * @code
+ * const option::Descriptor usage[] = {
+ * {..., "-c, --create \tCreates something." },
+ * {..., "----------------------------------" },
+ * {..., "-k, --kill \tDestroys something." }, ...
+ *
+ * // results in
+ *
+ * -c, --create Creates something.
+ * ----------------------------------
+ * -k, --kill Destroys something.
+ * @endcode
+ *
+ * You can have multiple tables within the same usage whose columns are
+ * aligned independently. Simply insert a dummy Descriptor with @c help==0.
+ *
+ * @code
+ * const option::Descriptor usage[] = {
+ * {..., "Long options:" },
+ * {..., "--very-long-option \tDoes something long." },
+ * {..., "--ultra-super-mega-long-option \tTakes forever to complete." },
+ * {..., 0 }, // ---------- table break -----------
+ * {..., "Short options:" },
+ * {..., "-s \tShort." },
+ * {..., "-q \tQuick." }, ...
+ *
+ * // results in
+ *
+ * Long options:
+ * --very-long-option Does something long.
+ * --ultra-super-mega-long-option Takes forever to complete.
+ * Short options:
+ * -s Short.
+ * -q Quick.
+ *
+ * // Without the table break it would be
+ *
+ * Long options:
+ * --very-long-option Does something long.
+ * --ultra-super-mega-long-option Takes forever to complete.
+ * Short options:
+ * -s Short.
+ * -q Quick.
+ * @endcode
+ *
+ * <b>Output methods:</b>
+ *
+ * Because TheLeanMeanC++Option parser is freestanding, you have to provide the means for
+ * output in the first argument(s) to printUsage(). Because printUsage() is implemented as
+ * a set of template functions, you have great flexibility in your choice of output
+ * method. The following example demonstrates typical uses. Anything that's similar enough
+ * will work.
+ *
+ * @code
+ * #include <unistd.h> // write()
+ * #include <iostream> // cout
+ * #include <sstream> // ostringstream
+ * #include <cstdio> // fwrite()
+ * using namespace std;
+ *
+ * void my_write(const char* str, int size) {
+ * fwrite(str, size, 1, stdout);
+ * }
+ *
+ * struct MyWriter {
+ * void write(const char* buf, size_t size) const {
+ * fwrite(str, size, 1, stdout);
+ * }
+ * };
+ *
+ * struct MyWriteFunctor {
+ * void operator()(const char* buf, size_t size) {
+ * fwrite(str, size, 1, stdout);
+ * }
+ * };
+ * ...
+ * printUsage(my_write, usage); // custom write function
+ * printUsage(MyWriter(), usage); // temporary of a custom class
+ * MyWriter writer;
+ * printUsage(writer, usage); // custom class object
+ * MyWriteFunctor wfunctor;
+ * printUsage(&wfunctor, usage); // custom functor
+ * printUsage(write, 1, usage); // write() to file descriptor 1
+ * printUsage(cout, usage); // an ostream&
+ * printUsage(fwrite, stdout, usage); // fwrite() to stdout
+ * ostringstream sstr;
+ * printUsage(sstr, usage); // an ostringstream&
+ *
+ * @endcode
+ *
+ * @par Notes:
+ * @li the @c write() method of a class that is to be passed as a temporary
+ * as @c MyWriter() is in the example, must be a @c const method, because
+ * temporary objects are passed as const reference. This only applies to
+ * temporary objects that are created and destroyed in the same statement.
+ * If you create an object like @c writer in the example, this restriction
+ * does not apply.
+ * @li a functor like @c MyWriteFunctor in the example must be passed as a pointer.
+ * This differs from the way functors are passed to e.g. the STL algorithms.
+ * @li All printUsage() templates are tiny wrappers around a shared non-template implementation.
+ * So there's no penalty for using different versions in the same program.
+ * @li printUsage() always interprets Descriptor::help as UTF-8 and always produces UTF-8-encoded
+ * output. If your system uses a different charset, you must do your own conversion. You
+ * may also need to change the font of the console to see non-ASCII characters properly.
+ * This is particularly true for Windows.
+ * @li @b Security @b warning: Do not insert untrusted strings (such as user-supplied arguments)
+ * into the usage. printUsage() has no protection against malicious UTF-8 sequences.
+ *
+ * @param prn The output method to use. See the examples above.
+ * @param usage the Descriptor[] array whose @c help texts will be formatted.
+ * @param width the maximum number of characters per output line. Note that this number is
+ * in actual characters, not bytes. printUsage() supports UTF-8 in @c help and will
+ * count multi-byte UTF-8 sequences properly. Asian wide characters are counted
+ * as 2 characters.
+ * @param last_column_min_percent (0-100) The minimum percentage of @c width that should be available
+ * for the last column (which typically contains the textual explanation of an option).
+ * If less space is available, the last column will be printed on its own line, indented
+ * according to @c last_column_own_line_max_percent.
+ * @param last_column_own_line_max_percent (0-100) If the last column is printed on its own line due to
+ * less than @c last_column_min_percent of the width being available, then only
+ * @c last_column_own_line_max_percent of the extra line(s) will be used for the
+ * last column's text. This ensures an indentation. See example below.
+ *
+ * @code
+ * // width=20, last_column_min_percent=50 (i.e. last col. min. width=10)
+ * --3456789 1234567890
+ * 1234567890
+ *
+ * // width=20, last_column_min_percent=75 (i.e. last col. min. width=15)
+ * // last_column_own_line_max_percent=75
+ * --3456789
+ * 123456789012345
+ * 67890
+ *
+ * // width=20, last_column_min_percent=75 (i.e. last col. min. width=15)
+ * // last_column_own_line_max_percent=33 (i.e. max. 5)
+ * --3456789
+ * 12345
+ * 67890
+ * 12345
+ * 67890
+ * @endcode
+ */
+template<typename OStream>
+void printUsage(OStream& prn, const Descriptor usage[], int width = 80, int last_column_min_percent = 50,
+ int last_column_own_line_max_percent = 75)
+{
+ PrintUsageImplementation::OStreamWriter<OStream> write(prn);
+ PrintUsageImplementation::printUsage(write, usage, width, last_column_min_percent, last_column_own_line_max_percent);
+}
+
+template<typename Function>
+void printUsage(Function* prn, const Descriptor usage[], int width = 80, int last_column_min_percent = 50,
+ int last_column_own_line_max_percent = 75)
+{
+ PrintUsageImplementation::FunctionWriter<Function> write(prn);
+ PrintUsageImplementation::printUsage(write, usage, width, last_column_min_percent, last_column_own_line_max_percent);
+}
+
+template<typename Temporary>
+void printUsage(const Temporary& prn, const Descriptor usage[], int width = 80, int last_column_min_percent = 50,
+ int last_column_own_line_max_percent = 75)
+{
+ PrintUsageImplementation::TemporaryWriter<Temporary> write(prn);
+ PrintUsageImplementation::printUsage(write, usage, width, last_column_min_percent, last_column_own_line_max_percent);
+}
+
+template<typename Syscall>
+void printUsage(Syscall* prn, int fd, const Descriptor usage[], int width = 80, int last_column_min_percent = 50,
+ int last_column_own_line_max_percent = 75)
+{
+ PrintUsageImplementation::SyscallWriter<Syscall> write(prn, fd);
+ PrintUsageImplementation::printUsage(write, usage, width, last_column_min_percent, last_column_own_line_max_percent);
+}
+
+template<typename Function, typename Stream>
+void printUsage(Function* prn, Stream* stream, const Descriptor usage[], int width = 80, int last_column_min_percent =
+ 50,
+ int last_column_own_line_max_percent = 75)
+{
+ PrintUsageImplementation::StreamWriter<Function, Stream> write(prn, stream);
+ PrintUsageImplementation::printUsage(write, usage, width, last_column_min_percent, last_column_own_line_max_percent);
+}
+
+}
+// namespace option
+
+#ifdef _MSC_VER
+#pragma warning(pop)
+#endif
+
+#endif /* OPTIONPARSER_H_ */
diff --git a/vendor/bandit/bandit/failure_formatters/default_failure_formatter.h b/vendor/bandit/bandit/failure_formatters/default_failure_formatter.h
new file mode 100644
index 00000000..48cc9021
--- /dev/null
+++ b/vendor/bandit/bandit/failure_formatters/default_failure_formatter.h
@@ -0,0 +1,30 @@
+#ifndef BANDIT_DEFAULT_FAILURE_FORMATTER_H
+#define BANDIT_DEFAULT_FAILURE_FORMATTER_H
+
+namespace bandit { namespace detail {
+
+ struct default_failure_formatter : public failure_formatter
+ {
+ std::string format(const assertion_exception& err) const
+ {
+ std::stringstream ss;
+ if(err.file_name().size())
+ {
+ ss << err.file_name();
+
+ if(err.line_number())
+ {
+ ss << ":" << err.line_number();
+ }
+
+ ss << ": ";
+ }
+
+ ss << err.what();
+
+ return ss.str();
+ }
+ };
+}}
+
+#endif
diff --git a/vendor/bandit/bandit/failure_formatters/failure_formatter.h b/vendor/bandit/bandit/failure_formatters/failure_formatter.h
new file mode 100644
index 00000000..486624f0
--- /dev/null
+++ b/vendor/bandit/bandit/failure_formatters/failure_formatter.h
@@ -0,0 +1,13 @@
+#ifndef BANDIT_FAILURE_FORMATTER_H
+#define BANDIT_FAILURE_FORMATTER_H
+
+namespace bandit { namespace detail {
+
+ struct failure_formatter
+ {
+ virtual std::string format(const assertion_exception&) const = 0;
+ };
+ typedef std::unique_ptr<failure_formatter> failure_formatter_ptr;
+}}
+
+#endif
diff --git a/vendor/bandit/bandit/failure_formatters/failure_formatters.h b/vendor/bandit/bandit/failure_formatters/failure_formatters.h
new file mode 100644
index 00000000..d0914651
--- /dev/null
+++ b/vendor/bandit/bandit/failure_formatters/failure_formatters.h
@@ -0,0 +1,16 @@
+#ifndef BANDIT_FAILURE_FORMATTERS
+#define BANDIT_FAILURE_FORMATTERS
+
+#include "failure_formatter.h"
+#include "default_failure_formatter.h"
+#include "visual_studio_failure_formatter.h"
+
+namespace bandit { namespace detail {
+ inline failure_formatter& registered_failure_formatter()
+ {
+ static default_failure_formatter formatter;
+ return formatter;
+ }
+}}
+
+#endif
diff --git a/vendor/bandit/bandit/failure_formatters/visual_studio_failure_formatter.h b/vendor/bandit/bandit/failure_formatters/visual_studio_failure_formatter.h
new file mode 100644
index 00000000..6ff3fdeb
--- /dev/null
+++ b/vendor/bandit/bandit/failure_formatters/visual_studio_failure_formatter.h
@@ -0,0 +1,36 @@
+#ifndef BANDIT_VISUAL_STUDIO_FAILURE_FORMATTER_H
+#define BANDIT_VISUAL_STUDIO_FAILURE_FORMATTER_H
+
+namespace bandit { namespace detail {
+
+ struct visual_studio_failure_formatter : public failure_formatter
+ {
+ std::string format(const assertion_exception& err) const
+ {
+ std::stringstream ss;
+ if(err.file_name().size())
+ {
+ ss << err.file_name();
+
+ if(err.line_number())
+ {
+ ss << "(" << err.line_number() << ")";
+ }
+
+ ss << ": ";
+ }
+ else
+ {
+ ss << "bandit: ";
+ }
+
+ ss << err.what();
+
+ return ss.str();
+
+ }
+ };
+
+}}
+
+#endif
diff --git a/vendor/bandit/bandit/grammar.h b/vendor/bandit/bandit/grammar.h
new file mode 100644
index 00000000..1f973344
--- /dev/null
+++ b/vendor/bandit/bandit/grammar.h
@@ -0,0 +1,185 @@
+#ifndef BANDIT_GRAMMAR_H
+#define BANDIT_GRAMMAR_H
+
+namespace bandit {
+
+ inline void describe(const char* desc, detail::voidfunc_t func,
+ detail::listener& listener, detail::contextstack_t& context_stack,
+ bool hard_skip = false)
+ {
+ listener.context_starting(desc);
+
+ context_stack.back()->execution_is_starting();
+
+ detail::bandit_context ctxt(desc, hard_skip);
+
+ context_stack.push_back(&ctxt);
+ try
+ {
+ func();
+ }
+ catch(const bandit::detail::test_run_error& error)
+ {
+ listener.test_run_error(desc, error);
+ }
+
+ context_stack.pop_back();
+
+ listener.context_ended(desc);
+ }
+
+ inline void describe(const char* desc, detail::voidfunc_t func)
+ {
+ describe(desc, func, detail::registered_listener(), detail::context_stack());
+ }
+
+ inline void describe_skip(const char* desc, detail::voidfunc_t func,
+ detail::listener& listener, detail::contextstack_t& context_stack)
+ {
+ bool skip = true;
+ describe(desc, func, listener, context_stack, skip);
+ }
+
+ inline void describe_skip(const char* desc, detail::voidfunc_t func)
+ {
+ describe_skip(desc, func, detail::registered_listener(),
+ detail::context_stack());
+ }
+
+ inline void xdescribe(const char* desc, detail::voidfunc_t func,
+ detail::listener& listener=detail::registered_listener(),
+ detail::contextstack_t& context_stack=detail::context_stack())
+ {
+ describe_skip(desc, func, listener, context_stack);
+ }
+
+ inline void before_each(detail::voidfunc_t func,
+ detail::contextstack_t& context_stack)
+ {
+ context_stack.back()->register_before_each(func);
+ }
+
+ inline void before_each(detail::voidfunc_t func)
+ {
+ before_each(func, detail::context_stack());
+ }
+
+ inline void after_each(detail::voidfunc_t func,
+ detail::contextstack_t& context_stack)
+ {
+ context_stack.back()->register_after_each(func);
+ }
+
+ inline void after_each(detail::voidfunc_t func)
+ {
+ after_each(func, detail::context_stack());
+ }
+
+ inline void it_skip(const char* desc, detail::voidfunc_t, detail::listener& listener)
+ {
+ listener.it_skip(desc);
+ }
+
+ inline void it_skip(const char* desc, detail::voidfunc_t func)
+ {
+ it_skip(desc, func, detail::registered_listener());
+ }
+
+ inline void xit(const char* desc, detail::voidfunc_t func, detail::listener& listener=detail::registered_listener())
+ {
+ it_skip(desc, func, listener);
+ }
+
+ inline void it(const char* desc, detail::voidfunc_t func, detail::listener& listener,
+ detail::contextstack_t& context_stack,
+ bandit::adapters::assertion_adapter& assertion_adapter,
+ detail::run_policy& run_policy)
+ {
+ if(!run_policy.should_run(desc, context_stack))
+ {
+ it_skip(desc, func, listener);
+ return;
+ }
+
+ listener.it_starting(desc);
+
+ context_stack.back()->execution_is_starting();
+
+ auto run_before_eaches = [&](){
+ for_each(context_stack.begin(), context_stack.end(), [](detail::context* ctxt){
+ ctxt->run_before_eaches();
+ });
+ };
+
+ auto run_after_eaches = [&](){
+ for_each(context_stack.begin(), context_stack.end(), [](detail::context* ctxt){
+ ctxt->run_after_eaches();
+ });
+ };
+
+ bool we_have_been_successful_so_far = false;
+ try
+ {
+ assertion_adapter.adapt_exceptions([&](){
+ run_before_eaches();
+
+ func();
+ we_have_been_successful_so_far = true;
+ });
+ }
+ catch(const bandit::detail::assertion_exception& ex)
+ {
+ listener.it_failed(desc, ex);
+ run_policy.encountered_failure();
+ }
+ catch(const std::exception& ex)
+ {
+ std::string err = std::string("exception: ") + ex.what();
+ listener.it_failed(desc, bandit::detail::assertion_exception(err));
+ run_policy.encountered_failure();
+ }
+ catch(...)
+ {
+ listener.it_unknown_error(desc);
+ run_policy.encountered_failure();
+ }
+
+ try
+ {
+ assertion_adapter.adapt_exceptions([&](){
+ run_after_eaches();
+
+ if(we_have_been_successful_so_far)
+ {
+ listener.it_succeeded(desc);
+ }
+ });
+ }
+ catch(const bandit::detail::assertion_exception& ex)
+ {
+ listener.it_failed(desc, ex);
+ run_policy.encountered_failure();
+ }
+ catch(const std::exception& ex)
+ {
+ std::string err = std::string("exception: ") + ex.what();
+ listener.it_failed(desc, bandit::detail::assertion_exception(err));
+ run_policy.encountered_failure();
+ }
+ catch(...)
+ {
+ listener.it_unknown_error(desc);
+ run_policy.encountered_failure();
+ }
+ }
+
+ inline void it(const char* desc, detail::voidfunc_t func)
+ {
+ it(desc, func, detail::registered_listener(), detail::context_stack(),
+ detail::registered_adapter(), detail::registered_run_policy());
+ }
+
+
+}
+
+#endif
diff --git a/vendor/bandit/bandit/listener.h b/vendor/bandit/bandit/listener.h
new file mode 100644
index 00000000..07501fcf
--- /dev/null
+++ b/vendor/bandit/bandit/listener.h
@@ -0,0 +1,27 @@
+#ifndef BANDIT_LISTENER_H
+#define BANDIT_LISTENER_H
+
+namespace bandit { namespace detail {
+ struct listener
+ {
+ virtual ~listener() {}
+
+ virtual void test_run_starting() = 0;
+ virtual void test_run_complete() = 0;
+
+ virtual void context_starting(const char* desc) = 0;
+ virtual void context_ended(const char* desc) = 0;
+ virtual void test_run_error(const char* desc, const test_run_error& error) = 0;
+
+ virtual void it_starting(const char* desc) = 0;
+ virtual void it_succeeded(const char* desc) = 0;
+ virtual void it_failed(const char* desc, const detail::assertion_exception& ex) = 0;
+ virtual void it_unknown_error(const char* desc) = 0;
+ virtual void it_skip(const char* desc) = 0;
+
+ virtual bool did_we_pass() const = 0;
+ };
+ typedef std::unique_ptr<listener> listener_ptr;
+}}
+
+#endif
diff --git a/vendor/bandit/bandit/options.h b/vendor/bandit/bandit/options.h
new file mode 100644
index 00000000..493512cf
--- /dev/null
+++ b/vendor/bandit/bandit/options.h
@@ -0,0 +1,111 @@
+#ifndef BANDIT_OPTIONS_H
+#define BANDIT_OPTIONS_H
+
+namespace bandit { namespace detail {
+
+ // TODO: print any unknown options
+ // TODO: check for parser errors
+ struct options
+ {
+
+ options(int argc, char* argv[])
+ {
+ argc -= (argc>0); argv += (argc>0); // Skip program name (argv[0]) if present
+ option::Stats stats(usage(), argc, argv);
+ options_.resize(stats.options_max);
+ std::vector<option::Option> buffer(stats.buffer_max);
+ option::Parser parse(usage(), argc, argv, options_.data(), buffer.data());
+ parsed_ok_ = !parse.error();
+ }
+
+ bool help() const
+ {
+ return options_[HELP] != NULL;
+ }
+
+ void print_usage() const
+ {
+ option::printUsage(std::cout, usage());
+ }
+
+ bool version() const
+ {
+ return options_[VERSION] != NULL;
+ }
+
+ const char* reporter() const
+ {
+ return options_[REPORTER].arg;
+ }
+
+ bool no_color() const
+ {
+ return options_[NO_COLOR] != NULL;
+ }
+
+ typedef enum
+ {
+ FORMATTER_DEFAULT,
+ FORMATTER_VS,
+ FORMATTER_UNKNOWN
+ } formatters;
+
+ formatters formatter() const
+ {
+ std::string arg = options_[FORMATTER].arg ? options_[FORMATTER].arg : "";
+ if(arg == "vs")
+ {
+ return formatters::FORMATTER_VS;
+ }
+
+ return formatters::FORMATTER_DEFAULT;
+ }
+
+ const char* skip() const
+ {
+ return options_[SKIP].arg ? options_[SKIP].arg : "";
+ }
+
+ const char* only() const
+ {
+ return options_[ONLY].arg ? options_[ONLY].arg : "";
+ }
+
+ bool break_on_failure() const
+ {
+ return options_[BREAK_ON_FAILURE] != NULL;
+ }
+
+ private:
+ enum option_index { UNKNOWN, VERSION, HELP, REPORTER, NO_COLOR,
+ FORMATTER, SKIP, ONLY, BREAK_ON_FAILURE };
+
+ static const option::Descriptor* usage()
+ {
+ static const option::Descriptor usage[] =
+ {
+ {UNKNOWN, 0, "", "", option::Arg::None, "USAGE: <executable> [options]\n\n"
+ "Options:" },
+ {VERSION, 0, "", "version", option::Arg::None, " --version, \tPrint version of bandit"},
+ {HELP, 0, "", "help", option::Arg::None, " --help, \tPrint usage and exit."},
+ {REPORTER, 0, "", "reporter", option::Arg::Optional, " --reporter=<reporter>, \tSelect reporter (dots, singleline, xunit, info, spec)"},
+ {NO_COLOR, 0, "", "no-color", option::Arg::None, " --no-color, \tSuppress colors in output"},
+ {FORMATTER, 0, "", "formatter", option::Arg::Optional, " --formatter=<formatter>, \tSelect formatting of errors (default, vs)"},
+ {SKIP, 0, "", "skip", option::Arg::Optional, " --skip=<substring>, \tskip all 'describe' and 'it' containing substring"},
+ {ONLY, 0, "", "only", option::Arg::Optional, " --only=<substring>, \tonly run 'describe' and 'it' containing substring"},
+ {BREAK_ON_FAILURE, 0, "", "break-on-failure", option::Arg::Optional, " --break-on-failure, \tstop test run on first failing test"},
+ {0, 0, 0, 0, 0, 0}
+ };
+
+ return usage;
+ }
+
+ private:
+ std::vector<option::Option> options_;
+ bool parsed_ok_;
+
+ };
+
+}}
+
+#endif
diff --git a/vendor/bandit/bandit/registration/registrar.h b/vendor/bandit/bandit/registration/registrar.h
new file mode 100644
index 00000000..d57a1f46
--- /dev/null
+++ b/vendor/bandit/bandit/registration/registrar.h
@@ -0,0 +1,25 @@
+#ifndef BANDIT_REGISTRAR_H
+#define BANDIT_REGISTRAR_H
+
+namespace bandit { namespace detail {
+
+ struct spec_registrar
+ {
+ spec_registrar( bandit::detail::voidfunc_t func)
+ {
+ bandit::detail::specs().push_back(func);
+ }
+ };
+
+}}
+
+#define go_bandit \
+ static bandit::detail::spec_registrar bandit_registrar
+
+#define SPEC_BEGIN(name) \
+go_bandit([]{
+
+#define SPEC_END \
+});
+
+#endif
diff --git a/vendor/bandit/bandit/registration/registration.h b/vendor/bandit/bandit/registration/registration.h
new file mode 100644
index 00000000..ad3f8b06
--- /dev/null
+++ b/vendor/bandit/bandit/registration/registration.h
@@ -0,0 +1,7 @@
+#ifndef BANDIT_REGISTRATION_H
+#define BANDIT_REGISTRATION_H
+
+#include <bandit/registration/spec_registry.h>
+#include <bandit/registration/registrar.h>
+
+#endif
diff --git a/vendor/bandit/bandit/registration/spec_registry.h b/vendor/bandit/bandit/registration/spec_registry.h
new file mode 100644
index 00000000..50c35402
--- /dev/null
+++ b/vendor/bandit/bandit/registration/spec_registry.h
@@ -0,0 +1,17 @@
+#ifndef BANDIT_SPEC_REGISTRY_H
+#define BANDIT_SPEC_REGISTRY_H
+
+namespace bandit {
+ namespace detail {
+ typedef std::list<voidfunc_t> spec_registry;
+
+ inline detail::spec_registry& specs()
+ {
+ static detail::spec_registry registry;
+ return registry;
+ }
+ }
+
+}
+
+#endif
diff --git a/vendor/bandit/bandit/reporters/colorizer.h b/vendor/bandit/bandit/reporters/colorizer.h
new file mode 100644
index 00000000..e8979eec
--- /dev/null
+++ b/vendor/bandit/bandit/reporters/colorizer.h
@@ -0,0 +1,141 @@
+#ifndef BANDIT_REPORTERS_COLORIZER_H
+#define BANDIT_REPORTERS_COLORIZER_H
+
+#ifdef _WIN32
+ #ifndef NOMINMAX
+ #define NOMINMAX
+ #endif
+
+ #define WIN32_LEAN_AND_MEAN
+ #include <windows.h>
+#endif
+
+namespace bandit { namespace detail {
+
+#ifdef _WIN32
+ struct colorizer
+ {
+ colorizer(bool colors_enabled = true)
+ : colors_enabled_(colors_enabled),
+ stdout_handle_(GetStdHandle(STD_OUTPUT_HANDLE))
+ {
+ original_color_ = get_console_color();
+ }
+
+ const char* green() const
+ {
+ if(colors_enabled_)
+ {
+ set_console_color(FOREGROUND_GREEN);
+ }
+ return "";
+ }
+
+ const char* yellow() const
+ {
+ if(colors_enabled_)
+ {
+ set_console_color(FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_INTENSITY);
+ }
+ return "";
+ }
+
+ const char* blue() const
+ {
+ if(colors_enabled_)
+ {
+ set_console_color(FOREGROUND_BLUE);
+ }
+ return "";
+ }
+
+ const char* red() const
+ {
+ if(colors_enabled_)
+ {
+ set_console_color(FOREGROUND_RED);
+ }
+ return "";
+ }
+
+ const char* white() const
+ {
+ if(colors_enabled_)
+ {
+ set_console_color(FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY);
+ }
+ return "";
+ }
+
+ const char* reset() const
+ {
+ if(colors_enabled_)
+ {
+ set_console_color(original_color_);
+ }
+ return "";
+ }
+
+ private:
+ WORD get_console_color() const
+ {
+ CONSOLE_SCREEN_BUFFER_INFO info{};
+ GetConsoleScreenBufferInfo(stdout_handle_, &info);
+ return info.wAttributes;
+ }
+
+ void set_console_color(WORD color) const
+ {
+ SetConsoleTextAttribute(stdout_handle_, color);
+ }
+
+ private:
+ bool colors_enabled_;
+ HANDLE stdout_handle_;
+ WORD original_color_;
+ };
+
+#else
+ struct colorizer
+ {
+ colorizer(bool colors_enabled = true)
+ : colors_enabled_(colors_enabled)
+ {}
+
+ const char* green() const
+ {
+ return colors_enabled_ ? "\033[1;32m" : "";
+ }
+
+ const char* yellow() const
+ {
+ return colors_enabled_ ? "\033[1;33m" : "";
+ }
+
+ const char* blue() const
+ {
+ return colors_enabled_ ? "\033[1;34m" : "";
+ }
+
+ const char* red() const
+ {
+ return colors_enabled_ ? "\033[1;31m" : "";
+ }
+
+ const char* white() const
+ {
+ return colors_enabled_ ? "\033[1;37m" : "";
+ }
+
+ const char* reset() const
+ {
+ return colors_enabled_ ? "\033[0m" : "";
+ }
+
+ private:
+ bool colors_enabled_;
+ };
+#endif
+}}
+
+#endif
diff --git a/vendor/bandit/bandit/reporters/dots_reporter.h b/vendor/bandit/bandit/reporters/dots_reporter.h
new file mode 100644
index 00000000..3c5083fe
--- /dev/null
+++ b/vendor/bandit/bandit/reporters/dots_reporter.h
@@ -0,0 +1,69 @@
+#ifndef BANDIT_DOTS_REPORTER_H
+#define BANDIT_DOTS_REPORTER_H
+
+namespace bandit { namespace detail {
+
+ struct dots_reporter : public progress_reporter
+ {
+ dots_reporter(std::ostream& stm, const failure_formatter& failure_formatter,
+ const detail::colorizer& colorizer)
+ : progress_reporter(failure_formatter), stm_(stm), colorizer_(colorizer)
+ {}
+
+ dots_reporter(const failure_formatter& failure_formatter, const detail::colorizer& colorizer)
+ : progress_reporter(failure_formatter), stm_(std::cout), colorizer_(colorizer)
+ {}
+
+ dots_reporter& operator=(const dots_reporter&) { return *this; }
+
+ void test_run_complete()
+ {
+ progress_reporter::test_run_complete();
+
+ stm_ << std::endl;
+
+ test_run_summary summary(specs_run_, specs_failed_, specs_succeeded_, specs_skipped_, failures_,
+ test_run_errors_, colorizer_);
+ summary.write(stm_);
+ stm_.flush();
+ }
+
+ void test_run_error(const char* desc, const struct test_run_error& err)
+ {
+ progress_reporter::test_run_error(desc, err);
+
+ std::stringstream ss;
+ ss << std::endl;
+ ss << "Failed to run \"" << current_context_name() << "\": error \"" << err.what() << "\"" << std::endl;
+
+ test_run_errors_.push_back(ss.str());
+ }
+
+ void it_succeeded(const char* desc)
+ {
+ progress_reporter::it_succeeded(desc);
+ stm_ << colorizer_.green() << "." << colorizer_.reset();
+ stm_.flush();
+ }
+
+ void it_failed(const char* desc, const assertion_exception& ex)
+ {
+ progress_reporter::it_failed(desc, ex);
+ stm_ << colorizer_.red() << "F" << colorizer_.reset();
+ stm_.flush();
+ }
+
+ void it_unknown_error(const char* desc)
+ {
+ progress_reporter::it_unknown_error(desc);
+ stm_ << colorizer_.red() << "E" << colorizer_.reset();
+ stm_.flush();
+ }
+
+ private:
+ std::ostream& stm_;
+ const detail::colorizer& colorizer_;
+ };
+}}
+
+#endif
diff --git a/vendor/bandit/bandit/reporters/info_reporter.h b/vendor/bandit/bandit/reporters/info_reporter.h
new file mode 100644
index 00000000..f9b987d0
--- /dev/null
+++ b/vendor/bandit/bandit/reporters/info_reporter.h
@@ -0,0 +1,194 @@
+#ifndef BANDIT_INFO_REPORTER_H
+#define BANDIT_INFO_REPORTER_H
+
+namespace bandit {
+namespace detail {
+
+struct info_reporter : public progress_reporter
+{
+ info_reporter(std::ostream &stm, const failure_formatter &failure_formatter,
+ const detail::colorizer &colorizer)
+ : progress_reporter(failure_formatter)
+ , stm_(stm)
+ , colorizer_(colorizer)
+ , indentation_(0)
+ {}
+
+ info_reporter(const failure_formatter &failure_formatter, const detail::colorizer &colorizer)
+ : progress_reporter(failure_formatter)
+ , stm_(std::cout)
+ , colorizer_(colorizer)
+ , indentation_(0)
+ {}
+
+ info_reporter &operator=(const info_reporter &)
+ {
+ return *this;
+ }
+
+ void summary()
+ {
+ stm_
+ << colorizer_.white()
+ << "Tests run: " << specs_run_
+ << std::endl;
+ if (specs_skipped_ > 0) {
+ stm_
+ << colorizer_.yellow()
+ << "Skipped: " << specs_skipped_
+ << std::endl;
+ }
+ if (specs_succeeded_ > 0) {
+ stm_
+ << colorizer_.green()
+ << "Passed: " << specs_succeeded_
+ << std::endl;
+ }
+ if (specs_failed_ > 0) {
+ stm_
+ << colorizer_.red()
+ << "Failed: " << specs_failed_
+ << std::endl;
+ std::for_each(failures_.begin(), failures_.end(), [&](const std::string &failure) {
+ stm_
+ << colorizer_.white()
+ << " (*) "
+ << colorizer_.red()
+ << failure << std::endl;
+ });
+ }
+ if (test_run_errors_.size() > 0) {
+ stm_
+ << colorizer_.red()
+ << "Errors: " << test_run_errors_.size()
+ << std::endl;
+ std::for_each(test_run_errors_.begin(), test_run_errors_.end(), [&](const std::string &error) {
+ stm_
+ << colorizer_.white()
+ << " (*) "
+ << colorizer_.red()
+ << error << std::endl;
+ });
+ }
+ stm_
+ << colorizer_.reset()
+ << std::endl;
+ }
+
+ void test_run_complete()
+ {
+ progress_reporter::test_run_complete();
+ stm_ << std::endl;
+ summary();
+ stm_.flush();
+ }
+
+ void test_run_error(const char *desc, const struct test_run_error &err)
+ {
+ progress_reporter::test_run_error(desc, err);
+
+ std::stringstream ss;
+ ss << std::endl;
+ ss << "Failed to run \"" << current_context_name() << "\": error \"" << err.what() << "\"" << std::endl;
+
+ test_run_errors_.push_back(ss.str());
+ }
+
+ virtual void context_starting(const char *desc)
+ {
+ progress_reporter::context_starting(desc);
+
+ stm_
+ << indent()
+ << colorizer_.blue()
+ << "begin "
+ << colorizer_.white()
+ << desc
+ << colorizer_.reset()
+ << std::endl;
+ ++indentation_;
+ stm_.flush();
+
+ }
+
+ virtual void context_ended(const char *desc)
+ {
+ progress_reporter::context_ended(desc);
+ --indentation_;
+ stm_
+ << indent()
+ << colorizer_.blue()
+ << "end "
+ << colorizer_.reset()
+ << desc << std::endl;
+ }
+
+ virtual void it_starting(const char *desc)
+ {
+ progress_reporter::it_starting(desc);
+ stm_
+ << indent()
+ << colorizer_.yellow()
+ << "[ TEST ]"
+ << colorizer_.reset()
+ << " it " << desc;
+ ++indentation_;
+ stm_.flush();
+ }
+
+ virtual void it_succeeded(const char *desc)
+ {
+ progress_reporter::it_succeeded(desc);
+ --indentation_;
+ stm_
+ << "\r" << indent()
+ << colorizer_.green()
+ << "[ PASS ]"
+ << colorizer_.reset()
+ << " it " << desc
+ << std::endl;
+ stm_.flush();
+ }
+
+ virtual void it_failed(const char *desc, const assertion_exception &ex)
+ {
+ progress_reporter::it_failed(desc, ex);
+ --indentation_;
+ stm_
+ << "\r" << indent()
+ << colorizer_.red()
+ << "[ FAIL ]"
+ << colorizer_.reset()
+ << " it " << desc
+ << std::endl;
+ stm_.flush();
+ }
+
+ virtual void it_unknown_error(const char *desc)
+ {
+ progress_reporter::it_unknown_error(desc);
+ --indentation_;
+ stm_
+ << "\r" << indent()
+ << colorizer_.red()
+ << "-ERROR->"
+ << colorizer_.reset()
+ << " it " << desc
+ << std::endl;
+ stm_.flush();
+ }
+
+private:
+ std::string indent()
+ {
+ return std::string(2*indentation_, ' ');
+ }
+
+ std::ostream &stm_;
+ const detail::colorizer &colorizer_;
+ int indentation_;
+};
+}
+}
+
+#endif
diff --git a/vendor/bandit/bandit/reporters/progress_reporter.h b/vendor/bandit/bandit/reporters/progress_reporter.h
new file mode 100644
index 00000000..d9dc47bd
--- /dev/null
+++ b/vendor/bandit/bandit/reporters/progress_reporter.h
@@ -0,0 +1,116 @@
+#ifndef BANDIT_PROGRESS_REPORTER_H
+#define BANDIT_PROGRESS_REPORTER_H
+
+namespace bandit { namespace detail {
+
+ struct progress_reporter : public listener
+ {
+ progress_reporter(const detail::failure_formatter& failure_formatter)
+ : specs_run_(0), specs_succeeded_(0), specs_failed_(0), specs_skipped_(0),
+ failure_formatter_(failure_formatter)
+ {}
+
+ progress_reporter& operator=(const progress_reporter&) { return *this; }
+
+ virtual void test_run_starting()
+ {
+ specs_run_ = 0;
+ specs_succeeded_ = 0;
+ specs_failed_ = 0;
+ specs_skipped_ = 0;
+ failures_.clear();
+ contexts_.clear();
+ }
+
+ virtual void test_run_complete()
+ {
+ }
+
+ virtual void context_starting(const char* desc)
+ {
+ contexts_.push_back(std::string(desc));
+ }
+
+ virtual void context_ended(const char*)
+ {
+ contexts_.pop_back();
+ }
+
+ virtual void test_run_error(const char*, const struct test_run_error&)
+ {}
+
+ void it_starting(const char*)
+ {
+ specs_run_++;
+ }
+
+ void it_succeeded(const char*)
+ {
+ specs_succeeded_++;
+ }
+
+ void it_failed(const char* desc, const assertion_exception& ex)
+ {
+ specs_failed_++;
+
+ std::stringstream ss;
+ ss << std::endl;
+ ss << current_context_name() << " " << desc << ":" << std::endl;
+ ss << failure_formatter_.format(ex);
+
+ failures_.push_back(ss.str());
+ }
+
+ void it_unknown_error(const char* desc)
+ {
+ specs_failed_++;
+
+ std::stringstream ss;
+ ss << std::endl;
+ ss << current_context_name() << " " << desc << ":" << std::endl;
+ ss << "Unknown exception";
+ ss << std::endl;
+
+ failures_.push_back(ss.str());
+ }
+
+ void it_skip(const char* /* desc */)
+ {
+ specs_skipped_++;
+ }
+
+ bool did_we_pass() const
+ {
+ return specs_run_ > 0 && specs_failed_ == 0 && test_run_errors_.size() == 0;
+ }
+
+ protected:
+ std::string current_context_name()
+ {
+ std::string name;
+
+ std::for_each(contexts_.begin(), contexts_.end(), [&](const std::string context){
+ if(name.size() > 0)
+ {
+ name += " ";
+ }
+
+ name += context;
+ });
+
+ return name;
+ }
+
+ protected:
+ int specs_run_;
+ int specs_succeeded_;
+ int specs_failed_;
+ int specs_skipped_;
+ const detail::failure_formatter& failure_formatter_;
+ std::list<std::string> contexts_;
+ std::list<std::string> failures_;
+ std::list<std::string> test_run_errors_;
+ };
+}}
+
+#endif
diff --git a/vendor/bandit/bandit/reporters/reporters.h b/vendor/bandit/bandit/reporters/reporters.h
new file mode 100644
index 00000000..12179270
--- /dev/null
+++ b/vendor/bandit/bandit/reporters/reporters.h
@@ -0,0 +1,29 @@
+#ifndef BANDIT_REPORTERS_H
+#define BANDIT_REPORTERS_H
+
+#include <bandit/reporters/colorizer.h>
+#include <bandit/reporters/progress_reporter.h>
+#include <bandit/reporters/test_run_summary.h>
+#include <bandit/reporters/dots_reporter.h>
+#include <bandit/reporters/single_line_reporter.h>
+#include <bandit/reporters/xunit_reporter.h>
+#include <bandit/reporters/info_reporter.h>
+#include <bandit/reporters/spec_reporter.h>
+
+namespace bandit { namespace detail {
+
+ inline listener& registered_listener(listener* reporter = NULL)
+ {
+ static struct listener* reporter_;
+
+ if(reporter)
+ {
+ reporter_ = reporter;
+ }
+
+ return *reporter_;
+ }
+
+}}
+
+#endif
diff --git a/vendor/bandit/bandit/reporters/single_line_reporter.h b/vendor/bandit/bandit/reporters/single_line_reporter.h
new file mode 100644
index 00000000..08d1c08d
--- /dev/null
+++ b/vendor/bandit/bandit/reporters/single_line_reporter.h
@@ -0,0 +1,86 @@
+#ifndef BANDIT_REPORTERS_SINGLE_LINE_REPORTER_H
+#define BANDIT_REPORTERS_SINGLE_LINE_REPORTER_H
+
+namespace bandit { namespace detail {
+
+ struct single_line_reporter : public progress_reporter
+ {
+ single_line_reporter(std::ostream& stm, const failure_formatter& failure_formatter,
+ const detail::colorizer& colorizer)
+ : progress_reporter(failure_formatter), stm_(stm), colorizer_(colorizer)
+ {}
+
+ single_line_reporter(const failure_formatter& failure_formatter,
+ const detail::colorizer& colorizer)
+ : progress_reporter(failure_formatter), stm_(std::cout), colorizer_(colorizer)
+ {}
+
+ single_line_reporter& operator=(const single_line_reporter&) { return *this; }
+
+ void test_run_complete()
+ {
+ progress_reporter::test_run_complete();
+
+ stm_ << std::endl;
+
+ test_run_summary summary(specs_run_, specs_failed_, specs_succeeded_, specs_skipped_, failures_,
+ test_run_errors_, colorizer_);
+ summary.write(stm_);
+ }
+
+ void test_run_error(const char* desc, const struct test_run_error& err)
+ {
+ progress_reporter::test_run_error(desc, err);
+
+ std::stringstream ss;
+ ss << std::endl;
+ ss << "Failed to run \"" << current_context_name() << "\": error \"" << err.what() << "\"" << std::endl;
+
+ test_run_errors_.push_back(ss.str());
+ }
+
+ void it_starting(const char* desc)
+ {
+ print_status_line();
+ progress_reporter::it_starting(desc);
+ }
+
+ void it_succeeded(const char* desc)
+ {
+ progress_reporter::it_succeeded(desc);
+ print_status_line();
+ }
+
+ void it_failed(const char* desc, const assertion_exception& ex)
+ {
+ progress_reporter::it_failed(desc, ex);
+ print_status_line();
+ }
+
+ void it_unknown_error(const char* desc)
+ {
+ progress_reporter::it_unknown_error(desc);
+ print_status_line();
+ }
+
+ private:
+ void print_status_line()
+ {
+ stm_ << '\r';
+ stm_ << "Executed " << specs_run_ << " tests.";
+
+ if(specs_failed_)
+ {
+ stm_ << " " << specs_succeeded_ << " succeeded. " << colorizer_.red() << specs_failed_ <<
+ " failed." << colorizer_.reset();
+ }
+ stm_.flush();
+ }
+
+ private:
+ std::ostream& stm_;
+ const detail::colorizer& colorizer_;
+ };
+}}
+
+#endif
diff --git a/vendor/bandit/bandit/reporters/spec_reporter.h b/vendor/bandit/bandit/reporters/spec_reporter.h
new file mode 100644
index 00000000..6d63bfb0
--- /dev/null
+++ b/vendor/bandit/bandit/reporters/spec_reporter.h
@@ -0,0 +1,126 @@
+#ifndef BANDIT_SPEC_REPORTER_H
+#define BANDIT_SPEC_REPORTER_H
+
+namespace bandit { namespace detail {
+
+ struct spec_reporter : public progress_reporter
+ {
+ spec_reporter(std::ostream& stm, const failure_formatter& failure_formatter,
+ const detail::colorizer& colorizer)
+ : progress_reporter(failure_formatter), stm_(stm), colorizer_(colorizer), indentation_(0)
+ {}
+
+ spec_reporter(const failure_formatter& failure_formatter, const detail::colorizer& colorizer)
+ : progress_reporter(failure_formatter), stm_(std::cout), colorizer_(colorizer), indentation_(0)
+ {}
+
+ spec_reporter& operator=(const spec_reporter&) { return *this; }
+
+ void test_run_complete()
+ {
+ progress_reporter::test_run_complete();
+
+ stm_ << std::endl;
+
+ test_run_summary summary(specs_run_, specs_failed_, specs_succeeded_, specs_skipped_, failures_,
+ test_run_errors_, colorizer_);
+ summary.write(stm_);
+ stm_.flush();
+ }
+
+ void test_run_error(const char* desc, const struct test_run_error& err)
+ {
+ progress_reporter::test_run_error(desc, err);
+
+ std::stringstream ss;
+ ss << std::endl;
+ ss << "Failed to run \"" << current_context_name() << "\": error \"" << err.what() << "\"" << std::endl;
+
+ test_run_errors_.push_back(ss.str());
+ }
+
+ virtual void context_starting(const char* desc)
+ {
+ progress_reporter::context_starting(desc);
+
+ stm_ << indent();
+ stm_ << "describe " << desc << std::endl;
+ increase_indent();
+ stm_.flush();
+
+ }
+
+ virtual void context_ended(const char* desc)
+ {
+ progress_reporter::context_ended(desc);
+ decrease_indent();
+ }
+
+ virtual void it_starting(const char* desc)
+ {
+ progress_reporter::it_starting(desc);
+ stm_ << indent() << "- it " << desc << " ... ";
+ stm_.flush();
+ }
+
+ virtual void it_succeeded(const char* desc)
+ {
+ progress_reporter::it_succeeded(desc);
+ stm_ << colorizer_.green();
+ stm_ << "OK";
+ stm_ << colorizer_.reset();
+ stm_ << std::endl;
+ stm_.flush();
+ }
+
+ virtual void it_failed(const char* desc, const assertion_exception& ex)
+ {
+ progress_reporter::it_failed(desc, ex);
+ stm_ << colorizer_.red();
+ stm_ << "FAILED";
+ stm_ << colorizer_.reset();
+ stm_ << std::endl;
+ stm_.flush();
+ }
+
+ virtual void it_unknown_error(const char* desc)
+ {
+ progress_reporter::it_unknown_error(desc);
+ stm_ << colorizer_.red();
+ stm_ << "ERROR";
+ stm_ << colorizer_.reset();
+ stm_ << std::endl;
+ stm_.flush();
+ }
+
+ virtual void it_skip(const char* desc)
+ {
+ progress_reporter::it_skip(desc);
+ stm_ << indent() << "- it " << desc << " ... SKIPPED" << std::endl;
+ stm_.flush();
+ }
+
+ private:
+ void increase_indent()
+ {
+ indentation_++;
+ }
+
+ void decrease_indent()
+ {
+ indentation_--;
+ }
+
+ std::string indent()
+ {
+ return std::string(indentation_, '\t');
+ }
+
+ private:
+ std::ostream& stm_;
+ const detail::colorizer& colorizer_;
+ int indentation_;
+ };
+}}
+
+#endif
diff --git a/vendor/bandit/bandit/reporters/test_run_summary.h b/vendor/bandit/bandit/reporters/test_run_summary.h
new file mode 100644
index 00000000..aa1d4a59
--- /dev/null
+++ b/vendor/bandit/bandit/reporters/test_run_summary.h
@@ -0,0 +1,90 @@
+#ifndef BANDIT_TEST_RUN_SUMMARY_H
+#define BANDIT_TEST_RUN_SUMMARY_H
+
+namespace bandit { namespace detail {
+
+ struct test_run_summary
+ {
+ test_run_summary(int specs_run, int specs_failed, int specs_succeeded, int specs_skipped,
+ const std::list<std::string>& failures, const std::list<std::string>& test_run_errors,
+ const detail::colorizer& colorizer)
+ : specs_run_(specs_run), specs_succeeded_(specs_succeeded), specs_failed_(specs_failed),
+ specs_skipped_(specs_skipped), failures_(failures), test_run_errors_(test_run_errors),
+ colorizer_(colorizer)
+ {}
+
+ test_run_summary& operator=(const test_run_summary&) { return *this; }
+
+ void write(std::ostream& stm)
+ {
+ if(specs_run_ == 0 && test_run_errors_.size() == 0)
+ {
+ stm << colorizer_.red();
+ stm << "Could not find any tests.";
+ stm << colorizer_.reset();
+ stm << std::endl;
+ return;
+ }
+
+ if(specs_failed_ == 0 && test_run_errors_.size() == 0)
+ {
+ stm << colorizer_.green();
+ stm << "Success!";
+ stm << colorizer_.reset();
+ stm << std::endl;
+ }
+
+ if(test_run_errors_.size() > 0)
+ {
+ std::for_each(test_run_errors_.begin(), test_run_errors_.end(),
+ [&](const std::string& error){
+ stm << error << std::endl;
+ });
+ }
+
+
+ if(specs_failed_ > 0)
+ {
+ stm << colorizer_.red();
+ stm << "There were failures!";
+ stm << colorizer_.reset() << std::endl;
+ std::for_each(failures_.begin(), failures_.end(),
+ [&](const std::string& failure) {
+ stm << failure << std::endl;
+ });
+ stm << std::endl;
+ }
+
+ stm << "Test run complete. " << specs_run_ << " tests run. " << specs_succeeded_ <<
+ " succeeded.";
+
+ if(specs_skipped_ > 0)
+ {
+ stm << " " << specs_skipped_ << " skipped.";
+ }
+
+ if(specs_failed_ > 0)
+ {
+ stm << " " << specs_failed_ << " failed.";
+ }
+
+ if(test_run_errors_.size() > 0)
+ {
+ stm << " " << test_run_errors_.size() << " test run errors.";
+ }
+
+ stm << std::endl;
+ }
+
+ private:
+ int specs_run_;
+ int specs_succeeded_;
+ int specs_failed_;
+ int specs_skipped_;
+ std::list<std::string> failures_;
+ std::list<std::string> test_run_errors_;
+ const detail::colorizer& colorizer_;
+ };
+}}
+
+#endif
diff --git a/vendor/bandit/bandit/reporters/xunit_reporter.h b/vendor/bandit/bandit/reporters/xunit_reporter.h
new file mode 100644
index 00000000..15f6ea29
--- /dev/null
+++ b/vendor/bandit/bandit/reporters/xunit_reporter.h
@@ -0,0 +1,109 @@
+#ifndef BANDIT_REPORTERS_XUNIT_REPORTER_H
+#define BANDIT_REPORTERS_XUNIT_REPORTER_H
+
+namespace bandit { namespace detail {
+
+ struct xunit_reporter : public progress_reporter
+ {
+ xunit_reporter(std::ostream& stm, const failure_formatter& formatter)
+ : progress_reporter(formatter), stm_(stm)
+ {
+ }
+
+ xunit_reporter(const failure_formatter& formatter)
+ : progress_reporter(formatter), stm_(std::cout)
+ {
+ }
+
+ void it_starting(const char* desc)
+ {
+ progress_reporter::it_starting(desc);
+ work_stm_ << "\t<testcase classname=\"" << escape(current_context_name()) << "\" ";
+ work_stm_ << "name=\"" << escape(desc) << "\" time=\"0\">\n";
+ }
+
+ void it_succeeded(const char* desc)
+ {
+ progress_reporter::it_succeeded(desc);
+ work_stm_ << "\t</testcase>\n";
+ }
+
+ void it_failed(const char* desc, const assertion_exception& ex)
+ {
+ progress_reporter::it_failed(desc, ex);
+ work_stm_ << "\t\t<failure message=\"" << escape(failure_formatter_.format(ex)) << "\" />\n";
+ work_stm_ << "\t</testcase>\n";
+ }
+
+ void it_unknown_error(const char* desc)
+ {
+ progress_reporter::it_unknown_error(desc);
+ work_stm_ << "\t\t<failure message=\"Unknown exception\" />\n";
+ work_stm_ << "\t</testcase>\n";
+ }
+
+ void it_skip(const char* desc)
+ {
+ progress_reporter::it_skip(desc);
+ work_stm_ << "\t<testcase classname=\"" << escape(current_context_name()) << "\" ";
+ work_stm_ << "name=\"" << escape(desc) << "\" time=\"0\">\n";
+ work_stm_ << "\t\t<skipped />\n";
+ work_stm_ << "\t</testcase>\n";
+ }
+
+ void test_run_complete()
+ {
+ stm_ << "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n";
+ stm_ << "<testsuite name=\"bandit\" tests=\"" << specs_run_ << "\" errors=\"0\" failures=\""
+ << specs_failed_ << "\"";
+
+ if(specs_skipped_ > 0)
+ {
+ stm_ << " skipped=\"" << specs_skipped_ << "\"";
+ }
+
+ stm_ << ">\n";
+
+ stm_ << work_stm_.str();
+
+ stm_ << "</testsuite>\n";
+ }
+
+ private:
+ std::string escape(const std::string& str)
+ {
+ std::stringstream stm;
+
+ std::for_each(str.begin(), str.end(), [&](char c){
+ switch(c)
+ {
+ case '&':
+ stm << "&amp;";
+ break;
+ case '<':
+ stm << "&lt;";
+ break;
+ case '>':
+ stm << "&gt;";
+ break;
+ case '\\':
+ stm << "&apos;";
+ break;
+ case '\"':
+ stm << "&quot;";
+ break;
+ default:
+ stm << c;
+ }
+ });
+
+ return stm.str();
+ }
+
+ private:
+ std::ostream& stm_;
+ std::stringstream work_stm_;
+ };
+}}
+
+#endif
diff --git a/vendor/bandit/bandit/run_policies/always_run_policy.h b/vendor/bandit/bandit/run_policies/always_run_policy.h
new file mode 100644
index 00000000..29bdc627
--- /dev/null
+++ b/vendor/bandit/bandit/run_policies/always_run_policy.h
@@ -0,0 +1,16 @@
+#ifndef BANDIT_ALWAYS_RUN_POLICY_H
+#define BANDIT_ALWAYS_RUN_POLICY_H
+
+namespace bandit { namespace detail {
+
+ struct always_run_policy : public run_policy
+ {
+ bool should_run(const char* /* it_name */, const contextstack_t& /* contexts */) const
+ {
+ return true;
+ }
+ };
+
+}}
+
+#endif
diff --git a/vendor/bandit/bandit/run_policies/bandit_run_policy.h b/vendor/bandit/bandit/run_policies/bandit_run_policy.h
new file mode 100644
index 00000000..4a5c0808
--- /dev/null
+++ b/vendor/bandit/bandit/run_policies/bandit_run_policy.h
@@ -0,0 +1,161 @@
+#ifndef BANDIT_BANDIT_RUN_POLICY_H
+#define BANDIT_BANDIT_RUN_POLICY_H
+
+namespace bandit { namespace detail {
+
+ struct bandit_run_policy : public run_policy
+ {
+ bandit_run_policy(const char* skip_pattern, const char* only_pattern, bool break_on_failure)
+ : run_policy(), skip_pattern_(skip_pattern), only_pattern_(only_pattern), break_on_failure_(break_on_failure)
+ {}
+
+ bool should_run(const char* it_name, const contextstack_t& contexts) const
+ {
+ if(break_on_failure_ && has_encountered_failure())
+ {
+ return false;
+ }
+
+ //
+ // Never run if a context has been marked as skip
+ // using 'describe_skip'
+ //
+ if(has_context_with_hard_skip(contexts))
+ {
+ return false;
+ }
+
+ //
+ // Always run if no patterns have been specifed
+ //
+ if(!has_skip_pattern() && !has_only_pattern())
+ {
+ return true;
+ }
+
+ if(has_only_pattern() && !has_skip_pattern())
+ {
+ return context_matches_only_pattern(contexts)
+ || matches_only_pattern(it_name);
+ }
+
+ if(has_skip_pattern() && !has_only_pattern())
+ {
+ bool skip = context_matches_skip_pattern(contexts) ||
+ matches_skip_pattern(it_name);
+ return !skip;
+ }
+
+ //
+ // If we've come this far, both 'skip' and 'only'
+ // have been specified.
+ //
+ // If our contexts match 'only' we're still good
+ // regardless of whether there's a 'skip' somewhere
+ // in the context stack as well.
+ if(context_matches_only_pattern(contexts))
+ {
+ //
+ // We can still mark the current 'it' as 'skip'
+ // and ignore it. We check that here.
+ //
+ return !matches_skip_pattern(it_name);
+ }
+
+ //
+ // If we've gotten this far, the context matches 'skip'
+ // We can still run this spec if it is specifically marked
+ // as 'only'.
+ //
+ return matches_only_pattern(it_name);
+ }
+
+ private:
+ bool has_context_with_hard_skip(const contextstack_t& contexts) const
+ {
+ contextstack_t::const_iterator it;
+ for(it = contexts.begin(); it != contexts.end(); it++)
+ {
+ if((*it)->hard_skip())
+ {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ bool has_only_pattern() const
+ {
+ return only_pattern_.size() > 0;
+ }
+
+ bool has_skip_pattern() const
+ {
+ return skip_pattern_.size() > 0;
+ }
+
+ bool context_matches_only_pattern(const contextstack_t& contexts) const
+ {
+ contextstack_t::const_iterator it;
+ for(it = contexts.begin(); it != contexts.end(); it++)
+ {
+ if(matches_only_pattern((*it)->name()))
+ {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ bool context_matches_skip_pattern(const contextstack_t& contexts) const
+ {
+ contextstack_t::const_iterator it;
+ for(it = contexts.begin(); it != contexts.end(); it++)
+ {
+ if(matches_skip_pattern((*it)->name()))
+ {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ bool matches_only_pattern(const char* name) const
+ {
+ std::string n(name);
+ return matches_only_pattern(n);
+ }
+
+ bool matches_only_pattern(const std::string& name) const
+ {
+ return matches_pattern(name, only_pattern_);
+ }
+
+ bool matches_skip_pattern(const char* name) const
+ {
+ std::string n(name);
+ return matches_skip_pattern(n);
+ }
+
+ bool matches_skip_pattern(const std::string& name) const
+ {
+ return matches_pattern(name, skip_pattern_);
+ }
+
+ bool matches_pattern(const std::string& name, const std::string& pattern) const
+ {
+ return name.find(pattern) != std::string::npos;
+ }
+
+ private:
+ std::string skip_pattern_;
+ std::string only_pattern_;
+ bool break_on_failure_;
+ };
+
+}}
+
+#endif
diff --git a/vendor/bandit/bandit/run_policies/never_run_policy.h b/vendor/bandit/bandit/run_policies/never_run_policy.h
new file mode 100644
index 00000000..003fd889
--- /dev/null
+++ b/vendor/bandit/bandit/run_policies/never_run_policy.h
@@ -0,0 +1,14 @@
+#ifndef BANDIT_NEVER_RUN_POLICY_H
+#define BANDIT_NEVER_RUN_POLICY_H
+
+namespace bandit { namespace detail {
+
+ struct never_run_policy : public run_policy
+ {
+ bool should_run(const char* /* it_name */, const contextstack_t& /* contexts */) const
+ {
+ return false;
+ }
+ };
+}}
+#endif
diff --git a/vendor/bandit/bandit/run_policies/run_policies.h b/vendor/bandit/bandit/run_policies/run_policies.h
new file mode 100644
index 00000000..88d8dbb5
--- /dev/null
+++ b/vendor/bandit/bandit/run_policies/run_policies.h
@@ -0,0 +1,9 @@
+#ifndef BANDIT_RUN_POLICIES_H
+#define BANDIT_RUN_POLICIES_H
+
+#include "run_policy.h"
+#include "always_run_policy.h"
+#include "never_run_policy.h"
+#include "bandit_run_policy.h"
+
+#endif
diff --git a/vendor/bandit/bandit/run_policies/run_policy.h b/vendor/bandit/bandit/run_policies/run_policy.h
new file mode 100644
index 00000000..4a6e8e1d
--- /dev/null
+++ b/vendor/bandit/bandit/run_policies/run_policy.h
@@ -0,0 +1,44 @@
+#ifndef BANDIT_RUN_POLICY_H
+#define BANDIT_RUN_POLICY_H
+
+namespace bandit { namespace detail {
+
+ struct run_policy
+ {
+ run_policy() : encountered_failure_(false) {}
+ run_policy(const run_policy& other) = default;
+ run_policy(run_policy&&) = default;
+ virtual ~run_policy() {}
+
+ virtual bool should_run(const char* it_name, const contextstack_t& contexts) const = 0;
+
+ virtual void encountered_failure()
+ {
+ encountered_failure_ = true;
+ }
+
+ virtual bool has_encountered_failure() const
+ {
+ return encountered_failure_;
+ }
+
+ private:
+ bool encountered_failure_;
+ };
+ typedef std::unique_ptr<run_policy> run_policy_ptr;
+
+ inline run_policy& registered_run_policy(run_policy* policy = NULL)
+ {
+ static struct run_policy* policy_;
+
+ if(policy)
+ {
+ policy_ = policy;
+ }
+
+ return *policy_;
+ }
+
+}}
+
+#endif
diff --git a/vendor/bandit/bandit/runner.h b/vendor/bandit/bandit/runner.h
new file mode 100644
index 00000000..1f8dcd11
--- /dev/null
+++ b/vendor/bandit/bandit/runner.h
@@ -0,0 +1,103 @@
+#ifndef BANDIT_RUNNER_H
+#define BANDIT_RUNNER_H
+
+namespace bandit {
+
+ namespace detail {
+
+ inline run_policy_ptr create_run_policy(const options& opt)
+ {
+ return run_policy_ptr(new bandit_run_policy(opt.skip(), opt.only(), opt.break_on_failure()));
+ }
+
+ inline listener_ptr create_reporter(const options& opt,
+ const failure_formatter* formatter, const colorizer& colorizer)
+ {
+ std::string name(opt.reporter() ? opt.reporter() : "");
+
+ if(name == "singleline")
+ {
+ return std::unique_ptr<detail::listener>(new single_line_reporter(*formatter, colorizer));
+ }
+
+ if(name == "xunit")
+ {
+ return std::unique_ptr<detail::listener>(new xunit_reporter(*formatter));
+ }
+
+ if(name == "info")
+ {
+ return std::unique_ptr<detail::listener>(new info_reporter(*formatter, colorizer));
+ }
+
+ if(name == "spec")
+ {
+ return std::unique_ptr<detail::listener>(new spec_reporter(*formatter, colorizer));
+ }
+
+ return std::unique_ptr<detail::listener>(new dots_reporter(*formatter, colorizer));
+ }
+
+ typedef std::function<listener_ptr (const std::string&, const failure_formatter*)> reporter_factory_fn;
+ typedef std::function<detail::listener* (detail::listener*)> register_reporter_fn;
+
+ inline failure_formatter_ptr create_formatter(const options& opt)
+ {
+ if(opt.formatter() == options::formatters::FORMATTER_VS)
+ {
+ return failure_formatter_ptr(new visual_studio_failure_formatter());
+ }
+
+ return failure_formatter_ptr(new default_failure_formatter());
+ }
+ }
+
+ inline int run(const detail::options& opt, const detail::spec_registry& specs,
+ detail::contextstack_t& context_stack, detail::listener& listener)
+ {
+ if(opt.help())
+ {
+ opt.print_usage();
+ return 0;
+ }
+
+ if(opt.version())
+ {
+ std::cout << "bandit version " << BANDIT_VERSION << std::endl;
+ return 0;
+ }
+
+ auto call_func = [](const detail::voidfunc_t& func) {
+ func();
+ };
+
+ listener.test_run_starting();
+
+ bool hard_skip = false;
+ detail::bandit_context global_context("", hard_skip);
+ context_stack.push_back(&global_context);
+
+ for_each(specs.begin(), specs.end(), call_func);
+
+ listener.test_run_complete();
+
+ return listener.did_we_pass() ? 0 : 1;
+ }
+
+ inline int run(int argc, char* argv[])
+ {
+ detail::options opt(argc, argv);
+ detail::failure_formatter_ptr formatter(create_formatter(opt));
+ bandit::detail::colorizer colorizer(!opt.no_color());
+ detail::listener_ptr reporter(create_reporter(opt, formatter.get(), colorizer));
+
+ detail::registered_listener(reporter.get());
+
+ detail::run_policy_ptr run_policy = create_run_policy(opt);
+ registered_run_policy(run_policy.get());
+
+ return run(opt, detail::specs(), detail::context_stack(), *reporter);
+ }
+}
+
+#endif
diff --git a/vendor/bandit/bandit/skip_policies/always_include_policy.h b/vendor/bandit/bandit/skip_policies/always_include_policy.h
new file mode 100644
index 00000000..2e978308
--- /dev/null
+++ b/vendor/bandit/bandit/skip_policies/always_include_policy.h
@@ -0,0 +1,16 @@
+#ifndef BANDIT_ALWAYS_INCLUDE_POLICY_H
+#define BANDIT_ALWAYS_INCLUDE_POLICY_H
+
+namespace bandit { namespace detail {
+
+ struct always_include_policy : public skip_policy
+ {
+ bool should_skip(const char*) const
+ {
+ return false;
+ }
+ };
+
+}}
+
+#endif
diff --git a/vendor/bandit/bandit/skip_policies/always_skip_policy.h b/vendor/bandit/bandit/skip_policies/always_skip_policy.h
new file mode 100644
index 00000000..9d6a4bfc
--- /dev/null
+++ b/vendor/bandit/bandit/skip_policies/always_skip_policy.h
@@ -0,0 +1,15 @@
+#ifndef BANDIT_ALWAYS_SKIP_POLICY_H
+#define BANDIT_ALWAYS_SKIP_POLICY_H
+
+namespace bandit { namespace detail {
+
+ struct always_skip_policy : public skip_policy
+ {
+ bool should_skip(const char*) const
+ {
+ return true;
+ }
+ };
+}}
+
+#endif
diff --git a/vendor/bandit/bandit/skip_policies/name_contains_skip_policy.h b/vendor/bandit/bandit/skip_policies/name_contains_skip_policy.h
new file mode 100644
index 00000000..da727c3d
--- /dev/null
+++ b/vendor/bandit/bandit/skip_policies/name_contains_skip_policy.h
@@ -0,0 +1,28 @@
+#ifndef BANDIT_NAME_CONTAINS_SKIP_POLICY_H
+#define BANDIT_NAME_CONTAINS_SKIP_POLICY_H
+
+namespace bandit { namespace detail {
+ struct name_contains_skip_policy : public skip_policy
+ {
+ name_contains_skip_policy(const char* pattern)
+ : pattern_(pattern)
+ {}
+
+ bool should_skip(const char* name) const
+ {
+ if(pattern_.size() == 0)
+ {
+ return false;
+ }
+
+ std::string n(name);
+ bool skip = n.find(pattern_) != std::string::npos;
+ return skip;
+ }
+
+ private:
+ const std::string pattern_;
+ };
+}}
+
+#endif
diff --git a/vendor/bandit/bandit/skip_policies/skip_policies.h b/vendor/bandit/bandit/skip_policies/skip_policies.h
new file mode 100644
index 00000000..f3fbfbfd
--- /dev/null
+++ b/vendor/bandit/bandit/skip_policies/skip_policies.h
@@ -0,0 +1,9 @@
+#ifndef BANDIT_SKIP_POLICIES
+#define BANDIT_SKIP_POLICIES
+
+#include <bandit/skip_policies/skip_policy.h>
+#include <bandit/skip_policies/always_include_policy.h>
+#include <bandit/skip_policies/always_skip_policy.h>
+#include <bandit/skip_policies/name_contains_skip_policy.h>
+
+#endif
diff --git a/vendor/bandit/bandit/skip_policies/skip_policy.h b/vendor/bandit/bandit/skip_policies/skip_policy.h
new file mode 100644
index 00000000..ca606dfb
--- /dev/null
+++ b/vendor/bandit/bandit/skip_policies/skip_policy.h
@@ -0,0 +1,29 @@
+#ifndef BANDIT_SKIP_POLICY_H
+#define BANDIT_SKIP_POLICY_H
+
+namespace bandit {
+
+ struct skip_policy
+ {
+ virtual bool should_skip(const char* name) const = 0;
+ };
+ typedef std::unique_ptr<skip_policy> skip_policy_ptr;
+
+ namespace detail {
+
+ inline skip_policy& registered_skip_policy(skip_policy* policy = NULL)
+ {
+ static struct skip_policy* policy_;
+
+ if(policy)
+ {
+ policy_ = policy;
+ }
+
+ return *policy_;
+ }
+ }
+
+}
+
+#endif
diff --git a/vendor/bandit/bandit/test_run_error.h b/vendor/bandit/bandit/test_run_error.h
new file mode 100644
index 00000000..307ef3fe
--- /dev/null
+++ b/vendor/bandit/bandit/test_run_error.h
@@ -0,0 +1,12 @@
+#ifndef BANDIT_TEST_RUN_ERROR
+#define BANDIT_TEST_RUN_ERROR
+
+namespace bandit { namespace detail {
+
+ struct test_run_error : public std::runtime_error
+ {
+ test_run_error(const char* message) : std::runtime_error(message) {}
+ };
+}}
+
+#endif
diff --git a/vendor/bandit/cmake/cotire.cmake b/vendor/bandit/cmake/cotire.cmake
new file mode 100644
index 00000000..a6e3141c
--- /dev/null
+++ b/vendor/bandit/cmake/cotire.cmake
@@ -0,0 +1,3185 @@
+# - cotire (compile time reducer)
+#
+# See the cotire manual for usage hints.
+#
+#=============================================================================
+# Copyright 2012-2013 Sascha Kratky
+#
+# 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 AUTHORS OR COPYRIGHT
+# HOLDERS 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.
+#=============================================================================
+
+if(__COTIRE_INCLUDED)
+ return()
+endif()
+set(__COTIRE_INCLUDED TRUE)
+
+# call cmake_minimum_required, but prevent modification of the CMake policy stack in include mode
+# cmake_minimum_required also sets the policy version as a side effect, which we have to avoid
+if (NOT CMAKE_SCRIPT_MODE_FILE)
+ cmake_policy(PUSH)
+endif()
+# we need the CMake variables CMAKE_SCRIPT_MODE_FILE and CMAKE_ARGV available since 2.8.5
+# we need APPEND_STRING option for set_property available since 2.8.6
+cmake_minimum_required(VERSION 2.8.6)
+if (NOT CMAKE_SCRIPT_MODE_FILE)
+ cmake_policy(POP)
+endif()
+
+set (COTIRE_CMAKE_MODULE_FILE "${CMAKE_CURRENT_LIST_FILE}")
+set (COTIRE_CMAKE_MODULE_VERSION "1.4.1")
+
+include(CMakeParseArguments)
+include(ProcessorCount)
+
+function (cotire_determine_compiler_version _language _versionPrefix)
+ if (NOT ${_versionPrefix}_VERSION)
+ # use CMake's predefined compiler version variable (available since CMake 2.8.8)
+ if (DEFINED CMAKE_${_language}_COMPILER_VERSION)
+ set (${_versionPrefix}_VERSION "${CMAKE_${_language}_COMPILER_VERSION}")
+ elseif (WIN32)
+ # cl.exe messes with the output streams unless the environment variable VS_UNICODE_OUTPUT is cleared
+ unset (ENV{VS_UNICODE_OUTPUT})
+ string (STRIP "${CMAKE_${_language}_COMPILER_ARG1}" _compilerArg1)
+ execute_process (COMMAND ${CMAKE_${_language}_COMPILER} ${_compilerArg1}
+ ERROR_VARIABLE _versionLine OUTPUT_QUIET TIMEOUT 10)
+ string (REGEX REPLACE ".*Version *([0-9]+(\\.[0-9]+)*).*" "\\1" ${_versionPrefix}_VERSION "${_versionLine}")
+ else()
+ # assume GCC like command line interface
+ string (STRIP "${CMAKE_${_language}_COMPILER_ARG1}" _compilerArg1)
+ execute_process (COMMAND ${CMAKE_${_language}_COMPILER} ${_compilerArg1} "-dumpversion"
+ OUTPUT_VARIABLE ${_versionPrefix}_VERSION
+ RESULT_VARIABLE _result
+ OUTPUT_STRIP_TRAILING_WHITESPACE TIMEOUT 10)
+ if (_result)
+ set (${_versionPrefix}_VERSION "")
+ endif()
+ endif()
+ if (${_versionPrefix}_VERSION)
+ set (${_versionPrefix}_VERSION "${${_versionPrefix}_VERSION}" CACHE INTERNAL "${_language} compiler version")
+ endif()
+ set (${_versionPrefix}_VERSION "${${_versionPrefix}_VERSION}" PARENT_SCOPE)
+ if (COTIRE_DEBUG)
+ message (STATUS "${CMAKE_${_language}_COMPILER} version ${${_versionPrefix}_VERSION}")
+ endif()
+ endif()
+endfunction()
+
+function (cotire_get_source_file_extension _sourceFile _extVar)
+ # get_filename_component returns extension from first occurrence of . in file name
+ # this function computes the extension from last occurrence of . in file name
+ string (FIND "${_sourceFile}" "." _index REVERSE)
+ if (_index GREATER -1)
+ math (EXPR _index "${_index} + 1")
+ string (SUBSTRING "${_sourceFile}" ${_index} -1 _sourceExt)
+ else()
+ set (_sourceExt "")
+ endif()
+ set (${_extVar} "${_sourceExt}" PARENT_SCOPE)
+endfunction()
+
+macro (cotire_check_is_path_relative_to _path _isRelativeVar)
+ set (${_isRelativeVar} FALSE)
+ if (IS_ABSOLUTE "${_path}")
+ foreach (_dir ${ARGN})
+ file (RELATIVE_PATH _relPath "${_dir}" "${_path}")
+ if (NOT _relPath OR (NOT IS_ABSOLUTE "${_relPath}" AND NOT "${_relPath}" MATCHES "^\\.\\."))
+ set (${_isRelativeVar} TRUE)
+ break()
+ endif()
+ endforeach()
+ endif()
+endmacro()
+
+function (cotire_filter_language_source_files _language _sourceFilesVar _excludedSourceFilesVar _cotiredSourceFilesVar)
+ set (_sourceFiles "")
+ set (_excludedSourceFiles "")
+ set (_cotiredSourceFiles "")
+ if (CMAKE_${_language}_SOURCE_FILE_EXTENSIONS)
+ set (_languageExtensions "${CMAKE_${_language}_SOURCE_FILE_EXTENSIONS}")
+ else()
+ set (_languageExtensions "")
+ endif()
+ if (CMAKE_${_language}_IGNORE_EXTENSIONS)
+ set (_ignoreExtensions "${CMAKE_${_language}_IGNORE_EXTENSIONS}")
+ else()
+ set (_ignoreExtensions "")
+ endif()
+ if (COTIRE_UNITY_SOURCE_EXCLUDE_EXTENSIONS)
+ set (_excludeExtensions "${COTIRE_UNITY_SOURCE_EXCLUDE_EXTENSIONS}")
+ else()
+ set (_excludeExtensions "")
+ endif()
+ if (COTIRE_DEBUG)
+ message (STATUS "${_language} source file extensions: ${_languageExtensions}")
+ message (STATUS "${_language} ignore extensions: ${_ignoreExtensions}")
+ message (STATUS "${_language} exclude extensions: ${_excludeExtensions}")
+ endif()
+ foreach (_sourceFile ${ARGN})
+ get_source_file_property(_sourceIsHeaderOnly "${_sourceFile}" HEADER_FILE_ONLY)
+ get_source_file_property(_sourceIsExternal "${_sourceFile}" EXTERNAL_OBJECT)
+ get_source_file_property(_sourceIsSymbolic "${_sourceFile}" SYMBOLIC)
+ get_source_file_property(_sourceLanguage "${_sourceFile}" LANGUAGE)
+ set (_sourceIsFiltered FALSE)
+ if (NOT _sourceIsHeaderOnly AND NOT _sourceIsExternal AND NOT _sourceIsSymbolic)
+ cotire_get_source_file_extension("${_sourceFile}" _sourceExt)
+ if (_sourceExt)
+ list (FIND _ignoreExtensions "${_sourceExt}" _ignoreIndex)
+ if (_ignoreIndex LESS 0)
+ list (FIND _excludeExtensions "${_sourceExt}" _excludeIndex)
+ if (_excludeIndex GREATER -1)
+ list (APPEND _excludedSourceFiles "${_sourceFile}")
+ else()
+ list (FIND _languageExtensions "${_sourceExt}" _sourceIndex)
+ if (_sourceIndex GREATER -1)
+ set (_sourceIsFiltered TRUE)
+ elseif ("${_sourceLanguage}" STREQUAL "${_language}")
+ # add to excluded sources, if file is not ignored and has correct language without having the correct extension
+ list (APPEND _excludedSourceFiles "${_sourceFile}")
+ endif()
+ endif()
+ endif()
+ endif()
+ endif()
+ if (COTIRE_DEBUG)
+ message (STATUS "${_sourceFile} filtered=${_sourceIsFiltered} language=${_sourceLanguage} header=${_sourceIsHeaderOnly}")
+ endif()
+ if (_sourceIsFiltered)
+ get_source_file_property(_sourceIsExcluded "${_sourceFile}" COTIRE_EXCLUDED)
+ get_source_file_property(_sourceIsCotired "${_sourceFile}" COTIRE_TARGET)
+ get_source_file_property(_sourceCompileFlags "${_sourceFile}" COMPILE_FLAGS)
+ if (COTIRE_DEBUG)
+ message (STATUS "${_sourceFile} excluded=${_sourceIsExcluded} cotired=${_sourceIsCotired}")
+ endif()
+ if (_sourceIsCotired)
+ list (APPEND _cotiredSourceFiles "${_sourceFile}")
+ elseif (_sourceIsExcluded OR _sourceCompileFlags)
+ list (APPEND _excludedSourceFiles "${_sourceFile}")
+ else()
+ list (APPEND _sourceFiles "${_sourceFile}")
+ endif()
+ endif()
+ endforeach()
+ if (COTIRE_DEBUG)
+ message (STATUS "All: ${ARGN}")
+ message (STATUS "${_language}: ${_sourceFiles}")
+ message (STATUS "Excluded: ${_excludedSourceFiles}")
+ message (STATUS "Cotired: ${_cotiredSourceFiles}")
+ endif()
+ set (${_sourceFilesVar} ${_sourceFiles} PARENT_SCOPE)
+ set (${_excludedSourceFilesVar} ${_excludedSourceFiles} PARENT_SCOPE)
+ set (${_cotiredSourceFilesVar} ${_cotiredSourceFiles} PARENT_SCOPE)
+endfunction()
+
+function (cotire_get_objects_with_property_on _filteredObjectsVar _property _type)
+ set (_filteredObjects "")
+ foreach (_object ${ARGN})
+ get_property(_isSet ${_type} "${_object}" PROPERTY ${_property} SET)
+ if (_isSet)
+ get_property(_propertyValue ${_type} "${_object}" PROPERTY ${_property})
+ if (_propertyValue)
+ list (APPEND _filteredObjects "${_object}")
+ endif()
+ endif()
+ endforeach()
+ set (${_filteredObjectsVar} ${_filteredObjects} PARENT_SCOPE)
+endfunction()
+
+function (cotire_get_objects_with_property_off _filteredObjectsVar _property _type)
+ set (_filteredObjects "")
+ foreach (_object ${ARGN})
+ get_property(_isSet ${_type} "${_object}" PROPERTY ${_property} SET)
+ if (_isSet)
+ get_property(_propertyValue ${_type} "${_object}" PROPERTY ${_property})
+ if (NOT _propertyValue)
+ list (APPEND _filteredObjects "${_object}")
+ endif()
+ endif()
+ endforeach()
+ set (${_filteredObjectsVar} ${_filteredObjects} PARENT_SCOPE)
+endfunction()
+
+function (cotire_get_source_file_property_values _valuesVar _property)
+ set (_values "")
+ foreach (_sourceFile ${ARGN})
+ get_source_file_property(_propertyValue "${_sourceFile}" ${_property})
+ if (_propertyValue)
+ list (APPEND _values "${_propertyValue}")
+ endif()
+ endforeach()
+ set (${_valuesVar} ${_values} PARENT_SCOPE)
+endfunction()
+
+function (cotrie_resolve_config_properites _configurations _propertiesVar)
+ set (_properties "")
+ foreach (_property ${ARGN})
+ if ("${_property}" MATCHES "<CONFIG>")
+ foreach (_config ${_configurations})
+ string (TOUPPER "${_config}" _upperConfig)
+ string (REPLACE "<CONFIG>" "${_upperConfig}" _configProperty "${_property}")
+ list (APPEND _properties ${_configProperty})
+ endforeach()
+ else()
+ list (APPEND _properties ${_property})
+ endif()
+ endforeach()
+ set (${_propertiesVar} ${_properties} PARENT_SCOPE)
+endfunction()
+
+function (cotrie_copy_set_properites _configurations _type _source _target)
+ cotrie_resolve_config_properites("${_configurations}" _properties ${ARGN})
+ foreach (_property ${_properties})
+ get_property(_isSet ${_type} ${_source} PROPERTY ${_property} SET)
+ if (_isSet)
+ get_property(_propertyValue ${_type} ${_source} PROPERTY ${_property})
+ set_property(${_type} ${_target} PROPERTY ${_property} "${_propertyValue}")
+ endif()
+ endforeach()
+endfunction()
+
+function (cotire_filter_compile_flags _language _flagFilter _matchedOptionsVar _unmatchedOptionsVar)
+ if (WIN32 AND CMAKE_${_language}_COMPILER_ID MATCHES "MSVC|Intel")
+ set (_flagPrefix "[/-]")
+ else()
+ set (_flagPrefix "--?")
+ endif()
+ set (_optionFlag "")
+ set (_matchedOptions "")
+ set (_unmatchedOptions "")
+ foreach (_compileFlag ${ARGN})
+ if (_compileFlag)
+ if (_optionFlag AND NOT "${_compileFlag}" MATCHES "^${_flagPrefix}")
+ # option with separate argument
+ list (APPEND _matchedOptions "${_compileFlag}")
+ set (_optionFlag "")
+ elseif ("${_compileFlag}" MATCHES "^(${_flagPrefix})(${_flagFilter})$")
+ # remember option
+ set (_optionFlag "${CMAKE_MATCH_2}")
+ elseif ("${_compileFlag}" MATCHES "^(${_flagPrefix})(${_flagFilter})(.+)$")
+ # option with joined argument
+ list (APPEND _matchedOptions "${CMAKE_MATCH_3}")
+ set (_optionFlag "")
+ else()
+ # flush remembered option
+ if (_optionFlag)
+ list (APPEND _matchedOptions "${_optionFlag}")
+ set (_optionFlag "")
+ endif()
+ # add to unfiltered options
+ list (APPEND _unmatchedOptions "${_compileFlag}")
+ endif()
+ endif()
+ endforeach()
+ if (_optionFlag)
+ list (APPEND _matchedOptions "${_optionFlag}")
+ endif()
+ if (COTIRE_DEBUG)
+ message (STATUS "Filter ${_flagFilter}")
+ if (_matchedOptions)
+ message (STATUS "Matched ${_matchedOptions}")
+ endif()
+ if (_unmatchedOptions)
+ message (STATUS "Unmatched ${_unmatchedOptions}")
+ endif()
+ endif()
+ set (${_matchedOptionsVar} ${_matchedOptions} PARENT_SCOPE)
+ set (${_unmatchedOptionsVar} ${_unmatchedOptions} PARENT_SCOPE)
+endfunction()
+
+function (cotire_get_target_compile_flags _config _language _directory _target _flagsVar)
+ string (TOUPPER "${_config}" _upperConfig)
+ # collect options from CMake language variables
+ set (_compileFlags "")
+ if (CMAKE_${_language}_FLAGS)
+ set (_compileFlags "${_compileFlags} ${CMAKE_${_language}_FLAGS}")
+ endif()
+ if (CMAKE_${_language}_FLAGS_${_upperConfig})
+ set (_compileFlags "${_compileFlags} ${CMAKE_${_language}_FLAGS_${_upperConfig}}")
+ endif()
+ if (_target)
+ # add option from CMake target type variable
+ get_target_property(_targetType ${_target} TYPE)
+ if (POLICY CMP0018)
+ # handle POSITION_INDEPENDENT_CODE property introduced with CMake 2.8.9 if policy CMP0018 is turned on
+ cmake_policy(GET CMP0018 _PIC_Policy)
+ else()
+ # default to old behavior
+ set (_PIC_Policy "OLD")
+ endif()
+ if (COTIRE_DEBUG)
+ message(STATUS "CMP0018=${_PIC_Policy}")
+ endif()
+ if (_PIC_Policy STREQUAL "NEW")
+ # NEW behavior: honor the POSITION_INDEPENDENT_CODE target property
+ get_target_property(_targetPIC ${_target} POSITION_INDEPENDENT_CODE)
+ if (_targetPIC)
+ if (_targetType STREQUAL "EXECUTABLE" AND CMAKE_${_language}_COMPILE_OPTIONS_PIE)
+ set (_compileFlags "${_compileFlags} ${CMAKE_${_language}_COMPILE_OPTIONS_PIE}")
+ elseif (CMAKE_${_language}_COMPILE_OPTIONS_PIC)
+ set (_compileFlags "${_compileFlags} ${CMAKE_${_language}_COMPILE_OPTIONS_PIC}")
+ endif()
+ endif()
+ else()
+ # OLD behavior or policy not set: use the value of CMAKE_SHARED_LIBRARY_<Lang>_FLAGS
+ if (_targetType STREQUAL "MODULE_LIBRARY")
+ # flags variable for module library uses different name SHARED_MODULE
+ # (e.g., CMAKE_SHARED_MODULE_C_FLAGS)
+ set (_targetType SHARED_MODULE)
+ endif()
+ if (CMAKE_${_targetType}_${_language}_FLAGS)
+ set (_compileFlags "${_compileFlags} ${CMAKE_${_targetType}_${_language}_FLAGS}")
+ endif()
+ endif()
+ endif()
+ if (_directory)
+ # add_definitions may have been used to add flags to the compiler command
+ get_directory_property(_dirDefinitions DIRECTORY "${_directory}" DEFINITIONS)
+ if (_dirDefinitions)
+ set (_compileFlags "${_compileFlags} ${_dirDefinitions}")
+ endif()
+ endif()
+ if (_target)
+ # add target compile options
+ get_target_property(_targetflags ${_target} COMPILE_FLAGS)
+ if (_targetflags)
+ set (_compileFlags "${_compileFlags} ${_targetflags}")
+ endif()
+ endif()
+ if (UNIX)
+ separate_arguments(_compileFlags UNIX_COMMAND "${_compileFlags}")
+ elseif(WIN32)
+ separate_arguments(_compileFlags WINDOWS_COMMAND "${_compileFlags}")
+ else()
+ separate_arguments(_compileFlags)
+ endif()
+ # platform specific flags
+ if (APPLE)
+ get_target_property(_architectures ${_target} OSX_ARCHITECTURES_${_upperConfig})
+ if (NOT _architectures)
+ get_target_property(_architectures ${_target} OSX_ARCHITECTURES)
+ endif()
+ foreach (_arch ${_architectures})
+ list (APPEND _compileFlags "-arch" "${_arch}")
+ endforeach()
+ if (CMAKE_OSX_SYSROOT AND CMAKE_OSX_SYSROOT_DEFAULT AND CMAKE_${_language}_HAS_ISYSROOT)
+ if (NOT "${CMAKE_OSX_SYSROOT}" STREQUAL "${CMAKE_OSX_SYSROOT_DEFAULT}")
+ list (APPEND _compileFlags "-isysroot" "${CMAKE_OSX_SYSROOT}")
+ endif()
+ endif()
+ if (CMAKE_OSX_DEPLOYMENT_TARGET AND CMAKE_${_language}_OSX_DEPLOYMENT_TARGET_FLAG)
+ list (APPEND _compileFlags "${CMAKE_${_language}_OSX_DEPLOYMENT_TARGET_FLAG}${CMAKE_OSX_DEPLOYMENT_TARGET}")
+ endif()
+ endif()
+ if (COTIRE_DEBUG AND _compileFlags)
+ message (STATUS "Target ${_target} compile flags ${_compileFlags}")
+ endif()
+ set (${_flagsVar} ${_compileFlags} PARENT_SCOPE)
+endfunction()
+
+function (cotire_get_target_include_directories _config _language _targetSourceDir _targetBinaryDir _target _includeDirsVar)
+ set (_includeDirs "")
+ # default include dirs
+ if (CMAKE_INCLUDE_CURRENT_DIR)
+ list (APPEND _includeDirs "${_targetBinaryDir}")
+ list (APPEND _includeDirs "${_targetSourceDir}")
+ endif()
+ # parse additional include directories from target compile flags
+ set (_targetFlags "")
+ cotire_get_target_compile_flags("${_config}" "${_language}" "${_targetSourceDir}" "${_target}" _targetFlags)
+ cotire_filter_compile_flags("${_language}" "I" _dirs _ignore ${_targetFlags})
+ if (_dirs)
+ list (APPEND _includeDirs ${_dirs})
+ endif()
+ # target include directories
+ get_directory_property(_dirs DIRECTORY "${_targetSourceDir}" INCLUDE_DIRECTORIES)
+ if (_target)
+ get_target_property(_targetDirs ${_target} INCLUDE_DIRECTORIES)
+ if (_targetDirs)
+ list (APPEND _dirs ${_targetDirs})
+ list (REMOVE_DUPLICATES _dirs)
+ endif()
+ endif()
+ list (LENGTH _includeDirs _projectInsertIndex)
+ foreach (_dir ${_dirs})
+ if (CMAKE_INCLUDE_DIRECTORIES_PROJECT_BEFORE)
+ cotire_check_is_path_relative_to("${_dir}" _isRelative "${CMAKE_SOURCE_DIR}" "${CMAKE_BINARY_DIR}")
+ if (_isRelative)
+ list (LENGTH _includeDirs _len)
+ if (_len EQUAL _projectInsertIndex)
+ list (APPEND _includeDirs "${_dir}")
+ else()
+ list (INSERT _includeDirs _projectInsertIndex "${_dir}")
+ endif()
+ math (EXPR _projectInsertIndex "${_projectInsertIndex} + 1")
+ else()
+ list (APPEND _includeDirs "${_dir}")
+ endif()
+ else()
+ list (APPEND _includeDirs "${_dir}")
+ endif()
+ endforeach()
+ list (REMOVE_DUPLICATES _includeDirs)
+ if (CMAKE_${_language}_IMPLICIT_INCLUDE_DIRECTORIES)
+ list (REMOVE_ITEM _includeDirs ${CMAKE_${_language}_IMPLICIT_INCLUDE_DIRECTORIES})
+ endif()
+ if (COTIRE_DEBUG AND _includeDirs)
+ message (STATUS "Target ${_target} include dirs ${_includeDirs}")
+ endif()
+ set (${_includeDirsVar} ${_includeDirs} PARENT_SCOPE)
+endfunction()
+
+macro (cotire_make_C_identifier _identifierVar _str)
+ # mimic CMake SystemTools::MakeCindentifier behavior
+ if ("${_str}" MATCHES "^[0-9].+$")
+ set (_str "_${str}")
+ endif()
+ string (REGEX REPLACE "[^a-zA-Z0-9]" "_" ${_identifierVar} "${_str}")
+endmacro()
+
+function (cotire_get_target_export_symbol _target _exportSymbolVar)
+ set (_exportSymbol "")
+ get_target_property(_targetType ${_target} TYPE)
+ get_target_property(_enableExports ${_target} ENABLE_EXPORTS)
+ if (_targetType MATCHES "(SHARED|MODULE)_LIBRARY" OR
+ (_targetType STREQUAL "EXECUTABLE" AND _enableExports))
+ get_target_property(_exportSymbol ${_target} DEFINE_SYMBOL)
+ if (NOT _exportSymbol)
+ set (_exportSymbol "${_target}_EXPORTS")
+ endif()
+ cotire_make_C_identifier(_exportSymbol "${_exportSymbol}")
+ endif()
+ set (${_exportSymbolVar} ${_exportSymbol} PARENT_SCOPE)
+endfunction()
+
+function (cotire_get_target_compile_definitions _config _language _directory _target _definitionsVar)
+ string (TOUPPER "${_config}" _upperConfig)
+ set (_configDefinitions "")
+ # CMAKE_INTDIR for multi-configuration build systems
+ if (NOT "${CMAKE_CFG_INTDIR}" STREQUAL ".")
+ list (APPEND _configDefinitions "CMAKE_INTDIR=\"${_config}\"")
+ endif()
+ # target export define symbol
+ cotire_get_target_export_symbol("${_target}" _defineSymbol)
+ if (_defineSymbol)
+ list (APPEND _configDefinitions "${_defineSymbol}")
+ endif()
+ # directory compile definitions
+ get_directory_property(_definitions DIRECTORY "${_directory}" COMPILE_DEFINITIONS)
+ if (_definitions)
+ list (APPEND _configDefinitions ${_definitions})
+ endif()
+ get_directory_property(_definitions DIRECTORY "${_directory}" COMPILE_DEFINITIONS_${_upperConfig})
+ if (_definitions)
+ list (APPEND _configDefinitions ${_definitions})
+ endif()
+ # target compile definitions
+ get_target_property(_definitions ${_target} COMPILE_DEFINITIONS)
+ if (_definitions)
+ list (APPEND _configDefinitions ${_definitions})
+ endif()
+ get_target_property(_definitions ${_target} COMPILE_DEFINITIONS_${_upperConfig})
+ if (_definitions)
+ list (APPEND _configDefinitions ${_definitions})
+ endif()
+ # parse additional compile definitions from target compile flags
+ # and don't look at directory compile definitions, which we already handled
+ set (_targetFlags "")
+ cotire_get_target_compile_flags("${_config}" "${_language}" "" "${_target}" _targetFlags)
+ cotire_filter_compile_flags("${_language}" "D" _definitions _ignore ${_targetFlags})
+ if (_definitions)
+ list (APPEND _configDefinitions ${_definitions})
+ endif()
+ list (REMOVE_DUPLICATES _configDefinitions)
+ if (COTIRE_DEBUG AND _configDefinitions)
+ message (STATUS "Target ${_target} compile definitions ${_configDefinitions}")
+ endif()
+ set (${_definitionsVar} ${_configDefinitions} PARENT_SCOPE)
+endfunction()
+
+function (cotire_get_target_compiler_flags _config _language _directory _target _compilerFlagsVar)
+ # parse target compile flags omitting compile definitions and include directives
+ set (_targetFlags "")
+ cotire_get_target_compile_flags("${_config}" "${_language}" "${_directory}" "${_target}" _targetFlags)
+ set (_compilerFlags "")
+ cotire_filter_compile_flags("${_language}" "[ID]" _ignore _compilerFlags ${_targetFlags})
+ if (COTIRE_DEBUG AND _compilerFlags)
+ message (STATUS "Target ${_target} compiler flags ${_compilerFlags}")
+ endif()
+ set (${_compilerFlagsVar} ${_compilerFlags} PARENT_SCOPE)
+endfunction()
+
+function (cotire_add_sys_root_paths _pathsVar)
+ if (APPLE)
+ if (CMAKE_OSX_SYSROOT AND CMAKE_${_language}_HAS_ISYSROOT)
+ foreach (_path IN LISTS ${_pathsVar})
+ if (IS_ABSOLUTE "${_path}")
+ get_filename_component(_path "${CMAKE_OSX_SYSROOT}/${_path}" ABSOLUTE)
+ if (EXISTS "${_path}")
+ list (APPEND ${_pathsVar} "${_path}")
+ endif()
+ endif()
+ endforeach()
+ endif()
+ endif()
+ set (${_pathsVar} ${${_pathsVar}} PARENT_SCOPE)
+ if (COTIRE_DEBUG)
+ message (STATUS "${_pathsVar}=${${_pathsVar}}")
+ endif()
+endfunction()
+
+function (cotire_get_source_extra_properties _sourceFile _pattern _resultVar)
+ set (_extraProperties ${ARGN})
+ set (_result "")
+ if (_extraProperties)
+ list (FIND _extraProperties "${_sourceFile}" _index)
+ if (_index GREATER -1)
+ math (EXPR _index "${_index} + 1")
+ list (LENGTH _extraProperties _len)
+ math (EXPR _len "${_len} - 1")
+ foreach (_index RANGE ${_index} ${_len})
+ list (GET _extraProperties ${_index} _value)
+ if ("${_value}" MATCHES "${_pattern}")
+ list (APPEND _result "${_value}")
+ else()
+ break()
+ endif()
+ endforeach()
+ endif()
+ endif()
+ set (${_resultVar} ${_result} PARENT_SCOPE)
+endfunction()
+
+function (cotire_get_source_compile_definitions _config _language _sourceFile _definitionsVar)
+ set (_compileDefinitions "")
+ if (NOT CMAKE_SCRIPT_MODE_FILE)
+ string (TOUPPER "${_config}" _upperConfig)
+ get_source_file_property(_definitions "${_sourceFile}" COMPILE_DEFINITIONS)
+ if (_definitions)
+ list (APPEND _compileDefinitions ${_definitions})
+ endif()
+ get_source_file_property(_definitions "${_sourceFile}" COMPILE_DEFINITIONS_${_upperConfig})
+ if (_definitions)
+ list (APPEND _compileDefinitions ${_definitions})
+ endif()
+ endif()
+ cotire_get_source_extra_properties("${_sourceFile}" "^[a-zA-Z0-9_]+(=.*)?$" _definitions ${ARGN})
+ if (_definitions)
+ list (APPEND _compileDefinitions ${_definitions})
+ endif()
+ if (COTIRE_DEBUG AND _compileDefinitions)
+ message (STATUS "Source ${_sourceFile} compile definitions ${_compileDefinitions}")
+ endif()
+ set (${_definitionsVar} ${_compileDefinitions} PARENT_SCOPE)
+endfunction()
+
+function (cotire_get_source_files_compile_definitions _config _language _definitionsVar)
+ set (_configDefinitions "")
+ foreach (_sourceFile ${ARGN})
+ cotire_get_source_compile_definitions("${_config}" "${_language}" "${_sourceFile}" _sourceDefinitions)
+ if (_sourceDefinitions)
+ list (APPEND _configDefinitions "${_sourceFile}" ${_sourceDefinitions} "-")
+ endif()
+ endforeach()
+ set (${_definitionsVar} ${_configDefinitions} PARENT_SCOPE)
+endfunction()
+
+function (cotire_get_source_undefs _sourceFile _property _sourceUndefsVar)
+ set (_sourceUndefs "")
+ if (NOT CMAKE_SCRIPT_MODE_FILE)
+ get_source_file_property(_undefs "${_sourceFile}" ${_property})
+ if (_undefs)
+ list (APPEND _sourceUndefs ${_undefs})
+ endif()
+ endif()
+ cotire_get_source_extra_properties("${_sourceFile}" "^[a-zA-Z0-9_]+$" _undefs ${ARGN})
+ if (_undefs)
+ list (APPEND _sourceUndefs ${_undefs})
+ endif()
+ if (COTIRE_DEBUG AND _sourceUndefs)
+ message (STATUS "Source ${_sourceFile} ${_property} undefs ${_sourceUndefs}")
+ endif()
+ set (${_sourceUndefsVar} ${_sourceUndefs} PARENT_SCOPE)
+endfunction()
+
+function (cotire_get_source_files_undefs _property _sourceUndefsVar)
+ set (_sourceUndefs "")
+ foreach (_sourceFile ${ARGN})
+ cotire_get_source_undefs("${_sourceFile}" ${_property} _undefs)
+ if (_undefs)
+ list (APPEND _sourceUndefs "${_sourceFile}" ${_undefs} "-")
+ endif()
+ endforeach()
+ set (${_sourceUndefsVar} ${_sourceUndefs} PARENT_SCOPE)
+endfunction()
+
+macro (cotire_set_cmd_to_prologue _cmdVar)
+ set (${_cmdVar} "${CMAKE_COMMAND}")
+ if (COTIRE_DEBUG)
+ list (APPEND ${_cmdVar} "--warn-uninitialized")
+ endif()
+ list (APPEND ${_cmdVar} "-DCOTIRE_BUILD_TYPE:STRING=$<CONFIGURATION>")
+ if (COTIRE_VERBOSE)
+ list (APPEND ${_cmdVar} "-DCOTIRE_VERBOSE:BOOL=ON")
+ elseif("${CMAKE_GENERATOR}" MATCHES "Makefiles")
+ list (APPEND ${_cmdVar} "-DCOTIRE_VERBOSE:BOOL=$(VERBOSE)")
+ endif()
+endmacro()
+
+function (cotire_init_compile_cmd _cmdVar _language _compilerExe _compilerArg1)
+ if (NOT _compilerExe)
+ set (_compilerExe "${CMAKE_${_language}_COMPILER}")
+ endif()
+ if (NOT _compilerArg1)
+ set (_compilerArg1 ${CMAKE_${_language}_COMPILER_ARG1})
+ endif()
+ string (STRIP "${_compilerArg1}" _compilerArg1)
+ set (${_cmdVar} "${_compilerExe}" ${_compilerArg1} PARENT_SCOPE)
+endfunction()
+
+macro (cotire_add_definitions_to_cmd _cmdVar _language)
+ foreach (_definition ${ARGN})
+ if (WIN32 AND CMAKE_${_language}_COMPILER_ID MATCHES "MSVC|Intel")
+ list (APPEND ${_cmdVar} "/D${_definition}")
+ else()
+ list (APPEND ${_cmdVar} "-D${_definition}")
+ endif()
+ endforeach()
+endmacro()
+
+macro (cotire_add_includes_to_cmd _cmdVar _language)
+ foreach (_include ${ARGN})
+ if (WIN32 AND CMAKE_${_language}_COMPILER_ID MATCHES "MSVC|Intel")
+ file (TO_NATIVE_PATH "${_include}" _include)
+ list (APPEND ${_cmdVar} "/I${_include}")
+ else()
+ list (APPEND ${_cmdVar} "-I${_include}")
+ endif()
+ endforeach()
+endmacro()
+
+macro (cotire_add_compile_flags_to_cmd _cmdVar)
+ foreach (_flag ${ARGN})
+ list (APPEND ${_cmdVar} "${_flag}")
+ endforeach()
+endmacro()
+
+function (cotire_check_file_up_to_date _fileIsUpToDateVar _file)
+ set (${_fileIsUpToDateVar} FALSE PARENT_SCOPE)
+ set (_triggerFile "")
+ foreach (_dependencyFile ${ARGN})
+ if (EXISTS "${_dependencyFile}" AND "${_dependencyFile}" IS_NEWER_THAN "${_file}")
+ set (_triggerFile "${_dependencyFile}")
+ break()
+ endif()
+ endforeach()
+ get_filename_component(_fileName "${_file}" NAME)
+ if (EXISTS "${_file}")
+ if (_triggerFile)
+ if (COTIRE_VERBOSE)
+ message (STATUS "${_fileName} update triggered by ${_triggerFile} change.")
+ endif()
+ else()
+ if (COTIRE_VERBOSE)
+ message (STATUS "${_fileName} is up-to-date.")
+ endif()
+ set (${_fileIsUpToDateVar} TRUE PARENT_SCOPE)
+ endif()
+ else()
+ if (COTIRE_VERBOSE)
+ message (STATUS "${_fileName} does not exist yet.")
+ endif()
+ endif()
+endfunction()
+
+macro (cotire_find_closest_relative_path _headerFile _includeDirs _relPathVar)
+ set (${_relPathVar} "")
+ foreach (_includeDir ${_includeDirs})
+ if (IS_DIRECTORY "${_includeDir}")
+ file (RELATIVE_PATH _relPath "${_includeDir}" "${_headerFile}")
+ if (NOT IS_ABSOLUTE "${_relPath}" AND NOT "${_relPath}" MATCHES "^\\.\\.")
+ string (LENGTH "${${_relPathVar}}" _closestLen)
+ string (LENGTH "${_relPath}" _relLen)
+ if (_closestLen EQUAL 0 OR _relLen LESS _closestLen)
+ set (${_relPathVar} "${_relPath}")
+ endif()
+ endif()
+ elseif ("${_includeDir}" STREQUAL "${_headerFile}")
+ # if path matches exactly, return short non-empty string
+ set (${_relPathVar} "1")
+ break()
+ endif()
+ endforeach()
+endmacro()
+
+macro (cotire_check_header_file_location _headerFile _insideIncudeDirs _outsideIncudeDirs _headerIsInside)
+ # check header path against ignored and honored include directories
+ cotire_find_closest_relative_path("${_headerFile}" "${_insideIncudeDirs}" _insideRelPath)
+ if (_insideRelPath)
+ # header is inside, but could be become outside if there is a shorter outside match
+ cotire_find_closest_relative_path("${_headerFile}" "${_outsideIncudeDirs}" _outsideRelPath)
+ if (_outsideRelPath)
+ string (LENGTH "${_insideRelPath}" _insideRelPathLen)
+ string (LENGTH "${_outsideRelPath}" _outsideRelPathLen)
+ if (_outsideRelPathLen LESS _insideRelPathLen)
+ set (${_headerIsInside} FALSE)
+ else()
+ set (${_headerIsInside} TRUE)
+ endif()
+ else()
+ set (${_headerIsInside} TRUE)
+ endif()
+ else()
+ # header is outside
+ set (${_headerIsInside} FALSE)
+ endif()
+endmacro()
+
+macro (cotire_check_ignore_header_file_path _headerFile _headerIsIgnoredVar)
+ if (NOT EXISTS "${_headerFile}")
+ set (${_headerIsIgnoredVar} TRUE)
+ elseif (IS_DIRECTORY "${_headerFile}")
+ set (${_headerIsIgnoredVar} TRUE)
+ elseif ("${_headerFile}" MATCHES "\\.\\.|[_-]fixed" AND "${_headerFile}" MATCHES "\\.h$")
+ # heuristic: ignore C headers with embedded parent directory references or "-fixed" or "_fixed" in path
+ # these often stem from using GCC #include_next tricks, which may break the precompiled header compilation
+ # with the error message "error: no include path in which to search for header.h"
+ set (${_headerIsIgnoredVar} TRUE)
+ else()
+ set (${_headerIsIgnoredVar} FALSE)
+ endif()
+endmacro()
+
+macro (cotire_check_ignore_header_file_ext _headerFile _ignoreExtensionsVar _headerIsIgnoredVar)
+ # check header file extension
+ cotire_get_source_file_extension("${_headerFile}" _headerFileExt)
+ set (${_headerIsIgnoredVar} FALSE)
+ if (_headerFileExt)
+ list (FIND ${_ignoreExtensionsVar} "${_headerFileExt}" _index)
+ if (_index GREATER -1)
+ set (${_headerIsIgnoredVar} TRUE)
+ endif()
+ endif()
+endmacro()
+
+macro (cotire_parse_line _line _headerFileVar _headerDepthVar)
+ if (MSVC)
+ # cl.exe /showIncludes output looks different depending on the language pack used, e.g.:
+ # English: "Note: including file: C:\directory\file"
+ # German: "Hinweis: Einlesen der Datei: C:\directory\file"
+ # We use a very general regular expression, relying on the presence of the : characters
+ if ("${_line}" MATCHES ":( +)([^:]+:[^:]+)$")
+ # Visual Studio compiler output
+ string (LENGTH "${CMAKE_MATCH_1}" ${_headerDepthVar})
+ get_filename_component(${_headerFileVar} "${CMAKE_MATCH_2}" ABSOLUTE)
+ else()
+ set (${_headerFileVar} "")
+ set (${_headerDepthVar} 0)
+ endif()
+ else()
+ if ("${_line}" MATCHES "^(\\.+) (.*)$")
+ # GCC like output
+ string (LENGTH "${CMAKE_MATCH_1}" ${_headerDepthVar})
+ if (IS_ABSOLUTE "${CMAKE_MATCH_2}")
+ set (${_headerFileVar} "${CMAKE_MATCH_2}")
+ else()
+ get_filename_component(${_headerFileVar} "${CMAKE_MATCH_2}" REALPATH)
+ endif()
+ else()
+ set (${_headerFileVar} "")
+ set (${_headerDepthVar} 0)
+ endif()
+ endif()
+endmacro()
+
+function (cotire_parse_includes _language _scanOutput _ignoredIncudeDirs _honoredIncudeDirs _ignoredExtensions _selectedIncludesVar _unparsedLinesVar)
+ if (WIN32)
+ # prevent CMake macro invocation errors due to backslash characters in Windows paths
+ string (REPLACE "\\" "/" _scanOutput "${_scanOutput}")
+ endif()
+ # canonize slashes
+ string (REPLACE "//" "/" _scanOutput "${_scanOutput}")
+ # prevent semicolon from being interpreted as a line separator
+ string (REPLACE ";" "\\;" _scanOutput "${_scanOutput}")
+ # then separate lines
+ string (REGEX REPLACE "\n" ";" _scanOutput "${_scanOutput}")
+ list (LENGTH _scanOutput _len)
+ # remove duplicate lines to speed up parsing
+ list (REMOVE_DUPLICATES _scanOutput)
+ list (LENGTH _scanOutput _uniqueLen)
+ if (COTIRE_VERBOSE)
+ message (STATUS "Scanning ${_uniqueLen} unique lines of ${_len} for includes")
+ if (_ignoredExtensions)
+ message (STATUS "Ignored extensions: ${_ignoredExtensions}")
+ endif()
+ if (_ignoredIncudeDirs)
+ message (STATUS "Ignored paths: ${_ignoredIncudeDirs}")
+ endif()
+ if (_honoredIncudeDirs)
+ message (STATUS "Included paths: ${_honoredIncudeDirs}")
+ endif()
+ endif()
+ set (_sourceFiles ${ARGN})
+ set (_selectedIncludes "")
+ set (_unparsedLines "")
+ # stack keeps track of inside/outside project status of processed header files
+ set (_headerIsInsideStack "")
+ foreach (_line IN LISTS _scanOutput)
+ if (_line)
+ cotire_parse_line("${_line}" _headerFile _headerDepth)
+ if (_headerFile)
+ cotire_check_header_file_location("${_headerFile}" "${_ignoredIncudeDirs}" "${_honoredIncudeDirs}" _headerIsInside)
+ if (COTIRE_DEBUG)
+ message (STATUS "${_headerDepth}: ${_headerFile} ${_headerIsInside}")
+ endif()
+ # update stack
+ list (LENGTH _headerIsInsideStack _stackLen)
+ if (_headerDepth GREATER _stackLen)
+ math (EXPR _stackLen "${_stackLen} + 1")
+ foreach (_index RANGE ${_stackLen} ${_headerDepth})
+ list (APPEND _headerIsInsideStack ${_headerIsInside})
+ endforeach()
+ else()
+ foreach (_index RANGE ${_headerDepth} ${_stackLen})
+ list (REMOVE_AT _headerIsInsideStack -1)
+ endforeach()
+ list (APPEND _headerIsInsideStack ${_headerIsInside})
+ endif()
+ if (COTIRE_DEBUG)
+ message (STATUS "${_headerIsInsideStack}")
+ endif()
+ # header is a candidate if it is outside project
+ if (NOT _headerIsInside)
+ # get parent header file's inside/outside status
+ if (_headerDepth GREATER 1)
+ math (EXPR _index "${_headerDepth} - 2")
+ list (GET _headerIsInsideStack ${_index} _parentHeaderIsInside)
+ else()
+ set (_parentHeaderIsInside TRUE)
+ endif()
+ # select header file if parent header file is inside project
+ # (e.g., a project header file that includes a standard header file)
+ if (_parentHeaderIsInside)
+ cotire_check_ignore_header_file_path("${_headerFile}" _headerIsIgnored)
+ if (NOT _headerIsIgnored)
+ cotire_check_ignore_header_file_ext("${_headerFile}" _ignoredExtensions _headerIsIgnored)
+ if (NOT _headerIsIgnored)
+ list (APPEND _selectedIncludes "${_headerFile}")
+ else()
+ # fix header's inside status on stack, it is ignored by extension now
+ list (REMOVE_AT _headerIsInsideStack -1)
+ list (APPEND _headerIsInsideStack TRUE)
+ endif()
+ endif()
+ if (COTIRE_DEBUG)
+ message (STATUS "${_headerFile} ${_ignoredExtensions} ${_headerIsIgnored}")
+ endif()
+ endif()
+ endif()
+ else()
+ if (MSVC)
+ # for cl.exe do not keep unparsed lines which solely consist of a source file name
+ string (FIND "${_sourceFiles}" "${_line}" _index)
+ if (_index LESS 0)
+ list (APPEND _unparsedLines "${_line}")
+ endif()
+ else()
+ list (APPEND _unparsedLines "${_line}")
+ endif()
+ endif()
+ endif()
+ endforeach()
+ list (REMOVE_DUPLICATES _selectedIncludes)
+ set (${_selectedIncludesVar} ${_selectedIncludes} PARENT_SCOPE)
+ set (${_unparsedLinesVar} ${_unparsedLines} PARENT_SCOPE)
+endfunction()
+
+function (cotire_scan_includes _includesVar)
+ set(_options "")
+ set(_oneValueArgs COMPILER_ID COMPILER_EXECUTABLE COMPILER_VERSION LANGUAGE UNPARSED_LINES)
+ set(_multiValueArgs COMPILE_DEFINITIONS COMPILE_FLAGS INCLUDE_DIRECTORIES IGNORE_PATH INCLUDE_PATH IGNORE_EXTENSIONS)
+ cmake_parse_arguments(_option "${_options}" "${_oneValueArgs}" "${_multiValueArgs}" ${ARGN})
+ set (_sourceFiles ${_option_UNPARSED_ARGUMENTS})
+ if (NOT _option_LANGUAGE)
+ set (_option_LANGUAGE "CXX")
+ endif()
+ if (NOT _option_COMPILER_ID)
+ set (_option_COMPILER_ID "${CMAKE_${_option_LANGUAGE}_ID}")
+ endif()
+ set (_cmd "${_option_COMPILER_EXECUTABLE}" ${_option_COMPILER_ARG1})
+ cotire_init_compile_cmd(_cmd "${_option_LANGUAGE}" "${_option_COMPILER_EXECUTABLE}" "${_option_COMPILER_ARG1}")
+ cotire_add_definitions_to_cmd(_cmd "${_option_LANGUAGE}" ${_option_COMPILE_DEFINITIONS})
+ cotire_add_compile_flags_to_cmd(_cmd ${_option_COMPILE_FLAGS})
+ cotire_add_includes_to_cmd(_cmd "${_option_LANGUAGE}" ${_option_INCLUDE_DIRECTORIES})
+ cotire_add_makedep_flags("${_option_LANGUAGE}" "${_option_COMPILER_ID}" "${_option_COMPILER_VERSION}" _cmd)
+ # only consider existing source files for scanning
+ set (_existingSourceFiles "")
+ foreach (_sourceFile ${_sourceFiles})
+ if (EXISTS "${_sourceFile}")
+ list (APPEND _existingSourceFiles "${_sourceFile}")
+ endif()
+ endforeach()
+ if (NOT _existingSourceFiles)
+ set (${_includesVar} "" PARENT_SCOPE)
+ return()
+ endif()
+ list (APPEND _cmd ${_existingSourceFiles})
+ if (COTIRE_VERBOSE)
+ message (STATUS "execute_process: ${_cmd}")
+ endif()
+ if (_option_COMPILER_ID MATCHES "MSVC")
+ if (COTIRE_DEBUG)
+ message (STATUS "clearing VS_UNICODE_OUTPUT")
+ endif()
+ # cl.exe messes with the output streams unless the environment variable VS_UNICODE_OUTPUT is cleared
+ unset (ENV{VS_UNICODE_OUTPUT})
+ endif()
+ execute_process(COMMAND ${_cmd} WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
+ RESULT_VARIABLE _result OUTPUT_QUIET ERROR_VARIABLE _output)
+ if (_result)
+ message (STATUS "Result ${_result} scanning includes of ${_existingSourceFiles}.")
+ endif()
+ cotire_parse_includes(
+ "${_option_LANGUAGE}" "${_output}"
+ "${_option_IGNORE_PATH}" "${_option_INCLUDE_PATH}"
+ "${_option_IGNORE_EXTENSIONS}"
+ _includes _unparsedLines
+ ${_sourceFiles})
+ set (${_includesVar} ${_includes} PARENT_SCOPE)
+ if (_option_UNPARSED_LINES)
+ set (${_option_UNPARSED_LINES} ${_unparsedLines} PARENT_SCOPE)
+ endif()
+endfunction()
+
+macro (cotire_append_undefs _contentsVar)
+ set (_undefs ${ARGN})
+ if (_undefs)
+ list (REMOVE_DUPLICATES _undefs)
+ foreach (_definition ${_undefs})
+ list (APPEND ${_contentsVar} "#undef ${_definition}")
+ endforeach()
+ endif()
+endmacro()
+
+macro (cotire_comment_str _language _commentText _commentVar)
+ if ("${_language}" STREQUAL "CMAKE")
+ set (${_commentVar} "# ${_commentText}")
+ else()
+ set (${_commentVar} "/* ${_commentText} */")
+ endif()
+endmacro()
+
+function (cotire_write_file _language _file _contents _force)
+ get_filename_component(_moduleName "${COTIRE_CMAKE_MODULE_FILE}" NAME)
+ cotire_comment_str("${_language}" "${_moduleName} ${COTIRE_CMAKE_MODULE_VERSION} generated file" _header1)
+ cotire_comment_str("${_language}" "${_file}" _header2)
+ set (_contents "${_header1}\n${_header2}\n${_contents}")
+ if (COTIRE_DEBUG)
+ message (STATUS "${_contents}")
+ endif()
+ if (_force OR NOT EXISTS "${_file}")
+ file (WRITE "${_file}" "${_contents}")
+ else()
+ file (READ "${_file}" _oldContents)
+ if (NOT "${_oldContents}" STREQUAL "${_contents}")
+ file (WRITE "${_file}" "${_contents}")
+ else()
+ if (COTIRE_DEBUG)
+ message (STATUS "${_file} unchanged")
+ endif()
+ endif()
+ endif()
+endfunction()
+
+function (cotire_generate_unity_source _unityFile)
+ set(_options "")
+ set(_oneValueArgs LANGUAGE)
+ set(_multiValueArgs
+ DEPENDS SOURCES_COMPILE_DEFINITIONS
+ PRE_UNDEFS SOURCES_PRE_UNDEFS POST_UNDEFS SOURCES_POST_UNDEFS PROLOGUE EPILOGUE)
+ cmake_parse_arguments(_option "${_options}" "${_oneValueArgs}" "${_multiValueArgs}" ${ARGN})
+ if (_option_DEPENDS)
+ cotire_check_file_up_to_date(_unityFileIsUpToDate "${_unityFile}" ${_option_DEPENDS})
+ if (_unityFileIsUpToDate)
+ return()
+ endif()
+ endif()
+ set (_sourceFiles ${_option_UNPARSED_ARGUMENTS})
+ if (NOT _option_PRE_UNDEFS)
+ set (_option_PRE_UNDEFS "")
+ endif()
+ if (NOT _option_SOURCES_PRE_UNDEFS)
+ set (_option_SOURCES_PRE_UNDEFS "")
+ endif()
+ if (NOT _option_POST_UNDEFS)
+ set (_option_POST_UNDEFS "")
+ endif()
+ if (NOT _option_SOURCES_POST_UNDEFS)
+ set (_option_SOURCES_POST_UNDEFS "")
+ endif()
+ set (_contents "")
+ if (_option_PROLOGUE)
+ list (APPEND _contents ${_option_PROLOGUE})
+ endif()
+ if (_option_LANGUAGE AND _sourceFiles)
+ if ("${_option_LANGUAGE}" STREQUAL "CXX")
+ list (APPEND _contents "#ifdef __cplusplus")
+ elseif ("${_option_LANGUAGE}" STREQUAL "C")
+ list (APPEND _contents "#ifndef __cplusplus")
+ endif()
+ endif()
+ set (_compileUndefinitions "")
+ foreach (_sourceFile ${_sourceFiles})
+ cotire_get_source_compile_definitions(
+ "${_option_CONFIGURATION}" "${_option_LANGUAGE}" "${_sourceFile}" _compileDefinitions
+ ${_option_SOURCES_COMPILE_DEFINITIONS})
+ cotire_get_source_undefs("${_sourceFile}" COTIRE_UNITY_SOURCE_PRE_UNDEFS _sourcePreUndefs ${_option_SOURCES_PRE_UNDEFS})
+ cotire_get_source_undefs("${_sourceFile}" COTIRE_UNITY_SOURCE_POST_UNDEFS _sourcePostUndefs ${_option_SOURCES_POST_UNDEFS})
+ if (_option_PRE_UNDEFS)
+ list (APPEND _compileUndefinitions ${_option_PRE_UNDEFS})
+ endif()
+ if (_sourcePreUndefs)
+ list (APPEND _compileUndefinitions ${_sourcePreUndefs})
+ endif()
+ if (_compileUndefinitions)
+ cotire_append_undefs(_contents ${_compileUndefinitions})
+ set (_compileUndefinitions "")
+ endif()
+ if (_sourcePostUndefs)
+ list (APPEND _compileUndefinitions ${_sourcePostUndefs})
+ endif()
+ if (_option_POST_UNDEFS)
+ list (APPEND _compileUndefinitions ${_option_POST_UNDEFS})
+ endif()
+ foreach (_definition ${_compileDefinitions})
+ if ("${_definition}" MATCHES "^([a-zA-Z0-9_]+)=(.+)$")
+ list (APPEND _contents "#define ${CMAKE_MATCH_1} ${CMAKE_MATCH_2}")
+ list (INSERT _compileUndefinitions 0 "${CMAKE_MATCH_1}")
+ else()
+ list (APPEND _contents "#define ${_definition}")
+ list (INSERT _compileUndefinitions 0 "${_definition}")
+ endif()
+ endforeach()
+ get_filename_component(_sourceFile "${_sourceFile}" ABSOLUTE)
+ if (WIN32)
+ file (TO_NATIVE_PATH "${_sourceFile}" _sourceFile)
+ endif()
+ list (APPEND _contents "#include \"${_sourceFile}\"")
+ endforeach()
+ if (_compileUndefinitions)
+ cotire_append_undefs(_contents ${_compileUndefinitions})
+ set (_compileUndefinitions "")
+ endif()
+ if (_option_LANGUAGE AND _sourceFiles)
+ list (APPEND _contents "#endif")
+ endif()
+ if (_option_EPILOGUE)
+ list (APPEND _contents ${_option_EPILOGUE})
+ endif()
+ list (APPEND _contents "")
+ string (REPLACE ";" "\n" _contents "${_contents}")
+ if (COTIRE_VERBOSE)
+ message ("${_contents}")
+ endif()
+ cotire_write_file("${_option_LANGUAGE}" "${_unityFile}" "${_contents}" TRUE)
+endfunction()
+
+function (cotire_generate_prefix_header _prefixFile)
+ set(_options "")
+ set(_oneValueArgs LANGUAGE COMPILER_EXECUTABLE COMPILER_ID COMPILER_VERSION)
+ set(_multiValueArgs DEPENDS COMPILE_DEFINITIONS COMPILE_FLAGS
+ INCLUDE_DIRECTORIES IGNORE_PATH INCLUDE_PATH IGNORE_EXTENSIONS)
+ cmake_parse_arguments(_option "${_options}" "${_oneValueArgs}" "${_multiValueArgs}" ${ARGN})
+ if (_option_DEPENDS)
+ cotire_check_file_up_to_date(_prefixFileIsUpToDate "${_prefixFile}" ${_option_DEPENDS})
+ if (_prefixFileIsUpToDate)
+ return()
+ endif()
+ endif()
+ set (_epilogue "")
+ if (_option_COMPILER_ID MATCHES "Intel")
+ # Intel compiler requires hdrstop pragma to stop generating PCH file
+ set (_epilogue "#pragma hdrstop")
+ endif()
+ set (_sourceFiles ${_option_UNPARSED_ARGUMENTS})
+ cotire_scan_includes(_selectedHeaders ${_sourceFiles}
+ LANGUAGE "${_option_LANGUAGE}"
+ COMPILER_EXECUTABLE "${_option_COMPILER_EXECUTABLE}"
+ COMPILER_ID "${_option_COMPILER_ID}"
+ COMPILER_VERSION "${_option_COMPILER_VERSION}"
+ COMPILE_DEFINITIONS ${_option_COMPILE_DEFINITIONS}
+ COMPILE_FLAGS ${_option_COMPILE_FLAGS}
+ INCLUDE_DIRECTORIES ${_option_INCLUDE_DIRECTORIES}
+ IGNORE_PATH ${_option_IGNORE_PATH}
+ INCLUDE_PATH ${_option_INCLUDE_PATH}
+ IGNORE_EXTENSIONS ${_option_IGNORE_EXTENSIONS}
+ UNPARSED_LINES _unparsedLines)
+ cotire_generate_unity_source("${_prefixFile}" EPILOGUE ${_epilogue} LANGUAGE "${_option_LANGUAGE}" ${_selectedHeaders})
+ set (_unparsedLinesFile "${_prefixFile}.log")
+ if (_unparsedLines)
+ if (COTIRE_VERBOSE OR NOT _selectedHeaders)
+ list (LENGTH _unparsedLines _skippedLineCount)
+ file (RELATIVE_PATH _unparsedLinesFileRelPath "${CMAKE_BINARY_DIR}" "${_unparsedLinesFile}")
+ message (STATUS "${_skippedLineCount} line(s) skipped, see ${_unparsedLinesFileRelPath}")
+ endif()
+ string (REPLACE ";" "\n" _unparsedLines "${_unparsedLines}")
+ endif()
+ file (WRITE "${_unparsedLinesFile}" "${_unparsedLines}\n")
+endfunction()
+
+function (cotire_add_makedep_flags _language _compilerID _compilerVersion _flagsVar)
+ set (_flags ${${_flagsVar}})
+ if (_compilerID MATCHES "MSVC")
+ # cl.exe options used
+ # /nologo suppresses display of sign-on banner
+ # /TC treat all files named on the command line as C source files
+ # /TP treat all files named on the command line as C++ source files
+ # /EP preprocess to stdout without #line directives
+ # /showIncludes list include files
+ set (_sourceFileTypeC "/TC")
+ set (_sourceFileTypeCXX "/TP")
+ if (_flags)
+ # append to list
+ list (APPEND _flags /nologo "${_sourceFileType${_language}}" /EP /showIncludes)
+ else()
+ # return as a flag string
+ set (_flags "${_sourceFileType${_language}} /EP /showIncludes")
+ endif()
+ elseif (_compilerID MATCHES "GNU")
+ # GCC options used
+ # -H print the name of each header file used
+ # -E invoke preprocessor
+ # -fdirectives-only do not expand macros, requires GCC >= 4.3
+ if (_flags)
+ # append to list
+ list (APPEND _flags -H -E)
+ if (NOT "${_compilerVersion}" VERSION_LESS "4.3.0")
+ list (APPEND _flags "-fdirectives-only")
+ endif()
+ else()
+ # return as a flag string
+ set (_flags "-H -E")
+ if (NOT "${_compilerVersion}" VERSION_LESS "4.3.0")
+ set (_flags "${_flags} -fdirectives-only")
+ endif()
+ endif()
+ elseif (_compilerID MATCHES "Clang")
+ # Clang options used
+ # -H print the name of each header file used
+ # -E invoke preprocessor
+ if (_flags)
+ # append to list
+ list (APPEND _flags -H -E)
+ else()
+ # return as a flag string
+ set (_flags "-H -E")
+ endif()
+ elseif (_compilerID MATCHES "Intel")
+ if (WIN32)
+ # Windows Intel options used
+ # /nologo do not display compiler version information
+ # /QH display the include file order
+ # /EP preprocess to stdout, omitting #line directives
+ # /TC process all source or unrecognized file types as C source files
+ # /TP process all source or unrecognized file types as C++ source files
+ set (_sourceFileTypeC "/TC")
+ set (_sourceFileTypeCXX "/TP")
+ if (_flags)
+ # append to list
+ list (APPEND _flags /nologo "${_sourceFileType${_language}}" /EP /QH)
+ else()
+ # return as a flag string
+ set (_flags "${_sourceFileType${_language}} /EP /QH")
+ endif()
+ else()
+ # Linux / Mac OS X Intel options used
+ # -H print the name of each header file used
+ # -EP preprocess to stdout, omitting #line directives
+ # -Kc++ process all source or unrecognized file types as C++ source files
+ if (_flags)
+ # append to list
+ if ("${_language}" STREQUAL "CXX")
+ list (APPEND _flags -Kc++)
+ endif()
+ list (APPEND _flags -H -EP)
+ else()
+ # return as a flag string
+ if ("${_language}" STREQUAL "CXX")
+ set (_flags "-Kc++ ")
+ endif()
+ set (_flags "${_flags}-H -EP")
+ endif()
+ endif()
+ else()
+ message (FATAL_ERROR "Unsupported ${_language} compiler ${_compilerID} version ${_compilerVersion}.")
+ endif()
+ set (${_flagsVar} ${_flags} PARENT_SCOPE)
+endfunction()
+
+function (cotire_add_pch_compilation_flags _language _compilerID _compilerVersion _prefixFile _pchFile _hostFile _flagsVar)
+ set (_flags ${${_flagsVar}})
+ if (_compilerID MATCHES "MSVC")
+ file (TO_NATIVE_PATH "${_prefixFile}" _prefixFileNative)
+ file (TO_NATIVE_PATH "${_pchFile}" _pchFileNative)
+ file (TO_NATIVE_PATH "${_hostFile}" _hostFileNative)
+ # cl.exe options used
+ # /Yc creates a precompiled header file
+ # /Fp specifies precompiled header binary file name
+ # /FI forces inclusion of file
+ # /TC treat all files named on the command line as C source files
+ # /TP treat all files named on the command line as C++ source files
+ # /Zs syntax check only
+ set (_sourceFileTypeC "/TC")
+ set (_sourceFileTypeCXX "/TP")
+ if (_flags)
+ # append to list
+ list (APPEND _flags /nologo "${_sourceFileType${_language}}"
+ "/Yc${_prefixFileNative}" "/Fp${_pchFileNative}" "/FI${_prefixFileNative}" /Zs "${_hostFileNative}")
+ else()
+ # return as a flag string
+ set (_flags "/Yc\"${_prefixFileNative}\" /Fp\"${_pchFileNative}\" /FI\"${_prefixFileNative}\"")
+ endif()
+ elseif (_compilerID MATCHES "GNU|Clang")
+ # GCC / Clang options used
+ # -x specify the source language
+ # -c compile but do not link
+ # -o place output in file
+ set (_xLanguage_C "c-header")
+ set (_xLanguage_CXX "c++-header")
+ if (_flags)
+ # append to list
+ list (APPEND _flags "-x" "${_xLanguage_${_language}}" "-c" "${_prefixFile}" -o "${_pchFile}")
+ else()
+ # return as a flag string
+ set (_flags "-x ${_xLanguage_${_language}} -c \"${_prefixFile}\" -o \"${_pchFile}\"")
+ endif()
+ elseif (_compilerID MATCHES "Intel")
+ if (WIN32)
+ file (TO_NATIVE_PATH "${_prefixFile}" _prefixFileNative)
+ file (TO_NATIVE_PATH "${_pchFile}" _pchFileNative)
+ file (TO_NATIVE_PATH "${_hostFile}" _hostFileNative)
+ # Windows Intel options used
+ # /nologo do not display compiler version information
+ # /Yc create a precompiled header (PCH) file
+ # /Fp specify a path or file name for precompiled header files
+ # /FI tells the preprocessor to include a specified file name as the header file
+ # /TC process all source or unrecognized file types as C source files
+ # /TP process all source or unrecognized file types as C++ source files
+ # /Zs syntax check only
+ # /Wpch-messages enable diagnostics related to pre-compiled headers (requires Intel XE 2013 Update 2)
+ set (_sourceFileTypeC "/TC")
+ set (_sourceFileTypeCXX "/TP")
+ if (_flags)
+ # append to list
+ list (APPEND _flags /nologo "${_sourceFileType${_language}}"
+ "/Yc" "/Fp${_pchFileNative}" "/FI${_prefixFileNative}" /Zs "${_hostFileNative}")
+ if (NOT "${_compilerVersion}" VERSION_LESS "13.1.0")
+ list (APPEND _flags "/Wpch-messages")
+ endif()
+ else()
+ # return as a flag string
+ set (_flags "/Yc /Fp\"${_pchFileNative}\" /FI\"${_prefixFileNative}\"")
+ if (NOT "${_compilerVersion}" VERSION_LESS "13.1.0")
+ set (_flags "${_flags} /Wpch-messages")
+ endif()
+ endif()
+ else()
+ # Linux / Mac OS X Intel options used
+ # -pch-dir location for precompiled header files
+ # -pch-create name of the precompiled header (PCH) to create
+ # -Kc++ process all source or unrecognized file types as C++ source files
+ # -fsyntax-only check only for correct syntax
+ # -Wpch-messages enable diagnostics related to pre-compiled headers (requires Intel XE 2013 Update 2)
+ get_filename_component(_pchDir "${_pchFile}" PATH)
+ get_filename_component(_pchName "${_pchFile}" NAME)
+ set (_xLanguage_C "c-header")
+ set (_xLanguage_CXX "c++-header")
+ if (_flags)
+ # append to list
+ if ("${_language}" STREQUAL "CXX")
+ list (APPEND _flags -Kc++)
+ endif()
+ list (APPEND _flags "-include" "${_prefixFile}" "-pch-dir" "${_pchDir}" "-pch-create" "${_pchName}" "-fsyntax-only" "${_hostFile}")
+ if (NOT "${_compilerVersion}" VERSION_LESS "13.1.0")
+ list (APPEND _flags "-Wpch-messages")
+ endif()
+ else()
+ # return as a flag string
+ set (_flags "-include \"${_prefixFile}\" -pch-dir \"${_pchDir}\" -pch-create \"${_pchName}\"")
+ if (NOT "${_compilerVersion}" VERSION_LESS "13.1.0")
+ set (_flags "${_flags} -Wpch-messages")
+ endif()
+ endif()
+ endif()
+ else()
+ message (FATAL_ERROR "Unsupported ${_language} compiler ${_compilerID} version ${_compilerVersion}.")
+ endif()
+ set (${_flagsVar} ${_flags} PARENT_SCOPE)
+endfunction()
+
+function (cotire_add_pch_inclusion_flags _language _compilerID _compilerVersion _prefixFile _pchFile _flagsVar)
+ set (_flags ${${_flagsVar}})
+ if (_compilerID MATCHES "MSVC")
+ file (TO_NATIVE_PATH "${_prefixFile}" _prefixFileNative)
+ file (TO_NATIVE_PATH "${_pchFile}" _pchFileNative)
+ # cl.exe options used
+ # /Yu uses a precompiled header file during build
+ # /Fp specifies precompiled header binary file name
+ # /FI forces inclusion of file
+ if (_flags)
+ # append to list
+ list (APPEND _flags "/Yu${_prefixFileNative}" "/Fp${_pchFileNative}" "/FI${_prefixFileNative}")
+ else()
+ # return as a flag string
+ set (_flags "/Yu\"${_prefixFileNative}\" /Fp\"${_pchFileNative}\" /FI\"${_prefixFileNative}\"")
+ endif()
+ elseif (_compilerID MATCHES "GNU")
+ # GCC options used
+ # -include process include file as the first line of the primary source file
+ # -Winvalid-pch warns if precompiled header is found but cannot be used
+ if (_flags)
+ # append to list
+ list (APPEND _flags "-include" "${_prefixFile}" "-Winvalid-pch")
+ else()
+ # return as a flag string
+ set (_flags "-include \"${_prefixFile}\" -Winvalid-pch")
+ endif()
+ elseif (_compilerID MATCHES "Clang")
+ # Clang options used
+ # -include process include file as the first line of the primary source file
+ # -Qunused-arguments don't emit warning for unused driver arguments
+ if (_flags)
+ # append to list
+ list (APPEND _flags "-include" "${_prefixFile}" "-Qunused-arguments")
+ else()
+ # return as a flag string
+ set (_flags "-include \"${_prefixFile}\" -Qunused-arguments")
+ endif()
+ elseif (_compilerID MATCHES "Intel")
+ if (WIN32)
+ file (TO_NATIVE_PATH "${_prefixFile}" _prefixFileNative)
+ file (TO_NATIVE_PATH "${_pchFile}" _pchFileNative)
+ # Windows Intel options used
+ # /Yu use a precompiled header (PCH) file
+ # /Fp specify a path or file name for precompiled header files
+ # /FI tells the preprocessor to include a specified file name as the header file
+ # /Wpch-messages enable diagnostics related to pre-compiled headers (requires Intel XE 2013 Update 2)
+ if (_flags)
+ # append to list
+ list (APPEND _flags "/Yu" "/Fp${_pchFileNative}" "/FI${_prefixFileNative}")
+ if (NOT "${_compilerVersion}" VERSION_LESS "13.1.0")
+ list (APPEND _flags "/Wpch-messages")
+ endif()
+ else()
+ # return as a flag string
+ set (_flags "/Yu /Fp\"${_pchFileNative}\" /FI\"${_prefixFileNative}\"")
+ if (NOT "${_compilerVersion}" VERSION_LESS "13.1.0")
+ set (_flags "${_flags} /Wpch-messages")
+ endif()
+ endif()
+ else()
+ # Linux / Mac OS X Intel options used
+ # -pch-dir location for precompiled header files
+ # -pch-use name of the precompiled header (PCH) to use
+ # -include process include file as the first line of the primary source file
+ # -Wpch-messages enable diagnostics related to pre-compiled headers (requires Intel XE 2013 Update 2)
+ get_filename_component(_pchDir "${_pchFile}" PATH)
+ get_filename_component(_pchName "${_pchFile}" NAME)
+ if (_flags)
+ # append to list
+ list (APPEND _flags "-include" "${_prefixFile}" "-pch-dir" "${_pchDir}" "-pch-use" "${_pchName}")
+ if (NOT "${_compilerVersion}" VERSION_LESS "13.1.0")
+ list (APPEND _flags "-Wpch-messages")
+ endif()
+ else()
+ # return as a flag string
+ set (_flags "-include \"${_prefixFile}\" -pch-dir \"${_pchDir}\" -pch-use \"${_pchName}\"")
+ if (NOT "${_compilerVersion}" VERSION_LESS "13.1.0")
+ set (_flags "${_flags} -Wpch-messages")
+ endif()
+ endif()
+ endif()
+ else()
+ message (FATAL_ERROR "Unsupported ${_language} compiler ${_compilerID} version ${_compilerVersion}.")
+ endif()
+ set (${_flagsVar} ${_flags} PARENT_SCOPE)
+endfunction()
+
+function (cotire_precompile_prefix_header _prefixFile _pchFile _hostFile)
+ set(_options "")
+ set(_oneValueArgs COMPILER_EXECUTABLE COMPILER_ID COMPILER_VERSION LANGUAGE)
+ set(_multiValueArgs COMPILE_DEFINITIONS COMPILE_FLAGS INCLUDE_DIRECTORIES)
+ cmake_parse_arguments(_option "${_options}" "${_oneValueArgs}" "${_multiValueArgs}" ${ARGN})
+ if (NOT _option_LANGUAGE)
+ set (_option_LANGUAGE "CXX")
+ endif()
+ if (NOT _option_COMPILER_ID)
+ set (_option_COMPILER_ID "${CMAKE_${_option_LANGUAGE}_ID}")
+ endif()
+ cotire_init_compile_cmd(_cmd "${_option_LANGUAGE}" "${_option_COMPILER_EXECUTABLE}" "${_option_COMPILER_ARG1}")
+ cotire_add_definitions_to_cmd(_cmd "${_option_LANGUAGE}" ${_option_COMPILE_DEFINITIONS})
+ cotire_add_compile_flags_to_cmd(_cmd ${_option_COMPILE_FLAGS})
+ cotire_add_includes_to_cmd(_cmd "${_option_LANGUAGE}" ${_option_INCLUDE_DIRECTORIES})
+ cotire_add_pch_compilation_flags(
+ "${_option_LANGUAGE}" "${_option_COMPILER_ID}" "${_option_COMPILER_VERSION}"
+ "${_prefixFile}" "${_pchFile}" "${_hostFile}" _cmd)
+ if (COTIRE_VERBOSE)
+ message (STATUS "execute_process: ${_cmd}")
+ endif()
+ if (_option_COMPILER_ID MATCHES "MSVC")
+ if (COTIRE_DEBUG)
+ message (STATUS "clearing VS_UNICODE_OUTPUT")
+ endif()
+ # cl.exe messes with the output streams unless the environment variable VS_UNICODE_OUTPUT is cleared
+ unset (ENV{VS_UNICODE_OUTPUT})
+ endif()
+ execute_process(COMMAND ${_cmd} WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" RESULT_VARIABLE _result)
+ if (_result)
+ message (FATAL_ERROR "Error ${_result} precompiling ${_prefixFile}.")
+ endif()
+endfunction()
+
+function (cotire_check_precompiled_header_support _language _targetSourceDir _target _msgVar)
+ set (_unsupportedCompiler
+ "Precompiled headers not supported for ${_language} compiler ${CMAKE_${_language}_COMPILER_ID}")
+ if (CMAKE_${_language}_COMPILER_ID MATCHES "MSVC")
+ # supported since Visual Studio C++ 6.0
+ # and CMake does not support an earlier version
+ set (${_msgVar} "" PARENT_SCOPE)
+ elseif (CMAKE_${_language}_COMPILER_ID MATCHES "GNU")
+ # GCC PCH support requires version >= 3.4
+ cotire_determine_compiler_version("${_language}" COTIRE_${_language}_COMPILER)
+ if ("${COTIRE_${_language}_COMPILER_VERSION}" MATCHES ".+" AND
+ "${COTIRE_${_language}_COMPILER_VERSION}" VERSION_LESS "3.4.0")
+ set (${_msgVar} "${_unsupportedCompiler} version ${COTIRE_${_language}_COMPILER_VERSION}." PARENT_SCOPE)
+ else()
+ set (${_msgVar} "" PARENT_SCOPE)
+ endif()
+ elseif (CMAKE_${_language}_COMPILER_ID MATCHES "Clang")
+ # all Clang versions have PCH support
+ set (${_msgVar} "" PARENT_SCOPE)
+ elseif (CMAKE_${_language}_COMPILER_ID MATCHES "Intel")
+ # Intel PCH support requires version >= 8.0.0
+ cotire_determine_compiler_version("${_language}" COTIRE_${_language}_COMPILER)
+ if ("${COTIRE_${_language}_COMPILER_VERSION}" MATCHES ".+" AND
+ "${COTIRE_${_language}_COMPILER_VERSION}" VERSION_LESS "8.0.0")
+ set (${_msgVar} "${_unsupportedCompiler} version ${COTIRE_${_language}_COMPILER_VERSION}." PARENT_SCOPE)
+ else()
+ set (${_msgVar} "" PARENT_SCOPE)
+ endif()
+ else()
+ set (${_msgVar} "${_unsupportedCompiler}." PARENT_SCOPE)
+ endif()
+ if (APPLE)
+ # PCH compilation not supported by GCC / Clang for multi-architecture builds (e.g., i386, x86_64)
+ if (CMAKE_CONFIGURATION_TYPES)
+ set (_configs ${CMAKE_CONFIGURATION_TYPES})
+ elseif (CMAKE_BUILD_TYPE)
+ set (_configs ${CMAKE_BUILD_TYPE})
+ else()
+ set (_configs "None")
+ endif()
+ foreach (_config ${_configs})
+ set (_targetFlags "")
+ cotire_get_target_compile_flags("${_config}" "${_language}" "${_targetSourceDir}" "${_target}" _targetFlags)
+ cotire_filter_compile_flags("${_language}" "arch" _architectures _ignore ${_targetFlags})
+ list (LENGTH _architectures _numberOfArchitectures)
+ if (_numberOfArchitectures GREATER 1)
+ string (REPLACE ";" ", " _architectureStr "${_architectures}")
+ set (${_msgVar}
+ "Precompiled headers not supported on Darwin for multi-architecture builds (${_architectureStr})."
+ PARENT_SCOPE)
+ break()
+ endif()
+ endforeach()
+ endif()
+endfunction()
+
+macro (cotire_get_intermediate_dir _cotireDir)
+ get_filename_component(${_cotireDir} "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/${COTIRE_INTDIR}" ABSOLUTE)
+endmacro()
+
+macro (cotire_setup_file_extension_variables)
+ set (_unityFileExt_C ".c")
+ set (_unityFileExt_CXX ".cxx")
+ set (_prefixFileExt_C ".h")
+ set (_prefixFileExt_CXX ".hxx")
+endmacro()
+
+function (cotire_make_single_unity_source_file_path _language _target _unityFileVar)
+ cotire_setup_file_extension_variables()
+ if (NOT DEFINED _unityFileExt_${_language})
+ set (${_unityFileVar} "" PARENT_SCOPE)
+ return()
+ endif()
+ set (_unityFileBaseName "${_target}_${_language}${COTIRE_UNITY_SOURCE_FILENAME_SUFFIX}")
+ set (_unityFileName "${_unityFileBaseName}${_unityFileExt_${_language}}")
+ cotire_get_intermediate_dir(_baseDir)
+ set (_unityFile "${_baseDir}/${_unityFileName}")
+ set (${_unityFileVar} "${_unityFile}" PARENT_SCOPE)
+ if (COTIRE_DEBUG)
+ message(STATUS "${_unityFile}")
+ endif()
+endfunction()
+
+function (cotire_make_unity_source_file_paths _language _target _maxIncludes _unityFilesVar)
+ cotire_setup_file_extension_variables()
+ if (NOT DEFINED _unityFileExt_${_language})
+ set (${_unityFileVar} "" PARENT_SCOPE)
+ return()
+ endif()
+ set (_unityFileBaseName "${_target}_${_language}${COTIRE_UNITY_SOURCE_FILENAME_SUFFIX}")
+ cotire_get_intermediate_dir(_baseDir)
+ set (_startIndex 0)
+ set (_index 0)
+ set (_unityFiles "")
+ set (_sourceFiles ${ARGN})
+ foreach (_sourceFile ${_sourceFiles})
+ get_source_file_property(_startNew "${_sourceFile}" COTIRE_START_NEW_UNITY_SOURCE)
+ math (EXPR _unityFileCount "${_index} - ${_startIndex}")
+ if (_startNew OR (_maxIncludes GREATER 0 AND NOT _unityFileCount LESS _maxIncludes))
+ if (_index GREATER 0)
+ # start new unity file segment
+ math (EXPR _endIndex "${_index} - 1")
+ set (_unityFileName "${_unityFileBaseName}_${_startIndex}_${_endIndex}${_unityFileExt_${_language}}")
+ list (APPEND _unityFiles "${_baseDir}/${_unityFileName}")
+ endif()
+ set (_startIndex ${_index})
+ endif()
+ math (EXPR _index "${_index} + 1")
+ endforeach()
+ list (LENGTH _sourceFiles _numberOfSources)
+ if (_startIndex EQUAL 0)
+ # there is only a single unity file
+ cotire_make_single_unity_source_file_path(${_language} ${_target} _unityFiles)
+ elseif (_startIndex LESS _numberOfSources)
+ # end with final unity file segment
+ math (EXPR _endIndex "${_index} - 1")
+ set (_unityFileName "${_unityFileBaseName}_${_startIndex}_${_endIndex}${_unityFileExt_${_language}}")
+ list (APPEND _unityFiles "${_baseDir}/${_unityFileName}")
+ endif()
+ set (${_unityFilesVar} ${_unityFiles} PARENT_SCOPE)
+ if (COTIRE_DEBUG)
+ message(STATUS "${_unityFiles}")
+ endif()
+endfunction()
+
+function (cotire_unity_to_prefix_file_path _language _target _unityFile _prefixFileVar)
+ cotire_setup_file_extension_variables()
+ if (NOT DEFINED _unityFileExt_${_language})
+ set (${_prefixFileVar} "" PARENT_SCOPE)
+ return()
+ endif()
+ set (_unityFileBaseName "${_target}_${_language}${COTIRE_UNITY_SOURCE_FILENAME_SUFFIX}")
+ set (_prefixFileBaseName "${_target}_${_language}${COTIRE_PREFIX_HEADER_FILENAME_SUFFIX}")
+ string (REPLACE "${_unityFileBaseName}" "${_prefixFileBaseName}" _prefixFile "${_unityFile}")
+ string (REGEX REPLACE "${_unityFileExt_${_language}}$" "${_prefixFileExt_${_language}}" _prefixFile "${_prefixFile}")
+ set (${_prefixFileVar} "${_prefixFile}" PARENT_SCOPE)
+endfunction()
+
+function (cotire_make_prefix_file_name _language _target _prefixFileBaseNameVar _prefixFileNameVar)
+ cotire_setup_file_extension_variables()
+ if (NOT _language)
+ set (_prefixFileBaseName "${_target}${COTIRE_PREFIX_HEADER_FILENAME_SUFFIX}")
+ set (_prefixFileName "${_prefixFileBaseName}${_prefixFileExt_C}")
+ elseif (DEFINED _prefixFileExt_${_language})
+ set (_prefixFileBaseName "${_target}_${_language}${COTIRE_PREFIX_HEADER_FILENAME_SUFFIX}")
+ set (_prefixFileName "${_prefixFileBaseName}${_prefixFileExt_${_language}}")
+ else()
+ set (_prefixFileBaseName "")
+ set (_prefixFileName "")
+ endif()
+ set (${_prefixFileBaseNameVar} "${_prefixFileBaseName}" PARENT_SCOPE)
+ set (${_prefixFileNameVar} "${_prefixFileName}" PARENT_SCOPE)
+endfunction()
+
+function (cotire_make_prefix_file_path _language _target _prefixFileVar)
+ cotire_make_prefix_file_name("${_language}" "${_target}" _prefixFileBaseName _prefixFileName)
+ set (${_prefixFileVar} "" PARENT_SCOPE)
+ if (_prefixFileName)
+ if (NOT _language)
+ set (_language "C")
+ endif()
+ if (MSVC OR CMAKE_${_language}_COMPILER_ID MATCHES "GNU|Clang|Intel")
+ cotire_get_intermediate_dir(_baseDir)
+ set (${_prefixFileVar} "${_baseDir}/${_prefixFileName}" PARENT_SCOPE)
+ endif()
+ endif()
+endfunction()
+
+function (cotire_make_pch_file_path _language _targetSourceDir _target _pchFileVar)
+ cotire_make_prefix_file_name("${_language}" "${_target}" _prefixFileBaseName _prefixFileName)
+ set (${_pchFileVar} "" PARENT_SCOPE)
+ if (_prefixFileBaseName AND _prefixFileName)
+ cotire_check_precompiled_header_support("${_language}" "${_targetSourceDir}" "${_target}" _msg)
+ if (NOT _msg)
+ if (XCODE)
+ # For Xcode, we completely hand off the compilation of the prefix header to the IDE
+ return()
+ endif()
+ cotire_get_intermediate_dir(_baseDir)
+ if (CMAKE_${_language}_COMPILER_ID MATCHES "MSVC")
+ # MSVC uses the extension .pch added to the prefix header base name
+ set (${_pchFileVar} "${_baseDir}/${_prefixFileBaseName}.pch" PARENT_SCOPE)
+ elseif (CMAKE_${_language}_COMPILER_ID MATCHES "GNU|Clang")
+ # GCC / Clang look for a precompiled header corresponding to the prefix header with the extension .gch appended
+ set (${_pchFileVar} "${_baseDir}/${_prefixFileName}.gch" PARENT_SCOPE)
+ elseif (CMAKE_${_language}_COMPILER_ID MATCHES "Intel")
+ # Intel uses the extension .pchi added to the prefix header base name
+ set (${_pchFileVar} "${_baseDir}/${_prefixFileBaseName}.pchi" PARENT_SCOPE)
+ endif()
+ endif()
+ endif()
+endfunction()
+
+function (cotire_select_unity_source_files _unityFile _sourcesVar)
+ set (_sourceFiles ${ARGN})
+ if (_sourceFiles AND "${_unityFile}" MATCHES "${COTIRE_UNITY_SOURCE_FILENAME_SUFFIX}_([0-9]+)_([0-9]+)")
+ set (_startIndex ${CMAKE_MATCH_1})
+ set (_endIndex ${CMAKE_MATCH_2})
+ list (LENGTH _sourceFiles _numberOfSources)
+ if (NOT _startIndex LESS _numberOfSources)
+ math (EXPR _startIndex "${_numberOfSources} - 1")
+ endif()
+ if (NOT _endIndex LESS _numberOfSources)
+ math (EXPR _endIndex "${_numberOfSources} - 1")
+ endif()
+ set (_files "")
+ foreach (_index RANGE ${_startIndex} ${_endIndex})
+ list (GET _sourceFiles ${_index} _file)
+ list (APPEND _files "${_file}")
+ endforeach()
+ else()
+ set (_files ${_sourceFiles})
+ endif()
+ set (${_sourcesVar} ${_files} PARENT_SCOPE)
+endfunction()
+
+function (cotire_get_unity_source_dependencies _language _target _dependencySourcesVar)
+ set (_dependencySources "")
+ # depend on target's generated source files
+ cotire_get_objects_with_property_on(_generatedSources GENERATED SOURCE ${ARGN})
+ if (_generatedSources)
+ # but omit all generated source files that have the COTIRE_EXCLUDED property set to true
+ cotire_get_objects_with_property_on(_excludedGeneratedSources COTIRE_EXCLUDED SOURCE ${_generatedSources})
+ if (_excludedGeneratedSources)
+ list (REMOVE_ITEM _generatedSources ${_excludedGeneratedSources})
+ endif()
+ # and omit all generated source files that have the COTIRE_DEPENDENCY property set to false explicitly
+ cotire_get_objects_with_property_off(_excludedNonDependencySources COTIRE_DEPENDENCY SOURCE ${_generatedSources})
+ if (_excludedNonDependencySources)
+ list (REMOVE_ITEM _generatedSources ${_excludedNonDependencySources})
+ endif()
+ if (_generatedSources)
+ list (APPEND _dependencySources ${_generatedSources})
+ endif()
+ endif()
+ if (COTIRE_DEBUG AND _dependencySources)
+ message (STATUS "${_language} ${_target} unity source depends on ${_dependencySources}")
+ endif()
+ set (${_dependencySourcesVar} ${_dependencySources} PARENT_SCOPE)
+endfunction()
+
+function (cotire_get_prefix_header_dependencies _language _target _dependencySourcesVar)
+ # depend on target source files marked with custom COTIRE_DEPENDENCY property
+ set (_dependencySources "")
+ cotire_get_objects_with_property_on(_dependencySources COTIRE_DEPENDENCY SOURCE ${ARGN})
+ if (COTIRE_DEBUG AND _dependencySources)
+ message (STATUS "${_language} ${_target} prefix header DEPENDS ${_dependencySources}")
+ endif()
+ set (${_dependencySourcesVar} ${_dependencySources} PARENT_SCOPE)
+endfunction()
+
+function (cotire_generate_target_script _language _configurations _targetSourceDir _targetBinaryDir _target _targetScriptVar)
+ set (COTIRE_TARGET_SOURCES ${ARGN})
+ get_filename_component(_moduleName "${COTIRE_CMAKE_MODULE_FILE}" NAME)
+ set (_targetCotireScript "${CMAKE_CURRENT_BINARY_DIR}/${_target}_${_language}_${_moduleName}")
+ cotire_get_prefix_header_dependencies(${_language} ${_target} COTIRE_TARGET_PREFIX_DEPENDS ${COTIRE_TARGET_SOURCES})
+ cotire_get_unity_source_dependencies(${_language} ${_target} COTIRE_TARGET_UNITY_DEPENDS ${COTIRE_TARGET_SOURCES})
+ # set up variables to be configured
+ set (COTIRE_TARGET_LANGUAGE "${_language}")
+ cotire_determine_compiler_version("${COTIRE_TARGET_LANGUAGE}" COTIRE_${_language}_COMPILER)
+ get_target_property(COTIRE_TARGET_IGNORE_PATH ${_target} COTIRE_PREFIX_HEADER_IGNORE_PATH)
+ cotire_add_sys_root_paths(COTIRE_TARGET_IGNORE_PATH)
+ get_target_property(COTIRE_TARGET_INCLUDE_PATH ${_target} COTIRE_PREFIX_HEADER_INCLUDE_PATH)
+ cotire_add_sys_root_paths(COTIRE_TARGET_INCLUDE_PATH)
+ get_target_property(COTIRE_TARGET_PRE_UNDEFS ${_target} COTIRE_UNITY_SOURCE_PRE_UNDEFS)
+ get_target_property(COTIRE_TARGET_POST_UNDEFS ${_target} COTIRE_UNITY_SOURCE_POST_UNDEFS)
+ get_target_property(COTIRE_TARGET_MAXIMUM_NUMBER_OF_INCLUDES ${_target} COTIRE_UNITY_SOURCE_MAXIMUM_NUMBER_OF_INCLUDES)
+ cotire_get_source_files_undefs(COTIRE_UNITY_SOURCE_PRE_UNDEFS COTIRE_TARGET_SOURCES_PRE_UNDEFS ${COTIRE_TARGET_SOURCES})
+ cotire_get_source_files_undefs(COTIRE_UNITY_SOURCE_POST_UNDEFS COTIRE_TARGET_SOURCES_POST_UNDEFS ${COTIRE_TARGET_SOURCES})
+ set (COTIRE_TARGET_CONFIGURATION_TYPES "${_configurations}")
+ foreach (_config ${_configurations})
+ string (TOUPPER "${_config}" _upperConfig)
+ cotire_get_target_include_directories(
+ "${_config}" "${_language}" "${_targetSourceDir}" "${_targetBinaryDir}" "${_target}" COTIRE_TARGET_INCLUDE_DIRECTORIES_${_upperConfig})
+ cotire_get_target_compile_definitions(
+ "${_config}" "${_language}" "${_targetSourceDir}" "${_target}" COTIRE_TARGET_COMPILE_DEFINITIONS_${_upperConfig})
+ cotire_get_target_compiler_flags(
+ "${_config}" "${_language}" "${_targetSourceDir}" "${_target}" COTIRE_TARGET_COMPILE_FLAGS_${_upperConfig})
+ cotire_get_source_files_compile_definitions(
+ "${_config}" "${_language}" COTIRE_TARGET_SOURCES_COMPILE_DEFINITIONS_${_upperConfig} ${COTIRE_TARGET_SOURCES})
+ endforeach()
+ get_cmake_property(_vars VARIABLES)
+ string (REGEX MATCHALL "COTIRE_[A-Za-z0-9_]+" _matchVars "${_vars}")
+ # remove COTIRE_VERBOSE which is passed as a CMake define on command line
+ list (REMOVE_ITEM _matchVars COTIRE_VERBOSE)
+ set (_contents "")
+ foreach (_var IN LISTS _matchVars ITEMS
+ MSVC CMAKE_GENERATOR CMAKE_BUILD_TYPE CMAKE_CONFIGURATION_TYPES
+ CMAKE_${_language}_COMPILER_ID CMAKE_${_language}_COMPILER CMAKE_${_language}_COMPILER_ARG1
+ CMAKE_${_language}_SOURCE_FILE_EXTENSIONS)
+ if (DEFINED ${_var})
+ string (REPLACE "\"" "\\\"" _value "${${_var}}")
+ set (_contents "${_contents}set (${_var} \"${_value}\")\n")
+ endif()
+ endforeach()
+ cotire_write_file("CMAKE" "${_targetCotireScript}" "${_contents}" FALSE)
+ set (${_targetScriptVar} "${_targetCotireScript}" PARENT_SCOPE)
+endfunction()
+
+function (cotire_setup_pch_file_compilation _language _targetBinaryDir _targetScript _prefixFile _pchFile)
+ set (_sourceFiles ${ARGN})
+ if (CMAKE_${_language}_COMPILER_ID MATCHES "MSVC|Intel")
+ # for Visual Studio and Intel, we attach the precompiled header compilation to the first source file
+ # the remaining files include the precompiled header, see cotire_setup_prefix_file_inclusion
+ if (_sourceFiles)
+ file (TO_NATIVE_PATH "${_prefixFile}" _prefixFileNative)
+ file (TO_NATIVE_PATH "${_pchFile}" _pchFileNative)
+ list (GET _sourceFiles 0 _hostFile)
+ set (_flags "")
+ cotire_determine_compiler_version("${_language}" COTIRE_${_language}_COMPILER)
+ cotire_add_pch_compilation_flags(
+ "${_language}" "${CMAKE_${_language}_COMPILER_ID}" "${COTIRE_${_language}_COMPILER_VERSION}"
+ "${_prefixFile}" "${_pchFile}" "${_hostFile}" _flags)
+ set_property (SOURCE ${_hostFile} APPEND_STRING PROPERTY COMPILE_FLAGS " ${_flags} ")
+ set_property (SOURCE ${_hostFile} APPEND PROPERTY OBJECT_OUTPUTS "${_pchFile}")
+ # make first source file depend on prefix header
+ set_property (SOURCE ${_hostFile} APPEND PROPERTY OBJECT_DEPENDS "${_prefixFile}")
+ endif()
+ elseif ("${CMAKE_GENERATOR}" MATCHES "Makefiles|Ninja")
+ # for makefile based generator, we add a custom command to precompile the prefix header
+ if (_targetScript)
+ cotire_set_cmd_to_prologue(_cmds)
+ list (GET _sourceFiles 0 _hostFile)
+ list (APPEND _cmds -P "${COTIRE_CMAKE_MODULE_FILE}" "precompile" "${_targetScript}" "${_prefixFile}" "${_pchFile}" "${_hostFile}")
+ file (RELATIVE_PATH _pchFileRelPath "${CMAKE_BINARY_DIR}" "${_pchFile}")
+ if (COTIRE_DEBUG)
+ message (STATUS "add_custom_command: OUTPUT ${_pchFile} ${_cmds} DEPENDS ${_prefixFile} IMPLICIT_DEPENDS ${_language} ${_prefixFile}")
+ endif()
+ set_property (SOURCE "${_pchFile}" PROPERTY GENERATED TRUE)
+ add_custom_command(OUTPUT "${_pchFile}"
+ COMMAND ${_cmds}
+ DEPENDS "${_prefixFile}"
+ IMPLICIT_DEPENDS ${_language} "${_prefixFile}"
+ WORKING_DIRECTORY "${_targetSourceDir}"
+ COMMENT "Building ${_language} precompiled header ${_pchFileRelPath}" VERBATIM)
+ endif()
+ endif()
+endfunction()
+
+function (cotire_setup_prefix_file_inclusion _language _target _wholeTarget _prefixFile _pchFile)
+ set (_sourceFiles ${ARGN})
+ if (CMAKE_${_language}_COMPILER_ID MATCHES "MSVC|Intel")
+ # for Visual Studio and Intel, we include the precompiled header in all but the first source file
+ # the first source file does the precompiled header compilation, see cotire_setup_pch_file_compilation
+ list (LENGTH _sourceFiles _numberOfSourceFiles)
+ if (_numberOfSourceFiles GREATER 1)
+ # mark sources as cotired to prevent them from being used in another cotired target
+ set_source_files_properties(${_sourceFiles} PROPERTIES COTIRE_TARGET "${_target}")
+ list (REMOVE_AT _sourceFiles 0)
+ set (_flags "")
+ cotire_determine_compiler_version("${_language}" COTIRE_${_language}_COMPILER)
+ cotire_add_pch_inclusion_flags(
+ "${_language}" "${CMAKE_${_language}_COMPILER_ID}" "${COTIRE_${_language}_COMPILER_VERSION}"
+ "${_prefixFile}" "${_pchFile}" _flags)
+ set_property (SOURCE ${_sourceFiles} APPEND_STRING PROPERTY COMPILE_FLAGS " ${_flags} ")
+ # make source files depend on precompiled header
+ set_property (SOURCE ${_sourceFiles} APPEND PROPERTY OBJECT_DEPENDS "${_pchFile}")
+ endif()
+ elseif ("${CMAKE_GENERATOR}" MATCHES "Makefiles|Ninja")
+ if (NOT _wholeTarget)
+ # for makefile based generator, we force the inclusion of the prefix header for a subset
+ # of the source files, if this is a multi-language target or has excluded files
+ set (_flags "")
+ cotire_determine_compiler_version("${_language}" COTIRE_${_language}_COMPILER)
+ cotire_add_pch_inclusion_flags(
+ "${_language}" "${CMAKE_${_language}_COMPILER_ID}" "${COTIRE_${_language}_COMPILER_VERSION}"
+ "${_prefixFile}" "${_pchFile}" _flags)
+ set_property (SOURCE ${_sourceFiles} APPEND_STRING PROPERTY COMPILE_FLAGS " ${_flags} ")
+ # mark sources as cotired to prevent them from being used in another cotired target
+ set_source_files_properties(${_sourceFiles} PROPERTIES COTIRE_TARGET "${_target}")
+ endif()
+ # make source files depend on precompiled header
+ set_property (SOURCE ${_sourceFiles} APPEND PROPERTY OBJECT_DEPENDS "${_pchFile}")
+ endif()
+endfunction()
+
+function (cotire_get_first_set_property_value _propertyValueVar _type _object)
+ set (_properties ${ARGN})
+ foreach (_property ${_properties})
+ get_property(_propertyValue ${_type} "${_object}" PROPERTY ${_property})
+ if (_propertyValue)
+ set (${_propertyValueVar} ${_propertyValue} PARENT_SCOPE)
+ return()
+ endif()
+ endforeach()
+ set (${_propertyValueVar} "" PARENT_SCOPE)
+endfunction()
+
+function (cotire_setup_combine_command _language _sourceDir _targetScript _joinedFile _cmdsVar)
+ set (_files ${ARGN})
+ set (_filesPaths "")
+ foreach (_file ${_files})
+ if (IS_ABSOLUTE "${_file}")
+ set (_filePath "${_file}")
+ else()
+ get_filename_component(_filePath "${_sourceDir}/${_file}" ABSOLUTE)
+ endif()
+ file (RELATIVE_PATH _fileRelPath "${_sourceDir}" "${_filePath}")
+ if (NOT IS_ABSOLUTE "${_fileRelPath}" AND NOT "${_fileRelPath}" MATCHES "^\\.\\.")
+ list (APPEND _filesPaths "${_fileRelPath}")
+ else()
+ list (APPEND _filesPaths "${_filePath}")
+ endif()
+ endforeach()
+ cotire_set_cmd_to_prologue(_prefixCmd)
+ list (APPEND _prefixCmd -P "${COTIRE_CMAKE_MODULE_FILE}" "combine")
+ if (_targetScript)
+ list (APPEND _prefixCmd "${_targetScript}")
+ endif()
+ list (APPEND _prefixCmd "${_joinedFile}" ${_filesPaths})
+ if (COTIRE_DEBUG)
+ message (STATUS "add_custom_command: OUTPUT ${_joinedFile} COMMAND ${_prefixCmd} DEPENDS ${_files}")
+ endif()
+ set_property (SOURCE "${_joinedFile}" PROPERTY GENERATED TRUE)
+ file (RELATIVE_PATH _joinedFileRelPath "${CMAKE_BINARY_DIR}" "${_joinedFile}")
+ get_filename_component(_joinedFileName "${_joinedFileRelPath}" NAME_WE)
+ if (_language AND _joinedFileName MATCHES "${COTIRE_UNITY_SOURCE_FILENAME_SUFFIX}$")
+ set (_comment "Generating ${_language} unity source ${_joinedFileRelPath}")
+ elseif (_language AND _joinedFileName MATCHES "${COTIRE_UNITY_SOURCE_FILENAME_SUFFIX}$")
+ set (_comment "Generating ${_language} prefix header ${_joinedFileRelPath}")
+ else()
+ set (_comment "Generating ${_joinedFileRelPath}")
+ endif()
+ add_custom_command(
+ OUTPUT "${_joinedFile}"
+ COMMAND ${_prefixCmd}
+ DEPENDS ${_files}
+ COMMENT "${_comment}"
+ WORKING_DIRECTORY "${_sourceDir}" VERBATIM)
+ list (APPEND ${_cmdsVar} COMMAND ${_prefixCmd})
+ set (${_cmdsVar} ${${_cmdsVar}} PARENT_SCOPE)
+endfunction()
+
+function (cotire_setup_target_pch_usage _languages _targetSourceDir _target _wholeTarget)
+ if (XCODE)
+ # for Xcode, we attach a pre-build action to generate the unity sources and prefix headers
+ # if necessary, we also generate a single prefix header which includes all language specific prefix headers
+ set (_prefixFiles "")
+ foreach (_language ${_languages})
+ get_property(_prefixFile TARGET ${_target} PROPERTY COTIRE_${_language}_PREFIX_HEADER)
+ if (_prefixFile)
+ list (APPEND _prefixFiles "${_prefixFile}")
+ endif()
+ endforeach()
+ set (_cmds ${ARGN})
+ list (LENGTH _prefixFiles _numberOfPrefixFiles)
+ if (_numberOfPrefixFiles GREATER 1)
+ cotire_make_prefix_file_path("" ${_target} _prefixHeader)
+ cotire_setup_combine_command("" "${_targetSourceDir}" "" "${_prefixHeader}" _cmds ${_prefixFiles})
+ else()
+ set (_prefixHeader "${_prefixFiles}")
+ endif()
+ if (COTIRE_DEBUG)
+ message (STATUS "add_custom_command: TARGET ${_target} PRE_BUILD ${_cmds}")
+ endif()
+ add_custom_command(TARGET "${_target}"
+ PRE_BUILD ${_cmds}
+ WORKING_DIRECTORY "${_targetSourceDir}"
+ COMMENT "Updating target ${_target} prefix headers" VERBATIM)
+ # make Xcode precompile the generated prefix header with ProcessPCH and ProcessPCH++
+ set_target_properties(${_target} PROPERTIES XCODE_ATTRIBUTE_GCC_PRECOMPILE_PREFIX_HEADER "YES")
+ set_target_properties(${_target} PROPERTIES XCODE_ATTRIBUTE_GCC_PREFIX_HEADER "${_prefixHeader}")
+ elseif ("${CMAKE_GENERATOR}" MATCHES "Makefiles|Ninja")
+ # for makefile based generator, we force inclusion of the prefix header for all target source files
+ # if this is a single-language target without any excluded files
+ if (_wholeTarget)
+ set (_language "${_languages}")
+ # for Visual Studio and Intel, precompiled header inclusion is always done on the source file level
+ # see cotire_setup_prefix_file_inclusion
+ if (NOT CMAKE_${_language}_COMPILER_ID MATCHES "MSVC|Intel")
+ get_property(_prefixFile TARGET ${_target} PROPERTY COTIRE_${_language}_PREFIX_HEADER)
+ get_property(_pchFile TARGET ${_target} PROPERTY COTIRE_${_language}_PRECOMPILED_HEADER)
+ set (_flags "")
+ cotire_determine_compiler_version("${_language}" COTIRE_${_language}_COMPILER)
+ cotire_add_pch_inclusion_flags(
+ "${_language}" "${CMAKE_${_language}_COMPILER_ID}" "${COTIRE_${_language}_COMPILER_VERSION}"
+ "${_prefixFile}" "${_pchFile}" _flags)
+ set_property (TARGET ${_target} APPEND_STRING PROPERTY COMPILE_FLAGS " ${_flags} ")
+ endif()
+ endif()
+ endif()
+endfunction()
+
+function (cotire_setup_unity_generation_commands _language _targetSourceDir _target _targetScript _unityFiles _cmdsVar)
+ set (_dependencySources "")
+ cotire_get_unity_source_dependencies(${_language} ${_target} _dependencySources ${ARGN})
+ foreach (_unityFile ${_unityFiles})
+ file (RELATIVE_PATH _unityFileRelPath "${CMAKE_BINARY_DIR}" "${_unityFile}")
+ set_property (SOURCE "${_unityFile}" PROPERTY GENERATED TRUE)
+ # set up compiled unity source dependencies
+ # this ensures that missing source files are generated before the unity file is compiled
+ if (COTIRE_DEBUG AND _dependencySources)
+ message (STATUS "${_unityFile} OBJECT_DEPENDS ${_dependencySources}")
+ endif()
+ if (_dependencySources)
+ set_property (SOURCE "${_unityFile}" PROPERTY OBJECT_DEPENDS ${_dependencySources})
+ endif()
+ if (WIN32 AND CMAKE_${_language}_COMPILER_ID MATCHES "MSVC|Intel")
+ # unity file compilation results in potentially huge object file, thus use /bigobj by default unter MSVC and Windows Intel
+ set_property (SOURCE "${_unityFile}" APPEND_STRING PROPERTY COMPILE_FLAGS "/bigobj")
+ endif()
+ cotire_set_cmd_to_prologue(_unityCmd)
+ list (APPEND _unityCmd -P "${COTIRE_CMAKE_MODULE_FILE}" "unity" "${_targetScript}" "${_unityFile}")
+ if (COTIRE_DEBUG)
+ message (STATUS "add_custom_command: OUTPUT ${_unityFile} COMMAND ${_unityCmd} DEPENDS ${_targetScript}")
+ endif()
+ add_custom_command(
+ OUTPUT "${_unityFile}"
+ COMMAND ${_unityCmd}
+ DEPENDS "${_targetScript}"
+ COMMENT "Generating ${_language} unity source ${_unityFileRelPath}"
+ WORKING_DIRECTORY "${_targetSourceDir}" VERBATIM)
+ list (APPEND ${_cmdsVar} COMMAND ${_unityCmd})
+ endforeach()
+ list (LENGTH _unityFiles _numberOfUnityFiles)
+ if (_numberOfUnityFiles GREATER 1)
+ # create a joint unity file from all unity file segments
+ cotire_make_single_unity_source_file_path(${_language} ${_target} _unityFile)
+ cotire_setup_combine_command(${_language} "${_targetSourceDir}" "${_targetScript}" "${_unityFile}" ${_cmdsVar} ${_unityFiles})
+ endif()
+ set (${_cmdsVar} ${${_cmdsVar}} PARENT_SCOPE)
+endfunction()
+
+function (cotire_setup_single_prefix_generation_command _language _target _targetSourceDir _targetScript _prefixFile _unityFile _cmdsVar)
+ set (_sourceFiles ${ARGN})
+ set (_dependencySources "")
+ cotire_get_prefix_header_dependencies(${_language} ${_target} _dependencySources ${_sourceFiles})
+ cotire_set_cmd_to_prologue(_prefixCmd)
+ list (APPEND _prefixCmd -P "${COTIRE_CMAKE_MODULE_FILE}" "prefix" "${_targetScript}" "${_prefixFile}" "${_unityFile}")
+ set_property (SOURCE "${_prefixFile}" PROPERTY GENERATED TRUE)
+ if (COTIRE_DEBUG)
+ message (STATUS "add_custom_command: OUTPUT ${_prefixFile} COMMAND ${_prefixCmd} DEPENDS ${_targetScript} ${_unityFile} ${_dependencySources}")
+ endif()
+ file (RELATIVE_PATH _prefixFileRelPath "${CMAKE_BINARY_DIR}" "${_prefixFile}")
+ add_custom_command(
+ OUTPUT "${_prefixFile}" "${_prefixFile}.log"
+ COMMAND ${_prefixCmd}
+ DEPENDS "${_targetScript}" "${_unityFile}" ${_dependencySources}
+ COMMENT "Generating ${_language} prefix header ${_prefixFileRelPath}"
+ WORKING_DIRECTORY "${CMAKE_BINARY_DIR}" VERBATIM)
+ list (APPEND ${_cmdsVar} COMMAND ${_prefixCmd})
+ set (${_cmdsVar} ${${_cmdsVar}} PARENT_SCOPE)
+endfunction()
+
+function (cotire_setup_multi_prefix_generation_command _language _target _targetSourceDir _targetScript _prefixFile _unityFiles _cmdsVar)
+ set (_sourceFiles ${ARGN})
+ list (LENGTH _unityFiles _numberOfUnityFiles)
+ if (_numberOfUnityFiles GREATER 1)
+ cotire_make_single_unity_source_file_path(${_language} ${_target} _unityFile)
+ cotire_setup_single_prefix_generation_command(
+ ${_language} ${_target} "${_targetSourceDir}" "${_targetScript}"
+ "${_prefixFile}" "${_unityFile}" ${_cmdsVar} ${_sourceFiles})
+ else()
+ cotire_setup_single_prefix_generation_command(
+ ${_language} ${_target} "${_targetSourceDir}" "${_targetScript}"
+ "${_prefixFile}" "${_unityFiles}" ${_cmdsVar} ${_sourceFiles})
+ endif()
+ set (${_cmdsVar} ${${_cmdsVar}} PARENT_SCOPE)
+endfunction()
+
+function (cotire_init_cotire_target_properties _target)
+ get_property(_isSet TARGET ${_target} PROPERTY COTIRE_ENABLE_PRECOMPILED_HEADER SET)
+ if (NOT _isSet)
+ set_property(TARGET ${_target} PROPERTY COTIRE_ENABLE_PRECOMPILED_HEADER TRUE)
+ endif()
+ get_property(_isSet TARGET ${_target} PROPERTY COTIRE_ADD_UNITY_BUILD SET)
+ if (NOT _isSet)
+ set_property(TARGET ${_target} PROPERTY COTIRE_ADD_UNITY_BUILD TRUE)
+ endif()
+ get_property(_isSet TARGET ${_target} PROPERTY COTIRE_ADD_CLEAN SET)
+ if (NOT _isSet)
+ set_property(TARGET ${_target} PROPERTY COTIRE_ADD_CLEAN FALSE)
+ endif()
+ get_property(_isSet TARGET ${_target} PROPERTY COTIRE_PREFIX_HEADER_IGNORE_PATH SET)
+ if (NOT _isSet)
+ set_property(TARGET ${_target} PROPERTY COTIRE_PREFIX_HEADER_IGNORE_PATH "${CMAKE_SOURCE_DIR}")
+ cotire_check_is_path_relative_to("${CMAKE_BINARY_DIR}" _isRelative "${CMAKE_SOURCE_DIR}")
+ if (NOT _isRelative)
+ set_property(TARGET ${_target} APPEND PROPERTY COTIRE_PREFIX_HEADER_IGNORE_PATH "${CMAKE_BINARY_DIR}")
+ endif()
+ endif()
+ get_property(_isSet TARGET ${_target} PROPERTY COTIRE_PREFIX_HEADER_INCLUDE_PATH SET)
+ if (NOT _isSet)
+ set_property(TARGET ${_target} PROPERTY COTIRE_PREFIX_HEADER_INCLUDE_PATH "")
+ endif()
+ get_property(_isSet TARGET ${_target} PROPERTY COTIRE_UNITY_SOURCE_PRE_UNDEFS SET)
+ if (NOT _isSet)
+ set_property(TARGET ${_target} PROPERTY COTIRE_UNITY_SOURCE_PRE_UNDEFS "")
+ endif()
+ get_property(_isSet TARGET ${_target} PROPERTY COTIRE_UNITY_SOURCE_POST_UNDEFS SET)
+ if (NOT _isSet)
+ set_property(TARGET ${_target} PROPERTY COTIRE_UNITY_SOURCE_POST_UNDEFS "")
+ endif()
+ get_property(_isSet TARGET ${_target} PROPERTY COTIRE_UNITY_SOURCE_MAXIMUM_NUMBER_OF_INCLUDES SET)
+ if (NOT _isSet)
+ if (COTIRE_MAXIMUM_NUMBER_OF_UNITY_INCLUDES)
+ set_property(TARGET ${_target} PROPERTY COTIRE_UNITY_SOURCE_MAXIMUM_NUMBER_OF_INCLUDES "${COTIRE_MAXIMUM_NUMBER_OF_UNITY_INCLUDES}")
+ else()
+ set_property(TARGET ${_target} PROPERTY COTIRE_UNITY_SOURCE_MAXIMUM_NUMBER_OF_INCLUDES "")
+ endif()
+ endif()
+endfunction()
+
+function (cotire_make_target_message _target _languages _disableMsg _targetMsgVar)
+ get_target_property(_targetUsePCH ${_target} COTIRE_ENABLE_PRECOMPILED_HEADER)
+ get_target_property(_targetAddSCU ${_target} COTIRE_ADD_UNITY_BUILD)
+ string (REPLACE ";" " " _languagesStr "${_languages}")
+ string (REPLACE ";" ", " _excludedStr "${ARGN}")
+ set (_targetMsg "")
+ if (NOT _languages)
+ set (_targetMsg "Target ${_target} cannot be cotired.")
+ if (_disableMsg)
+ set (_targetMsg "${_targetMsg} ${_disableMsg}")
+ endif()
+ elseif (NOT _targetUsePCH AND NOT _targetAddSCU)
+ set (_targetMsg "${_languagesStr} target ${_target} cotired without unity build and precompiled header.")
+ if (_disableMsg)
+ set (_targetMsg "${_targetMsg} ${_disableMsg}")
+ endif()
+ elseif (NOT _targetUsePCH)
+ if (_allExcludedSourceFiles)
+ set (_targetMsg "${_languagesStr} target ${_target} cotired excluding files ${_excludedStr} without precompiled header.")
+ else()
+ set (_targetMsg "${_languagesStr} target ${_target} cotired without precompiled header.")
+ endif()
+ if (_disableMsg)
+ set (_targetMsg "${_targetMsg} ${_disableMsg}")
+ endif()
+ elseif (NOT _targetAddSCU)
+ if (_allExcludedSourceFiles)
+ set (_targetMsg "${_languagesStr} target ${_target} cotired excluding files ${_excludedStr} without unity build.")
+ else()
+ set (_targetMsg "${_languagesStr} target ${_target} cotired without unity build.")
+ endif()
+ else()
+ if (_allExcludedSourceFiles)
+ set (_targetMsg "${_languagesStr} target ${_target} cotired excluding files ${_excludedStr}.")
+ else()
+ set (_targetMsg "${_languagesStr} target ${_target} cotired.")
+ endif()
+ endif()
+ set (${_targetMsgVar} "${_targetMsg}" PARENT_SCOPE)
+endfunction()
+
+function (cotire_choose_target_languages _targetSourceDir _target _targetLanguagesVar)
+ set (_languages ${ARGN})
+ set (_allSourceFiles "")
+ set (_allExcludedSourceFiles "")
+ set (_allCotiredSourceFiles "")
+ set (_targetLanguages "")
+ get_target_property(_targetType ${_target} TYPE)
+ get_target_property(_targetSourceFiles ${_target} SOURCES)
+ get_target_property(_targetUsePCH ${_target} COTIRE_ENABLE_PRECOMPILED_HEADER)
+ get_target_property(_targetAddSCU ${_target} COTIRE_ADD_UNITY_BUILD)
+ set (_disableMsg "")
+ foreach (_language ${_languages})
+ get_target_property(_prefixHeader ${_target} COTIRE_${_language}_PREFIX_HEADER)
+ get_target_property(_unityBuildFile ${_target} COTIRE_${_language}_UNITY_SOURCE)
+ if (_prefixHeader OR _unityBuildFile)
+ message (WARNING "Target ${_target} has already been cotired.")
+ set (${_targetLanguagesVar} "" PARENT_SCOPE)
+ return()
+ endif()
+ if (_targetUsePCH AND "${_language}" STREQUAL "C" OR "${_language}" STREQUAL "CXX")
+ cotire_check_precompiled_header_support("${_language}" "${_targetSourceDir}" "${_target}" _disableMsg)
+ if (_disableMsg)
+ set (_targetUsePCH FALSE)
+ endif()
+ endif()
+ set (_sourceFiles "")
+ set (_excludedSources "")
+ set (_cotiredSources "")
+ cotire_filter_language_source_files(${_language} _sourceFiles _excludedSources _cotiredSources ${_targetSourceFiles})
+ if (_sourceFiles OR _excludedSources OR _cotiredSources)
+ list (APPEND _targetLanguages ${_language})
+ endif()
+ if (_sourceFiles)
+ list (APPEND _allSourceFiles ${_sourceFiles})
+ endif()
+ if (_excludedSources)
+ list (APPEND _allExcludedSourceFiles ${_excludedSources})
+ endif()
+ if (_cotiredSources)
+ list (APPEND _allCotiredSourceFiles ${_cotiredSources})
+ endif()
+ endforeach()
+ set (_targetMsgLevel STATUS)
+ if (NOT _targetLanguages)
+ string (REPLACE ";" " or " _languagesStr "${_languages}")
+ set (_disableMsg "No ${_languagesStr} source files.")
+ set (_targetUsePCH FALSE)
+ set (_targetAddSCU FALSE)
+ endif()
+ if (_targetUsePCH)
+ list (LENGTH _allSourceFiles _numberOfSources)
+ if (_numberOfSources LESS ${COTIRE_MINIMUM_NUMBER_OF_TARGET_SOURCES})
+ set (_disableMsg "Too few applicable sources.")
+ set (_targetUsePCH FALSE)
+ elseif (_allCotiredSourceFiles)
+ cotire_get_source_file_property_values(_cotireTargets COTIRE_TARGET ${_allCotiredSourceFiles})
+ list (REMOVE_DUPLICATES _cotireTargets)
+ string (REPLACE ";" ", " _cotireTargetsStr "${_cotireTargets}")
+ set (_disableMsg "Target sources already include a precompiled header for target(s) ${_cotireTargets}.")
+ set (_disableMsg "${_disableMsg} Set target property COTIRE_ENABLE_PRECOMPILED_HEADER to FALSE for targets ${_target},")
+ set (_disableMsg "${_disableMsg} ${_cotireTargetsStr} to get a workable build system.")
+ set (_targetMsgLevel SEND_ERROR)
+ set (_targetUsePCH FALSE)
+ elseif (XCODE AND _allExcludedSourceFiles)
+ # for Xcode, we cannot apply the precompiled header to individual sources, only to the whole target
+ set (_disableMsg "Exclusion of source files not supported for generator Xcode.")
+ set (_targetUsePCH FALSE)
+ elseif (XCODE AND "${_targetType}" STREQUAL "OBJECT_LIBRARY")
+ # for Xcode, we cannot apply the required PRE_BUILD action to generate the prefix header to an OBJECT_LIBRARY target
+ set (_disableMsg "Required PRE_BUILD action not supported for OBJECT_LIBRARY targets for generator Xcode.")
+ set (_targetUsePCH FALSE)
+ endif()
+ endif()
+ set_property(TARGET ${_target} PROPERTY COTIRE_ENABLE_PRECOMPILED_HEADER ${_targetUsePCH})
+ set_property(TARGET ${_target} PROPERTY COTIRE_ADD_UNITY_BUILD ${_targetAddSCU})
+ cotire_make_target_message(${_target} "${_targetLanguages}" "${_disableMsg}" _targetMsg ${_allExcludedSourceFiles})
+ if (_targetMsg)
+ if (NOT DEFINED COTIREMSG_${_target})
+ set (COTIREMSG_${_target} "")
+ endif()
+ if (COTIRE_VERBOSE OR NOT "${_targetMsgLevel}" STREQUAL "STATUS" OR
+ NOT "${COTIREMSG_${_target}}" STREQUAL "${_targetMsg}")
+ # cache message to avoid redundant messages on re-configure
+ set (COTIREMSG_${_target} "${_targetMsg}" CACHE INTERNAL "${_target} cotire message.")
+ message (${_targetMsgLevel} "${_targetMsg}")
+ endif()
+ endif()
+ set (${_targetLanguagesVar} ${_targetLanguages} PARENT_SCOPE)
+endfunction()
+
+function (cotire_compute_unity_max_number_of_includes _target _maxIncludesVar)
+ set (_sourceFiles ${ARGN})
+ get_target_property(_maxIncludes ${_target} COTIRE_UNITY_SOURCE_MAXIMUM_NUMBER_OF_INCLUDES)
+ if (_maxIncludes MATCHES "(-j|--parallel|--jobs) ?([0-9]*)")
+ set (_numberOfThreads "${CMAKE_MATCH_2}")
+ if (NOT _numberOfThreads)
+ # use all available cores
+ ProcessorCount(_numberOfThreads)
+ endif()
+ list (LENGTH _sourceFiles _numberOfSources)
+ math (EXPR _maxIncludes "(${_numberOfSources} + ${_numberOfThreads} - 1) / ${_numberOfThreads}")
+ # a unity source segment must not contain less than COTIRE_MINIMUM_NUMBER_OF_TARGET_SOURCES files
+ if (_maxIncludes LESS ${COTIRE_MINIMUM_NUMBER_OF_TARGET_SOURCES})
+ set (_maxIncludes ${COTIRE_MINIMUM_NUMBER_OF_TARGET_SOURCES})
+ endif()
+ elseif (NOT _maxIncludes MATCHES "[0-9]+")
+ set (_maxIncludes 0)
+ endif()
+ if (COTIRE_DEBUG)
+ message (STATUS "${_target} unity source max includes = ${_maxIncludes}")
+ endif()
+ set (${_maxIncludesVar} ${_maxIncludes} PARENT_SCOPE)
+endfunction()
+
+function (cotire_process_target_language _language _configurations _targetSourceDir _targetBinaryDir _target _wholeTargetVar _cmdsVar)
+ set (${_cmdsVar} "" PARENT_SCOPE)
+ get_target_property(_targetSourceFiles ${_target} SOURCES)
+ set (_sourceFiles "")
+ set (_excludedSources "")
+ set (_cotiredSources "")
+ cotire_filter_language_source_files(${_language} _sourceFiles _excludedSources _cotiredSources ${_targetSourceFiles})
+ if (NOT _sourceFiles AND NOT _cotiredSources)
+ return()
+ endif()
+ set (_wholeTarget ${${_wholeTargetVar}})
+ set (_cmds "")
+ # check for user provided unity source file list
+ get_property(_unitySourceFiles TARGET ${_target} PROPERTY COTIRE_${_language}_UNITY_SOURCE_INIT)
+ if (NOT _unitySourceFiles)
+ set (_unitySourceFiles ${_sourceFiles} ${_cotiredSources})
+ endif()
+ cotire_generate_target_script(
+ ${_language} "${_configurations}" "${_targetSourceDir}" "${_targetBinaryDir}" ${_target} _targetScript ${_unitySourceFiles})
+ cotire_compute_unity_max_number_of_includes(${_target} _maxIncludes ${_unitySourceFiles})
+ cotire_make_unity_source_file_paths(${_language} ${_target} ${_maxIncludes} _unityFiles ${_unitySourceFiles})
+ if (NOT _unityFiles)
+ return()
+ endif()
+ cotire_setup_unity_generation_commands(
+ ${_language} "${_targetSourceDir}" ${_target} "${_targetScript}" "${_unityFiles}" _cmds ${_unitySourceFiles})
+ cotire_make_prefix_file_path(${_language} ${_target} _prefixFile)
+ if (_prefixFile)
+ # check for user provided prefix header files
+ get_property(_prefixHeaderFiles TARGET ${_target} PROPERTY COTIRE_${_language}_PREFIX_HEADER_INIT)
+ if (_prefixHeaderFiles)
+ cotire_setup_combine_command(${_language} "${_targetSourceDir}" "${_targetScript}" "${_prefixFile}" _cmds ${_prefixHeaderFiles})
+ else()
+ cotire_setup_multi_prefix_generation_command(
+ ${_language} ${_target} "${_targetSourceDir}" "${_targetScript}" "${_prefixFile}" "${_unityFiles}" _cmds ${_unitySourceFiles})
+ endif()
+ get_target_property(_targetUsePCH ${_target} COTIRE_ENABLE_PRECOMPILED_HEADER)
+ if (_targetUsePCH)
+ cotire_make_pch_file_path(${_language} "${_targetSourceDir}" ${_target} _pchFile)
+ if (_pchFile)
+ cotire_setup_pch_file_compilation(
+ ${_language} "${_targetBinaryDir}" "${_targetScript}" "${_prefixFile}" "${_pchFile}" ${_sourceFiles})
+ if (_excludedSources)
+ set (_wholeTarget FALSE)
+ endif()
+ cotire_setup_prefix_file_inclusion(
+ ${_language} ${_target} ${_wholeTarget} "${_prefixFile}" "${_pchFile}" ${_sourceFiles})
+ endif()
+ endif()
+ endif()
+ # mark target as cotired for language
+ set_property(TARGET ${_target} PROPERTY COTIRE_${_language}_UNITY_SOURCE "${_unityFiles}")
+ if (_prefixFile)
+ set_property(TARGET ${_target} PROPERTY COTIRE_${_language}_PREFIX_HEADER "${_prefixFile}")
+ if (_targetUsePCH AND _pchFile)
+ set_property(TARGET ${_target} PROPERTY COTIRE_${_language}_PRECOMPILED_HEADER "${_pchFile}")
+ endif()
+ endif()
+ set (${_wholeTargetVar} ${_wholeTarget} PARENT_SCOPE)
+ set (${_cmdsVar} ${_cmds} PARENT_SCOPE)
+endfunction()
+
+function (cotire_setup_clean_target _target)
+ set (_cleanTargetName "${_target}${COTIRE_CLEAN_TARGET_SUFFIX}")
+ if (NOT TARGET "${_cleanTargetName}")
+ cotire_set_cmd_to_prologue(_cmds)
+ get_filename_component(_outputDir "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}" ABSOLUTE)
+ list (APPEND _cmds -P "${COTIRE_CMAKE_MODULE_FILE}" "cleanup" "${_outputDir}" "${COTIRE_INTDIR}" "${_target}")
+ add_custom_target(${_cleanTargetName} COMMAND ${_cmds} WORKING_DIRECTORY "${CMAKE_BINARY_DIR}"
+ COMMENT "Cleaning up target ${_target} cotire generated files" VERBATIM)
+ cotire_init_target("${_cleanTargetName}")
+ endif()
+endfunction()
+
+function (cotire_setup_pch_target _languages _configurations _target)
+ if ("${CMAKE_GENERATOR}" MATCHES "Makefiles|Ninja")
+ # for makefile based generators, we add a custom target to trigger the generation of the cotire related files
+ set (_dependsFiles "")
+ foreach (_language ${_languages})
+ set (_props COTIRE_${_language}_PREFIX_HEADER COTIRE_${_language}_UNITY_SOURCE)
+ if (NOT CMAKE_${_language}_COMPILER_ID MATCHES "MSVC|Intel")
+ # Visual Studio and Intel only create precompiled header as a side effect
+ list (INSERT _props 0 COTIRE_${_language}_PRECOMPILED_HEADER)
+ endif()
+ cotire_get_first_set_property_value(_dependsFile TARGET ${_target} ${_props})
+ if (_dependsFile)
+ list (APPEND _dependsFiles "${_dependsFile}")
+ endif()
+ endforeach()
+ if (_dependsFiles)
+ set (_pchTargetName "${_target}${COTIRE_PCH_TARGET_SUFFIX}")
+ add_custom_target("${_pchTargetName}" DEPENDS ${_dependsFiles})
+ cotire_init_target("${_pchTargetName}")
+ cotire_add_to_pch_all_target(${_pchTargetName})
+ endif()
+ else()
+ # for other generators, we add the "clean all" target to clean up the precompiled header
+ cotire_setup_clean_all_target()
+ endif()
+endfunction()
+
+function (cotire_setup_unity_build_target _languages _configurations _targetSourceDir _target)
+ get_target_property(_unityTargetName ${_target} COTIRE_UNITY_TARGET_NAME)
+ if (NOT _unityTargetName)
+ set (_unityTargetName "${_target}${COTIRE_UNITY_BUILD_TARGET_SUFFIX}")
+ endif()
+ # determine unity target sub type
+ get_target_property(_targetType ${_target} TYPE)
+ if ("${_targetType}" STREQUAL "EXECUTABLE")
+ get_target_property(_isWin32 ${_target} WIN32_EXECUTABLE)
+ get_target_property(_isMacOSX_Bundle ${_target} MACOSX_BUNDLE)
+ if (_isWin32)
+ set (_unityTargetSubType WIN32)
+ elseif (_isMacOSX_Bundle)
+ set (_unityTargetSubType MACOSX_BUNDLE)
+ else()
+ set (_unityTargetSubType "")
+ endif()
+ elseif (_targetType MATCHES "(STATIC|SHARED|MODULE|OBJECT)_LIBRARY")
+ set (_unityTargetSubType "${CMAKE_MATCH_1}")
+ else()
+ message (WARNING "Unknown target type ${_targetType}.")
+ return()
+ endif()
+ # determine unity target sources
+ get_target_property(_targetSourceFiles ${_target} SOURCES)
+ set (_unityTargetSources ${_targetSourceFiles})
+ foreach (_language ${_languages})
+ get_property(_unityFiles TARGET ${_target} PROPERTY COTIRE_${_language}_UNITY_SOURCE)
+ if (_unityFiles)
+ # remove source files that are included in the unity source
+ set (_sourceFiles "")
+ set (_excludedSources "")
+ set (_cotiredSources "")
+ cotire_filter_language_source_files(${_language} _sourceFiles _excludedSources _cotiredSources ${_targetSourceFiles})
+ if (_sourceFiles OR _cotiredSources)
+ list (REMOVE_ITEM _unityTargetSources ${_sourceFiles} ${_cotiredSources})
+ endif()
+ # if cotire is applied to a target which has not been added in the current source dir,
+ # non-existing files cannot be referenced from the unity build target (this is a CMake restriction)
+ if (NOT "${_targetSourceDir}" STREQUAL "${CMAKE_CURRENT_SOURCE_DIR}")
+ set (_nonExistingFiles "")
+ foreach (_file ${_unityTargetSources})
+ if (NOT EXISTS "${_file}")
+ list (APPEND _nonExistingFiles "${_file}")
+ endif()
+ endforeach()
+ if (_nonExistingFiles)
+ if (COTIRE_VERBOSE)
+ message (STATUS "removing non-existing ${_nonExistingFiles} from ${_unityTargetName}")
+ endif()
+ list (REMOVE_ITEM _unityTargetSources ${_nonExistingFiles})
+ endif()
+ endif()
+ # add unity source files instead
+ list (APPEND _unityTargetSources ${_unityFiles})
+ endif()
+ endforeach()
+ if (COTIRE_DEBUG)
+ message (STATUS "add ${_targetType} ${_unityTargetName} ${_unityTargetSubType} EXCLUDE_FROM_ALL ${_unityTargetSources}")
+ endif()
+ # generate unity target
+ if ("${_targetType}" STREQUAL "EXECUTABLE")
+ add_executable(${_unityTargetName} ${_unityTargetSubType} EXCLUDE_FROM_ALL ${_unityTargetSources})
+ else()
+ add_library(${_unityTargetName} ${_unityTargetSubType} EXCLUDE_FROM_ALL ${_unityTargetSources})
+ endif()
+ set (_outputDirProperties
+ ARCHIVE_OUTPUT_DIRECTORY ARCHIVE_OUTPUT_DIRECTORY_<CONFIG>
+ LIBRARY_OUTPUT_DIRECTORY LIBRARY_OUTPUT_DIRECTORY_<CONFIG>
+ RUNTIME_OUTPUT_DIRECTORY RUNTIME_OUTPUT_DIRECTORY_<CONFIG>)
+ # copy output location properties
+ if (COTIRE_UNITY_OUTPUT_DIRECTORY)
+ set (_setDefaultOutputDir TRUE)
+ if (IS_ABSOLUTE "${COTIRE_UNITY_OUTPUT_DIRECTORY}")
+ set (_outputDir "${COTIRE_UNITY_OUTPUT_DIRECTORY}")
+ else()
+ cotrie_copy_set_properites("${_configurations}" TARGET ${_target} ${_unityTargetName} ${_outputDirProperties})
+ cotrie_resolve_config_properites("${_configurations}" _properties ${_outputDirProperties})
+ foreach (_property ${_properties})
+ get_property(_outputDir TARGET ${_target} PROPERTY ${_property})
+ if (_outputDir)
+ get_filename_component(_outputDir "${_outputDir}/${COTIRE_UNITY_OUTPUT_DIRECTORY}" ABSOLUTE)
+ set_property(TARGET ${_unityTargetName} PROPERTY ${_property} "${_outputDir}")
+ set (_setDefaultOutputDir FALSE)
+ endif()
+ endforeach()
+ if (_setDefaultOutputDir)
+ get_filename_component(_outputDir "${CMAKE_CURRENT_BINARY_DIR}/${COTIRE_UNITY_OUTPUT_DIRECTORY}" ABSOLUTE)
+ endif()
+ endif()
+ if (_setDefaultOutputDir)
+ set_target_properties(${_unityTargetName} PROPERTIES
+ ARCHIVE_OUTPUT_DIRECTORY "${_outputDir}"
+ LIBRARY_OUTPUT_DIRECTORY "${_outputDir}"
+ RUNTIME_OUTPUT_DIRECTORY "${_outputDir}")
+ endif()
+ else()
+ cotrie_copy_set_properites("${_configurations}" TARGET ${_target} ${_unityTargetName} ${_outputDirProperties})
+ endif()
+ # copy output name
+ cotrie_copy_set_properites("${_configurations}" TARGET ${_target} ${_unityTargetName}
+ ARCHIVE_OUTPUT_NAME ARCHIVE_OUTPUT_NAME_<CONFIG>
+ LIBRARY_OUTPUT_NAME LIBRARY_OUTPUT_NAME_<CONFIG>
+ OUTPUT_NAME OUTPUT_NAME_<CONFIG>
+ RUNTIME_OUTPUT_NAME RUNTIME_OUTPUT_NAME_<CONFIG>
+ PREFIX <CONFIG>_POSTFIX SUFFIX)
+ # copy compile stuff
+ cotrie_copy_set_properites("${_configurations}" TARGET ${_target} ${_unityTargetName}
+ COMPILE_DEFINITIONS COMPILE_DEFINITIONS_<CONFIG>
+ COMPILE_FLAGS Fortran_FORMAT
+ INCLUDE_DIRECTORIES
+ INTERPROCEDURAL_OPTIMIZATION INTERPROCEDURAL_OPTIMIZATION_<CONFIG>
+ POSITION_INDEPENDENT_CODE)
+ # copy link stuff
+ cotrie_copy_set_properites("${_configurations}" TARGET ${_target} ${_unityTargetName}
+ BUILD_WITH_INSTALL_RPATH INSTALL_RPATH INSTALL_RPATH_USE_LINK_PATH SKIP_BUILD_RPATH
+ LINKER_LANGUAGE LINK_DEPENDS
+ LINK_FLAGS LINK_FLAGS_<CONFIG>
+ LINK_INTERFACE_LIBRARIES LINK_INTERFACE_LIBRARIES_<CONFIG>
+ LINK_INTERFACE_MULTIPLICITY LINK_INTERFACE_MULTIPLICITY_<CONFIG>
+ LINK_SEARCH_START_STATIC LINK_SEARCH_END_STATIC
+ STATIC_LIBRARY_FLAGS STATIC_LIBRARY_FLAGS_<CONFIG>
+ NO_SONAME SOVERSION VERSION)
+ # copy Qt stuff
+ cotrie_copy_set_properites("${_configurations}" TARGET ${_target} ${_unityTargetName}
+ AUTOMOC AUTOMOC_MOC_OPTIONS)
+ # copy cmake stuff
+ cotrie_copy_set_properites("${_configurations}" TARGET ${_target} ${_unityTargetName}
+ IMPLICIT_DEPENDS_INCLUDE_TRANSFORM RULE_LAUNCH_COMPILE RULE_LAUNCH_CUSTOM RULE_LAUNCH_LINK)
+ # copy platform stuff
+ if (APPLE)
+ cotrie_copy_set_properites("${_configurations}" TARGET ${_target} ${_unityTargetName}
+ BUNDLE BUNDLE_EXTENSION FRAMEWORK INSTALL_NAME_DIR MACOSX_BUNDLE_INFO_PLIST MACOSX_FRAMEWORK_INFO_PLIST
+ OSX_ARCHITECTURES OSX_ARCHITECTURES_<CONFIG> PRIVATE_HEADER PUBLIC_HEADER RESOURCE)
+ elseif (WIN32)
+ cotrie_copy_set_properites("${_configurations}" TARGET ${_target} ${_unityTargetName}
+ GNUtoMS
+ PDB_NAME PDB_NAME_<CONFIG> PDB_OUTPUT_DIRECTORY PDB_OUTPUT_DIRECTORY_<CONFIG>
+ VS_DOTNET_REFERENCES VS_GLOBAL_KEYWORD VS_GLOBAL_PROJECT_TYPES VS_KEYWORD
+ VS_SCC_AUXPATH VS_SCC_LOCALPATH VS_SCC_PROJECTNAME VS_SCC_PROVIDER
+ VS_WINRT_EXTENSIONS VS_WINRT_REFERENCES)
+ endif()
+ # use output name from original target
+ get_target_property(_targetOutputName ${_unityTargetName} OUTPUT_NAME)
+ if (NOT _targetOutputName)
+ set_property(TARGET ${_unityTargetName} PROPERTY OUTPUT_NAME "${_target}")
+ endif()
+ # use export symbol from original target
+ cotire_get_target_export_symbol("${_target}" _defineSymbol)
+ if (_defineSymbol)
+ set_property(TARGET ${_unityTargetName} PROPERTY DEFINE_SYMBOL "${_defineSymbol}")
+ if ("${_targetType}" STREQUAL "EXECUTABLE")
+ set_property(TARGET ${_unityTargetName} PROPERTY ENABLE_EXPORTS TRUE)
+ endif()
+ endif()
+ cotire_init_target(${_unityTargetName})
+ cotire_add_to_unity_all_target(${_unityTargetName})
+ set_property(TARGET ${_target} PROPERTY COTIRE_UNITY_TARGET_NAME "${_unityTargetName}")
+endfunction(cotire_setup_unity_build_target)
+
+function (cotire_target _target)
+ set(_options "")
+ set(_oneValueArgs SOURCE_DIR BINARY_DIR)
+ set(_multiValueArgs LANGUAGES CONFIGURATIONS)
+ cmake_parse_arguments(_option "${_options}" "${_oneValueArgs}" "${_multiValueArgs}" ${ARGN})
+ if (NOT _option_SOURCE_DIR)
+ set (_option_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}")
+ endif()
+ if (NOT _option_BINARY_DIR)
+ set (_option_BINARY_DIR "${CMAKE_CURRENT_BINARY_DIR}")
+ endif()
+ if (NOT _option_LANGUAGES)
+ get_property (_option_LANGUAGES GLOBAL PROPERTY ENABLED_LANGUAGES)
+ endif()
+ if (NOT _option_CONFIGURATIONS)
+ if (CMAKE_CONFIGURATION_TYPES)
+ set (_option_CONFIGURATIONS ${CMAKE_CONFIGURATION_TYPES})
+ elseif (CMAKE_BUILD_TYPE)
+ set (_option_CONFIGURATIONS "${CMAKE_BUILD_TYPE}")
+ else()
+ set (_option_CONFIGURATIONS "None")
+ endif()
+ endif()
+ # trivial checks
+ get_target_property(_imported ${_target} IMPORTED)
+ if (_imported)
+ message (WARNING "Imported target ${_target} cannot be cotired.")
+ return()
+ endif()
+ # check if target needs to be cotired for build type
+ # when using configuration types, the test is performed at build time
+ cotire_init_cotire_target_properties(${_target})
+ if (NOT CMAKE_CONFIGURATION_TYPES)
+ if (CMAKE_BUILD_TYPE)
+ list (FIND _option_CONFIGURATIONS "${CMAKE_BUILD_TYPE}" _index)
+ else()
+ list (FIND _option_CONFIGURATIONS "None" _index)
+ endif()
+ if (_index EQUAL -1)
+ if (COTIRE_DEBUG)
+ message (STATUS "CMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} not cotired (${_option_CONFIGURATIONS})")
+ endif()
+ return()
+ endif()
+ endif()
+ # choose languages that apply to the target
+ cotire_choose_target_languages("${_option_SOURCE_DIR}" "${_target}" _targetLanguages ${_option_LANGUAGES})
+ if (NOT _targetLanguages)
+ return()
+ endif()
+ list (LENGTH _targetLanguages _numberOfLanguages)
+ if (_numberOfLanguages GREATER 1)
+ set (_wholeTarget FALSE)
+ else()
+ set (_wholeTarget TRUE)
+ endif()
+ set (_cmds "")
+ foreach (_language ${_targetLanguages})
+ cotire_process_target_language("${_language}" "${_option_CONFIGURATIONS}"
+ "${_option_SOURCE_DIR}" "${_option_BINARY_DIR}" ${_target} _wholeTarget _cmd)
+ if (_cmd)
+ list (APPEND _cmds ${_cmd})
+ endif()
+ endforeach()
+ get_target_property(_targetAddSCU ${_target} COTIRE_ADD_UNITY_BUILD)
+ if (_targetAddSCU)
+ cotire_setup_unity_build_target("${_targetLanguages}" "${_option_CONFIGURATIONS}" "${_option_SOURCE_DIR}" ${_target})
+ endif()
+ get_target_property(_targetUsePCH ${_target} COTIRE_ENABLE_PRECOMPILED_HEADER)
+ if (_targetUsePCH)
+ cotire_setup_target_pch_usage("${_targetLanguages}" "${_option_SOURCE_DIR}" ${_target} ${_wholeTarget} ${_cmds})
+ cotire_setup_pch_target("${_targetLanguages}" "${_option_CONFIGURATIONS}" ${_target})
+ endif()
+ get_target_property(_targetAddCleanTarget ${_target} COTIRE_ADD_CLEAN)
+ if (_targetAddCleanTarget)
+ cotire_setup_clean_target(${_target})
+ endif()
+endfunction()
+
+function (cotire_cleanup _binaryDir _cotireIntermediateDirName _targetName)
+ if (_targetName)
+ file (GLOB_RECURSE _cotireFiles "${_binaryDir}/${_targetName}*.*")
+ else()
+ file (GLOB_RECURSE _cotireFiles "${_binaryDir}/*.*")
+ endif()
+ # filter files in intermediate directory
+ set (_filesToRemove "")
+ foreach (_file ${_cotireFiles})
+ get_filename_component(_dir "${_file}" PATH)
+ get_filename_component(_dirName "${_dir}" NAME)
+ if ("${_dirName}" STREQUAL "${_cotireIntermediateDirName}")
+ list (APPEND _filesToRemove "${_file}")
+ endif()
+ endforeach()
+ if (_filesToRemove)
+ if (COTIRE_VERBOSE)
+ message (STATUS "removing ${_filesToRemove}")
+ endif()
+ file (REMOVE ${_filesToRemove})
+ endif()
+endfunction()
+
+function (cotire_init_target _targetName)
+ if (COTIRE_TARGETS_FOLDER)
+ set_target_properties(${_targetName} PROPERTIES FOLDER "${COTIRE_TARGETS_FOLDER}")
+ endif()
+ if (MSVC_IDE)
+ set_target_properties(${_targetName} PROPERTIES EXCLUDE_FROM_DEFAULT_BUILD TRUE)
+ endif()
+endfunction()
+
+function (cotire_add_to_pch_all_target _pchTargetName)
+ set (_targetName "${COTIRE_PCH_ALL_TARGET_NAME}")
+ if (NOT TARGET "${_targetName}")
+ add_custom_target("${_targetName}" WORKING_DIRECTORY "${CMAKE_BINARY_DIR}" VERBATIM)
+ cotire_init_target("${_targetName}")
+ endif()
+ cotire_setup_clean_all_target()
+ add_dependencies(${_targetName} ${_pchTargetName})
+endfunction()
+
+function (cotire_add_to_unity_all_target _unityTargetName)
+ set (_targetName "${COTIRE_UNITY_BUILD_ALL_TARGET_NAME}")
+ if (NOT TARGET "${_targetName}")
+ add_custom_target("${_targetName}" WORKING_DIRECTORY "${CMAKE_BINARY_DIR}" VERBATIM)
+ cotire_init_target("${_targetName}")
+ endif()
+ cotire_setup_clean_all_target()
+ add_dependencies(${_targetName} ${_unityTargetName})
+endfunction()
+
+function (cotire_setup_clean_all_target)
+ set (_targetName "${COTIRE_CLEAN_ALL_TARGET_NAME}")
+ if (NOT TARGET "${_targetName}")
+ cotire_set_cmd_to_prologue(_cmds)
+ list (APPEND _cmds -P "${COTIRE_CMAKE_MODULE_FILE}" "cleanup" "${CMAKE_BINARY_DIR}" "${COTIRE_INTDIR}")
+ add_custom_target(${_targetName} COMMAND ${_cmds}
+ WORKING_DIRECTORY "${CMAKE_BINARY_DIR}" COMMENT "Cleaning up all cotire generated files" VERBATIM)
+ cotire_init_target("${_targetName}")
+ endif()
+endfunction()
+
+function (cotire)
+ set(_options "")
+ set(_oneValueArgs SOURCE_DIR BINARY_DIR)
+ set(_multiValueArgs LANGUAGES CONFIGURATIONS)
+ cmake_parse_arguments(_option "${_options}" "${_oneValueArgs}" "${_multiValueArgs}" ${ARGN})
+ set (_targets ${_option_UNPARSED_ARGUMENTS})
+ if (NOT _option_SOURCE_DIR)
+ set (_option_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}")
+ endif()
+ if (NOT _option_BINARY_DIR)
+ set (_option_BINARY_DIR "${CMAKE_CURRENT_BINARY_DIR}")
+ endif()
+ foreach (_target ${_targets})
+ if (TARGET ${_target})
+ cotire_target(${_target} LANGUAGES ${_option_LANGUAGES} CONFIGURATIONS ${_option_CONFIGURATIONS}
+ SOURCE_DIR "${_option_SOURCE_DIR}" BINARY_DIR "${_option_BINARY_DIR}")
+ else()
+ message (WARNING "${_target} is not a target")
+ endif()
+ endforeach()
+endfunction()
+
+if (CMAKE_SCRIPT_MODE_FILE)
+
+ # cotire is being run in script mode
+ # locate -P on command args
+ set (COTIRE_ARGC -1)
+ foreach (_index RANGE ${CMAKE_ARGC})
+ if (COTIRE_ARGC GREATER -1)
+ set (COTIRE_ARGV${COTIRE_ARGC} "${CMAKE_ARGV${_index}}")
+ math (EXPR COTIRE_ARGC "${COTIRE_ARGC} + 1")
+ elseif ("${CMAKE_ARGV${_index}}" STREQUAL "-P")
+ set (COTIRE_ARGC 0)
+ endif()
+ endforeach()
+
+ # include target script if available
+ if ("${COTIRE_ARGV2}" MATCHES "\\.cmake$")
+ # the included target scripts sets up additional variables relating to the target (e.g., COTIRE_TARGET_SOURCES)
+ include("${COTIRE_ARGV2}")
+ endif()
+
+ if (COTIRE_DEBUG)
+ message (STATUS "${COTIRE_ARGV0} ${COTIRE_ARGV1} ${COTIRE_ARGV2} ${COTIRE_ARGV3} ${COTIRE_ARGV4} ${COTIRE_ARGV5}")
+ endif()
+
+ if (WIN32)
+ # for MSVC, compiler IDs may not always be set correctly
+ if (MSVC)
+ set (CMAKE_C_COMPILER_ID "MSVC")
+ set (CMAKE_CXX_COMPILER_ID "MSVC")
+ endif()
+ endif()
+
+ if (NOT COTIRE_BUILD_TYPE)
+ set (COTIRE_BUILD_TYPE "None")
+ endif()
+ string (TOUPPER "${COTIRE_BUILD_TYPE}" _upperConfig)
+ set (_includeDirs ${COTIRE_TARGET_INCLUDE_DIRECTORIES_${_upperConfig}})
+ set (_compileDefinitions ${COTIRE_TARGET_COMPILE_DEFINITIONS_${_upperConfig}})
+ set (_compileFlags ${COTIRE_TARGET_COMPILE_FLAGS_${_upperConfig}})
+ # check if target has been cotired for actual build type COTIRE_BUILD_TYPE
+ list (FIND COTIRE_TARGET_CONFIGURATION_TYPES "${COTIRE_BUILD_TYPE}" _index)
+ if (_index GREATER -1)
+ set (_sources ${COTIRE_TARGET_SOURCES})
+ set (_sourcesDefinitions ${COTIRE_TARGET_SOURCES_COMPILE_DEFINITIONS_${_upperConfig}})
+ else()
+ if (COTIRE_DEBUG)
+ message (STATUS "COTIRE_BUILD_TYPE=${COTIRE_BUILD_TYPE} not cotired (${COTIRE_TARGET_CONFIGURATION_TYPES})")
+ endif()
+ set (_sources "")
+ set (_sourcesDefinitions "")
+ endif()
+ set (_targetPreUndefs ${COTIRE_TARGET_PRE_UNDEFS})
+ set (_targetPostUndefs ${COTIRE_TARGET_POST_UNDEFS})
+ set (_sourcesPreUndefs ${COTIRE_TARGET_SOURCES_PRE_UNDEFS})
+ set (_sourcesPostUndefs ${COTIRE_TARGET_SOURCES_POST_UNDEFS})
+
+ if ("${COTIRE_ARGV1}" STREQUAL "unity")
+
+ cotire_select_unity_source_files("${COTIRE_ARGV3}" _sources ${_sources})
+ cotire_generate_unity_source(
+ "${COTIRE_ARGV3}" ${_sources}
+ LANGUAGE "${COTIRE_TARGET_LANGUAGE}"
+ DEPENDS "${COTIRE_ARGV0}" "${COTIRE_ARGV2}"
+ SOURCES_COMPILE_DEFINITIONS ${_sourcesDefinitions}
+ PRE_UNDEFS ${_targetPreUndefs}
+ POST_UNDEFS ${_targetPostUndefs}
+ SOURCES_PRE_UNDEFS ${_sourcesPreUndefs}
+ SOURCES_POST_UNDEFS ${_sourcesPostUndefs})
+
+ elseif ("${COTIRE_ARGV1}" STREQUAL "prefix")
+
+ set (_files "")
+ foreach (_index RANGE 4 ${COTIRE_ARGC})
+ if (COTIRE_ARGV${_index})
+ list (APPEND _files "${COTIRE_ARGV${_index}}")
+ endif()
+ endforeach()
+
+ cotire_generate_prefix_header(
+ "${COTIRE_ARGV3}" ${_files}
+ COMPILER_EXECUTABLE "${CMAKE_${COTIRE_TARGET_LANGUAGE}_COMPILER}"
+ COMPILER_ARG1 ${CMAKE_${COTIRE_TARGET_LANGUAGE}_COMPILER_ARG1}
+ COMPILER_ID "${CMAKE_${COTIRE_TARGET_LANGUAGE}_COMPILER_ID}"
+ COMPILER_VERSION "${COTIRE_${COTIRE_TARGET_LANGUAGE}_COMPILER_VERSION}"
+ LANGUAGE "${COTIRE_TARGET_LANGUAGE}"
+ DEPENDS "${COTIRE_ARGV0}" "${COTIRE_ARGV4}" ${COTIRE_TARGET_PREFIX_DEPENDS}
+ IGNORE_PATH "${COTIRE_TARGET_IGNORE_PATH};${COTIRE_ADDITIONAL_PREFIX_HEADER_IGNORE_PATH}"
+ INCLUDE_PATH ${COTIRE_TARGET_INCLUDE_PATH}
+ IGNORE_EXTENSIONS "${CMAKE_${COTIRE_TARGET_LANGUAGE}_SOURCE_FILE_EXTENSIONS};${COTIRE_ADDITIONAL_PREFIX_HEADER_IGNORE_EXTENSIONS}"
+ INCLUDE_DIRECTORIES ${_includeDirs}
+ COMPILE_DEFINITIONS ${_compileDefinitions}
+ COMPILE_FLAGS ${_compileFlags})
+
+ elseif ("${COTIRE_ARGV1}" STREQUAL "precompile")
+
+ set (_files "")
+ foreach (_index RANGE 5 ${COTIRE_ARGC})
+ if (COTIRE_ARGV${_index})
+ list (APPEND _files "${COTIRE_ARGV${_index}}")
+ endif()
+ endforeach()
+
+ cotire_precompile_prefix_header(
+ "${COTIRE_ARGV3}" "${COTIRE_ARGV4}" "${COTIRE_ARGV5}"
+ COMPILER_EXECUTABLE "${CMAKE_${COTIRE_TARGET_LANGUAGE}_COMPILER}"
+ COMPILER_ARG1 ${CMAKE_${COTIRE_TARGET_LANGUAGE}_COMPILER_ARG1}
+ COMPILER_ID "${CMAKE_${COTIRE_TARGET_LANGUAGE}_COMPILER_ID}"
+ COMPILER_VERSION "${COTIRE_${COTIRE_TARGET_LANGUAGE}_COMPILER_VERSION}"
+ LANGUAGE "${COTIRE_TARGET_LANGUAGE}"
+ INCLUDE_DIRECTORIES ${_includeDirs}
+ COMPILE_DEFINITIONS ${_compileDefinitions}
+ COMPILE_FLAGS ${_compileFlags})
+
+ elseif ("${COTIRE_ARGV1}" STREQUAL "combine")
+
+ if (COTIRE_TARGET_LANGUAGE)
+ set (_startIndex 3)
+ else()
+ set (_startIndex 2)
+ endif()
+ set (_files "")
+ foreach (_index RANGE ${_startIndex} ${COTIRE_ARGC})
+ if (COTIRE_ARGV${_index})
+ list (APPEND _files "${COTIRE_ARGV${_index}}")
+ endif()
+ endforeach()
+ if (COTIRE_TARGET_LANGUAGE)
+ cotire_generate_unity_source(${_files} LANGUAGE "${COTIRE_TARGET_LANGUAGE}")
+ else()
+ cotire_generate_unity_source(${_files})
+ endif()
+
+ elseif ("${COTIRE_ARGV1}" STREQUAL "cleanup")
+
+ cotire_cleanup("${COTIRE_ARGV2}" "${COTIRE_ARGV3}" "${COTIRE_ARGV4}")
+
+ else()
+ message (FATAL_ERROR "Unknown cotire command \"${COTIRE_ARGV1}\".")
+ endif()
+
+else()
+
+ # cotire is being run in include mode
+ # set up all variable and property definitions
+
+ unset (COTIRE_C_COMPILER_VERSION CACHE)
+ unset (COTIRE_CXX_COMPILER_VERSION CACHE)
+
+ if (NOT DEFINED COTIRE_DEBUG_INIT)
+ if (DEFINED COTIRE_DEBUG)
+ set (COTIRE_DEBUG_INIT ${COTIRE_DEBUG})
+ else()
+ set (COTIRE_DEBUG_INIT FALSE)
+ endif()
+ endif()
+ option (COTIRE_DEBUG "Enable cotire debugging output?" ${COTIRE_DEBUG_INIT})
+
+ if (NOT DEFINED COTIRE_VERBOSE_INIT)
+ if (DEFINED COTIRE_VERBOSE)
+ set (COTIRE_VERBOSE_INIT ${COTIRE_VERBOSE})
+ else()
+ set (COTIRE_VERBOSE_INIT FALSE)
+ endif()
+ endif()
+ option (COTIRE_VERBOSE "Enable cotire verbose output?" ${COTIRE_VERBOSE_INIT})
+
+ set (COTIRE_ADDITIONAL_PREFIX_HEADER_IGNORE_EXTENSIONS "inc;inl;ipp" CACHE STRING
+ "Ignore headers with the listed file extensions from the generated prefix header.")
+
+ set (COTIRE_ADDITIONAL_PREFIX_HEADER_IGNORE_PATH "" CACHE STRING
+ "Ignore headers from these directories when generating the prefix header.")
+
+ set (COTIRE_UNITY_SOURCE_EXCLUDE_EXTENSIONS "m;mm" CACHE STRING
+ "Ignore sources with the listed file extensions from the generated unity source.")
+
+ set (COTIRE_MINIMUM_NUMBER_OF_TARGET_SOURCES "3" CACHE STRING
+ "Minimum number of sources in target required to enable use of precompiled header.")
+
+ if (NOT DEFINED COTIRE_MAXIMUM_NUMBER_OF_UNITY_INCLUDES_INIT)
+ if (DEFINED COTIRE_MAXIMUM_NUMBER_OF_UNITY_INCLUDES)
+ set (COTIRE_MAXIMUM_NUMBER_OF_UNITY_INCLUDES_INIT ${COTIRE_MAXIMUM_NUMBER_OF_UNITY_INCLUDES})
+ elseif ("${CMAKE_GENERATOR}" MATCHES "JOM|Ninja|Visual Studio")
+ # enable parallelization for generators that run multiple jobs by default
+ set (COTIRE_MAXIMUM_NUMBER_OF_UNITY_INCLUDES_INIT "-j")
+ else()
+ set (COTIRE_MAXIMUM_NUMBER_OF_UNITY_INCLUDES_INIT "0")
+ endif()
+ endif()
+ set (COTIRE_MAXIMUM_NUMBER_OF_UNITY_INCLUDES "${COTIRE_MAXIMUM_NUMBER_OF_UNITY_INCLUDES_INIT}" CACHE STRING
+ "Maximum number of source files to include in a single unity source file.")
+
+ if (NOT COTIRE_PREFIX_HEADER_FILENAME_SUFFIX)
+ set (COTIRE_PREFIX_HEADER_FILENAME_SUFFIX "_prefix")
+ endif()
+ if (NOT COTIRE_UNITY_SOURCE_FILENAME_SUFFIX)
+ set (COTIRE_UNITY_SOURCE_FILENAME_SUFFIX "_unity")
+ endif()
+ if (NOT COTIRE_INTDIR)
+ set (COTIRE_INTDIR "cotire")
+ endif()
+ if (NOT COTIRE_PCH_ALL_TARGET_NAME)
+ set (COTIRE_PCH_ALL_TARGET_NAME "all_pch")
+ endif()
+ if (NOT COTIRE_UNITY_BUILD_ALL_TARGET_NAME)
+ set (COTIRE_UNITY_BUILD_ALL_TARGET_NAME "all_unity")
+ endif()
+ if (NOT COTIRE_CLEAN_ALL_TARGET_NAME)
+ set (COTIRE_CLEAN_ALL_TARGET_NAME "clean_cotire")
+ endif()
+ if (NOT COTIRE_CLEAN_TARGET_SUFFIX)
+ set (COTIRE_CLEAN_TARGET_SUFFIX "_clean_cotire")
+ endif()
+ if (NOT COTIRE_PCH_TARGET_SUFFIX)
+ set (COTIRE_PCH_TARGET_SUFFIX "_pch")
+ endif()
+ if (NOT COTIRE_UNITY_BUILD_TARGET_SUFFIX)
+ set (COTIRE_UNITY_BUILD_TARGET_SUFFIX "_unity")
+ endif()
+ if (NOT DEFINED COTIRE_TARGETS_FOLDER)
+ set (COTIRE_TARGETS_FOLDER "cotire")
+ endif()
+ if (NOT DEFINED COTIRE_UNITY_OUTPUT_DIRECTORY)
+ if ("${CMAKE_GENERATOR}" MATCHES "Ninja")
+ # generated Ninja build files do not work if the unity target produces the same output file as the cotired target
+ set (COTIRE_UNITY_OUTPUT_DIRECTORY "unity")
+ else()
+ set (COTIRE_UNITY_OUTPUT_DIRECTORY "")
+ endif()
+ endif()
+
+ # define cotire cache variables
+
+ define_property(
+ CACHED_VARIABLE PROPERTY "COTIRE_ADDITIONAL_PREFIX_HEADER_IGNORE_PATH"
+ BRIEF_DOCS "Ignore headers from these directories when generating the prefix header."
+ FULL_DOCS
+ "The variable can be set to a semicolon separated list of include directories."
+ "If a header file is found in one of these directories or sub-directories, it will be excluded from the generated prefix header."
+ "If not defined, defaults to empty list."
+ )
+
+ define_property(
+ CACHED_VARIABLE PROPERTY "COTIRE_ADDITIONAL_PREFIX_HEADER_IGNORE_EXTENSIONS"
+ BRIEF_DOCS "Ignore includes with the listed file extensions from the generated prefix header."
+ FULL_DOCS
+ "The variable can be set to a semicolon separated list of file extensions."
+ "If a header file extension matches one in the list, it will be excluded from the generated prefix header."
+ "Includes with an extension in CMAKE_<LANG>_SOURCE_FILE_EXTENSIONS are always ignored."
+ "If not defined, defaults to inc;inl;ipp."
+ )
+
+ define_property(
+ CACHED_VARIABLE PROPERTY "COTIRE_UNITY_SOURCE_EXCLUDE_EXTENSIONS"
+ BRIEF_DOCS "Exclude sources with the listed file extensions from the generated unity source."
+ FULL_DOCS
+ "The variable can be set to a semicolon separated list of file extensions."
+ "If a source file extension matches one in the list, it will be excluded from the generated unity source file."
+ "Source files with an extension in CMAKE_<LANG>_IGNORE_EXTENSIONS are always excluded."
+ "If not defined, defaults to m;mm."
+ )
+
+ define_property(
+ CACHED_VARIABLE PROPERTY "COTIRE_MINIMUM_NUMBER_OF_TARGET_SOURCES"
+ BRIEF_DOCS "Minimum number of sources in target required to enable use of precompiled header."
+ FULL_DOCS
+ "The variable can be set to an integer > 0."
+ "If a target contains less than that number of source files, cotire will not enable the use of the precompiled header for the target."
+ "If not defined, defaults to 3."
+ )
+
+ define_property(
+ CACHED_VARIABLE PROPERTY "COTIRE_MAXIMUM_NUMBER_OF_UNITY_INCLUDES"
+ BRIEF_DOCS "Maximum number of source files to include in a single unity source file."
+ FULL_DOCS
+ "This may be set to an integer >= 0."
+ "If 0, cotire will only create a single unity source file."
+ "If a target contains more than that number of source files, cotire will create multiple unity source files for it."
+ "Can be set to \"-j\" to optimize the count of unity source files for the number of available processor cores."
+ "Can be set to \"-j jobs\" to optimize the number of unity source files for the given number of simultaneous jobs."
+ "Is used to initialize the target property COTIRE_UNITY_SOURCE_MAXIMUM_NUMBER_OF_INCLUDES."
+ "Defaults to \"-j\" for the generators Visual Studio, JOM or Ninja. Defaults to 0 otherwise."
+ )
+
+ # define cotire directory properties
+
+ define_property(
+ DIRECTORY PROPERTY "COTIRE_ENABLE_PRECOMPILED_HEADER"
+ BRIEF_DOCS "Modify build command of cotired targets added in this directory to make use of the generated precompiled header."
+ FULL_DOCS
+ "See target property COTIRE_ENABLE_PRECOMPILED_HEADER."
+ )
+
+ define_property(
+ DIRECTORY PROPERTY "COTIRE_ADD_UNITY_BUILD"
+ BRIEF_DOCS "Add a new target that performs a unity build for cotired targets added in this directory."
+ FULL_DOCS
+ "See target property COTIRE_ADD_UNITY_BUILD."
+ )
+
+ define_property(
+ DIRECTORY PROPERTY "COTIRE_ADD_CLEAN"
+ BRIEF_DOCS "Add a new target that cleans all cotire generated files for cotired targets added in this directory."
+ FULL_DOCS
+ "See target property COTIRE_ADD_CLEAN."
+ )
+
+ define_property(
+ DIRECTORY PROPERTY "COTIRE_PREFIX_HEADER_IGNORE_PATH"
+ BRIEF_DOCS "Ignore headers from these directories when generating the prefix header."
+ FULL_DOCS
+ "See target property COTIRE_PREFIX_HEADER_IGNORE_PATH."
+ )
+
+ define_property(
+ DIRECTORY PROPERTY "COTIRE_PREFIX_HEADER_INCLUDE_PATH"
+ BRIEF_DOCS "Honor headers from these directories when generating the prefix header."
+ FULL_DOCS
+ "See target property COTIRE_PREFIX_HEADER_INCLUDE_PATH."
+ )
+
+ define_property(
+ DIRECTORY PROPERTY "COTIRE_UNITY_SOURCE_PRE_UNDEFS"
+ BRIEF_DOCS "Preprocessor undefs to place in the generated unity source file before the inclusion of each source file."
+ FULL_DOCS
+ "See target property COTIRE_UNITY_SOURCE_PRE_UNDEFS."
+ )
+
+ define_property(
+ DIRECTORY PROPERTY "COTIRE_UNITY_SOURCE_POST_UNDEFS"
+ BRIEF_DOCS "Preprocessor undefs to place in the generated unity source file after the inclusion of each source file."
+ FULL_DOCS
+ "See target property COTIRE_UNITY_SOURCE_POST_UNDEFS."
+ )
+
+ define_property(
+ DIRECTORY PROPERTY "COTIRE_UNITY_SOURCE_MAXIMUM_NUMBER_OF_INCLUDES"
+ BRIEF_DOCS "Maximum number of source files to include in a single unity source file."
+ FULL_DOCS
+ "See target property COTIRE_UNITY_SOURCE_MAXIMUM_NUMBER_OF_INCLUDES."
+ )
+
+ # define cotire target properties
+
+ define_property(
+ TARGET PROPERTY "COTIRE_ENABLE_PRECOMPILED_HEADER" INHERITED
+ BRIEF_DOCS "Modify this target's build command to make use of the generated precompiled header."
+ FULL_DOCS
+ "If this property is set to TRUE, cotire will modify the build command to make use of the generated precompiled header."
+ "Irrespective of the value of this property, cotire will setup custom commands to generate the unity source and prefix header for the target."
+ "For makefile based generators cotire will also set up a custom target to manually invoke the generation of the precompiled header."
+ "The target name will be set to this target's name with the suffix _pch appended."
+ "Inherited from directory."
+ "Defaults to TRUE."
+ )
+
+ define_property(
+ TARGET PROPERTY "COTIRE_ADD_UNITY_BUILD" INHERITED
+ BRIEF_DOCS "Add a new target that performs a unity build for this target."
+ FULL_DOCS
+ "If this property is set to TRUE, cotire creates a new target of the same type that uses the generated unity source file instead of the target sources."
+ "Most of the relevant target properties will be copied from this target to the new unity build target."
+ "Target dependencies and linked libraries have to be manually set up for the new unity build target."
+ "The unity target name will be set to this target's name with the suffix _unity appended."
+ "Inherited from directory."
+ "Defaults to TRUE."
+ )
+
+ define_property(
+ TARGET PROPERTY "COTIRE_ADD_CLEAN" INHERITED
+ BRIEF_DOCS "Add a new target that cleans all cotire generated files for this target."
+ FULL_DOCS
+ "If this property is set to TRUE, cotire creates a new target that clean all files (unity source, prefix header, precompiled header)."
+ "The clean target name will be set to this target's name with the suffix _clean_cotire appended."
+ "Inherited from directory."
+ "Defaults to FALSE."
+ )
+
+ define_property(
+ TARGET PROPERTY "COTIRE_PREFIX_HEADER_IGNORE_PATH" INHERITED
+ BRIEF_DOCS "Ignore headers from these directories when generating the prefix header."
+ FULL_DOCS
+ "The property can be set to a list of directories."
+ "If a header file is found in one of these directories or sub-directories, it will be excluded from the generated prefix header."
+ "Inherited from directory."
+ "If not set, this property is initialized to \${CMAKE_SOURCE_DIR};\${CMAKE_BINARY_DIR}."
+ )
+
+ define_property(
+ TARGET PROPERTY "COTIRE_PREFIX_HEADER_INCLUDE_PATH" INHERITED
+ BRIEF_DOCS "Honor headers from these directories when generating the prefix header."
+ FULL_DOCS
+ "The property can be set to a list of directories."
+ "If a header file is found in one of these directories or sub-directories, it will be included in the generated prefix header."
+ "If a header file is both selected by COTIRE_PREFIX_HEADER_IGNORE_PATH and COTIRE_PREFIX_HEADER_INCLUDE_PATH,"
+ "the option which yields the closer relative path match wins."
+ "Inherited from directory."
+ "If not set, this property is initialized to the empty list."
+ )
+
+ define_property(
+ TARGET PROPERTY "COTIRE_UNITY_SOURCE_PRE_UNDEFS" INHERITED
+ BRIEF_DOCS "Preprocessor undefs to place in the generated unity source file before the inclusion of each target source file."
+ FULL_DOCS
+ "This may be set to a semicolon-separated list of preprocessor symbols."
+ "cotire will add corresponding #undef directives to the generated unit source file before each target source file."
+ "Inherited from directory."
+ "Defaults to empty string."
+ )
+
+ define_property(
+ TARGET PROPERTY "COTIRE_UNITY_SOURCE_POST_UNDEFS" INHERITED
+ BRIEF_DOCS "Preprocessor undefs to place in the generated unity source file after the inclusion of each target source file."
+ FULL_DOCS
+ "This may be set to a semicolon-separated list of preprocessor symbols."
+ "cotire will add corresponding #undef directives to the generated unit source file after each target source file."
+ "Inherited from directory."
+ "Defaults to empty string."
+ )
+
+ define_property(
+ TARGET PROPERTY "COTIRE_UNITY_SOURCE_MAXIMUM_NUMBER_OF_INCLUDES" INHERITED
+ BRIEF_DOCS "Maximum number of source files to include in a single unity source file."
+ FULL_DOCS
+ "This may be set to an integer > 0."
+ "If a target contains more than that number of source files, cotire will create multiple unity build files for it."
+ "If not set, cotire will only create a single unity source file."
+ "Inherited from directory."
+ "Defaults to empty."
+ )
+
+ define_property(
+ TARGET PROPERTY "COTIRE_<LANG>_UNITY_SOURCE_INIT"
+ BRIEF_DOCS "User provided unity source file to be used instead of the automatically generated one."
+ FULL_DOCS
+ "If set, cotire will only add the given file(s) to the generated unity source file."
+ "If not set, cotire will add all the target source files to the generated unity source file."
+ "The property can be set to a user provided unity source file."
+ "Defaults to empty."
+ )
+
+ define_property(
+ TARGET PROPERTY "COTIRE_<LANG>_PREFIX_HEADER_INIT"
+ BRIEF_DOCS "User provided prefix header file to be used instead of the automatically generated one."
+ FULL_DOCS
+ "If set, cotire will add the given header file(s) to the generated prefix header file."
+ "If not set, cotire will generate a prefix header by tracking the header files included by the unity source file."
+ "The property can be set to a user provided prefix header file (e.g., stdafx.h)."
+ "Defaults to empty."
+ )
+
+ define_property(
+ TARGET PROPERTY "COTIRE_<LANG>_UNITY_SOURCE"
+ BRIEF_DOCS "Read-only property. The generated <LANG> unity source file(s)."
+ FULL_DOCS
+ "cotire sets this property to the path of the generated <LANG> single computation unit source file for the target."
+ "Defaults to empty string."
+ )
+
+ define_property(
+ TARGET PROPERTY "COTIRE_<LANG>_PREFIX_HEADER"
+ BRIEF_DOCS "Read-only property. The generated <LANG> prefix header file."
+ FULL_DOCS
+ "cotire sets this property to the full path of the generated <LANG> language prefix header for the target."
+ "Defaults to empty string."
+ )
+
+ define_property(
+ TARGET PROPERTY "COTIRE_<LANG>_PRECOMPILED_HEADER"
+ BRIEF_DOCS "Read-only property. The generated <LANG> precompiled header file."
+ FULL_DOCS
+ "cotire sets this property to the full path of the generated <LANG> language precompiled header binary for the target."
+ "Defaults to empty string."
+ )
+
+ define_property(
+ TARGET PROPERTY "COTIRE_UNITY_TARGET_NAME"
+ BRIEF_DOCS "The name of the generated unity build target corresponding to this target."
+ FULL_DOCS
+ "This property can be set to the desired name of the unity target that will be created by cotire."
+ "If not set, the unity target name will be set to this target's name with the suffix _unity appended."
+ "After this target has been processed by cotire, the property is set to the actual name of the generated unity target."
+ "Defaults to empty string."
+ )
+
+ # define cotire source properties
+
+ define_property(
+ SOURCE PROPERTY "COTIRE_EXCLUDED"
+ BRIEF_DOCS "Do not modify source file's build command."
+ FULL_DOCS
+ "If this property is set to TRUE, the source file's build command will not be modified to make use of the precompiled header."
+ "The source file will also be excluded from the generated unity source file."
+ "Source files that have their COMPILE_FLAGS property set will be excluded by default."
+ "Defaults to FALSE."
+ )
+
+ define_property(
+ SOURCE PROPERTY "COTIRE_DEPENDENCY"
+ BRIEF_DOCS "Add this source file to dependencies of the automatically generated prefix header file."
+ FULL_DOCS
+ "If this property is set to TRUE, the source file is added to dependencies of the generated prefix header file."
+ "If the file is modified, cotire will re-generate the prefix header source upon build."
+ "Defaults to FALSE."
+ )
+
+ define_property(
+ SOURCE PROPERTY "COTIRE_UNITY_SOURCE_PRE_UNDEFS"
+ BRIEF_DOCS "Preprocessor undefs to place in the generated unity source file before the inclusion of this source file."
+ FULL_DOCS
+ "This may be set to a semicolon-separated list of preprocessor symbols."
+ "cotire will add corresponding #undef directives to the generated unit source file before this file is included."
+ "Defaults to empty string."
+ )
+
+ define_property(
+ SOURCE PROPERTY "COTIRE_UNITY_SOURCE_POST_UNDEFS"
+ BRIEF_DOCS "Preprocessor undefs to place in the generated unity source file after the inclusion of this source file."
+ FULL_DOCS
+ "This may be set to a semicolon-separated list of preprocessor symbols."
+ "cotire will add corresponding #undef directives to the generated unit source file after this file is included."
+ "Defaults to empty string."
+ )
+
+ define_property(
+ SOURCE PROPERTY "COTIRE_START_NEW_UNITY_SOURCE"
+ BRIEF_DOCS "Start a new unity source file which includes this source file as the first one."
+ FULL_DOCS
+ "If this property is set to TRUE, cotire will complete the current unity file and start a new one."
+ "The new unity source file will include this source file as the first one."
+ "This property essentially works as a separator for unity source files."
+ "Defaults to FALSE."
+ )
+
+ define_property(
+ SOURCE PROPERTY "COTIRE_TARGET"
+ BRIEF_DOCS "Read-only property. Mark this source file as cotired for the given target."
+ FULL_DOCS
+ "cotire sets this property to the name of target, that the source file's build command has been altered for."
+ "Defaults to empty string."
+ )
+
+ message (STATUS "cotire ${COTIRE_CMAKE_MODULE_VERSION} loaded.")
+
+endif()
diff --git a/vendor/bandit/cross_compile.sh b/vendor/bandit/cross_compile.sh
new file mode 100755
index 00000000..7be77aaa
--- /dev/null
+++ b/vendor/bandit/cross_compile.sh
@@ -0,0 +1,43 @@
+#!/bin/bash
+
+build_results=()
+
+function build_for {
+ CC=$1
+ CXX=$2
+ BUILD_DIR=$CC
+
+ mkdir $BUILD_DIR
+ pushd $BUILD_DIR
+ CC=$CC CXX=$CXX cmake ../..
+ make
+ build_results+=("$CC: $?")
+ popd
+}
+
+if [[ -d builds ]]; then
+ rm -rf builds
+fi
+
+mkdir builds
+pushd builds
+
+build_for clang-3.6 clang++-3.6
+build_for gcc-5 g++-5
+build_for clang clang++
+build_for gcc-4.9 g++-4.9
+build_for gcc-4.8 g++-4.8
+build_for gcc-4.7 g++-4.7
+build_for gcc-4.6 g++-4.6
+build_for gcc-4.5 g++-4.5
+
+popd
+
+echo
+echo "Result:"
+for res in "${build_results[@]}"
+do
+ echo $res
+done
+
+echo "Done"
diff --git a/vendor/bandit/specs/before_each_after_each.spec.cpp b/vendor/bandit/specs/before_each_after_each.spec.cpp
new file mode 100644
index 00000000..29d40574
--- /dev/null
+++ b/vendor/bandit/specs/before_each_after_each.spec.cpp
@@ -0,0 +1,78 @@
+#include <specs/specs.h>
+
+namespace bf = bandit::fakes;
+
+go_bandit([](){
+
+ describe("before_each/after_each", [&](){
+ std::unique_ptr<bandit::detail::contextstack_t> context_stack;
+ std::unique_ptr<bf::fake_context> context;
+
+ before_each([&](){
+ context = std::unique_ptr<bf::fake_context>(new bf::fake_context());
+ context_stack = std::unique_ptr<bandit::detail::contextstack_t>(new bandit::detail::contextstack_t());
+ context_stack->push_back(context.get());
+ });
+
+ describe("before_each", [&](){
+ bandit::detail::voidfunc_t before_each_fn;
+
+ before_each([&](){
+ before_each_fn = [](){};
+ });
+
+ it("registers itself for the current context in the stack", [&](){
+ before_each(before_each_fn, *context_stack);
+ Assert::That(context->call_log(), Has().Exactly(1).EqualTo("register_before_each"));
+ });
+
+ });
+
+ describe("after_each", [&](){
+ bandit::detail::voidfunc_t after_each_fn;
+
+ before_each([&](){
+ after_each_fn = [](){};
+ });
+
+ it("registers itself for the current context in the stack", [&](){
+ after_each(after_each_fn, *context_stack);
+ Assert::That(context->call_log(), Has().Exactly(1).EqualTo("register_after_each"));
+ });
+
+ });
+ });
+
+ describe("before_each/after_each integration", [&](){
+ bandit::specs::logging_fake logger;
+
+ before_each([&](){
+ logger.log() << "first before_each called" << std::endl;
+ });
+
+ before_each([&](){
+ logger.log() << "second before_each called" << std::endl;
+ });
+
+ after_each([&](){
+ logger.log() << "first after_each called" << std::endl;
+ });
+
+ after_each([&](){
+ logger.log() << "second after_each called" << std::endl;
+ });
+
+ it("should only have called the before_each functions for the first test", [&](){
+ Assert::That(logger.call_log(), Has().Exactly(1).EqualTo("first before_each called"));
+ Assert::That(logger.call_log(), Has().Exactly(1).EqualTo("second before_each called"));
+ Assert::That(logger.call_log(), Has().None().Containing("after_each"));
+ });
+
+ it("should have called 'before_each' function twice, and 'after_each' functions once for the second test", [&](){
+ Assert::That(logger.call_log(), Has().Exactly(2).EqualTo("first before_each called"));
+ Assert::That(logger.call_log(), Has().Exactly(2).EqualTo("second before_each called"));
+ Assert::That(logger.call_log(), Has().Exactly(1).EqualTo("first after_each called"));
+ Assert::That(logger.call_log(), Has().Exactly(1).EqualTo("second after_each called"));
+ });
+ });
+});
diff --git a/vendor/bandit/specs/context.spec.cpp b/vendor/bandit/specs/context.spec.cpp
new file mode 100644
index 00000000..d517ef80
--- /dev/null
+++ b/vendor/bandit/specs/context.spec.cpp
@@ -0,0 +1,44 @@
+#include <specs/specs.h>
+
+go_bandit([](){
+
+ describe("bandit_context:", [&](){
+
+ std::unique_ptr<bandit::detail::bandit_context> context;
+
+ before_each([&](){
+ bool hard_skip = false;
+ context = std::unique_ptr<bandit::detail::bandit_context>(
+ new bandit::detail::bandit_context("context name", hard_skip));
+ });
+
+ it("is ok to register before_each as it is not executing", [&](){
+ context->register_before_each([](){});
+ });
+
+ it("is ok to register after_each as it is not executing", [&](){
+ context->register_after_each([](){});
+ });
+
+ describe("is executing", [&](){
+
+ before_each([&](){
+ context->execution_is_starting();
+ });
+
+ it("is not ok to register before_each", [&](){
+ AssertThrows(bandit::detail::test_run_error, context->register_before_each([](){}));
+ Assert::That(LastException<bandit::detail::test_run_error>().what(),
+ Equals("before_each was called after 'describe' or 'it'"));
+ });
+
+ it("is not ok to register after_each", [&](){
+ AssertThrows(bandit::detail::test_run_error, context->register_after_each([](){}));
+ Assert::That(LastException<bandit::detail::test_run_error>().what(),
+ Equals("after_each was called after 'describe' or 'it'"));
+ });
+ });
+
+ });
+
+});
diff --git a/vendor/bandit/specs/describe.spec.cpp b/vendor/bandit/specs/describe.spec.cpp
new file mode 100644
index 00000000..d4600a28
--- /dev/null
+++ b/vendor/bandit/specs/describe.spec.cpp
@@ -0,0 +1,117 @@
+#include <specs/specs.h>
+
+using namespace bandit::fakes;
+namespace bd = bandit::detail;
+
+SPEC_BEGIN(describe)
+
+ describe("describe:", [](){
+ bandit::detail::voidfunc_t describe_fn;
+ fake_reporter_ptr reporter;
+ std::unique_ptr<bd::contextstack_t> context_stack;
+ std::unique_ptr<fake_context> global_context;
+
+ before_each([&](){
+ reporter = fake_reporter_ptr(new fake_reporter());
+
+ context_stack = std::unique_ptr<bd::contextstack_t>(new bd::contextstack_t());
+
+ global_context = std::unique_ptr<fake_context>(new fake_context());
+ context_stack->push_back(global_context.get());
+ });
+
+
+ auto call_describe = [&](){
+ describe("context name", describe_fn, *reporter, *context_stack);
+ };
+
+ describe("with a succeeding 'it'", [&](){
+ int context_stack_size_while_running;
+
+ before_each([&](){
+ context_stack_size_while_running = 0;
+ describe_fn = [&](){context_stack_size_while_running = context_stack->size();};
+ });
+
+ it("tells its parent context that execution has started", [&](){
+ // This is important as once execution has started,
+ // before_each and after_each calls cannot be guaranteed to
+ // be run before any 'it' method.
+
+ call_describe();
+ AssertThat(global_context->call_log(), Has().AtLeast(1).EqualTo("execution_is_starting"));
+ });
+
+ it("tells reporter it's starting a run", [&](){
+ call_describe();
+ AssertThat(reporter->call_log(), Has().Exactly(1).EqualTo("context_starting: context name"));
+ });
+
+ it("tells reporter it's finished a run", [&](){
+ call_describe();
+ AssertThat(reporter->call_log(), Has().Exactly(1).EqualTo("context_ended: context name"));
+ });
+
+ it("pushes a new context during execution", [&](){
+ call_describe();
+ AssertThat(context_stack_size_while_running, Equals(2));
+ });
+
+ it("pops the context from the stack after execution so that only the global context is left", [&](){
+ call_describe();
+ AssertThat(*context_stack, Is().OfLength(1));
+ });
+
+ });
+
+ describe("with test run error", [&](){
+ //
+ // This can occur if after_each or before_each are called
+ // after execution has started for a context.
+ //
+
+ before_each([&](){
+ describe_fn = [&](){ throw bandit::detail::test_run_error("we dun goofed!"); };
+ });
+
+ it("doesn't propagate the error", [&](){
+ call_describe();
+ });
+
+ it("tells reporter to report the error", [&](){
+ call_describe();
+ AssertThat(reporter->call_log(), Has().Exactly(1).EqualTo("test_run_error: context name (we dun goofed!)"));
+ });
+
+ });
+
+ describe("skip", [&](){
+ bool context_is_hard_skip;
+ describe_fn =
+ [&](){ context_is_hard_skip = context_stack->back()->hard_skip(); };
+
+ before_each([&](){
+ context_is_hard_skip = false;
+ });
+
+ describe("describe_skip", [&](){
+
+ it("pushes a context marked as skipped on the stack", [&](){
+ describe_skip("context name", describe_fn, *reporter, *context_stack);
+ AssertThat(context_is_hard_skip, IsTrue());
+ });
+
+ });
+
+ describe("xdescribe", [&](){
+
+ it("pushes a context marked as skipped on the stack", [&](){
+ xdescribe("context name", describe_fn, *reporter, *context_stack);
+ AssertThat(context_is_hard_skip, IsTrue());
+ });
+
+ });
+ });
+ });
+
+SPEC_END
diff --git a/vendor/bandit/specs/failure_formatters/default_formatter.spec.cpp b/vendor/bandit/specs/failure_formatters/default_formatter.spec.cpp
new file mode 100644
index 00000000..6d29b694
--- /dev/null
+++ b/vendor/bandit/specs/failure_formatters/default_formatter.spec.cpp
@@ -0,0 +1,21 @@
+#include <specs/specs.h>
+namespace bd = bandit::detail;
+
+go_bandit([](){
+
+ describe("default failure formatter", [&](){
+ bd::default_failure_formatter formatter;
+
+ it("formats assertions with file and line number", [&](){
+ bd::assertion_exception exception("message", "file", 321);
+ AssertThat(formatter.format(exception), Equals("file:321: message"));
+ });
+
+ it("formats assertions without file and line number", [&](){
+ bd::assertion_exception exception("message");
+ AssertThat(formatter.format(exception), Equals("message"));
+ });
+
+ });
+
+});
diff --git a/vendor/bandit/specs/failure_formatters/visual_studio_failure_formatter.spec.cpp b/vendor/bandit/specs/failure_formatters/visual_studio_failure_formatter.spec.cpp
new file mode 100644
index 00000000..0d283c8e
--- /dev/null
+++ b/vendor/bandit/specs/failure_formatters/visual_studio_failure_formatter.spec.cpp
@@ -0,0 +1,22 @@
+#include <specs/specs.h>
+namespace bd = bandit::detail;
+
+go_bandit([](){
+
+ describe("Visual Studio failure formatter:", [&](){
+
+ bd::visual_studio_failure_formatter formatter;
+
+ it("formats assertions with file and line number", [&](){
+ bd::assertion_exception exception("message", "file", 321);
+ AssertThat(formatter.format(exception), Equals("file(321): message"));
+ });
+
+ it("formats assertions without file and line number", [&](){
+ bd::assertion_exception exception("message");
+ AssertThat(formatter.format(exception), Equals("bandit: message"));
+ });
+
+ });
+
+});
diff --git a/vendor/bandit/specs/fakes/fake_context.h b/vendor/bandit/specs/fakes/fake_context.h
new file mode 100644
index 00000000..e5d1d870
--- /dev/null
+++ b/vendor/bandit/specs/fakes/fake_context.h
@@ -0,0 +1,69 @@
+#ifndef BANDIT_FAKE_CONTEXT_H
+#define BANDIT_FAKE_CONTEXT_H
+
+namespace bandit { namespace fakes {
+
+ struct fake_context : public bandit::detail::context, public bandit::specs::logging_fake
+ {
+ fake_context() : hard_skip_(false), name_("fake_context"),
+ custom_after_each_([](){}), custom_before_each_([](){})
+ {}
+
+ const std::string& name()
+ {
+ log() << "name" << std::endl;
+ return name_;
+ }
+
+ void execution_is_starting()
+ {
+ log() << "execution_is_starting" << std::endl;
+ }
+
+ void register_before_each(detail::voidfunc_t)
+ {
+ log() << "register_before_each" << std::endl;
+ }
+
+ void register_after_each(detail::voidfunc_t)
+ {
+ log() << "register_after_each" << std::endl;
+ }
+
+ void run_before_eaches()
+ {
+ log() << "run_before_eaches" << std::endl;
+ custom_before_each_();
+ }
+
+ void run_after_eaches()
+ {
+ log() << "run_after_eaches" << std::endl;
+ custom_after_each_();
+ }
+
+ bool hard_skip()
+ {
+ log() << "hard_skip: returning " << hard_skip_ << std::endl;
+ return hard_skip_;
+ }
+
+ void with_after_each(detail::voidfunc_t call)
+ {
+ custom_after_each_ = call;
+ }
+
+ void with_before_each(detail::voidfunc_t call)
+ {
+ custom_before_each_ = call;
+ }
+
+ private:
+ bool hard_skip_;
+ std::string name_;
+ detail::voidfunc_t custom_after_each_;
+ detail::voidfunc_t custom_before_each_;
+ };
+}}
+
+#endif
diff --git a/vendor/bandit/specs/fakes/fake_reporter.h b/vendor/bandit/specs/fakes/fake_reporter.h
new file mode 100644
index 00000000..032ed44d
--- /dev/null
+++ b/vendor/bandit/specs/fakes/fake_reporter.h
@@ -0,0 +1,78 @@
+#ifndef BANDIT_SPECS_FAKE_REPORTER_H
+#define BANDIT_SPECS_FAKE_REPORTER_H
+
+namespace bandit { namespace fakes {
+ struct fake_reporter :
+ public bandit::detail::listener,
+ public bandit::specs::logging_fake
+ {
+ fake_reporter() : test_run_status_(true)
+ {}
+
+ void test_run_starting()
+ {
+ log() << "test_run_starting" << std::endl;
+ }
+
+ void test_run_complete()
+ {
+ log() << "test_run_complete" << std::endl;
+ }
+
+ void context_starting(const char* desc)
+ {
+ log() << "context_starting: " << desc << std::endl;
+ }
+
+ void context_ended(const char* desc)
+ {
+ log() << "context_ended: " << desc << std::endl;
+ }
+
+ void test_run_error(const char* desc, const struct bandit::detail::test_run_error& err)
+ {
+ log() << "test_run_error: " << desc << " (" << strip_newline(err.what()) << ")" << std::endl;
+ }
+
+ void it_starting(const char* desc)
+ {
+ log() << "it_starting: " << desc << std::endl;
+ }
+
+ void it_succeeded(const char* desc)
+ {
+ log() << "it_succeeded: " << desc << std::endl;
+ }
+
+ void it_failed(const char* desc, const bandit::detail::assertion_exception& ex)
+ {
+ log() << "it_failed: " << desc << " (" << strip_newline(ex.what()) << ")" << std::endl;
+ }
+
+ void it_unknown_error(const char* desc)
+ {
+ log() << "it_unknown_error: " << desc << std::endl;
+ }
+
+ void it_skip(const char* desc)
+ {
+ log() << "it_skip: " << desc << std::endl;
+ }
+
+ bool did_we_pass() const
+ {
+ return test_run_status_;
+ }
+
+ void set_test_run_status(bool status)
+ {
+ test_run_status_ = status;
+ }
+
+ private:
+ bool test_run_status_;
+ };
+ typedef std::unique_ptr<fake_reporter> fake_reporter_ptr;
+}}
+
+#endif
diff --git a/vendor/bandit/specs/fakes/fakes.h b/vendor/bandit/specs/fakes/fakes.h
new file mode 100644
index 00000000..a48517f6
--- /dev/null
+++ b/vendor/bandit/specs/fakes/fakes.h
@@ -0,0 +1,8 @@
+#ifndef BANDIT_SPECS_FAKES_H
+#define BANDIT_SPECS_FAKES_H
+
+#include <specs/fakes/logging_fake.h>
+#include <specs/fakes/fake_reporter.h>
+#include <specs/fakes/fake_context.h>
+
+#endif
diff --git a/vendor/bandit/specs/fakes/logging_fake.h b/vendor/bandit/specs/fakes/logging_fake.h
new file mode 100644
index 00000000..ac1d3dd0
--- /dev/null
+++ b/vendor/bandit/specs/fakes/logging_fake.h
@@ -0,0 +1,32 @@
+#ifndef BANDIT_SPECS_LOGGING_FAKE_H
+#define BANDIT_SPECS_LOGGING_FAKE_H
+#include <sstream>
+
+namespace bandit { namespace specs {
+
+ struct logging_fake
+ {
+ std::ostream& log()
+ {
+ return logstm_;
+ }
+
+ std::string strip_newline(const char* val)
+ {
+ std::string no_newline = val;
+ std::transform(no_newline.begin(), no_newline.end(), no_newline.begin(), [](const char& c) {
+ return (c == '\n' || c == '\r') ? ' ' : c;
+ });
+ return no_newline;
+ }
+
+ std::string call_log()
+ {
+ return logstm_.str();
+ }
+
+ private:
+ std::stringstream logstm_;
+ };
+}}
+#endif
diff --git a/vendor/bandit/specs/fuzzbox.spec.cpp b/vendor/bandit/specs/fuzzbox.spec.cpp
new file mode 100644
index 00000000..6515a554
--- /dev/null
+++ b/vendor/bandit/specs/fuzzbox.spec.cpp
@@ -0,0 +1,77 @@
+#include <specs/specs.h>
+
+namespace fuzzbox {
+
+ typedef enum {
+ clean,
+ distorted
+ } sounds;
+
+ struct fuzzbox
+ {
+ fuzzbox() : sound_(sounds::clean)
+ {}
+
+ void flip()
+ {
+ sound_ = sounds::distorted;
+ }
+
+ sounds sound()
+ {
+ return sound_;
+ }
+
+ private:
+ sounds sound_;
+ };
+ typedef std::unique_ptr<fuzzbox> fuzzbox_ptr;
+
+ struct guitar
+ {
+ void add_effect(fuzzbox* effect)
+ {
+ effect_ = effect;
+ }
+
+ sounds sound()
+ {
+ return effect_->sound();
+ }
+
+ private:
+ fuzzbox* effect_;
+ };
+ typedef std::unique_ptr<guitar> guitar_ptr;
+
+go_bandit([](){
+
+ describe("fuzzbox:", [](){
+ guitar_ptr guitar;
+ fuzzbox_ptr fuzzbox;
+
+ before_each([&](){
+ guitar = guitar_ptr(new struct guitar());
+ fuzzbox = fuzzbox_ptr(new struct fuzzbox());
+ guitar->add_effect(fuzzbox.get());
+ });
+
+ it("starts in clean mode", [&](){
+ AssertThat(guitar->sound(), Equals(sounds::clean));
+ });
+
+ describe("in distorted mode", [&](){
+
+ before_each([&](){
+ fuzzbox->flip();
+ });
+
+ it("sounds distorted", [&](){
+ AssertThat(guitar->sound(), Equals(sounds::distorted));
+ });
+ });
+ });
+
+});
+
+}
diff --git a/vendor/bandit/specs/it.spec.cpp b/vendor/bandit/specs/it.spec.cpp
new file mode 100644
index 00000000..287a1ede
--- /dev/null
+++ b/vendor/bandit/specs/it.spec.cpp
@@ -0,0 +1,355 @@
+#include <specs/specs.h>
+using namespace bandit::fakes;
+namespace bd = bandit::detail;
+
+go_bandit([](){
+ describe("it:", [&](){
+ bd::voidfunc_t it_func;
+ fake_reporter_ptr reporter;
+ std::unique_ptr<bd::contextstack_t> contexts;
+ std::unique_ptr<fake_context> context;
+ bandit::adapters::snowhouse_adapter assertion_adapter;
+ bd::run_policy_ptr run_policy;
+
+ before_each([&](){
+ reporter = fake_reporter_ptr(new fake_reporter());
+ contexts = std::unique_ptr<bd::contextstack_t>(new bd::contextstack_t());
+ context = std::unique_ptr<fake_context>(new fake_context());
+ contexts->push_back(context.get());
+
+ run_policy = bd::run_policy_ptr(new bd::always_run_policy());
+ });
+
+ auto call_it = [&]() {
+ it("my it", it_func, *reporter, *contexts, assertion_adapter, *run_policy);
+ };
+
+ it("tells the current context that execution has started", [&](){
+ // This is important as once execution has started,
+ // before_each and after_each calls cannot be guaranteed to
+ // be run before any 'it' method.
+
+ call_it();
+ AssertThat(context->call_log(), Has().AtLeast(1).EqualTo("execution_is_starting"));
+ });
+
+ describe("with succeeding test", [&](){
+ before_each([&](){
+ it_func = [](){};
+ });
+
+ it("tells reporter it's starting", [&](){
+ call_it();
+ AssertThat(reporter->call_log(), Has().Exactly(1).EqualTo("it_starting: my it"));
+ });
+
+ it("tells reporter it's succeeded", [&](){
+ call_it();
+ AssertThat(reporter->call_log(), Has().Exactly(1).EqualTo("it_succeeded: my it"));
+ });
+
+ it("calls before_each in context", [&](){
+ call_it();
+ AssertThat(context->call_log(), Has().Exactly(1).EqualTo("run_before_eaches"));
+ });
+
+ it("calls after_each in context", [&](){
+ call_it();
+ AssertThat(context->call_log(), Has().Exactly(1).EqualTo("run_after_eaches"));
+ });
+
+ describe("but with a failing after_each", [&](){
+
+ before_each([&](){
+ context->with_after_each([](){ AssertThat(2, Equals(3)); });
+ });
+
+ it("tells reporter it's failed", [&](){
+ call_it();
+ AssertThat(reporter->call_log(), Has().Exactly(1).EqualTo("it_failed: my it (Expected: equal to 3 Actual: 2 )"));
+ });
+
+ it("doesn't report a succeeding test", [&](){
+ call_it();
+ AssertThat(reporter->call_log(), Has().None().EqualTo("it_succeeded: my it"));
+ });
+
+ it("tells run_policy that we have a failing test", [&](){
+ call_it();
+ AssertThat(run_policy->has_encountered_failure(), IsTrue());
+ });
+ });
+
+ describe("but with a std::exception in after_each", [&](){
+
+ before_each([&](){
+ context->with_after_each([](){ throw std::logic_error("logic is wrong!"); });
+ });
+
+ it("tells reporter it's failed", [&](){
+ call_it();
+ AssertThat(reporter->call_log(), Has().Exactly(1).EqualTo("it_failed: my it (exception: logic is wrong!)"));
+ });
+
+ it("doesn't report a succeeding test", [&](){
+ call_it();
+ AssertThat(reporter->call_log(), Has().None().EqualTo("it_succeeded: my it"));
+ });
+
+ it("tells run_policy that we have a failing test", [&](){
+ call_it();
+ AssertThat(run_policy->has_encountered_failure(), IsTrue());
+ });
+
+ });
+
+ describe("but with an unknown error in after_each", [&](){
+
+ before_each([&](){
+ context->with_after_each([](){ throw 25; });
+ });
+
+ it("tells reporter it's failed", [&](){
+ call_it();
+ AssertThat(reporter->call_log(), Has().Exactly(1).EqualTo("it_unknown_error: my it"));
+ });
+
+ it("doesn't report a succeeding test", [&](){
+ call_it();
+ AssertThat(reporter->call_log(), Has().None().EqualTo("it_succeeded: my it"));
+ });
+
+ it("tells run_policy that we have a failing test", [&](){
+ call_it();
+ AssertThat(run_policy->has_encountered_failure(), IsTrue());
+ });
+ });
+
+ describe("but with a failing before_each", [&](){
+
+ before_each([&](){
+ context->with_before_each([](){ AssertThat(2, Equals(3)); });
+ });
+
+ it("tells reporter it's failed", [&](){
+ call_it();
+ AssertThat(reporter->call_log(), Has().Exactly(1).EqualTo("it_failed: my it (Expected: equal to 3 Actual: 2 )"));
+ });
+
+ it("doesn't report a succeeding test", [&](){
+ call_it();
+ AssertThat(reporter->call_log(), Has().None().EqualTo("it_succeeded: my it"));
+ });
+
+ it("tells run_policy that we have a failing test", [&](){
+ call_it();
+ AssertThat(run_policy->has_encountered_failure(), IsTrue());
+ });
+ });
+
+ describe("but with a std::exception in before_each", [&](){
+
+ before_each([&](){
+ context->with_before_each([](){ throw std::logic_error("logic is wrong!"); });
+ });
+
+ it("tells reporter it's failed", [&](){
+ call_it();
+ AssertThat(reporter->call_log(), Has().Exactly(1).EqualTo("it_failed: my it (exception: logic is wrong!)"));
+ });
+
+ it("doesn't report a succeeding test", [&](){
+ call_it();
+ AssertThat(reporter->call_log(), Has().None().EqualTo("it_succeeded: my it"));
+ });
+
+ it("tells run_policy that we have a failing test", [&](){
+ call_it();
+ AssertThat(run_policy->has_encountered_failure(), IsTrue());
+ });
+ });
+
+ describe("but with an unknown error in before_each", [&](){
+
+ before_each([&](){
+ context->with_before_each([](){ throw 25; });
+ });
+
+ it("tells reporter it's failed", [&](){
+ call_it();
+ AssertThat(reporter->call_log(), Has().Exactly(1).EqualTo("it_unknown_error: my it"));
+ });
+
+ it("doesn't report a succeeding test", [&](){
+ call_it();
+ AssertThat(reporter->call_log(), Has().None().EqualTo("it_succeeded: my it"));
+ });
+
+ it("tells run_policy that we have a failing test", [&](){
+ call_it();
+ AssertThat(run_policy->has_encountered_failure(), IsTrue());
+ });
+ });
+
+ });
+
+ describe("with failing test", [&](){
+ before_each([&](){
+ it_func = [](){ AssertThat(3, Equals(2)); };
+ });
+
+ it("tells reporter it's failed", [&](){
+ call_it();
+ AssertThat(reporter->call_log(), Has().Exactly(1).EqualTo("it_failed: my it (Expected: equal to 2 Actual: 3 )"));
+ });
+
+ it("calls before_each in context", [&](){
+ call_it();
+ AssertThat(context->call_log(), Has().Exactly(1).EqualTo("run_before_eaches"));
+ });
+
+ it("calls after_each in context", [&](){
+ call_it();
+ AssertThat(context->call_log(), Has().Exactly(1).EqualTo("run_after_eaches"));
+ });
+
+ it("tells run_policy that we have a failing test", [&](){
+ call_it();
+ AssertThat(run_policy->has_encountered_failure(), IsTrue());
+ });
+ });
+
+
+ describe("with crashing test", [&](){
+ before_each([&](){
+ it_func = [](){ throw 44; };
+ });
+
+ it("tells reporter it's failed", [&](){
+ call_it();
+ AssertThat(reporter->call_log(), Has().Exactly(1).EqualTo("it_unknown_error: my it"));
+ });
+
+ it("calls before_each in context", [&](){
+ call_it();
+ AssertThat(context->call_log(), Has().Exactly(1).EqualTo("run_before_eaches"));
+ });
+
+ it("calls after_each in context", [&](){
+ call_it();
+ AssertThat(context->call_log(), Has().Exactly(1).EqualTo("run_after_eaches"));
+ });
+
+ it("tells run_policy that we have a failing test", [&](){
+ call_it();
+ AssertThat(run_policy->has_encountered_failure(), IsTrue());
+ });
+ });
+
+ describe("with test throwing exception based on 'std::exception'", [&](){
+
+ before_each([&](){
+ it_func = [](){ throw std::logic_error("logic error"); };
+ });
+
+ it("tells reporter it's failed", [&](){
+ call_it();
+ AssertThat(reporter->call_log(), Has().Exactly(1).EqualTo("it_failed: my it (exception: logic error)"));
+ });
+
+ it("calls before_each in context", [&](){
+ call_it();
+ AssertThat(context->call_log(), Has().Exactly(1).EqualTo("run_before_eaches"));
+ });
+
+ it("calls after_each in context", [&](){
+ call_it();
+ AssertThat(context->call_log(), Has().Exactly(1).EqualTo("run_after_eaches"));
+ });
+
+ it("tells run_policy that we have a failing test", [&](){
+ call_it();
+ AssertThat(run_policy->has_encountered_failure(), IsTrue());
+ });
+
+ });
+
+ describe("it_skip", [&](){
+
+ it("tells reporter it's skipped", [&](){
+ it_skip("my it", [](){}, *reporter);
+ AssertThat(reporter->call_log(), Has().Exactly(1).EqualTo("it_skip: my it"));
+ });
+
+ it("doesn't call function", [&](){
+ bool called = false;
+ it_skip("my it", [&](){ called = true; }, *reporter);
+ AssertThat(called, IsFalse());
+ });
+
+ });
+
+ describe("xit", [&](){
+
+ it("tells reporter it's skipped", [&](){
+ xit("my it", [](){}, *reporter);
+ AssertThat(reporter->call_log(), Has().Exactly(1).EqualTo("it_skip: my it"));
+ });
+
+ it("doesn't call function", [&](){
+ bool called = false;
+ xit("my it", [&](){ called = true; }, *reporter);
+ AssertThat(called, IsFalse());
+ });
+
+ });
+
+ describe("with a run policy that says to skip this 'it'", [&](){
+ bool it_was_called;
+
+ before_each([&](){
+ run_policy = bd::run_policy_ptr(new bd::never_run_policy());
+ it_func = [&](){ it_was_called = true; };
+ it_was_called = false;
+ });
+
+ it("tells reporter it's skipped", [&](){
+ call_it();
+ AssertThat(reporter->call_log(), Has().Exactly(1).EqualTo("it_skip: my it"));
+ });
+
+ it("doesn't call function", [&](){
+ call_it();
+ AssertThat(it_was_called, IsFalse());
+ });
+
+ });
+
+ describe("skipping", [&](){
+ bool it_was_called;
+
+ before_each([&](){
+ it_func = [&](){ it_was_called = true; };
+ it_was_called = false;
+ });
+
+ describe("with a policy that says to skip this it", [&](){
+
+ before_each([&](){
+ run_policy = bd::run_policy_ptr(new bd::never_run_policy());
+ });
+
+ it("tells reporter it's skipped", [&](){
+ call_it();
+ AssertThat(reporter->call_log(), Has().Exactly(1).EqualTo("it_skip: my it"));
+ });
+
+ it("doesn't call function", [&](){
+ call_it();
+ AssertThat(it_was_called, IsFalse());
+ });
+
+ });
+ });
+ });
+});
diff --git a/vendor/bandit/specs/main.cpp b/vendor/bandit/specs/main.cpp
new file mode 100644
index 00000000..dde5de2d
--- /dev/null
+++ b/vendor/bandit/specs/main.cpp
@@ -0,0 +1,6 @@
+#include <specs/specs.h>
+
+int main(int argc, char* argv[])
+{
+ return bandit::run(argc, argv);
+}
diff --git a/vendor/bandit/specs/matchers/be_close_to.cpp b/vendor/bandit/specs/matchers/be_close_to.cpp
new file mode 100644
index 00000000..64309673
--- /dev/null
+++ b/vendor/bandit/specs/matchers/be_close_to.cpp
@@ -0,0 +1,112 @@
+#include <specs/specs.h>
+
+using namespace bandit::Matchers;
+
+SPEC_BEGIN(Matchers::BeCloseTo)
+
+describe("be_close_to matcher", []{
+ describe("when the actual value is declared as a float", [&]{
+ float actualValue = 2.0 / 3.0;
+
+ describe("and the expected value is also a float", [&]{
+ float expectedValue;
+
+ describe("with an explicit threshold", [&]{
+ float threshold = 0.1;
+
+ describe("and the values are within the given threshold", [&]{
+ before_each([&]{
+ expectedValue = 2.0 / 3.0 + 0.01;
+ });
+
+ it("must accept a positive match", [&]{
+ actualValue must be_close_to(expectedValue).within(threshold);
+ });
+
+ it("must reject a negative match", [&]{
+ AssertThrows(std::exception, [&]{ actualValue must_not be_close_to(expectedValue).within(threshold); }());
+ });
+ });
+
+ describe("and the values are not within the given threshold", [&]{
+ before_each([&]{
+ expectedValue = 2.0 / 3.0 + 0.2;
+ });
+
+ it("must accept a negative match", [&]{
+ actualValue must_not be_close_to(expectedValue).within(threshold);
+ });
+
+ it("must reject a positive match", [&]{
+ AssertThrows(std::exception, [&]{ actualValue must be_close_to(expectedValue).within(threshold); }());
+ });
+ });
+ });
+
+ describe("without an explicit threshold", [&]{
+ describe("and the values are within the default threshold", [&]{
+ before_each([&]{
+ expectedValue = 2.0 / 3.0 + 0.000001;
+ });
+
+ it("must accept a positive match", [&]{
+ actualValue must be_close_to(expectedValue);
+ });
+
+ it("must reject a negative match", [&]{
+ AssertThrows(std::exception, [&]{ actualValue must_not be_close_to(expectedValue); }());
+ });
+ });
+
+ describe("and the values are not within the default threshold", [&]{
+ before_each([&]{
+ expectedValue = 2.0 / 3.0 + 0.1;
+ });
+
+ it("must accept a negative match", [&]{
+ actualValue must_not be_close_to(expectedValue);
+ });
+
+ it("must reject a positive match", [&]{
+ AssertThrows(std::exception, [&]{ actualValue must be_close_to(expectedValue); }());
+ });
+ });
+ });
+ });
+
+ describe("and the expected value is a compatible non-float type", [&]{
+ int expectedValue;
+ float threshold = 1;
+
+ describe("and the values are within the given threshold", [&]{
+ before_each([&]{
+ expectedValue = 1;
+ });
+
+ it("must accept a positive match", [&]{
+ actualValue must be_close_to(expectedValue).within(threshold);
+ });
+
+ it("must reject a negative match", [&]{
+ AssertThrows(std::exception, [&]{ actualValue must_not be_close_to(expectedValue).within(threshold); }());
+ });
+ });
+
+ describe("and the values are not within the given threshold", [&]{
+ before_each([&]{
+ expectedValue = 5;
+ });
+
+ it("must accept a negative match", [&]{
+ actualValue must_not be_close_to(expectedValue).within(threshold);
+ });
+
+ it("must reject a positive match", [&]{
+ AssertThrows(std::exception, [&]{ actualValue must be_close_to(expectedValue).within(threshold); }());
+ });
+ });
+ });
+ });
+});
+
+SPEC_END
diff --git a/vendor/bandit/specs/matchers/be_empty.cpp b/vendor/bandit/specs/matchers/be_empty.cpp
new file mode 100644
index 00000000..3ed4a6f9
--- /dev/null
+++ b/vendor/bandit/specs/matchers/be_empty.cpp
@@ -0,0 +1,89 @@
+#include <set>
+
+#include <specs/specs.h>
+
+using namespace bandit::Matchers;
+
+SPEC_BEGIN(Matchers::BeEmpty)
+
+describe("be_empty matcher", [&]{
+ describe("when the value is an STL vector", [&]{
+ describe("which is empty", [&]{
+ std::vector<int> container;
+
+ it("must pass a positive match", [&]{
+ container must be_empty;
+ });
+
+ it("must reject a negative match", [&]{
+ AssertThrows(std::exception, [&]{ container must_not be_empty; }());
+ });
+ });
+
+ describe("which is not empty", [&]{
+ std::vector<int> container {2, 7};
+
+ it("must pass a negative match", [&]{
+ container must_not be_empty;
+ });
+
+ it("must reject a positive match", [&]{
+ AssertThrows(std::exception, [&]{ container must be_empty; }());
+ });
+ });
+ });
+
+ describe("when the value is an STL map", [&]{
+ describe("which is empty", [&]{
+ std::map<int, int> container;
+
+ it("must pass a positive match", [&]{
+ container must be_empty;
+ });
+
+ it("must reject a negative match", [&]{
+ AssertThrows(std::exception, [&]{ container must_not be_empty; }());
+ });
+ });
+
+ describe("which is not empty", [&]{
+ std::map<int, int> container {{5, 6}, {7,10}};
+
+ it("must pass a negative match", [&]{
+ container must_not be_empty;
+ });
+
+ it("must reject a positive match", [&]{
+ AssertThrows(std::exception, [&]{ container must be_empty; }());
+ });
+ });
+ });
+
+ describe("when the value is an STL set", [&]{
+ describe("which is empty", [&]{
+ std::set<int> container;
+
+ it("must pass a positive match", [&]{
+ container must be_empty;
+ });
+
+ it("must reject a negative match", [&]{
+ AssertThrows(std::exception, [&]{ container must_not be_empty; }());
+ });
+ });
+
+ describe("which is not empty", [&]{
+ std::set<int> container {5, 7};
+
+ it("must pass a negative match", [&]{
+ container must_not be_empty;
+ });
+
+ it("must reject a positive match", [&]{
+ AssertThrows(std::exception, [&]{ container must be_empty; }());
+ });
+ });
+ });
+});
+
+SPEC_END
diff --git a/vendor/bandit/specs/matchers/be_falsy.cpp b/vendor/bandit/specs/matchers/be_falsy.cpp
new file mode 100644
index 00000000..d8c71c1b
--- /dev/null
+++ b/vendor/bandit/specs/matchers/be_falsy.cpp
@@ -0,0 +1,85 @@
+#include <specs/specs.h>
+
+using namespace bandit::Matchers;
+
+SPEC_BEGIN(Matchers::BeFalsy)
+
+describe("be_falsy matcher", [&]{
+ describe("when the value is a built-in type", [&]{
+ bool value;
+
+ describe("which evaluates to false", [&]{
+ before_each([&]{
+ value = false;
+ });
+
+ it("must accept a positive match", [&]{
+ value must be_falsy;
+ });
+
+ it("must reject a negative match", [&]{
+ AssertThrows(std::exception, [&]{ value must_not be_falsy; }());
+ });
+ });
+
+ describe("which evaluates to true", [&]{
+ before_each([&]{
+ value = true;
+ });
+
+ it("must accept a negative match", [&]{
+ value must_not be_falsy;
+ });
+
+ it("must reject a positive match", [&]{
+ AssertThrows(std::exception, [&]{ value must be_falsy; }());
+ });
+ });
+ });
+
+ describe("when the value is nullptr", [&]{
+ auto value = nullptr;
+
+ it("must accept a positive match", [&]{
+ value must be_falsy;
+ });
+
+ it("must reject a negative match", [&]{
+ AssertThrows(std::exception, [&]{ value must_not be_falsy; }());
+ });
+ });
+
+ describe("when the value is a pointer", [&]{
+ char* value;
+
+ describe("which evaluates to false", [&]{
+ before_each([&]{
+ value = NULL;
+ });
+
+ it("must accept a positive match", [&]{
+ value must be_falsy;
+ });
+
+ it("must reject a negative match", [&]{
+ AssertThrows(std::exception, [&]{ value must_not be_falsy; }());
+ });
+ });
+
+ describe("which evaluates to true", [&]{
+ before_each([&]{
+ value = (char*)"cat";
+ });
+
+ it("must accept a negative match", [&]{
+ value must_not be_falsy;
+ });
+
+ it("must reject a positive match", [&]{
+ AssertThrows(std::exception, [&]{ value must be_falsy; }());
+ });
+ });
+ });
+});
+
+SPEC_END
diff --git a/vendor/bandit/specs/matchers/be_greater_than.cpp b/vendor/bandit/specs/matchers/be_greater_than.cpp
new file mode 100644
index 00000000..17a97fe3
--- /dev/null
+++ b/vendor/bandit/specs/matchers/be_greater_than.cpp
@@ -0,0 +1,105 @@
+#include <specs/specs.h>
+
+using namespace bandit::Matchers;
+
+SPEC_BEGIN(Matchers::BeGreaterThan)
+
+describe("be_greater_than matcher", []{
+ describe("when the actual value is a built-in type", [&]{
+ int actualValue = 10;
+
+ describe("and the expected value is the same built-in type", [&]{
+ int expectedValue;
+
+ describe("and the actual value is greater than the expected value", [&]{
+ before_each([&]{
+ expectedValue = 1;
+ });
+
+ it("must pass a positive match", [&]{
+ actualValue must be_greater_than(expectedValue);
+ });
+
+ it("must reject a negative match", [&]{
+ AssertThrows(std::exception, [&]{ actualValue must_not be_greater_than(expectedValue); }());
+ });
+ });
+
+ describe("and the actual value is less than the expected value", [&]{
+ before_each([&]{
+ expectedValue = 100;
+ });
+
+ it("must pass a negative match", [&]{
+ actualValue must_not be_greater_than(expectedValue);
+ });
+
+ it("must reject a positive match", [&]{
+ AssertThrows(std::exception, [&]{ actualValue must be_greater_than(expectedValue); }());
+ });
+ });
+
+ describe("and the actual value equals the expected value", [&]{
+ before_each([&]{
+ expectedValue = actualValue;
+ });
+
+ it("must pass a negative match", [&]{
+ actualValue must_not be_greater_than(expectedValue);
+ });
+
+ it("must reject a positive match", [&]{
+ AssertThrows(std::exception, [&]{ actualValue must be_greater_than(expectedValue); }());
+ });
+ });
+ });
+
+ describe("and the expected value is a different, but comparable, built-in type", [&]{
+ float expectedValue;
+
+ describe("and the actual value is greater than the expected value", [&]{
+ before_each([&]{
+ expectedValue = 1.1;
+ });
+
+ it("must pass a positive match", [&]{
+ actualValue must be_greater_than(expectedValue);
+ });
+
+ it("must reject a negative match", [&]{
+ AssertThrows(std::exception, [&]{ actualValue must_not be_greater_than(expectedValue); }());
+ });
+ });
+
+ describe("and the actual value is less than the expected value", [&]{
+ before_each([&]{
+ expectedValue = 100.1;
+ });
+
+ it("must pass a negative match", [&]{
+ actualValue must_not be_greater_than(expectedValue);
+ });
+
+ it("must reject a positive match", [&]{
+ AssertThrows(std::exception, [&]{ actualValue must be_greater_than(expectedValue); }());
+ });
+ });
+
+ describe("and the actual value equals the expected value", [&]{
+ before_each([&]{
+ expectedValue = actualValue;
+ });
+
+ it("must pass a negative match", [&]{
+ actualValue must_not be_greater_than(expectedValue);
+ });
+
+ it("must reject a positive match", [&]{
+ AssertThrows(std::exception, [&]{ actualValue must be_greater_than(expectedValue); }());
+ });
+ });
+ });
+ });
+});
+
+SPEC_END
diff --git a/vendor/bandit/specs/matchers/be_gte.cpp b/vendor/bandit/specs/matchers/be_gte.cpp
new file mode 100644
index 00000000..f0e18313
--- /dev/null
+++ b/vendor/bandit/specs/matchers/be_gte.cpp
@@ -0,0 +1,120 @@
+#include <specs/specs.h>
+
+using namespace bandit::Matchers;
+
+
+SPEC_BEGIN(Matchers::BeGTE)
+
+describe("be_gte matcher", [&]{
+ int someInteger = 10;
+
+ describe("when the actual value is a built-in type", [&]{
+ int actualValue = someInteger;
+
+ describe("and the expected value is the same built-in type", [&]{
+ int expectedValue;
+
+ describe("and the actual value is greater than the expected value", [&]{
+ before_each([&]{
+ expectedValue = 1;
+ });
+
+ it("must pass a positive match", [&]{
+ actualValue must be_gte(expectedValue);
+ actualValue must be_greater_than_or_equal_to(expectedValue);
+ });
+
+ it("must reject a negative match", [&]{
+ AssertThrows(std::exception, [&]{ actualValue must_not be_gte(expectedValue); }());
+ AssertThrows(std::exception, [&]{ actualValue must_not be_greater_than_or_equal_to(expectedValue); }());
+ });
+ });
+
+ describe("and the actual value is less than the expected value", [&]{
+ before_each([&]{
+ expectedValue = 100;
+ });
+
+ it("must pass a negative match", [&]{
+ actualValue must_not be_gte(expectedValue);
+ actualValue must_not be_greater_than_or_equal_to(expectedValue);
+ });
+
+ it("must reject a positive match", [&]{
+ AssertThrows(std::exception, [&]{ actualValue must be_gte(expectedValue); }());
+ AssertThrows(std::exception, [&]{ actualValue must be_greater_than_or_equal_to(expectedValue); }());
+ });
+ });
+
+ describe("and the actual value equals the expected value", [&]{
+ before_each([&]{
+ expectedValue = actualValue;
+ });
+
+ it("must pass a positive match", [&]{
+ actualValue must be_gte(expectedValue);
+ actualValue must be_greater_than_or_equal_to(expectedValue);
+ });
+
+ it("must reject a negative match", [&]{
+ AssertThrows(std::exception, [&]{ actualValue must_not be_gte(expectedValue); }());
+ AssertThrows(std::exception, [&]{ actualValue must_not be_greater_than_or_equal_to(expectedValue); }());
+ });
+ });
+ });
+
+ describe("and the expected value is a different, but comparable, built-in type", [&]{
+ float expectedValue;
+
+ describe("and the actual value is greater than the expected value", [&]{
+ before_each([&]{
+ expectedValue = 1.1;
+ });
+
+ it("must pass a positive match", [&]{
+ actualValue must be_gte(expectedValue);
+ actualValue must be_greater_than_or_equal_to(expectedValue);
+ });
+
+ it("must reject a negative match", [&]{
+ AssertThrows(std::exception, [&]{ actualValue must_not be_gte(expectedValue); }());
+ AssertThrows(std::exception, [&]{ actualValue must_not be_greater_than_or_equal_to(expectedValue); }());
+ });
+ });
+
+ describe("and the actual value is less than the expected value", [&]{
+ before_each([&]{
+ expectedValue = 100.1;
+ });
+
+ it("must pass a negative match", [&]{
+ actualValue must_not be_gte(expectedValue);
+ actualValue must_not be_greater_than_or_equal_to(expectedValue);
+ });
+
+ it("must reject a positive match", [&]{
+ AssertThrows(std::exception, [&]{ actualValue must be_gte(expectedValue); }());
+ AssertThrows(std::exception, [&]{ actualValue must be_greater_than_or_equal_to(expectedValue); }());
+ });
+ });
+
+ describe("and the actual value equals the expected value", [&]{
+ before_each([&]{
+ expectedValue = someInteger / 1.0;
+ });
+
+ it("must pass a positive match", [&]{
+ actualValue must be_gte(expectedValue);
+ actualValue must be_greater_than_or_equal_to(expectedValue);
+ });
+
+ it("must reject a negative match", [&]{
+ AssertThrows(std::exception, [&]{ actualValue must_not be_gte(expectedValue); }());
+ AssertThrows(std::exception, [&]{ actualValue must_not be_greater_than_or_equal_to(expectedValue); }());
+ });
+ });
+ });
+ });
+});
+
+SPEC_END
diff --git a/vendor/bandit/specs/matchers/be_less_than.cpp b/vendor/bandit/specs/matchers/be_less_than.cpp
new file mode 100644
index 00000000..30f60c47
--- /dev/null
+++ b/vendor/bandit/specs/matchers/be_less_than.cpp
@@ -0,0 +1,105 @@
+#include <specs/specs.h>
+
+using namespace bandit::Matchers;
+
+SPEC_BEGIN(Matchers::BeLessThan)
+
+describe("be_less_than matcher", []{
+ describe("when the actual value is a built-in type", [&]{
+ int actualValue = 10;
+
+ describe("and the expected value is the same built-in type", [&]{
+ int expectedValue;
+
+ describe("and the actual value is greater than the expected value", [&]{
+ before_each([&]{
+ expectedValue = 1;
+ });
+
+ it("must pass a negative match", [&]{
+ actualValue must_not be_less_than(expectedValue);
+ });
+
+ it("must reject a positive match", [&]{
+ AssertThrows(std::exception, [&]{ actualValue must be_less_than(expectedValue); }());
+ });
+ });
+
+ describe("and the actual value is less than the expected value", [&]{
+ before_each([&]{
+ expectedValue = 100;
+ });
+
+ it("must pass a positive match", [&]{
+ actualValue must be_less_than(expectedValue);
+ });
+
+ it("must reject a negative match", [&]{
+ AssertThrows(std::exception, [&]{ actualValue must_not be_less_than(expectedValue); }());
+ });
+ });
+
+ describe("and the actual value equals the expected value", [&]{
+ before_each([&]{
+ expectedValue = actualValue;
+ });
+
+ it("must pass a negative match", [&]{
+ actualValue must_not be_less_than(expectedValue);
+ });
+
+ it("must reject a positive match", [&]{
+ AssertThrows(std::exception, [&]{ actualValue must be_less_than(expectedValue); }());
+ });
+ });
+ });
+
+ describe("and the expected value is a different, but comparable, built-in type", [&]{
+ float expectedValue;
+
+ describe("and the actual value is greater than the expected value", [&]{
+ before_each([&]{
+ expectedValue = 1.1;
+ });
+
+ it("must pass a negative match", [&]{
+ actualValue must_not be_less_than(expectedValue);
+ });
+
+ it("must reject a positive match", [&]{
+ AssertThrows(std::exception, [&]{ actualValue must be_less_than(expectedValue); }());
+ });
+ });
+
+ describe("and the actual value is less than the expected value", [&]{
+ before_each([&]{
+ expectedValue = 100.1;
+ });
+
+ it("must pass a positive match", [&]{
+ actualValue must be_less_than(expectedValue);
+ });
+
+ it("must reject a negative match", [&]{
+ AssertThrows(std::exception, [&]{ actualValue must_not be_less_than(expectedValue); }());
+ });
+ });
+
+ describe("and the actual value equals the expected value", [&]{
+ before_each([&]{
+ expectedValue = actualValue;
+ });
+
+ it("must pass a negative match", [&]{
+ actualValue must_not be_less_than(expectedValue);
+ });
+
+ it("must reject a positive match", [&]{
+ AssertThrows(std::exception, [&]{ actualValue must be_less_than(expectedValue); }());
+ });
+ });
+ });
+ });
+});
+
+SPEC_END
diff --git a/vendor/bandit/specs/matchers/be_lte.cpp b/vendor/bandit/specs/matchers/be_lte.cpp
new file mode 100644
index 00000000..443ac1c5
--- /dev/null
+++ b/vendor/bandit/specs/matchers/be_lte.cpp
@@ -0,0 +1,119 @@
+#include <specs/specs.h>
+
+using namespace bandit::Matchers;
+
+SPEC_BEGIN(Matchers::BeLTE)
+
+describe("be_lte matcher", [&]{
+ int someInteger = 10;
+
+ describe("when the actual value is a built-in type", [&]{
+ int actualValue = someInteger;
+
+ describe("and the expected value is the same built-in type", [&]{
+ int expectedValue;
+
+ describe("and the actual value is greater than the expected value", [&]{
+ before_each([&]{
+ expectedValue = 1;
+ });
+
+ it("must pass a negative match", [&]{
+ actualValue must_not be_lte(expectedValue);
+ actualValue must_not be_less_than_or_equal_to(expectedValue);
+ });
+
+ it("must reject a positive match", [&]{
+ AssertThrows(std::exception, [&]{ actualValue must be_lte(expectedValue); }());
+ AssertThrows(std::exception, [&]{ actualValue must be_less_than_or_equal_to(expectedValue); }());
+ });
+ });
+
+ describe("and the actual value is less than the expected value", [&]{
+ before_each([&]{
+ expectedValue = 100;
+ });
+
+ it("must pass a positive match", [&]{
+ actualValue must be_lte(expectedValue);
+ actualValue must be_less_than_or_equal_to(expectedValue);
+ });
+
+ it("must reject a negative match", [&]{
+ AssertThrows(std::exception, [&]{ actualValue must_not be_lte(expectedValue); }());
+ AssertThrows(std::exception, [&]{ actualValue must_not be_less_than_or_equal_to(expectedValue); }());
+ });
+ });
+
+ describe("and the actual value equals the expected value", [&]{
+ before_each([&]{
+ expectedValue = actualValue;
+ });
+
+ it("must pass a positive match", [&]{
+ actualValue must be_lte(expectedValue);
+ actualValue must be_less_than_or_equal_to(expectedValue);
+ });
+
+ it("must reject a negative match", [&]{
+ AssertThrows(std::exception, [&]{ actualValue must_not be_lte(expectedValue); }());
+ AssertThrows(std::exception, [&]{ actualValue must_not be_less_than_or_equal_to(expectedValue); }());
+ });
+ });
+ });
+
+ describe("and the expected value is a different, but comparable, built-in type", [&]{
+ float expectedValue;
+
+ describe("and the actual value is greater than the expected value", [&]{
+ before_each([&]{
+ expectedValue = 1.1;
+ });
+
+ it("must pass a negative match", [&]{
+ actualValue must_not be_lte(expectedValue);
+ actualValue must_not be_less_than_or_equal_to(expectedValue);
+ });
+
+ it("must reject a positive match", [&]{
+ AssertThrows(std::exception, [&]{ actualValue must be_lte(expectedValue); }());
+ AssertThrows(std::exception, [&]{ actualValue must be_less_than_or_equal_to(expectedValue); }());
+ });
+ });
+
+ describe("and the actual value is less than the expected value", [&]{
+ before_each([&]{
+ expectedValue = 100.1;
+ });
+
+ it("must pass a positive match", [&]{
+ actualValue must be_lte(expectedValue);
+ actualValue must be_less_than_or_equal_to(expectedValue);
+ });
+
+ it("must reject a negative match", [&]{
+ AssertThrows(std::exception, [&]{ actualValue must_not be_lte(expectedValue); }());
+ AssertThrows(std::exception, [&]{ actualValue must_not be_less_than_or_equal_to(expectedValue); }());
+ });
+ });
+
+ describe("and the actual value equals the expected value", [&]{
+ before_each([&]{
+ expectedValue = someInteger / 1.0;
+ });
+
+ it("must pass a positive match", [&]{
+ actualValue must be_lte(expectedValue);
+ actualValue must be_less_than_or_equal_to(expectedValue);
+ });
+
+ it("must reject a negative match", [&]{
+ AssertThrows(std::exception, [&]{ actualValue must_not be_lte(expectedValue); }());
+ AssertThrows(std::exception, [&]{ actualValue must_not be_less_than_or_equal_to(expectedValue); }());
+ });
+ });
+ });
+ });
+});
+
+SPEC_END
diff --git a/vendor/bandit/specs/matchers/be_null.cpp b/vendor/bandit/specs/matchers/be_null.cpp
new file mode 100644
index 00000000..ae3cd40d
--- /dev/null
+++ b/vendor/bandit/specs/matchers/be_null.cpp
@@ -0,0 +1,43 @@
+#include <specs/specs.h>
+
+using namespace bandit::Matchers;
+
+SPEC_BEGIN(Matchers::BeNull)
+
+describe("be_null matcher", [&]{
+ describe("when the value is a pointer to a built-in type", [&]{
+ int* value;
+
+ describe("which is NULL", [&]{
+ before_each([&]{
+ value = NULL;
+ });
+
+ it("must pass a positive match", [&]{
+ value must be_null;
+ });
+
+ it("must reject a negative match", [&]{
+ AssertThrows(std::exception, [&]{ value must_not be_null; }());
+ });
+ });
+
+ describe("which is not NULL", [&]{
+ int i = 7;
+
+ before_each([&]{
+ value = &i;
+ });
+
+ it("must pass a negative match", [&]{
+ value must_not be_null;
+ });
+
+ it("must reject a positive match", [&]{
+ AssertThrows(std::exception, [&]{ value must be_null; }());
+ });
+ });
+ });
+});
+
+SPEC_END
diff --git a/vendor/bandit/specs/matchers/be_truthy.cpp b/vendor/bandit/specs/matchers/be_truthy.cpp
new file mode 100644
index 00000000..5e583fbf
--- /dev/null
+++ b/vendor/bandit/specs/matchers/be_truthy.cpp
@@ -0,0 +1,85 @@
+#include <specs/specs.h>
+
+using namespace bandit::Matchers;
+
+SPEC_BEGIN(Matchers::BeTruthy)
+
+describe("be_truthy matcher", [&]{
+ describe("when the value is a built-in type", [&]{
+ bool value;
+
+ describe("which evaluates to false", [&]{
+ before_each([&]{
+ value = false;
+ });
+
+ it("must accept a negative match", [&]{
+ value must_not be_truthy;
+ });
+
+ it("must reject a positive match", [&]{
+ AssertThrows(std::exception, [&]{ value must be_truthy; }());
+ });
+ });
+
+ describe("which evaluates to true", [&]{
+ before_each([&]{
+ value = true;
+ });
+
+ it("must accept a positive match", [&]{
+ value must be_truthy;
+ });
+
+ it("must reject a negative match", [&]{
+ AssertThrows(std::exception, [&]{ value must_not be_truthy; }());
+ });
+ });
+ });
+
+ describe("when the value is nullptr", [&]{
+ auto value = nullptr;
+
+ it("must accept a negative match", [&]{
+ value must_not be_truthy;
+ });
+
+ it("must reject a positive match", [&]{
+ AssertThrows(std::exception, [&]{ value must be_truthy; }());
+ });
+ });
+
+ describe("when the value is a pointer", [&]{
+ char* value;
+
+ describe("which evaluates to false", [&]{
+ before_each([&]{
+ value = NULL;
+ });
+
+ it("must accept a negative match", [&]{
+ value must_not be_truthy;
+ });
+
+ it("must reject a positive match", [&]{
+ AssertThrows(std::exception, [&]{ value must be_truthy; }());
+ });
+ });
+
+ describe("which evaluates to true", [&]{
+ before_each([&]{
+ value = (char*)"cat";
+ });
+
+ it("must accept a positive match", [&]{
+ value must be_truthy;
+ });
+
+ it("must reject a negative match", [&]{
+ AssertThrows(std::exception, [&]{ value must_not be_truthy; }());
+ });
+ });
+ });
+});
+
+SPEC_END
diff --git a/vendor/bandit/specs/matchers/contain.cpp b/vendor/bandit/specs/matchers/contain.cpp
new file mode 100644
index 00000000..2c0b4b3b
--- /dev/null
+++ b/vendor/bandit/specs/matchers/contain.cpp
@@ -0,0 +1,156 @@
+#include <set>
+
+#include <specs/specs.h>
+
+using namespace bandit::Matchers;
+
+SPEC_BEGIN(Matchers::Contain)
+
+describe("contain matcher", [&]{
+ std::string element0("element0");
+ std::string element1("element1");
+
+ describe("when the container is an STL vector", [&]{
+ describe("which contains the element", [&]{
+ std::vector<std::string> container {element0, element1};
+
+ it("must pass a positive match", [&]{
+ container must contain(element1);
+ });
+
+ it("must reject a negative match", [&]{
+ AssertThrows(std::exception, [&]{ container must_not contain(element1); }());
+ });
+ });
+
+ describe("which does not contain the element", [&]{
+ std::vector<int> container;
+
+ it("must pass a negative match", [&]{
+ container must_not contain(4);
+ });
+
+ it("must reject a positive match", [&]{
+ AssertThrows(std::exception, [&]{ container must contain(4); }());
+ });
+ });
+ });
+
+ describe("when the container is an STL map", [&]{
+ describe("which contains the expected key", [&]{
+ std::map<int, int> container {{5, 6}, {7,10}};
+
+ it("must pass a positive match", [&]{
+ container must contain(5);
+ });
+
+ it("must reject a negative match", [&]{
+ AssertThrows(std::exception, [&]{ container must_not contain(5); }());
+ });
+ });
+
+ describe("which does not contain the expected value", [&]{
+ std::map<int, int> container;
+
+ it("must pass a negative match", [&]{
+ container must_not contain(6);
+ });
+
+ it("must reject a positive match", [&]{
+ AssertThrows(std::exception, [&]{ container must contain(6); }());
+ });
+ });
+ });
+
+ describe("when the container is an STL set", [&]{
+ describe("which contains the element", [&]{
+ std::set<int> container {5, 7};
+
+ it("must pass a positive match", [&]{
+ container must contain(7);
+ });
+
+ it("must reject a negative match", [&]{
+ AssertThrows(std::exception, [&]{ container must_not contain(7); }());
+ });
+ });
+
+ describe("which does not contain the element", [&]{
+ std::set<int> container;
+
+ it("must pass a negative match", [&]{
+ container must_not contain(7);
+ });
+
+ it("must reject a positive match", [&]{
+ AssertThrows(std::exception, [&]{ container must contain(7); }());
+ });
+ });
+ });
+
+ describe("when the container is a C string", [&]{
+ describe("which is null", [&]{
+ char* container = NULL;
+
+ it("must reject a positive match", [&]{
+ AssertThrows(std::exception, [&]{ container must contain("foo"); }());
+ });
+ });
+
+ describe("which contains the substring", [&]{
+ char* container = (char*)"jack and jill";
+ char* element = (char*)"jack";
+
+ it("must pass a positive match", [&]{
+ container must contain(element);
+ });
+
+ it("must reject a negative match", [&]{
+ AssertThrows(std::exception, [&]{ container must_not contain(element); }());
+ });
+ });
+
+ describe("which does not contain the substring", [&]{
+ char* container = (char*)"batman and robin";
+ char* element = (char*)"catwoman";
+
+ it("must reject a positive match", [&]{
+ AssertThrows(std::exception, [&]{ container must contain(element); }());
+ });
+
+ it("must pass a negative match", [&]{
+ container must_not contain(element);
+ });
+ });
+ });
+
+ describe("when the container is a const C string", [&]{
+ describe("which contains the substring", [&]{
+ const char* container = (char*)"jack and jill";
+ const char* element = (char*)"jack";
+
+ it("must pass a positive match", [&]{
+ container must contain(element);
+ });
+
+ it("must reject a negative match", [&]{
+ AssertThrows(std::exception, [&]{ container must_not contain(element); }());
+ });
+ });
+
+ describe("which does not contain the substring", [&]{
+ const char* container = (char*)"batman and robin";
+ const char* element = (char*)"catwoman";
+
+ it("must reject a positive match", [&]{
+ AssertThrows(std::exception, [&]{ container must contain(element); }());
+ });
+
+ it("must pass a negative match", [&]{
+ container must_not contain(element);
+ });
+ });
+ });
+});
+
+SPEC_END
diff --git a/vendor/bandit/specs/matchers/equal.cpp b/vendor/bandit/specs/matchers/equal.cpp
new file mode 100644
index 00000000..f7f31b0b
--- /dev/null
+++ b/vendor/bandit/specs/matchers/equal.cpp
@@ -0,0 +1,214 @@
+#include <specs/specs.h>
+
+using namespace bandit::Matchers;
+
+SPEC_BEGIN(Matchers::Equal)
+
+describe("when the actual value is a built-in type", []{
+ int actualValue = 1;
+
+ describe("and the expected value is the same built-in type", [&]{
+ int expectedValue;
+
+ describe("and the values are equal", [&]{
+ before_each([&]{
+ expectedValue = 1;
+ });
+
+ it("must accept a positive match", [&]{
+ actualValue must equal(expectedValue);
+ });
+
+ it("must reject a negative match", [&]{
+ AssertThrows(std::exception, [&]{ actualValue must_not equal(expectedValue); }());
+ });
+ });
+
+ describe("and the values are not equal", [&]{
+ before_each([&]{
+ expectedValue = 147;
+ });
+
+ it("must accept a negative match", [&]{
+ actualValue must_not equal(expectedValue);
+ });
+
+ it("must reject a positive match", [&]{
+ AssertThrows(std::exception, [&]{ actualValue must equal(expectedValue); }());
+ });
+ });
+ });
+
+ describe("and the expected value is a different, but comparable, built-in type", [&]{
+ long int expectedValue;
+
+ describe("and the values are equal", [&]{
+ before_each([&]{
+ expectedValue = 1;
+ });
+
+ it("must accept a positive match", [&]{
+ actualValue must equal(expectedValue);
+ });
+
+ it("must reject a negative match", [&]{
+ AssertThrows(std::exception, [&]{ actualValue must_not equal(expectedValue); }());
+ });
+ });
+
+ describe("and the values are not equal", [&]{
+ before_each([&]{
+ expectedValue = 42;
+ });
+
+ it("must accept a negative match", [&]{
+ actualValue must_not equal(expectedValue);
+ });
+
+ it("must reject a positive match", [&]{
+ AssertThrows(std::exception, [&]{ actualValue must equal(expectedValue); }());
+ });
+ });
+ });
+});
+
+describe("when the actual value is declared as a C string", []{
+ char* actualValue = (char*)"actualValue";
+
+ describe("and the expected value is declared as a C string", [&]{
+ std::unique_ptr<char> expectedValue;
+
+ before_each([&]{
+ expectedValue.reset((char*)calloc(strlen(actualValue) + 1, sizeof(char)));
+ });
+
+ describe("and the values are equal", [&]{
+ before_each([&]{
+ stpcpy(expectedValue.get(), actualValue);
+ });
+
+ it("must accept a positive match", [&]{
+ actualValue must equal(expectedValue.get());
+ });
+
+ it("must reject a negative match", [&]{
+ AssertThrows(std::exception, [&]{ actualValue must_not equal(expectedValue.get()); }());
+ });
+ });
+
+ describe("and the values are not equal", [&]{
+ before_each([&]{
+ stpcpy(expectedValue.get(), "expectedVal");
+ });
+
+ it("must accept a negative match", [&]{
+ actualValue must_not equal(expectedValue.get());
+ });
+
+ it("must reject a positive match", [&]{
+ AssertThrows(std::exception, [&]{ actualValue must equal(expectedValue.get()); }());
+ });
+ });
+ });
+
+ describe("and the expected value is declared as a const C string", [&]{
+ const char *expectedValue;
+
+ describe("and the values are equal", [&]{
+ before_each([&]{
+ expectedValue = "actualValue";
+ });
+
+ it("must accept a positive match", [&]{
+ actualValue must equal(expectedValue);
+ });
+
+ it("must reject a negative match", [&]{
+ AssertThrows(std::exception, [&]{ actualValue must_not equal(expectedValue); }());
+ });
+ });
+ });
+
+ describe("when the expected value is a unique_ptr to a C string", [&]{
+ std::unique_ptr<char> expectedValue;
+
+ before_each([&]{
+ expectedValue.reset((char*)calloc(strlen(actualValue) + 1, sizeof(char)));
+ });
+
+ describe("and the values are equal", [&]{
+ before_each([&]{
+ stpcpy(expectedValue.get(), actualValue);
+ });
+
+ it("must accept a positive match", [&]{
+ actualValue must equal(expectedValue);
+ });
+
+ it("must reject a negative match", [&]{
+ AssertThrows(std::exception, [&]{ actualValue must_not equal(expectedValue); }());
+ });
+ });
+ });
+});
+
+describe("when the actual value is a unique_ptr", []{
+ std::unique_ptr<char> actualValue;
+ auto expectedValue = (char*)"expectedValue";
+
+ before_each([&]{
+ actualValue.reset((char*)calloc(strlen(expectedValue) + 1, sizeof(char)));
+ });
+
+ describe("when the strings are equal", [&]{
+ before_each([&]{
+ stpcpy(actualValue.get(), expectedValue);
+ });
+
+ it("must accept a positive match", [&]{
+ actualValue must equal(expectedValue);
+ });
+ });
+
+ describe("when the strings are not equal", [&]{
+ before_each([&]{
+ stpcpy(actualValue.get(), "hello");
+ });
+
+ it("must accept a negative match", [&]{
+ actualValue must_not equal(expectedValue);
+ });
+ });
+});
+
+describe("when the actual value is declared as char array", []{
+ describe("and the expected value is declared as a C string", []{
+ char actualValue[] = "actualValue";
+
+ describe("and the values are equal", [&]{
+ char* expectedValue = (char*)"actualValue";
+
+ it("must accept a positive match", [&]{
+ actualValue must equal(expectedValue);
+ });
+
+ it("must reject a negative match", [&]{
+ AssertThrows(std::exception, [&]{ actualValue must_not equal(expectedValue); }());
+ });
+ });
+
+ describe("and the values are not equal", [&]{
+ char* expectedValue = (char*)"expectedValue";
+
+ it("must reject a positive match", [&]{
+ AssertThrows(std::exception, [&]{ actualValue must equal(expectedValue); }());
+ });
+
+ it("must accept a negative match", [&]{
+ actualValue must_not equal(expectedValue);
+ });
+ });
+ });
+});
+
+SPEC_END \ No newline at end of file
diff --git a/vendor/bandit/specs/matchers/throw_exception.cpp b/vendor/bandit/specs/matchers/throw_exception.cpp
new file mode 100644
index 00000000..c7531d5f
--- /dev/null
+++ b/vendor/bandit/specs/matchers/throw_exception.cpp
@@ -0,0 +1,104 @@
+#include <specs/specs.h>
+
+using namespace bandit::Matchers;
+
+SPEC_BEGIN(Matchers::ThrowException)
+
+describe("throw_exception", []{
+ describe("when no exception is specified", [&]{
+ std::exception exception;
+
+ std::function<void()> exception_block = [&]{ throw exception; };
+
+ describe("when the block throws an exception", [&]{
+ it("must pass a positive match", [&]{
+ exception_block must throw_exception;
+ });
+
+ it("must reject a negative match", [&]{
+ AssertThrows(MatcherException, [&]{ exception_block must_not throw_exception; }());
+ });
+ });
+
+ describe("when the block does not throw an exception", [&]{
+ std::function<void()> quiet_block = [&]{};
+
+ it("must pass a negative match", [&]{
+ quiet_block must_not throw_exception;
+ });
+
+ it("must reject a positive match", [&]{
+ AssertThrows(std::exception, [&]{ quiet_block must throw_exception; }());
+ });
+ });
+ });
+
+ describe("with an exception class specified", [&]{
+ std::logic_error expected_exception("logic_error");
+
+ describe("when the block throws the expected exception", [&]{
+ std::function<void()> exception_block = [&]{ throw expected_exception; };
+
+ it("must pass a positive match", [&]{
+ exception_block must throw_exception.operator()<decltype(expected_exception)>();
+ });
+
+ it("must reject a negative match", [&]{
+ AssertThrows(std::exception, [&]{ exception_block must_not throw_exception.operator()<decltype(expected_exception)>(); }());
+ });
+ });
+
+ // TODO: Because C++ lacks reflection, there's no way to implement
+ // subclass-checking. I'm leaving these tests here for when the
+ // language has evolved sufficiently.
+ xdescribe("when the block throws a sublass of the specified exception", [&]{
+ std::function<void()> subclass_block = [&]{ throw std::invalid_argument("invalid argument"); };
+
+ describe("when subclasses are expected", [&]{
+ it("must pass a positive match", [&]{
+ subclass_block must throw_exception.operator()<std::logic_error>().or_subclass();
+ });
+
+ it("must reject a negative match", [&]{
+ AssertThrows(std::exception, [&]{ subclass_block must_not throw_exception.operator()<std::logic_error>().or_subclass(); }());
+ });
+ });
+
+ describe("when subclasses are not expected", [&]{
+ it("must pass a negative match", [&]{
+ subclass_block must_not throw_exception.operator()<std::logic_error>();
+ });
+
+ it("must reject a positive match", [&]{
+ AssertThrows(std::exception, [&]{ subclass_block must throw_exception.operator()<std::logic_error>(); }());
+ });
+ });
+ });
+
+ describe("when the block throws an unrelated exception", [&]{
+ std::function<void()> unrelated_block = [&]{ throw std::range_error("range error"); };
+
+ it("must pass a negative match", [&]{
+ unrelated_block must_not throw_exception.operator()<decltype(expected_exception)>();
+ });
+
+ it("must reject a positive match", [&]{
+ AssertThrows(std::exception, [&]{ unrelated_block must throw_exception.operator()<decltype(expected_exception)>(); }());
+ });
+ });
+
+ describe("when the block does not throw an exception", [&]{
+ std::function<void()> quiet_block = [&]{};
+
+ it("must pass a negative match", [&]{
+ quiet_block must_not throw_exception.operator()<decltype(expected_exception)>();
+ });
+
+ it("must reject a positive match", [&]{
+ AssertThrows(std::exception, [&]{ quiet_block must throw_exception.operator()<decltype(expected_exception)>(); }());
+ });
+ });
+ });
+});
+
+SPEC_END
diff --git a/vendor/bandit/specs/options.spec.cpp b/vendor/bandit/specs/options.spec.cpp
new file mode 100644
index 00000000..74d057ec
--- /dev/null
+++ b/vendor/bandit/specs/options.spec.cpp
@@ -0,0 +1,121 @@
+#include <specs/specs.h>
+
+using namespace bandit::specs::util;
+namespace bd = bandit::detail;
+
+go_bandit([](){
+
+ describe("options:", [&](){
+
+ it("parses the '--help' option", [&](){
+ const char* args[] = {"executable", "--help"};
+ argv_helper argv(2, args);
+
+ bd::options opt(argv.argc(), argv.argv());
+
+ AssertThat(opt.help(), IsTrue());
+ });
+
+ it("parses the '--version' option", [&](){
+ const char* args[] = {"executable", "--version"};
+ argv_helper argv(2, args);
+
+ bd::options opt(argv.argc(), argv.argv());
+
+ AssertThat(opt.version(), IsTrue());
+ });
+
+ it("parses the '--no-color' option", [&](){
+ const char* args[] = {"executable", "--no-color"};
+ argv_helper argv(2, args);
+
+ bd::options opt(argv.argc(), argv.argv());
+
+ AssertThat(opt.no_color(), IsTrue());
+ });
+
+ it("parser the '--formatter=vs' option", [&](){
+ const char* args[] = {"executable", "--formatter=vs"};
+ argv_helper argv(2, args);
+
+ bd::options opt(argv.argc(), argv.argv());
+ AssertThat(opt.formatter(), Equals(bd::options::formatters::FORMATTER_VS));
+ });
+
+ it("parser the '--formatter=default' option", [&](){
+ const char* args[] = {"executable", "--formatter=default"};
+ argv_helper argv(2, args);
+
+ bd::options opt(argv.argc(), argv.argv());
+ AssertThat(opt.formatter(), Equals(bd::options::formatters::FORMATTER_DEFAULT));
+ });
+
+ it("parses the '--skip=\"substring\"' option", [&](){
+ const char* args[] = {"executable", "--skip=substring"};
+ argv_helper argv(2, args);
+
+ bd::options opt(argv.argc(), argv.argv());
+ AssertThat(opt.skip(), Equals("substring"));
+ });
+
+ it("parses skip as empty string if not present", [&](){
+ const char* args[] = {"executable"};
+ argv_helper argv(1, args);
+
+ bd::options opt(argv.argc(), argv.argv());
+ AssertThat(opt.skip(), Equals(""));
+ });
+
+ it("parses the '--only=\"substring\"' option", [&](){
+ const char* args[] = {"executable", "--only=substring"};
+ argv_helper argv(2, args);
+
+ bd::options opt(argv.argc(), argv.argv());
+ AssertThat(opt.only(), Equals("substring"));
+ });
+
+ it("parses only as empty string if not present", [&](){
+ const char* args[] = {"executable"};
+ argv_helper argv(1, args);
+
+ bd::options opt(argv.argc(), argv.argv());
+ AssertThat(opt.only(), Equals(""));
+ });
+
+ it("parses the '--break-on-failure' oprtion", [&](){
+ const char* args[] = {"executable", "--break-on-failure"};
+ argv_helper argv(2, args);
+
+ bd::options opt(argv.argc(), argv.argv());
+
+ AssertThat(opt.break_on_failure(), IsTrue());
+ });
+
+ describe("with no arguments", [&](){
+ const char* args[] = {"executable"};
+ argv_helper argv(1, args);
+ bd::options opt(argv.argc(), argv.argv());
+
+ it("cannot find '--help'", [&](){
+ AssertThat(opt.help(), IsFalse());
+ });
+
+ it("cannot find '--version'", [&](){
+ AssertThat(opt.version(), IsFalse());
+ });
+
+ it("cannot find '--no-color'", [&](){
+ AssertThat(opt.no_color(), IsFalse());
+ });
+
+ it("cannot fine '--break-on-failure'", [&](){
+ AssertThat(opt.break_on_failure(), IsFalse())
+ });
+
+ it("uses default formatter for '--formatter'", [&](){
+ AssertThat(opt.formatter(), Equals(bd::options::formatters::FORMATTER_DEFAULT));
+ });
+ });
+ });
+
+});
diff --git a/vendor/bandit/specs/reporters/colorizer.spec.cpp b/vendor/bandit/specs/reporters/colorizer.spec.cpp
new file mode 100644
index 00000000..7708ec81
--- /dev/null
+++ b/vendor/bandit/specs/reporters/colorizer.spec.cpp
@@ -0,0 +1,45 @@
+#ifndef _WIN32
+#include <specs/specs.h>
+
+go_bandit([](){
+
+ describe("colorizer: ", [&](){
+
+ describe("colors enabled", [&](){
+ bandit::detail::colorizer colorizer;
+
+ it("can set color to green", [&](){
+ AssertThat(colorizer.green(), Equals("\033[1;32m"));
+ });
+
+ it("set color to red", [&](){
+ AssertThat(colorizer.red(), Equals("\033[1;31m"));
+ });
+ it("resets color", [&](){
+ AssertThat(colorizer.reset(), Equals("\033[0m"));
+ });
+
+ });
+
+ describe("colors disabled", [&](){
+
+ bandit::detail::colorizer colorizer(false);
+
+ it("ignores setting color to green", [&](){
+ AssertThat(colorizer.green(), Equals(""));
+ });
+
+ it("ignores setting color to red", [&](){
+ AssertThat(colorizer.red(), Equals(""));
+ });
+
+ it("ignores resetting colors", [&](){
+ AssertThat(colorizer.reset(), Equals(""));
+ });
+
+ });
+
+ });
+
+});
+#endif \ No newline at end of file
diff --git a/vendor/bandit/specs/reporters/dots_reporter.spec.cpp b/vendor/bandit/specs/reporters/dots_reporter.spec.cpp
new file mode 100644
index 00000000..f06c8d77
--- /dev/null
+++ b/vendor/bandit/specs/reporters/dots_reporter.spec.cpp
@@ -0,0 +1,202 @@
+#include <specs/specs.h>
+namespace bd = bandit::detail;
+
+go_bandit([](){
+
+ describe("dots_reporter:", [&](){
+ std::unique_ptr<std::stringstream> stm;
+ std::unique_ptr<bd::dots_reporter> reporter;
+ bd::default_failure_formatter formatter;
+ bd::colorizer colorizer(false);
+
+ before_each([&](){
+ stm = std::unique_ptr<std::stringstream>(new std::stringstream());
+ reporter = std::unique_ptr<bd::dots_reporter>(
+ new bd::dots_reporter(*stm, formatter, colorizer));
+ });
+
+ auto output = [&](){ return stm->str(); };
+
+ describe("an empty test run", [&](){
+
+ before_each([&](){
+ reporter->test_run_starting();
+ reporter->test_run_complete();
+ });
+
+ it("reports no tests where run", [&](){
+ AssertThat(output(), Equals("\nCould not find any tests.\n"));
+ });
+
+ it("is not considered successful", [&](){
+ AssertThat(reporter->did_we_pass(), Equals(false));
+ });
+
+ });
+
+ describe("a successful test run", [&](){
+
+ before_each([&](){
+ reporter->test_run_starting();
+ reporter->context_starting("my context");
+ reporter->it_starting("my test");
+ reporter->it_succeeded("my test");
+ reporter->context_ended("my context");
+ reporter->test_run_complete();
+ });
+
+ it("reports a successful test run", [&](){
+ AssertThat(output(), Contains("Success!"));
+ AssertThat(output(), EndsWith("Test run complete. 1 tests run. 1 succeeded.\n"));
+ });
+
+ it("displays a dot for the successful test", [&](){
+ AssertThat(output(), StartsWith("."));
+ });
+
+ it("reports a successful test run", [&](){
+ AssertThat(reporter->did_we_pass(), Equals(true));
+ });
+ });
+
+ describe("a failing test run", [&](){
+
+ before_each([&](){
+ reporter->test_run_starting();
+ reporter->context_starting("my context");
+ reporter->it_starting("my test");
+
+ bd::assertion_exception exception("assertion failed!", "some_file", 123);
+ reporter->it_failed("my test", exception);
+
+ reporter->context_ended("my context");
+ reporter->test_run_complete();
+ });
+
+ it("reports a failing test run in summary", [&](){
+ AssertThat(output(), EndsWith("Test run complete. 1 tests run. 0 succeeded. 1 failed.\n"));
+ });
+
+ it("reports the failed assertion", [&](){
+ AssertThat(output(), Contains("my context my test:\nsome_file:123: assertion failed!"));
+ });
+
+ it("only reports assertion failure once", [&](){
+ AssertThat(output(), Has().Exactly(1).EndingWith("assertion failed!"));
+ });
+
+ it("reports an 'F' for the failed assertion", [&](){
+ AssertThat(output(), StartsWith("F"));
+ });
+
+ it("reports a failed test run", [&](){
+ AssertThat(reporter->did_we_pass(), Equals(false));
+ });
+ });
+
+ describe("a test run with a non assertion_exception thrown", [&](){
+
+ before_each([&](){
+ reporter->test_run_starting();
+ reporter->context_starting("my context");
+ reporter->it_starting("my test");
+
+ reporter->it_unknown_error("my test");
+
+ reporter->context_ended("my context");
+ reporter->test_run_complete();
+ });
+
+ it("reports an 'E' for the failed test", [&](){
+ AssertThat(output(), StartsWith("E"));
+ });
+
+ it("reports the failed test", [&](){
+ AssertThat(output(), Contains("my context my test:\nUnknown exception"))
+ });
+
+ });
+
+ describe("a failing test run with nested contexts", [&](){
+
+ before_each([&](){
+ reporter->test_run_starting();
+ reporter->context_starting("my context");
+ reporter->context_starting("a nested context");
+ reporter->it_starting("my test");
+
+ bd::assertion_exception exception("assertion failed!", "some_file", 123);
+ reporter->it_failed("my test", exception);
+
+ reporter->context_ended("a nested context");
+ reporter->context_ended("my context");
+ reporter->test_run_complete();
+ });
+
+ it("reports a failing test run in summary", [&](){
+ AssertThat(output(), EndsWith("Test run complete. 1 tests run. 0 succeeded. 1 failed.\n"));
+ });
+
+ it("reports the failed assertion", [&](){
+ AssertThat(output(), Contains("my context a nested context my test:\nsome_file:123: assertion failed!"));
+ });
+
+ it("reports an 'F' for the failed assertion", [&](){
+ AssertThat(output(), StartsWith("F"));
+ });
+
+ it("reports a failed test run", [&](){
+ AssertThat(reporter->did_we_pass(), Equals(false));
+ });
+
+ });
+
+ describe("a context with test run errors", [&](){
+
+ before_each([&](){
+ reporter->test_run_starting();
+ reporter->context_starting("my context");
+
+ bd::test_run_error error("we dun goofed!");
+ reporter->test_run_error("my context", error);
+
+ reporter->context_ended("my context");
+ reporter->test_run_complete();
+ });
+
+ it("reports that the context has failed", [&](){
+ AssertThat(output(), Contains("Failed to run \"my context\": error \"we dun goofed!\""));
+ });
+
+ it("reports test run errors in summary", [&](){
+ AssertThat(output(), EndsWith("Test run complete. 0 tests run. 0 succeeded. 1 test run errors.\n"))
+ });
+
+ it("reports a failed test run", [&](){
+ AssertThat(reporter->did_we_pass(), Equals(false));
+ });
+ });
+
+ describe("a context with a skipped test", [&](){
+
+ before_each([&](){
+ reporter->test_run_starting();
+ reporter->context_starting("my context");
+
+ reporter->it_starting("my test");
+ reporter->it_succeeded("my test");
+ reporter->it_skip("my skipped test");
+
+ reporter->context_ended("my context");
+ reporter->test_run_complete();
+ });
+
+ it("reports that there is one skipped test in the summary", [&](){
+ AssertThat(output(), EndsWith("Test run complete. 1 tests run. 1 succeeded. 1 skipped.\n"));
+ });
+
+ });
+ });
+
+
+});
diff --git a/vendor/bandit/specs/reporters/single_line_reporter.spec.cpp b/vendor/bandit/specs/reporters/single_line_reporter.spec.cpp
new file mode 100644
index 00000000..ef7b5206
--- /dev/null
+++ b/vendor/bandit/specs/reporters/single_line_reporter.spec.cpp
@@ -0,0 +1,201 @@
+#include <specs/specs.h>
+namespace bd = bandit::detail;
+
+go_bandit([](){
+
+ describe("single line reporter", [&](){
+ std::unique_ptr<std::stringstream> stm;
+ std::unique_ptr<bd::single_line_reporter> reporter;
+ bd::default_failure_formatter formatter;
+ bd::colorizer colorizer(false);
+
+ before_each([&](){
+ stm = std::unique_ptr<std::stringstream>(new std::stringstream());
+ reporter = std::unique_ptr<bd::single_line_reporter>(
+ new bd::single_line_reporter(*stm, formatter, colorizer));
+ });
+
+ auto output = [&](){ return stm->str(); };
+
+ describe("an empty test run", [&](){
+
+ before_each([&](){
+ reporter->test_run_starting();
+ reporter->test_run_complete();
+ });
+
+ it("reports that no tests were run", [&](){
+ AssertThat(output(), Equals("\nCould not find any tests.\n"));
+ });
+
+ it("is not considered successful", [&](){
+ AssertThat(reporter->did_we_pass(), Equals(false));
+ });
+ });
+
+ describe("a successful test run", [&](){
+
+ before_each([&](){
+ reporter->test_run_starting();
+ reporter->context_starting("my context");
+ reporter->it_starting("my test");
+ reporter->it_succeeded("my test");
+ reporter->context_ended("my context");
+ reporter->test_run_complete();
+ });
+
+ it("reports a successful test run", [&](){
+ AssertThat(output(), EndsWith("Test run complete. 1 tests run. 1 succeeded.\n"));
+ });
+
+ it("displays progress for the test", [&](){
+ AssertThat(output(), StartsWith("\rExecuted 0 tests."
+ "\rExecuted 1 tests."));
+ });
+
+ it("reports a successful test run", [&](){
+ AssertThat(reporter->did_we_pass(), Equals(true));
+ });
+ });
+
+ describe("a failing test run", [&](){
+
+ before_each([&](){
+ reporter->test_run_starting();
+ reporter->context_starting("my context");
+ reporter->it_starting("my test");
+
+ bd::assertion_exception exception("assertion failed!", "some_file", 123);
+ reporter->it_failed("my test", exception);
+
+ reporter->context_ended("my context");
+ reporter->test_run_complete();
+ });
+
+ it("reports a failing test run in summary", [&](){
+ AssertThat(output(), EndsWith("Test run complete. 1 tests run. 0 succeeded. 1 failed.\n"));
+ });
+
+ it("reports the failed assertion", [&](){
+ AssertThat(output(), Contains("my context my test:\nsome_file:123: assertion failed!"));
+ });
+
+ it("reports failing test in progress", [&](){
+ AssertThat(output(), StartsWith("\rExecuted 0 tests."
+ "\rExecuted 1 tests. 0 succeeded. 1 failed."));
+ });
+
+ it("reports a failed test run", [&](){
+ AssertThat(reporter->did_we_pass(), Equals(false));
+ });
+ });
+
+ describe("a test run with a non assertion_exception thrown", [&](){
+
+ before_each([&](){
+ reporter->test_run_starting();
+ reporter->context_starting("my context");
+ reporter->it_starting("my test");
+
+ reporter->it_unknown_error("my test");
+
+ reporter->context_ended("my context");
+ reporter->test_run_complete();
+ });
+
+ it("reports failing test in progress", [&](){
+ AssertThat(output(), StartsWith("\rExecuted 0 tests."
+ "\rExecuted 1 tests. 0 succeeded. 1 failed."));
+ });
+
+ it("reports the failed test", [&](){
+ AssertThat(output(), Contains("my context my test:\nUnknown exception"))
+ });
+
+ });
+
+ describe("a failing test run with nested contexts", [&](){
+
+ before_each([&](){
+ reporter->test_run_starting();
+ reporter->context_starting("my context");
+ reporter->context_starting("a nested context");
+ reporter->it_starting("my test");
+
+ bd::assertion_exception exception("assertion failed!", "some_file", 123);
+ reporter->it_failed("my test", exception);
+
+ reporter->context_ended("a nested context");
+ reporter->context_ended("my context");
+ reporter->test_run_complete();
+ });
+
+ it("reports a failing test run in summary", [&](){
+ AssertThat(output(), EndsWith("Test run complete. 1 tests run. 0 succeeded. 1 failed.\n"));
+ });
+
+ it("reports the failed assertion", [&](){
+ AssertThat(output(), Contains("my context a nested context my test:\nsome_file:123: assertion failed!"));
+ });
+
+ it("displays a failed test in progress report", [&](){
+ AssertThat(output(), StartsWith("\rExecuted 0 tests."
+ "\rExecuted 1 tests. 0 succeeded. 1 failed."));
+ });
+
+ it("reports a failed test run", [&](){
+ AssertThat(reporter->did_we_pass(), Equals(false));
+ });
+
+ });
+
+ describe("a context with test run errors", [&](){
+
+ before_each([&](){
+ reporter->test_run_starting();
+ reporter->context_starting("my context");
+
+ bd::test_run_error error("we dun goofed!");
+ reporter->test_run_error("my context", error);
+
+ reporter->context_ended("my context");
+ reporter->test_run_complete();
+ });
+
+ it("reports that the context has failed", [&](){
+ AssertThat(output(), Contains("Failed to run \"my context\": error \"we dun goofed!\""));
+ });
+
+ it("reports test run errors in summary", [&](){
+ AssertThat(output(), EndsWith("Test run complete. 0 tests run. 0 succeeded. 1 test run errors.\n"))
+ });
+
+ it("reports a failed test run", [&](){
+ AssertThat(reporter->did_we_pass(), Equals(false));
+ });
+ });
+
+ describe("a context with a skipped test", [&](){
+
+ before_each([&](){
+ reporter->test_run_starting();
+ reporter->context_starting("my context");
+
+ reporter->it_starting("my test");
+ reporter->it_succeeded("my test");
+ reporter->it_skip("my skipped test");
+
+ reporter->context_ended("my context");
+ reporter->test_run_complete();
+ });
+
+ it("reports that there is one skipped test in the summary", [&](){
+ AssertThat(output(), EndsWith("Test run complete. 1 tests run. 1 succeeded. 1 skipped.\n"));
+ });
+
+ });
+
+
+ });
+
+});
diff --git a/vendor/bandit/specs/reporters/xunit_reporter.spec.cpp b/vendor/bandit/specs/reporters/xunit_reporter.spec.cpp
new file mode 100644
index 00000000..07f0c3b7
--- /dev/null
+++ b/vendor/bandit/specs/reporters/xunit_reporter.spec.cpp
@@ -0,0 +1,161 @@
+#include <specs/specs.h>
+namespace bd = bandit::detail;
+
+go_bandit([](){
+
+ describe("xunit_reporter:", [&](){
+ std::unique_ptr<std::stringstream> stm;
+ bd::default_failure_formatter formatter;
+ std::unique_ptr<bd::xunit_reporter> reporter;
+
+ auto output = [&](){ return stm->str(); };
+
+ before_each([&](){
+ stm = std::unique_ptr<std::stringstream>(new std::stringstream());
+ reporter = std::unique_ptr<bd::xunit_reporter>(new bd::xunit_reporter(*stm, formatter));
+ });
+
+ describe("an empty test run", [&](){
+
+ before_each([&](){
+ reporter->test_run_starting();
+ reporter->test_run_complete();
+ });
+
+ it("adds a header to the output", [&](){
+ AssertThat(output(), StartsWith("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"));
+ });
+
+ it("outputs an empty test report", [&](){
+ AssertThat(output(), Contains(
+ "<testsuite name=\"bandit\" tests=\"0\" errors=\"0\" failures=\"0\">\n"
+ "</testsuite>\n"));
+ });
+
+ });
+
+ describe("a test run with one, successful, test", [&](){
+
+ before_each([&](){
+ reporter->test_run_starting();
+ reporter->context_starting("my context");
+ reporter->it_starting("my test");
+ reporter->it_succeeded("my test");
+ reporter->context_ended("my context");
+ reporter->test_run_complete();
+ });
+
+ it("outputs info about the successful test", [&](){
+ AssertThat(output(), Contains(
+ "<testsuite name=\"bandit\" tests=\"1\" errors=\"0\" failures=\"0\">\n"
+ "\t<testcase classname=\"my context\" name=\"my test\" time=\"0\">\n"
+ "\t</testcase>\n"
+ "</testsuite>\n"));
+ });
+ });
+
+ describe("a test run with one, failing test", [&](){
+
+ before_each([&](){
+ reporter->test_run_starting();
+ reporter->context_starting("my context");
+ reporter->it_starting("my test");
+
+ bd::assertion_exception exception("assertion failed!", "some_file", 123);
+ reporter->it_failed("my test", exception);
+
+ reporter->context_ended("my context");
+ reporter->test_run_complete();
+
+ });
+
+ it("outputs the failing test", [&](){
+ AssertThat(output(), Contains(
+ "<testsuite name=\"bandit\" tests=\"1\" errors=\"0\" failures=\"1\">\n"
+ "\t<testcase classname=\"my context\" name=\"my test\" time=\"0\">\n"
+ "\t\t<failure message=\"some_file:123: assertion failed!\" />\n"
+ "\t</testcase>\n"
+ "</testsuite>\n"));
+ });
+
+ });
+
+ describe("a test run with one test with an unknown error", [&](){
+
+ before_each([&](){
+ reporter->test_run_starting();
+ reporter->context_starting("my context");
+ reporter->it_starting("my test");
+
+ reporter->it_unknown_error("my test");
+
+ reporter->context_ended("my context");
+ reporter->test_run_complete();
+ });
+
+ it("outputs the erroneous test", [&](){
+ AssertThat(output(), Contains(
+ "<testsuite name=\"bandit\" tests=\"1\" errors=\"0\" failures=\"1\">\n"
+ "\t<testcase classname=\"my context\" name=\"my test\" time=\"0\">\n"
+ "\t\t<failure message=\"Unknown exception\" />\n"
+ "\t</testcase>\n"
+ "</testsuite>\n"));
+ });
+
+ });
+
+ describe("a test run with one test failing with characters that need escaping", [&](){
+
+ before_each([&](){
+ reporter->test_run_starting();
+ reporter->context_starting("my context & < > \\ \"");
+ reporter->it_starting("my test & < > \\ \"");
+
+ bd::assertion_exception exception("assertion failed & < > \\ \"", "some_file", 123);
+ reporter->it_failed("my test & < > \\ \"", exception);
+
+ reporter->context_ended("my context & < > \\ \"");
+ reporter->test_run_complete();
+ });
+
+ it("outputs the escaped characters", [&](){
+ AssertThat(output(), Contains(
+ "<testsuite name=\"bandit\" tests=\"1\" errors=\"0\" failures=\"1\">\n"
+ "\t<testcase classname=\"my context &amp; &lt; &gt; &apos; &quot;\" name=\"my test &amp; &lt; &gt; &apos; &quot;\" time=\"0\">\n"
+ "\t\t<failure message=\"some_file:123: assertion failed &amp; &lt; &gt; &apos; &quot;\" />\n"
+ "\t</testcase>\n"
+ "</testsuite>\n"));
+ });
+
+ });
+
+ describe("a context with a skipped test", [&](){
+
+ before_each([&](){
+ reporter->test_run_starting();
+ reporter->context_starting("my context");
+
+ reporter->it_starting("my test");
+ reporter->it_succeeded("my test");
+ reporter->it_skip("my skipped test");
+
+ reporter->context_ended("my context");
+ reporter->test_run_complete();
+ });
+
+ it("outputs info about the skipped test", [&](){
+ AssertThat(output(), Contains(
+ "<testsuite name=\"bandit\" tests=\"1\" errors=\"0\" failures=\"0\" skipped=\"1\">\n"
+ "\t<testcase classname=\"my context\" name=\"my test\" time=\"0\">\n"
+ "\t</testcase>\n"
+ "\t<testcase classname=\"my context\" name=\"my skipped test\" time=\"0\">\n"
+ "\t\t<skipped />\n"
+ "\t</testcase>\n"
+ "</testsuite>\n"));
+ });
+
+ });
+
+ });
+
+});
diff --git a/vendor/bandit/specs/run.spec.cpp b/vendor/bandit/specs/run.spec.cpp
new file mode 100644
index 00000000..6e59bac7
--- /dev/null
+++ b/vendor/bandit/specs/run.spec.cpp
@@ -0,0 +1,77 @@
+#include <specs/specs.h>
+using namespace bandit::fakes;
+using namespace bandit::specs::util;
+namespace bd = bandit::detail;
+
+go_bandit([](){
+
+ describe("run:", [&](){
+ std::unique_ptr<bd::spec_registry> specs;
+ std::unique_ptr<argv_helper> argv;
+ fake_reporter_ptr reporter;
+ std::unique_ptr<bd::contextstack_t> context_stack;
+
+ auto call_run = [&]() -> int {
+ bd::options opt(argv->argc(), argv->argv());
+ return bandit::run(opt, *specs, *context_stack, *reporter);
+ };
+
+ before_each([&](){
+ specs = std::unique_ptr<bd::spec_registry>(new bd::spec_registry());
+
+ reporter = fake_reporter_ptr(new fake_reporter());
+
+ context_stack = std::unique_ptr<bd::contextstack_t>(new bd::contextstack_t());
+
+ const char* args[] = {"executable"};
+ argv = std::unique_ptr<argv_helper>(new argv_helper(1, args));
+ });
+
+ it("pushes the global context on the context stack", [&](){
+ call_run();
+ AssertThat(*context_stack, Is().OfLength(1));
+ });
+
+ describe("a successful test run", [&](){
+ int number_of_specs_called;
+
+ before_each([&](){
+ number_of_specs_called = 0;
+ specs->push_back([&](){ number_of_specs_called++; });
+ });
+
+ it("calls the context", [&](){
+ call_run();
+ AssertThat(number_of_specs_called, Equals(1));
+ });
+
+ it("tells reporter a test run is about to start", [&](){
+ call_run();
+ AssertThat(reporter->call_log(), Has().Exactly(1).EqualTo("test_run_starting"));
+ });
+
+ it("tells reporter a test run has completed", [&](){
+ call_run();
+ AssertThat(reporter->call_log(), Has().Exactly(1).EqualTo("test_run_complete"));
+ });
+
+ it("returns 0 as no specs failed", [&](){
+ AssertThat(call_run(), Equals(0));
+ });
+ });
+
+
+ describe("a failing test run", [&](){
+
+ before_each([&](){
+ reporter->set_test_run_status(false);
+ });
+
+ it("returns a non-zero error code", [&](){
+ AssertThat(call_run(), IsGreaterThan(0));
+ });
+
+ });
+ });
+
+});
diff --git a/vendor/bandit/specs/run_policies/bandit_run_policy.spec.cpp b/vendor/bandit/specs/run_policies/bandit_run_policy.spec.cpp
new file mode 100644
index 00000000..75f56bc6
--- /dev/null
+++ b/vendor/bandit/specs/run_policies/bandit_run_policy.spec.cpp
@@ -0,0 +1,250 @@
+#include <specs/specs.h>
+
+go_bandit([](){
+ namespace bd = bandit::detail;
+
+ describe("bandit run policy", [&](){
+ std::unique_ptr<bd::contextstack_t> contextstack;
+ std::unique_ptr<bd::context> global_context;
+ std::string only_pattern;
+ std::string skip_pattern;
+ bool break_on_failure;
+
+ auto create_policy = [&]() -> bd::bandit_run_policy {
+ return bd::bandit_run_policy(skip_pattern.c_str(), only_pattern.c_str(), break_on_failure);
+ };
+
+ before_each([&](){
+ contextstack = std::unique_ptr<bd::contextstack_t>(new bd::contextstack_t());
+ bool hard_skip = false;
+ global_context = std::unique_ptr<bd::context>(new bd::bandit_context("", hard_skip));
+ contextstack->push_back(global_context.get());
+ break_on_failure = false;
+ });
+
+ describe("neither skip nor only specified", [&](){
+ before_each([&](){
+ only_pattern = "";
+ skip_pattern = "";
+ });
+
+ it("always says run", [&](){
+ bd::bandit_run_policy policy = create_policy();
+ AssertThat(policy.should_run("it name", *contextstack), IsTrue());
+ });
+
+ describe("with 'break-on-failure' set", [&](){
+
+ before_each([&](){
+ break_on_failure = true;
+ });
+
+ it("says run if no failure has been encountered", [&](){
+ bd::bandit_run_policy policy = create_policy();
+ AssertThat(policy.should_run("it name", *contextstack), IsTrue());
+ });
+
+ it("says don't run if a failure has been encountered", [&](){
+ bd::bandit_run_policy policy = create_policy();
+ policy.encountered_failure();
+ AssertThat(policy.should_run("it name", *contextstack), IsFalse());
+ });
+
+ });
+
+ describe("has context marked with 'hard_skip' in stack", [&](){
+ std::unique_ptr<bd::context> hard_skip_context;
+
+ before_each([&](){
+ bool hard_skip = true;
+ hard_skip_context = std::unique_ptr<bd::context>(new bd::bandit_context("always ignore", hard_skip));
+ contextstack->push_back(hard_skip_context.get());
+ });
+
+ it("never runs", [&](){
+ bd::bandit_run_policy policy = create_policy();
+ AssertThat(policy.should_run("it name", *contextstack), IsFalse());
+ AssertThat(policy.should_run("it name matches 'skip'", *contextstack), IsFalse());
+ AssertThat(policy.should_run("it name matches 'only'", *contextstack), IsFalse());
+ });
+
+ });
+
+ });
+
+ describe("'skip' specified, 'only' unspecified", [&](){
+
+ before_each([&](){
+ only_pattern = "";
+ skip_pattern = "skip";
+ });
+
+ describe("current context matches 'skip'", [&](){
+ std::unique_ptr<bd::context> current_context;
+
+ before_each([&](){
+ bool hard_skip = false;
+ current_context = std::unique_ptr<bd::context>(new bd::bandit_context("context matches 'skip'", hard_skip));
+ contextstack->push_back(current_context.get());
+ });
+
+ it("never runs", [&](){
+ bd::bandit_run_policy policy = create_policy();
+ AssertThat(policy.should_run("it name", *contextstack), IsFalse());
+ });
+
+ });
+
+ describe("current context doesn't match 'skip'", [&](){
+ std::unique_ptr<bd::context> current_context;
+
+ before_each([&](){
+ bool hard_skip = false;
+ current_context = std::unique_ptr<bd::context>(new bd::bandit_context("context doesn't match", hard_skip));
+ contextstack->push_back(current_context.get());
+ });
+
+ it("runs if spec's name doesn't match", [&](){
+ bd::bandit_run_policy policy = create_policy();
+ AssertThat(policy.should_run("it name", *contextstack), IsTrue());
+ });
+
+ it("doesn't run if spec's name matches", [&](){
+ bd::bandit_run_policy policy = create_policy();
+ AssertThat(policy.should_run("it name matching 'skip'", *contextstack), IsFalse());
+ });
+
+ });
+
+ });
+
+ describe("'only' specified, 'skip' unspecified", [&](){
+
+ before_each([&](){
+ only_pattern = "only";
+ skip_pattern = "";
+ });
+
+ describe("current context matches 'only'", [&](){
+ std::unique_ptr<bd::context> current_context;
+
+ before_each([&](){
+ bool hard_skip = false;
+ current_context = std::unique_ptr<bd::context>(new bd::bandit_context("context matches 'only'", hard_skip));
+ contextstack->push_back(current_context.get());
+ });
+
+ it("always runs", [&](){
+ bd::bandit_run_policy policy = create_policy();
+ AssertThat(policy.should_run("it name", *contextstack), IsTrue());
+ });
+
+ });
+
+ describe("current context doesn't match 'only'", [&](){
+ std::unique_ptr<bd::context> current_context;
+
+ before_each([&](){
+ bool hard_skip = false;
+ current_context = std::unique_ptr<bd::context>(new bd::bandit_context("context doesn't match", hard_skip));
+ contextstack->push_back(current_context.get());
+ });
+
+ it("doesn't run if spec's name doesn't match", [&](){
+ bd::bandit_run_policy policy = create_policy();
+ AssertThat(policy.should_run("it name", *contextstack), IsFalse());
+ });
+
+ it("runs if spec's name matches", [&](){
+ bd::bandit_run_policy policy = create_policy();
+ AssertThat(policy.should_run("it name matching 'only'", *contextstack), IsTrue());
+ });
+
+ });
+
+ });
+
+ describe("'skip' specified, 'only' specified", [&](){
+
+ before_each([&](){
+ only_pattern = "only";
+ skip_pattern = "skip";
+ });
+
+ describe("current context matches 'skip'", [&](){
+ std::unique_ptr<bd::context> current_context;
+
+ before_each([&](){
+ bool hard_skip = false;
+ current_context = std::unique_ptr<bd::context>(new bd::bandit_context("context matches 'skip'", hard_skip));
+ contextstack->push_back(current_context.get());
+ });
+
+ it("doesn't run if 'it' doesn't match 'only'", [&](){
+ bd::bandit_run_policy policy = create_policy();
+ AssertThat(policy.should_run("it name", *contextstack), IsFalse());
+ });
+
+ it("runs if 'it' matches 'only'", [&](){
+ bd::bandit_run_policy policy = create_policy();
+ AssertThat(policy.should_run("it matches 'only'", *contextstack), IsTrue());
+ });
+
+ });
+
+ describe("current context 'only'", [&](){
+ std::unique_ptr<bd::context> current_context;
+
+ before_each([&](){
+ bool hard_skip = false;
+ current_context = std::unique_ptr<bd::context>(new bd::bandit_context("context matches 'only'", hard_skip));
+ contextstack->push_back(current_context.get());
+ });
+
+ it("runs if spec's name doesn't match anything", [&](){
+ bd::bandit_run_policy policy = create_policy();
+ AssertThat(policy.should_run("it name", *contextstack), IsTrue());
+ });
+
+ it("doesn't run if spec's name matches 'skip'", [&](){
+ bd::bandit_run_policy policy = create_policy();
+ AssertThat(policy.should_run("it name matching 'skip'", *contextstack), IsFalse());
+ });
+
+ });
+
+ describe("has both 'only' and 'skip' in context stack", [&](){
+ std::unique_ptr<bd::context> current_context;
+ std::unique_ptr<bd::context> parent_context;
+
+ before_each([&](){
+ bool hard_skip = false;
+ current_context = std::unique_ptr<bd::context>(new bd::bandit_context("context matches 'only'", hard_skip));
+ parent_context = std::unique_ptr<bd::context>(new bd::bandit_context("context matches 'skip'", hard_skip));
+ contextstack->push_back(parent_context.get());
+ contextstack->push_back(current_context.get());
+ });
+
+ it("runs if spec's name doesn't match anything", [&](){
+ bd::bandit_run_policy policy = create_policy();
+ AssertThat(policy.should_run("it name", *contextstack), IsTrue());
+ });
+
+ it("doesn't run if spec's name matches 'skip'", [&](){
+ bd::bandit_run_policy policy = create_policy();
+ AssertThat(policy.should_run("it name matching 'skip'", *contextstack), IsFalse());
+ });
+ it("runs if spec's name matches 'only'", [&](){
+ bd::bandit_run_policy policy = create_policy();
+ AssertThat(policy.should_run("it name matching 'only'", *contextstack), IsTrue());
+ });
+
+ });
+
+ });
+
+
+ });
+
+});
+
diff --git a/vendor/bandit/specs/specs.h b/vendor/bandit/specs/specs.h
new file mode 100644
index 00000000..219e89ee
--- /dev/null
+++ b/vendor/bandit/specs/specs.h
@@ -0,0 +1,10 @@
+#ifndef BANDIT_SPECS
+#define BANDIT_SPECS
+
+#include <bandit/bandit.h>
+using namespace bandit;
+
+#include <specs/fakes/fakes.h>
+#include <specs/util/util.h>
+
+#endif
diff --git a/vendor/bandit/specs/synopsis.spec.cpp b/vendor/bandit/specs/synopsis.spec.cpp
new file mode 100644
index 00000000..3b717f75
--- /dev/null
+++ b/vendor/bandit/specs/synopsis.spec.cpp
@@ -0,0 +1,54 @@
+#include <specs/specs.h>
+
+go_bandit([](){
+ describe("my first spec", [&]() {
+ int a;
+
+ before_each([&](){
+ a = 99;
+ });
+
+ it("should be initialized", [&](){
+ AssertThat(a, Equals(99));
+ a = 102;
+ });
+
+ describe("nested spec", [&](){
+
+ before_each([&](){
+ a += 3;
+ });
+
+ it("should build on outer spec", [&](){
+ AssertThat(a, Equals(102));
+ a = 666;
+ });
+
+ it("should build on outer spec yet again", [&](){
+ AssertThat(a, Equals(102));
+ a = 667;
+ });
+
+ });
+
+ it("should be initialized before each it", [&](){
+ AssertThat(a, Equals(99));
+ });
+ });
+
+ describe("my second spec", [&](){
+ int b;
+
+ before_each([&](){
+ b = 22;
+ });
+
+ before_each([&](){
+ b += 3;
+ });
+
+ it("should be 25", [&](){
+ AssertThat(b, Equals(25));
+ });
+ });
+});
diff --git a/vendor/bandit/specs/util/argv_helper.h b/vendor/bandit/specs/util/argv_helper.h
new file mode 100644
index 00000000..dac26765
--- /dev/null
+++ b/vendor/bandit/specs/util/argv_helper.h
@@ -0,0 +1,62 @@
+#ifndef BANDIT_SPECS_ARGV_HELPER_H
+#define BANDIT_SPECS_ARGV_HELPER_H
+
+#include <string.h>
+
+namespace bandit { namespace specs { namespace util {
+
+ //
+ // main() is supposed to receive its arguments as a non const 'char* argv[]'.
+ // This is a pain to create for each test. It's a whole lot easier to create
+ // a 'const char* argv[]' construct.
+ //
+ // This class helps copy from 'const char**' to 'char**' and handle cleanup
+ // automatically.
+ //
+ struct argv_helper
+ {
+ argv_helper(int argc_a, const char* argv_a[])
+ : argc_(argc_a)
+ {
+ non_const_argv_ = new char*[argc_];
+ for(int i=0; i < argc_; i++)
+ {
+ std::string s(argv_a[i]);
+ non_const_argv_[i] = new char[s.size() + 1];
+ for(size_t c=0;c<s.size();c++)
+ {
+ non_const_argv_[i][c] = s[c];
+ }
+ non_const_argv_[i][s.size()] = 0;
+ }
+ }
+
+
+
+ ~argv_helper()
+ {
+ for(int i=0; i < argc_; i++)
+ {
+ delete[] non_const_argv_[i];
+ }
+
+ delete[] non_const_argv_;
+ }
+
+ char** argv()
+ {
+ return non_const_argv_;
+ }
+
+ int argc()
+ {
+ return argc_;
+ }
+
+ private:
+ int argc_;
+ char** non_const_argv_;
+ };
+
+}}}
+#endif
diff --git a/vendor/bandit/specs/util/util.h b/vendor/bandit/specs/util/util.h
new file mode 100644
index 00000000..7ed17dd8
--- /dev/null
+++ b/vendor/bandit/specs/util/util.h
@@ -0,0 +1,6 @@
+#ifndef BANDIT_SPECS_UTIL_H
+#define BANDIT_SPECS_UTIL_H
+
+#include "argv_helper.h"
+
+#endif