Advertisement
Guest User

DCSS rc with ready

a guest
Apr 7th, 2024
29
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 57.95 KB | None | 0 0
  1. ##### Crawl Init file ###############################################
  2. # For descriptions of all options, as well as some more in-depth information
  3. # on setting them, consult the file
  4. # options_guide.txt
  5. # in your /docs directory. If you can't find it, the file is also available
  6. # online at:
  7. # https://github.com/crawl/crawl/blob/master/crawl-ref/docs/options_guide.txt
  8. #
  9. # Crawl uses the first file of the following list as its option file:
  10. # * init.txt in the -rcdir directory (if specified)
  11. # * .crawlrc in the -rcdir directory (if specified)
  12. # * init.txt (in the Crawl directory)
  13. # * ~/.crawl/init.txt (Unix only)
  14. # * ~/.crawlrc (Unix only)
  15. # * ~/init.txt (Unix only)
  16. # * settings/init.txt (in the Crawl directory)
  17.  
  18. ##### Some basic explanation of option syntax #######################
  19. # Lines beginning with '#' are comments. The basic syntax is:
  20. #
  21. # field = value or field.subfield = value
  22. #
  23. # Only one specification is allowed per line.
  24. #
  25. # The terms are typically case-insensitive except in the fairly obvious
  26. # cases (the character's name and specifying files or directories when
  27. # on a system that has case-sensitive filenames).
  28. #
  29. # White space is stripped from the beginning and end of the line, as
  30. # well as immediately before and after the '='. If the option allows
  31. # multiple comma/semicolon-separated terms (such as
  32. # autopickup_exceptions), all whitespace around the separator is also
  33. # trimmed. All other whitespace is left intact.
  34. #
  35. # There are three broad types of Crawl options: true/false values (booleans),
  36. # arbitrary values, and lists of values. The first two types use only the
  37. # simple =, with later options - which includes your options that are different
  38. # from the defaults - overriding earlier ones. List options allow using +=, ^=,
  39. # -=, and = to append, prepend, remove, and reset, respectively. Usually you will
  40. # want to use += to add to a list option. Lastly, there is := which you can use
  41. # to create an alias, like so:
  42. # ae := autopickup_exceptions
  43. # From there on, 'ae' will be treated as if it you typed autopickup_exceptions,
  44. # so you can save time typing it.
  45. #
  46.  
  47. ##### Other files ###################################################
  48. # You can include other files from your options file using the 'include'
  49. # option. Crawl will treat it as if you copied the whole text of that file
  50. # into your options file in that spot. You can uncomment some of the following
  51. # lines by removing the beginning '#' to include some of the other files in
  52. # this folder.
  53.  
  54. # Some useful, more advanced options, implemented in LUA.
  55. # include = advanced_optioneering.txt
  56.  
  57. # Alternative vi bindings for Dvorak users.
  58. # include = dvorak_command_keys.txt
  59.  
  60. # Alternative vi bindings for Colemak users.
  61. # include = colemak_command_keys.txt
  62.  
  63. # Alternative vi bindings for Neo users.
  64. # include = neo_command_keys.txt
  65.  
  66. # Override the vi movement keys with a non-command.
  67. # include = no_vi_command_keys.txt
  68.  
  69. # Turn the shift-vi keys into safe move, instead of run.
  70. # include = safe_move_shift.txt
  71.  
  72. ##### Ancient versions ##############################################
  73. # If you're used to the interface of ancient versions of Crawl, you may
  74. # get back parts of it by uncommenting the following options:
  75.  
  76. # include = 034_command_keys.txt
  77.  
  78. # And to revert monster glyph and colouring changes:
  79.  
  80. # include = 052_monster_glyphs.txt
  81. # include = 060_monster_glyphs.txt
  82. # include = 071_monster_glyphs.txt
  83. # include = 080_monster_glyphs.txt
  84. # include = 0.9_monster_glyphs.txt
  85. # include = 0.12_monster_glyphs.txt
  86. # include = 0.13_monster_glyphs.txt
  87. # include = 0.14_monster_glyphs.txt
  88.  
  89. show_more = false
  90.  
  91. # force_spell_targeter -= all
  92.  
  93. simple_targeting = true
  94.  
  95. macros += M 4 ===cast
  96. macros += M 3 ===cast_efficient
  97. macros += M 2 ===berder_test
  98. macros += M z z*
  99. macros += M Z Z*
  100.  
  101.  
  102. bindkey = [^D] CMD_LUA_CONSOLE
  103. # always_use_static_spell_targeters = true
  104.  
  105. # casting spells
  106. # ignition, orbofdestruction, fireball, starburst
  107. : LOS = 7
  108.  
  109. bindkey = [~] CMD_LUA_CONSOLE
  110.  
  111. {
  112.  
  113. function troll_fighter_set_skills()
  114. if you.race() == "Troll" and you.class() == "Fighter" then
  115. you.train_skill("Unarmed Combat", 2)
  116. you.set_training_target("Dodging",9.9)
  117. you.set_training_target("Fighting",19.9)
  118. you.set_training_target("Shields",16.6)
  119. you.set_training_target("Shapeshifting",23.3)
  120. -- you.set_training_target("Unarmed Combat",15)
  121. end
  122. end
  123.  
  124. function ready()
  125. if you.turns() == 0 then
  126. troll_fighter_set_skills()
  127. end
  128. end
  129.  
  130.  
  131.  
  132.  
  133. local monster_array
  134. local flamewave_start_turn=0
  135. local flamewave_last_turn=0
  136. local monster_ac
  137. -- maps (spell name with optional modifier) .. x .. "," .. y to damage_value
  138. -- so we don't have to recalculate it
  139. local mondam_cache = {}
  140. local acmus2_cache = {}
  141.  
  142. -- look at https://github.com/crawl/crawl/blob/0.31.0/crawl-ref/source/l-moninf.cc
  143. --
  144. -- c_persist is a persistent data store
  145. --
  146. -- TODO: fungus targeting issue (fireball)
  147. -- should continue flame wave if started even if high risk situation
  148. -- flame wave should have higher cost if we expect it to end early
  149. -- investigate nil value in cast_appropriate_spell
  150.  
  151. -- for some reason crawl.do_commands({"CMD_WAIT"}) does not work for this
  152. -- nor does crawl.process_keys(".")
  153. function wait()
  154. crawl.sendkeys(".")
  155. crawl.process_command()
  156. end
  157.  
  158. function berder_test()
  159. local messages = crawl.messages(100)
  160. crawl.mpr("#" .. view.feature_at(1,0))
  161. crawl.mpr(tostring(is_on_stairs()))
  162. crawl.mpr(you.contaminated())
  163. initialize_monster_array()
  164. update_monster_array()
  165. local x,y
  166. for x=-LOS,LOS do
  167. for y=-LOS,LOS do
  168. if valid_enemy(x, y) then
  169. local m = monster_array[x][y]
  170. crawl.mpr(m:name() .. "=" .. damage_value(1000, m))
  171. end
  172. end
  173. end
  174. -- crawl.mpr("danger:" .. danger())
  175.  
  176. end
  177.  
  178.  
  179. function initialize_monster_array()
  180. monster_array = {}
  181. local x
  182. for x = -LOS-5,LOS+5 do
  183. monster_array[x] = {}
  184. end
  185. mondam_cache = {}
  186. end
  187.  
  188. function update_monster_array()
  189. local x,y
  190. for x = -LOS,LOS do
  191. for y = -LOS,LOS do
  192. monster_array[x][y] = monster.get_monster_at(x, y)
  193. end
  194. end
  195. end
  196.  
  197. local max_spellpower_table = {foxfire=25, shock=25, ["flame wave"]=100, ["stone arrow"]=50, scorch=50, ["poisonous vapours"]=50, ["iskenderun's mystic blast"]=100}
  198.  
  199. function spellpower(spellname)
  200. local maxPower = 200
  201. local low_power = max_spellpower_table[spellname]
  202. if low_power ~= nil then
  203. maxPower = low_power
  204. end
  205. return spells.power_perc(spellname) * maxPower / 100.0
  206. end
  207.  
  208. function can_target(x, y)
  209. return you.see_cell_no_trans(x, y)
  210. end
  211.  
  212. function can_smite(x, y)
  213. return you.see_cell_no_trans(x, y) and not is_wall(x, y)
  214. end
  215.  
  216. function valid_enemy(x, y)
  217. m = monster_array[x][y]
  218. if m ~= nil then
  219. return m and m:attitude() == 0 and you.see_cell_no_trans(x, y) and not m:is_firewood()
  220. end
  221. return false
  222. end
  223.  
  224.  
  225. function valid_enemy_explosion(m, x, y, x2, y2)
  226. return m and m:attitude() == 0 and not m:is_firewood() and view.cell_see_cell(x, y, x2, y2)
  227. end
  228.  
  229. -- TODO account for: MP efficiency
  230. -- only account for MP efficiency if we're in MP conserving mode? not against dangerous enemies
  231. --
  232. -- accurate evasion calculations (difficult with the info given)
  233. -- accurate armor calculations (difficult with the info given)
  234. -- preferring to target close enemies
  235. -- instead of raw damage, look at something like (enemy danger level) * (damage dealt) / (enemy remaining HP + enemy max HP)
  236. -- so it rewards for hitting dangerous enemies, and rewards more for hitting dangerous enemies that are low on HP
  237.  
  238. function spell_cost(spellname)
  239. if spellname == "flame wave" then
  240. if flamewave_turns() > 0 then
  241. return 1
  242. else
  243. return 2 -- because it will cost less later on and we probably won't just do 1 cast
  244. end
  245. end
  246. return spells.mana_cost(spellname)
  247. end
  248.  
  249. -- a number indicating how urgent it is that we kill monsters quickly vs efficiently
  250. function danger()
  251. local x,y
  252. local danger=0
  253. -- any dangerous monsters within 2 squares?
  254. for x=-2,2 do
  255. for y=-2,2 do
  256. if valid_enemy(x, y) then
  257. local m = monster_array[x][y]
  258. if m:threat() >= 2 then
  259. danger = danger + m:threat()
  260. end
  261. end
  262. end
  263. end
  264. -- count dangerous monsters in LOS
  265. -- 3 make the overall situation dangerous
  266. for x=-7,7 do
  267. for y=-7,7 do
  268. if valid_enemy(x, y) then
  269. local m = monster_array[x][y]
  270. if m:threat() >= 2 then
  271. danger = danger + 0.7
  272. end
  273. end
  274. end
  275. end
  276. return danger
  277. end
  278.  
  279. function cast()
  280. cast_appropriate_spell(false, false)
  281. end
  282.  
  283. function cast_efficient()
  284. cast_appropriate_spell(true, false)
  285. end
  286.  
  287. function cast_quiet()
  288. -- assuming we'd usually also like to be efficient, if we're being quiet
  289. cast_appropriate_spell(true, true)
  290. end
  291.  
  292. -- argmax_x (f(x)) for x in t
  293. function table_max_by(t, f)
  294. if #t == 0 then
  295. return nil
  296. end
  297. local best = f(t[1])
  298. local bestIx = 1
  299. for i=1,#t do
  300. local value = f(t[i])
  301. if value > best then
  302. best = value
  303. bestIx = i
  304. end
  305. end
  306. return t[bestIx]
  307. end
  308.  
  309. -- score a value_table entry by efficiency
  310. function efficiency(x, minDamage)
  311. local continuingFlameWave = (x == "flame wave" and flamewave_turns() > 0)
  312. if x[1] < minDamage and not continuingFlameWave then
  313. return 0 -- even if it's efficient we want to deal decent damage
  314. -- but don't interrupt an ongoing flame wave so much
  315. end
  316. return x[1] / spell_cost(x[2])
  317. end
  318.  
  319. function cast_appropriate_spell(efficient, quiet)
  320. initialize_monster_array()
  321. update_monster_array()
  322. local value_table = {}
  323. table.insert(value_table, evaluate_ood()) -- targeting on this is a bit iffy
  324. table.insert(value_table, evaluate_starburst())
  325. table.insert(value_table, evaluate_foxfire())
  326.  
  327. table.insert(value_table, evaluate_stonearrow())
  328. table.insert(value_table, evaluate_bombard())
  329. table.insert(value_table, evaluate_scorch())
  330. table.insert(value_table, evaluate_airstrike())
  331. table.insert(value_table, evaluate_shock())
  332. table.insert(value_table, evaluate_flamewave())
  333. table.insert(value_table, evaluate_irradiate())
  334. table.insert(value_table, evaluate_lcs())
  335. table.insert(value_table, evaluate_imb())
  336. if not quiet then
  337. table.insert(value_table, evaluate_fireball())
  338. table.insert(value_table, evaluate_ignition())
  339. table.insert(value_table, evaluate_firestorm())
  340. table.insert(value_table, evaluate_lrd())
  341. end
  342.  
  343. if efficient then
  344. -- local totValue = total_damage_value()
  345. -- plan is
  346.  
  347. local bestDmg = table_max_by(value_table, function (x) return x[1] end)[1]
  348. local bestEfficiency = table_max_by(value_table, function (x) return efficiency(x, bestDmg / 2) end)
  349. table.sort(value_table, function (k1, k2) return efficiency(k1, bestDmg / 2) < efficiency(k2, bestDmg / 2) end)
  350. else
  351. table.sort(value_table, function (k1, k2) return k1[1] < k2[1] end)
  352. end
  353.  
  354. local best = value_table[#value_table]
  355.  
  356. local i
  357. for i = 1,#value_table do
  358. -- crawl.mpr(value_table[i][2])
  359. -- bpr(value_table[i][1])
  360. -- bpr(value_table[i][1]/spell_cost(value_table[i][2]))
  361. -- bpr(value_table[i][3])
  362. -- bpr(value_table[i][4])
  363. if value_table[i][1] ~= 0 then
  364. crawl.mpr("(" .. value_table[i][2] .. "=" .. value_table[i][1] .. "|" .. value_table[i][1]/spell_cost(value_table[i][2]) .. "@" .. value_table[i][3] .. "," .. value_table[i][4] .. ")")
  365. end
  366. end
  367.  
  368. if best[2] == "flame wave" then
  369. if flamewave_turns() > 0 then
  370. crawl.mpr("continuing flame wave")
  371. flamewave_last_turn = you.turns()
  372. wait()
  373. return
  374. end
  375. flamewave_start_turn = you.turns()
  376. flamewave_last_turn = you.turns()
  377. end
  378.  
  379.  
  380. if best[1] > 2 then
  381. if best[2] == "lee's rapid deconstruction" then
  382. cast_lrd(best[3], best[4])
  383. else
  384. spells.cast(best[2], best[3], best[4])
  385. end
  386. end
  387. end
  388.  
  389. function resisted_damage(dmg, res)
  390. if res == 0 then
  391. return dmg
  392. end
  393. if res <= -1 then
  394. return dmg*1.5
  395. end
  396. if res == 1 then
  397. return dmg * 0.5
  398. end
  399. if res == 2 then
  400. return 0 -- don't even bother
  401. -- return dmg * 0.2
  402. end
  403. if res == 3 then
  404. return 0
  405. end
  406. return 0
  407. end
  408.  
  409.  
  410. function guess_ac(m)
  411. local ac_pips = m:ac()
  412. -- pips is ceil(mi->ac/5.0) from l-moninfo.cc
  413. if ac_pips == 0 then
  414. return 0
  415. end
  416. if monster_ac[m:name()] ~= nil then
  417. if math.ceil(monster_ac[m:name()] / 5.0) == ac_pips then
  418. return monster_ac[m:name()]
  419. end
  420. end
  421. return 2.5 + (ac_pips - 1) * 5
  422. end
  423.  
  424. -- damage against ac assuming damage is uniformly chosen between 0 and dam
  425. function ac_damage_linear(dam, m)
  426. local ac = guess_ac(m)
  427. local mad = min(ac, dam)
  428. local numerator = mad * dam*dam*0.5 - mad*mad*dam*0.5 + mad*mad*mad/6.0
  429. local denom = dam*dam*0.5*ac
  430. return dam * numerator / denom
  431. end
  432.  
  433. -- sum vectors
  434. function sv(v1, v2)
  435. local v3, i
  436. for i=1,#v1 do
  437. v3[i] = v1[i] + v2[i]
  438. end
  439. return v3
  440. end
  441.  
  442. -- a number indicating how important it is to deal dmg damage to this enemy
  443. -- TODO: being close increases danger
  444. -- TODO: certain enemy types can be prioritized: floating eyes are always max danger
  445. -- shining eyes, ghost moths
  446. function damage_value(spell_context, dmg, m, kill_bonus)
  447. if m == nil then
  448. crawl.mpr("nil m in damage value")
  449. end
  450. local mhp = string.gsub(m:max_hp(), "about ", "")
  451. mhp = string.gsub(mhp, "~", "")
  452. mhp = tonumber(mhp)
  453. local hp = mhp * (6 - m:damage_level())/6.0 + 1
  454. local kill_value = m:threat() + 1
  455. if dmg > hp * 1.2 then
  456. dmg = hp * 2
  457. end
  458. local multiplier = 100
  459. if summoned_monster(m) then
  460. multiplier = 20
  461. end
  462. if m:is_safe() then
  463. multiplier = 10
  464. end
  465. local result = (dmg * kill_value / hp + dmg * kill_value / mhp) * multiplier
  466. if spell_context ~= nil then
  467. mondam_cache[spell_context .. "|" .. m:x_pos() .. "," .. m:y_pos()] = result
  468. end
  469. return result
  470. end
  471.  
  472. function total_damage_value()
  473. local x,y
  474. local totValue = 0
  475. for x=-LOS,LOS do
  476. for y=-LOS,LOS do
  477. if valid_enemy(x, y) then
  478. totValue = totValue + damage_value(nil, 10000, monster_array[x][y])
  479. end
  480. end
  481. end
  482. return totValue
  483. end
  484.  
  485. -- NdM damage against ac
  486. -- guess ac based on monster
  487. function ac_damage_NdM(N, M, m)
  488. local ac = guess_ac(m)
  489. return ac_damage_NdM_ac(N, M, ac)
  490. end
  491.  
  492. -- NdM damage against ac
  493. -- specify ac
  494. function ac_damage_NdM_ac(N, M, ac)
  495. local var_NdM = N * (M^2 - 1) / 12.0
  496. local mean_NdM = N * (M + 1) / 2.0
  497.  
  498. return ac_damage_mus2(mean_NdM, var_NdM, ac)
  499. end
  500.  
  501. -- AC damage if the damage is normally approximated with mean mu
  502. -- and variance s2
  503. function ac_damage_mus2(mu, s2, ac)
  504. local cached = acmus2_cache[mu .. "," .. s2 .. "," .. ac]
  505. if cached then
  506. return cached
  507. end
  508.  
  509. -- we'll crudely model this with ((3d2) + A) * B
  510. -- such that it has the same mean and variance
  511. -- mean of ((3d2) + A)*B is
  512. -- (3*3/2 + A) * B = mu
  513. -- var of ((3d2) + A)*B is
  514. -- B*B*3*(2*2-1)/12 = s2
  515. local B = math.sqrt(s2/0.75)
  516. local A = mu / B - 3 * 3 / 2
  517. local i, j, k, a
  518. local tdam = 0
  519. for i=1,2 do
  520. for j=1,2 do
  521. for k=1,2 do
  522. local d = ((i + j + k) + A) * B
  523. if d > ac then
  524. -- (sum_a=0^ac d-a) / (ac+1)
  525. -- = (sum_a=0^ac d - sum_a=0^ac a) / (ac+1)
  526. -- = (d(ac+1) - ac(ac+1)/2) / (ac+1)
  527. -- = d - ac/2
  528. tdam = tdam + d - ac/2
  529. else
  530. -- (sum_a=0^d d-a) / (ac+1) + (sum_a=d+1^ac 0) / (ac + 1)
  531. -- = ((sum_a=0^d d) - (sum_a=0^d a))/(ac+1)
  532. -- = (d(d+1) - d(d+1)/2)/(ac+1)
  533. tdam = tdam + (d*(d+1)/2) / (ac+1)
  534. end
  535. -- for a=0,ac do
  536. -- local d =
  537. -- if d > a then
  538. -- tdam = tdam + d - a
  539. -- end
  540. -- end
  541. end
  542. end
  543. end
  544. local result = tdam / (2*2*2)
  545. acmus2_cache[mu .. "," .. s2 .. "," .. ac] = result
  546. return result
  547. end
  548.  
  549. -- just ask if it has a shield or not
  550. -- can't be bothered to figure out the actual sh value
  551. -- (though it would be possible based on monster HD and shield description)
  552. -- if it has a shield just assume 50% block chance
  553. function sh_damage(dmg, m)
  554. local d = m:target_desc()
  555. -- could be a buckler but then it probably wouldn't be 50% block chance so w/e
  556. local has_shield = string.find(d, "shield")
  557. if has_shield then
  558. return dmg * 0.5
  559. end
  560. return dmg
  561. end
  562.  
  563. function summoned_monster(m)
  564. local d = m:target_desc()
  565. if string.find(d, "summoned") then
  566. return true
  567. end
  568. return false
  569. end
  570.  
  571. -- a friendly monster that isn't you
  572. function friendly_at(x, y)
  573. local m = monster_array[x][y]
  574. if m ~= nil then
  575. if m:attitude() > 0 then
  576. return true -- neutral or friendly monster
  577. end
  578. end
  579. return false
  580. end
  581.  
  582. -- is this beam blocked by an obstacle, so that we'd get an error if we tried to target?
  583. function blocked_beam(path)
  584. local i
  585. for i=1,#path do
  586. if firewood_at(path[i][1], path[i][2]) then
  587. return true
  588. end
  589. end
  590. return false
  591. end
  592.  
  593. -- a monster that blocks targeting for fireball
  594. function firewood_at(x, y)
  595. local m = monster_array[x][y]
  596. if m ~= nil then
  597. return m:is_firewood()
  598. -- local name = m:name()
  599. -- if name == "plant" or name == "demonic plant" or name == "withered plant" or name == "fungus" then
  600. -- return true
  601. -- end
  602. end
  603. return false
  604. end
  605.  
  606. function fireball_damage_at_target(x, y, N, M, avoidPlayer)
  607. local totDmg = 0
  608. -- 3d(3.33+Power/6)
  609. local x2, y2
  610. for x2 = -1, 1 do
  611. for y2 = -1, 1 do
  612. local m = monster_array[x+x2][y+y2]
  613. if valid_enemy_explosion(m, x+x2, y+y2, x, y) then
  614. local dmg = mondam_cache["fireball|" .. x .. "," .. y] or damage_value("fireball", resisted_damage(ac_damage_NdM(N, M, m), m:res_fire()), m)
  615. crawl.mpr("fireball" .. m:name() .. resisted_damage(ac_damage_NdM(N, M, m), m:res_fire()))
  616. totDmg = totDmg + dmg
  617. elseif not you.see_cell(x+x2, y+y2) then
  618. totDmg = totDmg + 0.1 -- just slightly prefer to hit out of sight tiles, in case they have enemies
  619. elseif avoidPlayer and x+x2 == 0 and y+y2 == 0 then
  620. return 0 -- don't hit yourself
  621. elseif friendly_at(x+x2, y+y2) then
  622. return 0
  623. end
  624. end
  625. end
  626. return totDmg
  627. end
  628.  
  629. function castable(spellname)
  630. if not spells.memorised(spellname) then
  631. return false
  632. end
  633. if spells.fail(spellname) > 14 then
  634. return false
  635. end
  636. if you.mp() < spells.level(spellname) then
  637. return false
  638. end
  639. if spells.fail_severity(spellname) > 2 then
  640. return false
  641. end
  642. return true
  643. end
  644.  
  645. function evaluate_fireball()
  646. if not castable("fireball") then
  647. return {0, "fireball", 0, 0}
  648. end
  649. local bestX = 0
  650. local bestY = 0
  651. local bestDmg = 0
  652. local range = spells.max_range("fireball")
  653. local x, y
  654. local N = 3
  655. local M = 3.33 + spellpower("fireball")/6
  656. for x = -range,range do
  657. for y = -range,range do
  658. if can_target(x, y) then
  659. local path = spells.path("fireball",x,y)
  660. if not blocked_beam(path) then
  661. local x2 = path[#path][1]
  662. local y2 = path[#path][2]
  663. local dmg = fireball_damage_at_target(x2, y2, N, M, true)
  664. if dmg > bestDmg then
  665. bestDmg = dmg
  666. bestX = x
  667. bestY = y
  668. end
  669. end
  670. end
  671. end
  672. end
  673. return {bestDmg * (1 - spells.fail("fireball")/100.0), "fireball", bestX, bestY}
  674. end
  675.  
  676. function evasion_check(m, spellname)
  677. local s = m:target_spell(spellname)
  678. local i, j = string.find(s, "%% to hit")
  679. if i ~= nil then
  680. local pct = string.sub(s, i-3, i-1)
  681. if tonumber(pct) == nil then
  682. pct = string.sub(s, i-2, i-1)
  683. end
  684. return tonumber(pct) * 0.01
  685. end
  686. return 1.0
  687. end
  688.  
  689. function evaluate_starburst()
  690. if not castable("starburst") then
  691. return {0, "starburst", 0, 0}
  692. end
  693. local totDmg = 0
  694. -- 6d(3+Power/9)
  695. local N = 6
  696. local M = 3 + spellpower("starburst")/9
  697. local range = spells.max_range("starburst")
  698. local ranges = {}
  699. local x, y
  700. for x=-1,1 do
  701. ranges[x] = {}
  702. for y=-1,1 do
  703. ranges[x][y] = range
  704. end
  705. end
  706. for R = 1,LOS do
  707. for x=-1,1 do
  708. for y=-1,1 do
  709. if x ~= 0 or y ~= 0 then
  710. local m = monster_array[R*x][R*y]
  711. if m ~= nil and valid_enemy(R*x, R*y) and ranges[x][y] >= R then
  712. local dmg = ac_damage_NdM(N, M, m)
  713. dmg = damage_value(nil, resisted_damage(dmg, m:res_fire()), m)
  714. dmg = dmg * evasion_check(m, "starburst")
  715. totDmg = totDmg + dmg
  716. ranges[x][y] = ranges[x][y] - 1
  717. end
  718. end
  719. end
  720. end
  721. end
  722. return {totDmg * (1 - spells.fail("starburst")/100.0), "starburst", 0, 0}
  723. end
  724.  
  725. function is_on_stairs()
  726. if string.find(view.feature_at(0,0), "stairs") then
  727. return true
  728. end
  729. return false
  730. end
  731.  
  732. function is_wall(x, y)
  733. return travel.feature_solid(view.feature_at(x, y))
  734. end
  735.  
  736. -- TODO track whether the target already has an OOD en route that is likely to kill them, and don't shoot a second
  737. function ood_damage_at_target(x, y, m)
  738.  
  739. -- if dist < 4
  740. -- 9d((60*dist*3/10 + pow*dist*3/10)/12)
  741. -- 9d((5 + pow/12) * dist * 3/10)
  742. --
  743. -- if dist >= 4, 9d(5 + pow/12)
  744. -- 9d(5 + Power/12)
  745. local dist = math.max(math.abs(x), math.abs(y))
  746. if dist > 3 then
  747. dist = dist - 1 -- assume enemy will take a step forward before being hit
  748. end
  749. local N = 9
  750. local M = 5 + spellpower("orb of destruction") / 12
  751. if dist < 4 then
  752. M = M * dist * 0.3
  753. end
  754. local baseDamage = damage_value(nil, ac_damage_NdM(N, M, m), m)
  755. baseDamage = sh_damage(baseDamage, m)
  756.  
  757. baseDamage = baseDamage * (1 - spells.fail("orb of destruction")/100.0)
  758.  
  759. local x2, y2
  760. local xstart, ystart
  761. local xend, yend
  762. xstart = 1
  763. ystart = 1
  764. xend = x
  765. yend = y
  766. if math.abs(x) < math.abs(y) then
  767. xstart = 0
  768. end
  769. if math.abs(y) < math.abs(x) then
  770. ystart = 0
  771. end
  772. if x < 0 then
  773. xend = -xstart
  774. xstart = x
  775. end
  776. if y < 0 then
  777. yend = -ystart
  778. ystart = y
  779. end
  780. for x2=xstart,xend do
  781. for y2=ystart,yend do
  782. if is_wall(x2, y2) or ((x2 ~= x or y2 ~= y) and monster_array[x2][y2]) then
  783. return 0
  784. end
  785. end
  786. end
  787. if x == 0 then
  788. for x2=-1,1 do
  789. for y2=ystart,yend do
  790. if is_wall(x2, y2) or ((x2 ~= x or y2 ~= y) and monster_array[x2][y2]) then
  791. baseDamage = baseDamage * 0.5
  792. end
  793. end
  794. end
  795. end
  796. return baseDamage
  797. end
  798.  
  799. function evaluate_ood()
  800. if not castable("orb of destruction") then
  801. return {0, "orb of destruction", 0, 0}
  802. end
  803. -- first check if there's an ood adjacent, and don't shoot if so
  804. local x1, y1
  805. for x1=-1,1 do
  806. for y1=-1,1 do
  807. local m = monster_array[x1][y1]
  808. if m and m:name() == "orb of destruction" then
  809. return {0, "orb of destruction", 0, 0}
  810. end
  811. end
  812. end
  813. local bestDmg=0
  814. local bestX=0
  815. local bestY=0
  816. local x, y
  817. for x=-LOS,LOS do
  818. for y=-LOS,LOS do
  819. local m = monster_array[x][y]
  820. -- todo monster shields
  821. if m and m:attitude() == 0 and you.see_cell_solid_see(x, y) then
  822. local dmg = ood_damage_at_target(x, y, m)
  823. if dmg > bestDmg then
  824. bestX = x
  825. bestY = y
  826. bestDmg = dmg
  827. end
  828. end
  829. end
  830. end
  831. return {bestDmg, "orb of destruction", bestX, bestY}
  832. end
  833.  
  834. function evaluate_ignition()
  835. if not castable("ignition") then
  836. return {0, "ignition", 0, 0}
  837. end
  838. local totDmg=0
  839. -- 3d(3.33+Power/9)
  840. local N = 3
  841. local M = 3.33 + spellpower("ignition") / 9
  842.  
  843. local x, y
  844. for x=-LOS,LOS do
  845. for y=-LOS,LOS do
  846. local m = monster_array[x][y]
  847. if valid_enemy(x, y) then
  848. local dmg = fireball_damage_at_target(x, y, N, M, false)
  849. totDmg = totDmg + dmg
  850. end
  851. end
  852. end
  853. return {totDmg * (1 - spells.fail("ignition")/100.0), "ignition", 0, 0}
  854. end
  855.  
  856. function flame_cloud_damage(m)
  857. -- (2d16)/2 + 5
  858. -- var_NdM = N * (M^2 - 1) / 12.0
  859. -- mean_NdM = N * (M + 1) / 2.0
  860. local mu = (2 * (16 + 1) / 2) / 2 + 5
  861. local s2 = (2 * (16*16 - 1) / 12) / 4
  862. return resisted_damage(ac_damage_mus2(mu, s2, guess_ac(m)), m:res_fire())
  863. end
  864.  
  865. function firestorm_damage_at_target(x, y, N, M)
  866. local totDmg = 0
  867. local x2, y2
  868. local pow = spellpower("fire storm")
  869. for x2 = -3, 3 do
  870. for y2 = -3, 3 do
  871. local m = monster_array[x+x2][y+y2]
  872. if valid_enemy_explosion(m, x+x2, y+y2, x, y) and view.cell_see_cell(x, y, x+x2, y+y2) then
  873. local dmg = mondam_cache["firestorm|" .. (x+x2) .. "," .. (y+y2)]
  874. if dmg == nil then
  875. dmg = ac_damage_NdM(N, M, m)
  876. dmg = resisted_damage(dmg*0.55, m:res_fire()) + dmg * 0.45
  877. local cloudDmg = flame_cloud_damage(m) * 2 -- assume it stays in the cloud for 2 turns
  878. -- crawl.mpr("firestorm " .. m:name() .. dmg + cloudDmg)
  879. dmg = damage_value("firestorm", dmg + cloudDmg, m)
  880. end
  881. if math.abs(x2) == 3 or math.abs(y2) == 3 then
  882. dmg = dmg * pow / 1000.0 -- chance of larger firestorm radius
  883. end
  884. totDmg = totDmg + dmg
  885. elseif math.abs(y2) <= 2 and math.abs(x2) <= 2 and not you.see_cell(x+x2, y+y2) and (view.cell_see_cell(x, y, x+x2, y+y2) or math.abs(x+x2) > LOS or math.abs(y+y2) > LOS) then
  886. totDmg = totDmg + 0.1 -- just slightly prefer to hit cells out of sight
  887. elseif math.abs(y2) <= 2 and math.abs(x2) <= 2 and is_wall(x+x2, y+y2) then
  888. totDmg = totDmg - 0.01 -- all other things equal, prefer to hit an open space
  889. end
  890. end
  891. end
  892. return totDmg
  893. end
  894.  
  895.  
  896. function evaluate_firestorm()
  897. if not castable("fire storm") then
  898. return {0, "fire storm uncastable", 0, 0}
  899. end
  900. local bestX = 0
  901. local bestY = 0
  902. local bestDmg = 0
  903. -- 8d(0.625+Power/8)
  904. local N = 8
  905. local M = 0.625 + spellpower("fire storm")/8
  906. -- also creates clouds
  907. local range = spells.max_range("fire storm")
  908. local x, y
  909. for x = -range,range do
  910. for y = -range,range do
  911. if (math.abs(x) > 3 or math.abs(y) > 3) and can_smite(x, y) then
  912. local dmg = firestorm_damage_at_target(x, y, N, M)
  913. -- bpr("firestorm at " .. tostring(x) .. tostring(y) .. " dmg" .. tostring(dmg))
  914. if dmg > bestDmg then
  915. bestDmg = dmg
  916. bestX = x
  917. bestY = y
  918. end
  919. end
  920. end
  921. end
  922. return {bestDmg * (1 - spells.fail("fire storm")/100.0), "fire storm", bestX, bestY}
  923. end
  924.  
  925. function evaluate_foxfire()
  926. if not castable("foxfire") then
  927. return {0, "foxfire", 0, 0}
  928. end
  929. -- 2 * 1d(4+ Power/5)
  930. local N = 2
  931. local M = 4 + spellpower("foxfire")/5.0
  932. local dmg = 0
  933. local bestDmg = 0
  934. local closest = LOS
  935. for x=-LOS,LOS do
  936. for y=-LOS,LOS do
  937. if valid_enemy(x, y) then
  938. local m = monster_array[x][y]
  939. local r = math.max(math.abs(x), math.abs(y))
  940. dmg = damage_value(nil, resisted_damage(N*ac_damage_NdM(1, M, m), m:res_fire()), m)
  941. if r <= closest then
  942. bestDmg = dmg
  943. closest = r
  944. end
  945. end
  946. end
  947. end
  948. bestDmg = bestDmg * (1 - spells.fail("foxfire")/100.0)
  949. local freeCount = 0
  950. for x=-1,1 do
  951. for y=-1,1 do
  952. if (x ~= 0 or y ~= 0) and not is_wall(x, y) and not monster_array[x][y] then
  953. freeCount = freeCount + 1
  954. end
  955. end
  956. end
  957. if freeCount == 0 then
  958. return {0, "foxfire", 0, 0}
  959. end
  960. if freeCount == 1 then
  961. return {bestDmg / 4.0, "foxfire", 0, 0}
  962. end
  963. if freeCount == 2 then
  964. return {bestDmg / 2.0, "foxfire", 0, 0}
  965. end
  966. return {bestDmg, "foxfire", 0, 0}
  967. end
  968.  
  969. -- Wave status: Wave, Wave+, Wave++, Wave+++
  970. -- this is not available to lua directly but we can scrape the message buffer
  971. -- When we cast flamewave, and each turn we maintain it, it says:
  972. -- "A wave of flame ripples out!"
  973. -- The first time we cast it, it says:
  974. -- "(Press . to intensify the flame waves.)"
  975. -- it ends if we are trampled, blinked, dispersal trap'd, or teleported
  976. -- "You blink"
  977. -- also it ends if we cast a spell, take a step, hit with a melee weapon, change jewellery, etc
  978. function flamewave_turns()
  979. if flamewave_last_turn ~= you.turns() - 1 then
  980. return 0
  981. end
  982. local messages = crawl.messages(100)
  983. -- delete messages up to the last cast of flame wave
  984. messages = string.gsub(messages, ".*A wave of flame ripples out!", "")
  985. if string.find(messages, "You blink") then
  986. return 0
  987. end
  988. if string.find(messages, "Your surroundings") then -- teleported
  989. return 0
  990. end
  991. if string.find(messages, "stumble backwards") then
  992. return 0
  993. end
  994. if string.find(messages, "drags you backwards") then
  995. return 0
  996. end
  997. if string.find(messages, "You miscast Flame Wave") then
  998. return 0
  999. end
  1000.  
  1001. if you.turns() - flamewave_start_turn < spells.max_range("flame wave") then
  1002. return you.turns() - flamewave_start_turn
  1003. end
  1004. return 0
  1005. end
  1006.  
  1007. -- local messages = crawl.messages(100)
  1008. function evaluate_flamewave()
  1009. local flame_range = flamewave_turns() + 1
  1010. if flame_range == 1 and not castable("flame wave") then
  1011. return {0, "flame wave", 0, 0}
  1012. end
  1013. if flame_range > 1 and you.mp() < 1 then
  1014. return {0, "flame wave", 0, 0}
  1015. end
  1016. -- 2d(4.5+Power/6)
  1017. local N = 2
  1018. local M = 4.5 + spellpower("flame wave")/6
  1019. local totDmg = 0
  1020. for x=-flame_range,flame_range do
  1021. for y=-flame_range,flame_range do
  1022. if valid_enemy(x, y) then
  1023. local m = monster_array[x][y]
  1024. local dmg = damage_value(nil, resisted_damage(ac_damage_NdM(N, M, m), m:res_fire()), m)
  1025. totDmg = totDmg + dmg
  1026. end
  1027. end
  1028. end
  1029. return {totDmg * (1 - spells.fail("flame wave")/100.0), "flame wave", 0, 0}
  1030. end
  1031.  
  1032. function evaluate_arrow(spellname, N, M)
  1033. if not castable(spellname) then
  1034. return {0, spellname, 0, 0}
  1035. end
  1036. local range = spells.max_range(spellname)
  1037. local x, y
  1038. local bestDmg = 0
  1039. local bestX = 0
  1040. local bestY = 0
  1041. for x = -range,range do
  1042. for y = -range,range do
  1043. if can_target(x, y) then
  1044. local path = spells.path(spellname,x,y)
  1045. if not blocked_beam(path) then
  1046. local cell
  1047. local totDmg = 0
  1048. local reachChance = 1.0
  1049. for cell = 1,#path do
  1050. local x2, y2
  1051. x2 = path[cell][1]
  1052. y2 = path[cell][2]
  1053. local m = monster_array[x2][y2]
  1054. if valid_enemy(x2, y2) and totDmg ~= -1 then
  1055. local hitChance = evasion_check(m, spellname)
  1056. local dmg = mondam_cache[spellname .. "|" .. x2 .. "," .. y2] or damage_value(spellname, ac_damage_NdM(N, M, m), m)
  1057. dmg = sh_damage(dmg * reachChance * hitChance, m)
  1058. reachChance = reachChance * (1 - hitChance)
  1059. totDmg = totDmg + dmg
  1060. elseif m then -- non-enemy monster in the way
  1061. totDmg = -1
  1062. end
  1063. end
  1064. if totDmg > bestDmg then
  1065. bestDmg = totDmg
  1066. bestX = x
  1067. bestY = y
  1068. end
  1069. end
  1070. end
  1071. end
  1072. end
  1073. return {bestDmg * (1 - spells.fail(spellname)/100.0), spellname, bestX, bestY}
  1074.  
  1075. end
  1076.  
  1077. function evaluate_stonearrow()
  1078. -- 3d(7+power/8)
  1079. local N = 3
  1080. local M = 7 + spellpower("stone arrow")/8
  1081.  
  1082. return evaluate_arrow("stone arrow", N, M)
  1083. end
  1084.  
  1085. function evaluate_lcs()
  1086. -- 10d(2.3 + power/10)
  1087. local N = 10
  1088. local M = 2.3 + spellpower("lehudib's crystal spear")/10
  1089. return evaluate_arrow("lehudib's crystal spear", N, M)
  1090. end
  1091.  
  1092. function evaluate_bombard()
  1093. -- 9d(1.44+Power/13)
  1094. if is_on_stairs() then
  1095. -- don't bombard ourselves off the stairs!
  1096. return {0, "bombard", 0, 0}
  1097. end
  1098. local N = 9
  1099. local M = 1.44 + spellpower("bombard")/13
  1100. return evaluate_arrow("bombard", N, M)
  1101. end
  1102.  
  1103. -- callable from a macro if you want, ===maybe_cast_lrd
  1104. function maybe_cast_lrd()
  1105. initialize_monster_array()
  1106. update_monster_array()
  1107. local eval = evaluate_lrd()
  1108. if eval[1] == 0 then
  1109. return
  1110. end
  1111. cast_lrd(eval[3], eval[4])
  1112. end
  1113.  
  1114. -- returns number of dice and explosion radius, and whether it's ice. see spl-damage.cc
  1115. function lrd_dice_terrain(feature)
  1116. feature = string.lower(feature)
  1117. if string.find(feature, "stair") then
  1118. return {0, 0, false}
  1119. end
  1120. local featuresRock = {"stone", "rock", "door", "slimy_wall", "petrified", "statue"}
  1121. local featuresMetal = {"metal", "iron"}
  1122. local featuresCrystal = {"crystal"}
  1123. local i
  1124. for i = 1,#featuresRock do
  1125. if string.find(feature, featuresRock[i]) then
  1126. return {3, 1, false}
  1127. end
  1128. end
  1129. for i = 1,#featuresMetal do
  1130. if string.find(feature, featuresMetal[i]) then
  1131. return {4, 1, false}
  1132. end
  1133. end
  1134. for i = 1,#featuresCrystal do
  1135. if string.find(feature, featuresCrystal[i]) then
  1136. return {4, 2, false}
  1137. end
  1138. end
  1139. return {0, 0, false}
  1140. end
  1141.  
  1142. -- number of dice, radius, and whether it's ice. see mon-data.cc and spl-damage.cc
  1143. function lrd_dice_monster(monster)
  1144. monster = string.lower(monster)
  1145. local monstersMetal = {"iron golem", "iron elemental", "peacekeeper", "war gargoyle"}
  1146. local monstersIce = {"ice beast", "simula", "ice statue"}
  1147. local monstersRockBone = {"toenail", "earth elemental", "saltling", "ushabti", "statue", "gargoyle", "skelet", "bone", "ancient champion", "revenant", "skull", "Murray", "rockslime"}
  1148. local monstersCrystal = {"orange statue", "crystal", "obsidian", "roxanne", "glass eye"}
  1149. -- check metal first because of war gargoyle/gargoyle
  1150. for i = 1,#monstersMetal do
  1151. if string.find(monster, monstersMetal[i]) then
  1152. return {4, 1, false}
  1153. end
  1154. end
  1155. for i = 1,#monstersCrystal do
  1156. if string.find(monster, monstersCrystal[i]) then
  1157. return {4, 2, false}
  1158. end
  1159. end
  1160. for i = 1,#monstersRockBone do
  1161. if string.find(monster, monstersRockBone[i]) then
  1162. return {3, 1, false}
  1163. end
  1164. end
  1165. for i = 1,#monstersIce do
  1166. if string.find(monster, monstersIce[i]) then
  1167. return {3, 1, true}
  1168. end
  1169. end
  1170. return {0, 0, false}
  1171. end
  1172.  
  1173. function lrd_damage_at_target(x, y, dmgPerDice, dice, radius, fromMonster, fromIce)
  1174. local x2, y2
  1175. local totDmg = 0
  1176. for x2 = -radius,radius do
  1177. for y2 = -radius,radius do
  1178. local m = monster_array[x+x2][y+y2]
  1179. if valid_enemy(x+x2, y+y2) then
  1180. if x2 == 0 and y2 == 0 and fromMonster then
  1181. totDmg = totDmg + damage_value(nil, dmgPerDice * dice, m)
  1182. elseif not fromIce then
  1183. totDmg = totDmg + damage_value(nil, ac_damage_NdM_ac(dice, dmgPerDice, guess_ac(m)*3), m)
  1184. else
  1185. totDmg = totDmg + damage_value(nil, resisted_damage(ac_damage_NdM_ac(dice, dmgPerDice, guess_ac(m)), m:res_cold()), m)
  1186. end
  1187. elseif friendly_at(x+x2, y+y2) then
  1188. return 0 -- don't hit neutrals, even unfriendly ones.
  1189. elseif x+x2 == 0 and y+y2 == 0 then
  1190. return 0 -- don't hit the player
  1191. end
  1192. end
  1193. end
  1194. return totDmg
  1195. end
  1196.  
  1197. function evaluate_lrd()
  1198. if not castable("lee's rapid deconstruction") then
  1199. return {0, "lee's rapid deconstruction", 0, 0}
  1200. end
  1201. local dmgPerDice = math.floor(5 + spellpower("lee's rapid deconstruction")/5.0)
  1202.  
  1203. local bestX = 0
  1204. local bestY = 0
  1205. local bestDmg = 0
  1206. local range = spells.max_range("lee's rapid deconstruction")
  1207. local x, y
  1208. for x = -range,range do
  1209. for y = -range,range do
  1210. if you.see_cell_solid_see(x, y) then
  1211. local feature = view.feature_at(x, y)
  1212. local lrdDice = {0, 0}
  1213. local m = monster_array[x][y]
  1214. local fromMonster = false
  1215. if m then
  1216. lrdDice = lrd_dice_monster(m:name())
  1217. end
  1218. if lrdDice[1] == 0 then
  1219. lrdDice = lrd_dice_terrain(feature)
  1220. else
  1221. fromMonster = true
  1222. end
  1223. if lrdDice[1] ~= 0 then
  1224. local dmg = lrd_damage_at_target(x, y, dmgPerDice, lrdDice[1], lrdDice[2], fromMonster, lrdDice[3])
  1225. if dmg > bestDmg then
  1226. bestDmg = dmg
  1227. bestX = x
  1228. bestY = y
  1229. end
  1230. end
  1231. end
  1232. end
  1233. end
  1234. return {bestDmg * (1 - spells.fail("lee's rapid deconstruction")/100.0), "lee's rapid deconstruction", bestX, bestY}
  1235. end
  1236.  
  1237. -- for some reason lrd can't be cast with spells.cast
  1238. -- so this is a workaround
  1239. function cast_lrd(x, y)
  1240. local cmdStr = "Z" .. spells.letter("lee's rapid deconstruction") .. "r"
  1241. local x2, y2
  1242. if x < 0 then
  1243. for x2 = x,-1 do
  1244. cmdStr = cmdStr .. "h"
  1245. end
  1246. elseif x > 0 then
  1247. for x2 = 1,x do
  1248. cmdStr = cmdStr .. "l"
  1249. end
  1250. end
  1251. if y < 0 then
  1252. for y2 = y,-1 do
  1253. cmdStr = cmdStr .. "k"
  1254. end
  1255. elseif y > 0 then
  1256. for y2 = 1,y do
  1257. cmdStr = cmdStr .. "j"
  1258. end
  1259. end
  1260. cmdStr = cmdStr .. "."
  1261. crawl.process_keys(cmdStr)
  1262. end
  1263.  
  1264. function evaluate_scorch()
  1265. if not castable("scorch") then
  1266. return {0, "scorch", 0, 0}
  1267. end
  1268. -- 2d(5+Power/10)
  1269. local N = 2
  1270. local M = 5 + spellpower("scorch")/10
  1271. local range = spells.range("scorch")
  1272. local x, y
  1273. local totDmg = 0
  1274. local numEnemies = 0
  1275. for x=-range,range do
  1276. for y=-range,range do
  1277. local m = monster_array[x][y]
  1278. if valid_enemy(x, y) then
  1279. totDmg = totDmg + damage_value(nil, resisted_damage(ac_damage_NdM(N, M, m), m:res_fire()), m)
  1280. numEnemies = numEnemies + 1
  1281. end
  1282. end
  1283. end
  1284. if numEnemies == 0 then
  1285. return {0, "scorch", 0, 0}
  1286. end
  1287. -- too many enemies in range isn't good because it hits randomly
  1288. if numEnemies > 2 then
  1289. return {0.5 * totDmg / numEnemies, "scorch", 0, 0}
  1290. end
  1291. return {totDmg / numEnemies * (1 - spells.fail("scorch")/100.0), "scorch", 0, 0}
  1292. end
  1293.  
  1294. function count_empty_spaces(x, y)
  1295. local x2, y2
  1296. local emptyCount = 0
  1297. for x2=-1,1 do
  1298. for y2=-1,1 do
  1299. if not is_wall(x+x2, y+y2) and not monster_array[x+x2][y+y2] then
  1300. emptyCount = emptyCount + 1
  1301. end
  1302. end
  1303. end
  1304. return emptyCount
  1305. end
  1306.  
  1307. function evaluate_airstrike()
  1308. if not castable("airstrike") then
  1309. return {0, "airstrike", 0, 0}
  1310. end
  1311. -- 2d([power + 13]/14 + 2m) where m = empty spaces
  1312. local N = 2
  1313. local M = (spellpower("airstrike") + 13)/14 -- + 2m
  1314. local bestX=0
  1315. local bestY=0
  1316. local bestDmg = 0
  1317. local x, y
  1318. for x=-LOS,LOS do
  1319. for y=-LOS,LOS do
  1320. local m = monster_array[x][y]
  1321. if valid_enemy(x, y) and can_smite(x, y) then
  1322. local dmg = damage_value(nil, ac_damage_NdM(N, M + 2 * count_empty_spaces(x, y), m), m)
  1323. if dmg > bestDmg then
  1324. bestDmg = dmg
  1325. bestX = x
  1326. bestY = y
  1327. end
  1328. end
  1329. end
  1330. end
  1331. return {bestDmg * (1 - spells.fail("airstrike")/100.0), "airstrike", bestX, bestY}
  1332. end
  1333.  
  1334. -- TODO account for bounces
  1335. function evaluate_shock()
  1336. if not castable("shock") then
  1337. return {0, "shock", 0, 0}
  1338. end
  1339. -- 1d(3+power/4)
  1340. local N = 1
  1341. local M = 3 + spellpower("shock")/4
  1342. local range = spells.max_range("shock")
  1343. local x, y
  1344. local bestDmg = 0
  1345. local bestX = 0
  1346. local bestY = 0
  1347. for x = -range,range do
  1348. for y = -range,range do
  1349. if can_target(x, y) then
  1350. local path = spells.path("shock",x,y)
  1351. local cell
  1352. local totDmg = 0
  1353. for cell = 1,#path do
  1354. local x2, y2
  1355. x2 = path[cell][1]
  1356. y2 = path[cell][2]
  1357. local m = monster_array[x2][y2]
  1358. if valid_enemy(x2, y2) and totDmg ~= -1 then
  1359. local dmg = mondam_cache["shock|" .. x2 .. "," .. y2] or damage_value("shock", resisted_damage(ac_damage_NdM_ac(N, M, guess_ac(m)/2), m:res_shock()), m) * evasion_check(m, "shock")
  1360. totDmg = totDmg + dmg
  1361. elseif friendly_at(x2, y2) then -- friend monster in the way
  1362. totDmg = -1
  1363. end
  1364. end
  1365. if totDmg > bestDmg then
  1366. bestDmg = totDmg
  1367. bestX = x
  1368. bestY = y
  1369. end
  1370. end
  1371. end
  1372. end
  1373. return {bestDmg * (1 - spells.fail("shock")/100.0), "shock", bestX, bestY}
  1374. end
  1375.  
  1376. function evaluate_irradiate()
  1377. if not castable("irradiate") then
  1378. return {0, "irradiate", 0, 0}
  1379. end
  1380. if you.contaminated() > 1 then -- another cast of this might give yellow contam
  1381. return {0, "irradiate", 0, 0}
  1382. end
  1383. -- 3d(11.66 + power/6)
  1384. local N = 3
  1385. -- +10 because the malmutate status is worth something
  1386. local M = 11.66 + spellpower("irradiate")/6 + 10
  1387. local totDmg = 0
  1388. local totEnemyThreat = 0
  1389. for x=-1,1 do
  1390. for y=-1,1 do
  1391. if valid_enemy(x, y) then
  1392. local m = monster_array[x][y]
  1393. totDmg = totDmg + damage_value(nil, ac_damage_NdM(N, M, m), m)
  1394. totEnemyThreat = totEnemyThreat + m:threat()
  1395. end
  1396. end
  1397. end
  1398. if totEnemyThreat < 3 and you.mp() > 10 then
  1399. -- don't cast irradiate without a good reason, i.e. multiple dangerous adjacent enemies or low on mp
  1400. return {0, "irradiate", 0, 0}
  1401. end
  1402. return {totDmg * (1 - spells.fail("irradiate")/100.0), "irradiate", 0, 0}
  1403. end
  1404.  
  1405. function evaluate_imb()
  1406. if not castable("iskenderun's mystic blast") then
  1407. return {0, "iskenderun's mystic blast", 0, 0}
  1408. end
  1409. -- 3d(11.66 + power/6)
  1410. local N = 2
  1411. local M = 3 + spellpower("iskenderun's mystic blast")/6
  1412. local range = spells.range("iskenderun's mystic blast")
  1413. local totDmg = 0
  1414. local totEnemyThreat = 0
  1415. for x=-range,range do
  1416. for y=-range,range do
  1417. if valid_enemy(x, y) then
  1418. local m = monster_array[x][y]
  1419. totDmg = totDmg + damage_value(nil, ac_damage_NdM(N, M, m), m)
  1420. end
  1421. end
  1422. end
  1423. return {totDmg * (1 - spells.fail("iskenderun's mystic blast")/100.0), "iskenderun's mystic blast", 0, 0}
  1424.  
  1425. end
  1426.  
  1427. -- function evaluate_poisonousvapours()
  1428. -- if not castable("poisonous vapours") then
  1429. -- return {0, "poisonous vapours", 0, 0}
  1430. -- end
  1431. -- -- there isn't a specific damage formula for poisonous vapours
  1432. -- -- we'll begin by assuming it is similar in value to scorch
  1433. -- -- (below is the damage formula for scorch)
  1434. -- local dmgPerHit = 2 * 0.5 * math.floor(6 + spellpower("poisonous vapours")/10.0)
  1435. -- -- targeting: we only want to target non-poison-resistant creatures
  1436. -- -- that are not already maximally poisoned
  1437. -- -- giving priority to the monster that is currently the most poisoned
  1438. -- -- and breaking ties going to the most dangerous monster
  1439. -- -- status() can be "poisoned", "very poisoned", "extremely poisoned"
  1440. -- local bestDmg = 0
  1441. -- local bestX, bestY
  1442. -- local x, y
  1443. -- local range = spells.max_range("poisonous vapours")
  1444. -- for x=-range,range do
  1445. -- for y=-range,range do
  1446. -- local m = monster_array[x][y]
  1447. -- if m and m:res_poison() <= 0 and not m:status("extremely poisoned") then
  1448. -- local dmg = damage_value(nil, dmgPerHit, m)
  1449. -- if m:threat() < 2 then
  1450. -- dmg = dmg * 0.5
  1451. -- elseif m:threat() > 3 then
  1452. -- dmg = dmg * 1.5
  1453. -- end
  1454. -- if m:status("very poisoned") then
  1455. -- dmg = dmg * 1.1
  1456. -- elseif m:status("poisoned") then
  1457. -- dmg = dmg * 1.05
  1458. -- end
  1459. -- if dmg > bestDmg then
  1460. -- bestDmg = dmg
  1461. -- bestX = x
  1462. -- bestY = y
  1463. -- end
  1464. -- end
  1465. -- end
  1466. -- end
  1467. -- return {bestDmg, "poisonous vapours", bestX, bestY}
  1468. -- end
  1469.  
  1470. function bpr(message)
  1471. crawl.mpr(tostring(message))
  1472. end
  1473.  
  1474. monster_ac = {["adder"] = 1 ,["jelly"] = 0 ,["Tiamat"] = 30 ,["Sonja"] = 2 ,["jumping spider"] = 6 ,["spatial vortex"] = 0 ,["formicid"] = 3 ,["queen bee"] = 10 ,["acid dragon"] = 5 ,["rime drake"] = 3 ,["dwarf"] = 2 ,["centaur"] = 3 ,["orb of destruction"] = 0 ,["deep elf zephyrmancer"] = 0 ,["hobgoblin"] = 2 ,["Amaemon"] = 3 ,["deep troll shaman"] = 6 ,["shadow imp"] = 3 ,["human"] = 3 ,["eldritch tentacle segment"] = 13 ,["twister"] = 0 ,["bat"] = 1 ,["glowing shapeshifter"] = 0 ,["Bai Suzhen"] = 22 ,["golden dragon"] = 15 ,["draconian annihilator"] = -1 ,["ophan"] = 10 ,["white draconian"] = 9 ,["death knight"] = 2 ,["radroach"] = 13 ,["Rupert"] = 0 ,["sky beast"] = 3 ,["test spawner"] = 127 ,["ballistomycete spore"] = 0 ,["black mamba"] = 4 ,
  1475. ["the Serpent of Hell"] = 16 ,["Gloorx Vloq"] = 10 ,["Roxanne"] = 20 ,["withered plant"] = 0 ,["white imp"] = 4 ,["Grinder"] = 3 ,["thermic dynamo"] = 4 ,["deep elf sorcerer"] = 0 ,["spectral thing"] = 8 ,["deep elf blademaster"] = 0 ,["bunyip"] = 6 ,["flayed ghost"] = 0 ,["kraken"] = 20 ,["bone dragon"] = 20 ,["bombardier beetle"] = 4 ,["tentacle segment"] = 5 ,["shard shrike"] = 2 ,["yaktaur"] = 4 ,["alligator"] = 4 ,["the Royal Jelly"] = 8 ,["emperor scorpion"] = 18 ,["snake"] = 0 ,["curse skull"] = 35 ,["tentacle"] = 5 ,["Gastronok"] = 2 ,["small abomination"] = 0 ,["minotaur"] = 6 ,["acid blob"] = 1 ,["deep elf master archer"] = 0 ,["orange demon"] = 3 ,["Executioner"] = 10 ,["naga"] = 6 ,["frilled lizard"] = 0 ,["oni"] = 1 ,["Louise"] = 0 ,["Murray"] = 30 ,["water elemental"] = 4 ,["bound soul"] = 8 ,["culicivora"] = 2 ,["mummy priest"] = 8 ,["green draconian"] = 9 ,["tentacled starspawn"] = 5 ,["faun"] = 2 ,["fire crab"] = 9 ,["yaktaur captain"] = 5 ,["pandemonium lord"] = 1 ,
  1476. ["servant of whispers"] = 1 ,["komodo dragon"] = 7 ,["occultist"] = 0 ,["goliath frog"] = 3 ,["hydra"] = 0 ,["hellwing"] = 16 ,["Mara"] = 10 ,["orc"] = 0 ,["dream sheep"] = 2 ,["wolf"] = 4 ,["gargoyle"] = 18 ,["Urug"] = 2 ,["Norris"] = 1 ,["ribbon worm"] = 1 ,["Sojobo"] = 2 ,["boggart"] = 0 ,["skyshark"] = 6 ,["Maggie"] = 0 ,["trivial sensed monster"] = 0 ,["reaper"] = 15 ,["Lom Lobon"] = 10 ,["large simulacrum"] = 10 ,["small zombie"] = 0 ,["satyr"] = 2 ,["fire vortex"] = 0 ,["ancient champion"] = 15 ,["mutant beast"] = 8 ,["demigod"] = 2 ,["snapping turtle"] = 16 ,["hell hound"] = 6 ,["spark wasp"] = 9 ,["deep troll earth mage"] = 12 ,["draconian"] = 10 ,["deep elf death mage"] = 0 ,["manticore"] = 5 ,["sun demon"] = 10 ,["giant cockroach"] = 3 ,["starspawn tentacle"] = 8 ,["spriggan air mage"] = 1 ,["ice dragon"] = 10 ,["halazid warlock"] = 8 ,["laughing skull"] = 4 ,["will-o-the-wisp"] = 4 ,["very ugly thing"] = 6 ,["Duvessa"] = 2 ,["Ijyb"] = 2 ,["hell lord"] = 0 ,["quicksilver dragon"] = 10 ,["entropy weaver"] = 7 ,["Natasha"] = 2 ,["deep elf high priest"] = 3 ,["ghost moth"] = 8 ,["balrug"] = 5 ,["hellion"] = 5 ,["fire elemental"] = 4 ,["dire elephant"] = 13 ,["silent spectre"] = 5 ,["chaos spawn"] = 4 ,["hell rat"] = 7 ,["walking divine tome"] = 10 ,["fungus"] = 0 ,["Sigmund"] = 0 ,["training dummy"] = 0 ,["demonspawn warmonger"] = 3 ,["foxfire"] = 0 ,["molten gargoyle"] = 14 ,["water moccasin"] = 2 ,["starcursed mass"] = 10 ,["Josephine"] = 0 ,["ogre mage"] = 1 ,["merfolk siren"] = 4 ,
  1477. ["draconian stormcaller"] = 0 ,["easy sensed monster"] = 0 ,["polar bear"] = 7 ,["demonspawn corrupter"] = 3 ,["Psyche"] = 0 ,["harpy"] = 2 ,["inugami"] = 5 ,["angel"] = 10 ,["quasit"] = 5 ,["Parghit"] = 1 ,["moth"] = 0 ,["eleionoma"] = 2 ,["spectral weapon"] = 5 ,["Zenata"] = 10 ,["sixfirhy"] = 2 ,["royal mummy"] = 10 ,["orc knight"] = 2 ,["blazeheart golem"] = 9 ,["merfolk avatar"] = 4 ,["vault guard"] = 1 ,["halfling"] = 2 ,["orb of fire"] = 20 ,["iron elemental"] = 20 ,["ancient lich"] = 20 ,["curse toe"] = 25 ,["demonspawn blood saint"] = 6 ,["tengu conjurer"] = 2 ,["boulder"] = 10 ,["orc sorcerer"] = 5 ,["Vv"] = 27 ,["purple draconian"] = 9 ,["guardian mummy"] = 6 ,["draconian monk"] = -3 ,["eidolon"] = 12 ,["sphinx"] = 5 ,["ynoxinul"] = 3 ,["fire bat"] = 1 ,["ironbound frostheart"] = 0 ,["death drake"] = 6 ,["shadow"] = 7 ,["stone giant"] = 12 ,["wight"] = 4 ,["bloated husk"] = 5 ,["ironbound preserver"] = 0 ,["wyvern"] = 5 ,["broodmother"] = 2 ,["frost giant"] = 9 ,["water nymph"] = 2 ,["hog"] = 2 ,["Mnoleg"] = 11 ,["Nessos"] = 4 ,["mummy"] = 3 ,["armataur"] = 15 ,["Agnes"] = 0 ,["sea snake"] = 2 ,["iron imp"] = 6 ,["golem"] = 0 ,["smoke demon"] = 5 ,["daeva"] = 10 ,["iron golem"] = 25 ,["Grum"] = 2 ,["Mennas"] = 15 ,["ghoul"] = 4 ,["formless jellyfish"] = 0 ,["animated tree"] = 0 ,["pillar of salt"] = 1 ,["lava snake"] = 2 ,["shadow demon"] = 7 ,["lightning spire"] = 13 ,["nasty sensed monster"] = 0 ,["merfolk javelineer"] = 0 ,["merfolk impaler"] = 0 ,["deep elf demonologist"] = 0 ,["sickly merfolk siren"] = 4 ,["sacred lotus"] = 24 ,["tyrant leech"] = 5 ,["phantasmal warrior"] = 12 ,
  1478. ["djinni"] = 5 ,["naga mage"] = 6 ,["Polyphemus"] = 10 ,["quokka"] = 2 ,["ball lightning"] = 0 ,["deathcap"] = 5 ,["snaplasher vine segment"] = 6 ,["Terence"] = 0 ,["fire dragon"] = 10 ,["hornet"] = 6 ,["wendigo"] = 4 ,["lich"] = 10 ,["briar patch"] = 10 ,["kobold demonologist"] = 2 ,["naga ritualist"] = 6 ,["fire giant"] = 8 ,["Ignacio"] = 10 ,["bennu"] = 6 ,["Crazy Yiuf"] = 2 ,["ufetubus"] = 2 ,["malarious merfolk avatar"] = 4 ,["giant"] = 0 ,["grey draconian"] = 16 ,["hell hog"] = 2 ,["living spell"] = 0 ,["shambling mangrove"] = 13 ,["sleepcap"] = 5 ,["bullfrog"] = 0 ,["death yak"] = 9 ,["player"] = 0 ,["Dissolution"] = 10 ,["the Lernaean hydra"] = 0 ,["ballistomycete"] = 1 ,["walking frostbound tome"] = 10 ,["elemental wellspring"] = 8 ,["Jory"] = 10 ,["deep elf annihilator"] = 0 ,["iron giant"] = 18 ,["spriggan"] = 1 ,["pale draconian"] = 9 ,["Joseph"] = 0 ,["the Serpent of Hell"] = 20 ,["ancient zyme"] = 6 ,["Chuck"] = 14 ,["nargun"] = 25 ,["ironbound convoker"] = 0 ,["kobold blastminer"] = 4 ,
  1479. ["peacekeeper"] = 20 ,["dragon"] = 0 ,["deep elf knight"] = 0 ,["small simulacrum"] = 10 ,["shock serpent"] = 2 ,["protean progenitor"] = 7 ,["Margery"] = 0 ,["animated armour"] = 8 ,["Lodul"] = 3 ,["snaplasher vine"] = 4 ,["mana viper"] = 3 ,["goblin"] = 0 ,["imperial myrmidon"] = 1 ,["tengu reaver"] = 2 ,["deep elf elementalist"] = 0 ,["worldbinder"] = 12 ,["orc warrior"] = 0 ,["Frederick"] = 0 ,["Jessica"] = 0 ,["elephant slug"] = 2 ,["moon troll"] = 20 ,["Pikel"] = 4 ,["starspawn tentacle segment"] = 8 ,["Azrael"] = 10 ,["draconian scorcher"] = -1 ,["Asmodeus"] = 30 ,["seraph"] = 10 ,["soul eater"] = 18 ,["great orb of eyes"] = 10 ,["crystal guardian"] = 20 ,["Khufu"] = 10 ,["salamander"] = 5 ,["golden eye"] = 0 ,["orange crystal statue"] = 12 ,["caustic shrike"] = 8 ,["two-headed ogre"] = 3 ,["rust devil"] = 10 ,["Maurice"] = 1 ,["Nellie"] = 13 ,["naga warrior"] = 6 ,["plant"] = 0 ,["floating eye"] = 0 ,["orc wizard"] = 1 ,["revenant"] = 8 ,["ice beast"] = 5 ,["death cob"] = 10 ,["holy swine"] = 2 ,["fenstrider witch"] = 3 ,["thrashing horror"] = 5 ,["meliai"] = 2 ,["drowned soul"] = 0 ,["demonspawn"] = 3 ,["glowing orange brain"] = 2 ,["war gargoyle"] = 25 ,["pearl dragon"] = 10 ,["spriggan berserker"] = 2 ,["spriggan druid"] = 1 ,["Prince Ribbit"] = 0 ,["vault sentinel"] = 1 ,["Cloud Mage"] = 0 ,["vine stalker"] = 2 ,["Kirke"] = 0 ,["green death"] = 5 ,["centaur warrior"] = 4 ,["basilisk"] = 3 ,["dancing weapon"] = 10 ,["tainted leviathan"] = 15 ,["draconian knight"] = 9 ,["orc warlord"] = 3 ,["raiju"] = 4 ,["diamond obelisk"] = 12 ,["warg"] = 9 ,["electric golem"] = 5 ,["Nergalle"] = 9 ,["fulminant prism"] = 3 ,["scrub nettle"] = 8 ,["martyred shade"] = 0 ,["ugly thing"] = 4 ,["demonspawn black sun"] = 9 ,["Vashnia"] = 6 ,["giant lizard"] = 0 ,["ice devil"] = 12 ,["orc priest"] = 1 ,["Saint Roka"] = 3 ,["storm dragon"] = 13 ,["eldritch tentacle"] = 13 ,["crystal echidna"] = 10 ,["burial acolyte"] = 0 ,["Robin"] = 1 ,["tormentor"] = 12 ,["Jorgrun"] = 2 ,["ironbound thunderhulk"] = 1 ,["glass eye"] = 2 ,["Fannar"] = 4 ,["toenail golem"] = 8 ,["block of ice"] = 15 ,["Hellbinder"] = 0 ,["red devil"] = 7 ,
  1480. ["ancestor"] = 5 ,["giant frog"] = 0 ,["Killer Klown"] = 10 ,["necromancer"] = 0 ,["meteoran"] = 2 ,["torpor snail"] = 8 ,["electric eel"] = 1 ,["juggernaut"] = 20 ,["hell beast"] = 5 ,["apocalypse crab"] = 11 ,["red draconian"] = 9 ,["tengu warrior"] = 2 ,["rat"] = 1 ,["guardian serpent"] = 6 ,["large zombie"] = 8 ,["Arachne"] = 3 ,["creeping inferno"] = 0 ,["spectator"] = 0 ,["slime creature"] = 1 ,["felid"] = 2 ,["merfolk aquamancer"] = 0 ,["demonic plant"] = 0 ,["doom hound"] = 6 ,["earth elemental"] = 14 ,["merfolk"] = 4 ,["iron dragon"] = 20 ,["Blork the orc"] = 0 ,["elephant"] = 8 ,["cacodemon"] = 11 ,["orc high priest"] = 1 ,["hell knight"] = 0 ,["lemure"] = 4 ,["gnoll sergeant"] = 2 ,["shadow dragon"] = 15 ,["Snorg"] = 0 ,["weeping skull"] = 7 ,["Xtahua"] = 18 ,["phantom"] = 3 ,["Ice Fiend"] = 15 ,["antique champion"] = 20 ,["Aizul"] = 8 ,["spellforged servitor"] = 10 ,["crimson imp"] = 3 ,["Ilsuiw"] = 5 ,["hexer"] = 5 ,["river rat"] = 5 ,["yellow draconian"] = 9 ,["titan"] = 10 ,["wolf spider"] = 3 ,["small skeleton"] = 0 ,["Orb Guardian"] = 13 ,["naga sharpshooter"] = 6 ,["vault warden"] = 1 ,
  1481. ["the Serpent of Hell"] = 16 ,["ball python"] = 0 ,["the Serpent of Hell"] = 30 ,["steam dragon"] = 5 ,["salamander tyrant"] = 5 ,["swamp worm"] = 3 ,["Frances"] = 0 ,["battlemage"] = 5 ,["death scarab"] = 7 ,["black bear"] = 2 ,["quicksilver ooze"] = 3 ,["arcanist"] = 0 ,["freezing wraith"] = 12 ,["test blob"] = 0 ,["yak"] = 4 ,["Jeremiah"] = 2 ,["deep elf pyromancer"] = 0 ,["jackal"] = 2 ,["spriggan rider"] = 1 ,["insubstantial wisp"] = 0 ,["necrophage"] = 2 ,["tentacled monstrosity"] = 5 ,["efreet"] = 10 ,["saltling"] = 15 ,["nameless horror"] = 8 ,["lost soul"] = 0 ,["octopode"] = 1 ,["Nikola"] = 1 ,["Edmund"] = 0 ,["ragged hierophant"] = 0 ,["strange machine"] = 12 ,["unseen horror"] = 5 ,["spriggan defender"] = 3 ,["shadow"] = 3 ,["dread lich"] = 20 ,["hound"] = 2 ,["nagaraja"] = 6 ,["Bai Suzhen"] = 14 ,["Brimstone Fiend"] = 15 ,["jiangshi"] = 10 ,["large skeleton"] = 0 ,["elemental"] = 0 ,["alligator snapping turtle"] = 19 ,["vampire mage"] = 10 ,["drake"] = 0 ,["catoblepas"] = 10 ,["tarantella"] = 3 ,["lindwurm"] = 8 ,["putrid mouth"] = 5 ,["Josephina"] = 10 ,["skeleton"] = 0 ,["swamp dragon"] = 7 ,
  1482. ["vampire mosquito"] = 2 ,["Mlioglotl"] = 10 ,["Donald"] = 3 ,["boulder beetle"] = 20 ,["vampire"] = 10 ,["troll"] = 3 ,["bush"] = 15 ,["ice statue"] = 12 ,["kobold"] = 2 ,["gnoll bouda"] = 2 ,["Geryon"] = 15 ,["eye of devastation"] = 12 ,["cerulean imp"] = 3 ,["cyclops"] = 5 ,["toadstool"] = 1 ,["ghost"] = 0 ,["vampire knight"] = 10 ,["simulacrum"] = 10 ,["kobold brigand"] = 3 ,["Menkaure"] = 3 ,["walking earthen tome"] = 20 ,["shapeshifter"] = 0 ,["bear"] = 0 ,["Ereshkigal"] = 10 ,["scorpion"] = 5 ,["blizzard demon"] = 10 ,["rakshasa"] = 6 ,["orb spider"] = 3 ,["spatial maelstrom"] = 0 ,["Pargi"] = 1 ,["Cerebov"] = 30 ,["black draconian"] = 9 ,["Hell Sentinel"] = 25 ,["Harold"] = 0 ,["neqoxec"] = 4 ,["draconian shifter"] = -1 ,["gnoll"] = 2 ,["statue"] = 12 ,["rockslime"] = 27 ,["wandering mushroom"] = 5 ,["friendly sensed monster"] = 0 ,["Antaeus"] = 28 ,["quicksilver elemental"] = 1 ,["battlesphere"] = 0 ,["Head Instructor"] = 0 ,["Grunn"] = 6 ,["salamander mystic"] = 5 ,["the Enchantress"] = 1 ,["Dispater"] = 35 ,["apis"] = 9 ,["hellephant"] = 13 ,["azure jelly"] = 5 ,["Erolcha"] = 3 ,["Asterion"] = 4 ,["zombie"] = 0 ,["cherub"] = 10 ,["program bug"] = 0 ,["lorocyproca"] = 10 ,["orc apostle"] = 2 ,
  1483. ["steelbarb worm"] = 11 ,["obsidian statue"] = 12 ,["test statue"] = 0 ,["deep dwarf"] = 2 ,["blazeheart core"] = 0 ,["cactus giant"] = 1 ,["walking crystal tome"] = 15 ,["shadow wraith"] = 7 ,["iguana"] = 5 ,["pharaoh ant"] = 4 ,["brain worm"] = 1 ,["redback"] = 2 ,["Dowan"] = 0 ,["anaconda"] = 4 ,["wraith"] = 10 ,["killer bee"] = 2 ,["merged slime creature"] = 0 ,["butterfly"] = 0 ,["endoplasm"] = 1 ,["moth of wrath"] = 0 ,["wind drake"] = 3 ,["crab"] = 0 ,["aspiring flesh"] = 2 ,["searing wretch"] = 4 ,["jorogumo"] = 4 ,["crocodile"] = 4 ,["starflower"] = 16 ,["barachi"] = 0 ,["ettin"] = 9 ,["ghost crab"] = 9 ,["profane servitor"] = 10 ,["shining eye"] = 3 ,["dryad"] = 6 ,["tough sensed monster"] = 0 ,["thorn hunter"] = 9 ,["demonic crawler"] = 10 ,["bog body"] = 1 ,["stoker"] = 5 ,["sensed monster"] = 0 ,["wretched star"] = 10 ,["deep troll"] = 6 ,["Eustachio"] = 0 ,["elf"] = 1 ,["vampire bat"] = 1 ,["cane toad"] = 6 ,["tengu"] = 2 ,["oklob plant"] = 10 ,["skeletal warrior"] = 15 ,["swamp drake"] = 3 ,["lurking horror"] = 0 ,["player ghost"] = 1 ,["iron troll"] = 20 ,["ushabti"] = 9 ,["Erica"] = 0 ,["howler monkey"] = 1 ,["blink frog"] = 0 ,["dart slug"] = 1 ,["spider"] = 0 ,["sun moth"] = 6 ,["ogre"] = 1 ,["knight"] = 5 ,["player illusion"] = 1 ,["Tzitzimitl"] = 12 ,["air elemental"] = 2 ,["walking tome"] = 0 ,["large abomination"] = 0 ,["deep elf archer"] = 0 ,["Boris"] = 12 ,["oklob sapling"] = 10}
  1484.  
  1485.  
  1486. }
  1487.  
  1488. ability_slot += berserk:B
  1489. ability_slot += potion petition:P
  1490.  
  1491. include +=HDamage.rc
  1492. include +=HDAForceMore.rc
  1493. include +=HDAColors.rc
  1494.  
  1495. ### General ###
  1496. explore_auto_rest = true
  1497.  
  1498. #autofight_throw = true
  1499. #autofight_throw_nomove = true
  1500. autofight_stop = 50
  1501. autopickup_starting_ammo = true
  1502. pickup_thrown = true
  1503. chunks_autopickup = true
  1504.  
  1505. explore_greedy = true
  1506. explore_wall_bias = 1
  1507.  
  1508.  
  1509. more := force_more_message
  1510.  
  1511. more += LOW HITPOINT
  1512. more += You feel like a meek peon again
  1513. more += You have got your breath back
  1514. more += Your skin stops crawling
  1515. more += Your transformation is almost over
  1516. more += calcifying dust hits you
  1517. more += crystal spear hits you
  1518. more += feel a terrible chill
  1519. more += is wielding .*distortion
  1520. more += is wielding .*electrocution
  1521. more += mighty Pandemonium lord
  1522. more += skill increases
  1523. more += skill increases to
  1524. more += strangely unstable
  1525. more += strikes you in flight
  1526. more += watched by something
  1527. more += wracked with pain
  1528. more += you are burned terribly
  1529. more += you convulse
  1530. more += you have finished your manual of
  1531. more += you have got your breath back
  1532. more += you have mastered
  1533.  
  1534.  
  1535.  
  1536.  
  1537. ### Inscriptions ###
  1538. ai := autoinscribe
  1539. ai += throwing net:!f
  1540. ai += potions? of mutation:!q
  1541. ai += potions? of degeneration:!q!q
  1542. ai += potions? of lignification:!q
  1543. ai += scrolls? of torment:!r
  1544. ai += scrolls? of vulnerability:!r
  1545. ai += scrolls? of silence:!r
  1546. ai += scrolls? of noise:!r!r
  1547. ai += scrolls? of summoning:!r
  1548. ai += staff of (conjuration|energy|wizardry|power):!a
  1549. ai += amulet of faith:!P
  1550.  
  1551.  
  1552.  
  1553.  
  1554.  
  1555.  
  1556.  
  1557.  
  1558.  
  1559.  
  1560.  
  1561.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement