SHARE
TWEET

Untitled

a guest Mar 24th, 2016 632 Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. diff --git a/lib/customize/pref.prf b/lib/customize/pref.prf
  2. index d6e32b2..0c6c082 100644
  3. --- a/lib/customize/pref.prf
  4. +++ b/lib/customize/pref.prf
  5. @@ -349,6 +349,9 @@ keymap-input:1:^C
  6.  # Message colors
  7.  %:message.prf
  8.  
  9. +# Message sounds
  10. +%:sound.prf
  11. +
  12.  ##### System Specific Subfiles #####
  13.  
  14.  ?:[EQU $SYS gcu]
  15. diff --git a/lib/customize/sound.prf b/lib/customize/sound.prf
  16. new file mode 100644
  17. index 0000000..3417bb3
  18. --- /dev/null
  19. +++ b/lib/customize/sound.prf
  20. @@ -0,0 +1,513 @@
  21. +# sound.cfg
  22. +#
  23. +# Configuration file for the Angband sound events
  24. +#
  25. +# The format is:
  26. +# <event name>:<sample-names seperated by spaces>
  27. +#
  28. +# Example:
  29. +# hit:hit hit1
  30. +#
  31. +
  32. +#
  33. +# This is the Dubtrain Angband Sound config list, v.3.1.0 - February 24th, 2009
  34. +#
  35. +# Licensed under a Creative Commons non-commercial agreement
  36. +#
  37. +# Inspired by the original Craig's Angband Sound Patch.
  38. +#
  39. +# But with all new sounds.
  40. +#
  41. +# contact angband@dubtrain.com
  42. +#
  43. +# download zipped archive at www.dubtrain.com/angband
  44. +#
  45. +#
  46. +
  47. +
  48. +#
  49. +# Ambient sounds
  50. +#
  51. +
  52. +# Town during the day.
  53. +sound:AMBIENT_DAY:amb_thunder_rain
  54. +
  55. +# Town during the night.
  56. +sound:AMBIENT_NITE:amb_guitar_chord amb_thunder_roll
  57. +
  58. +# Dungeon levels 1-20 (50'-1000')
  59. +sound:AMBIENT_DNG1:amb_door_iron amb_bell_metal1
  60. +
  61. +# Dungeon levels 21-40 (1050'-2000')
  62. +sound:AMBIENT_DNG2:amb_bell_tibet1 amb_bell_metal2 amb_gong_strike
  63. +
  64. +# Dungeon levels 41-60 (2050'-3000')
  65. +sound:AMBIENT_DNG3:amb_bell_tibet2 amb_dungeon_echo amb_pulse_low
  66. +
  67. +# Dungeon levels 61-80 (3050'-4000')
  68. +sound:AMBIENT_DNG4:amb_bell_tibet3 amb_dungeon_echowet amb_gong_undertone
  69. +
  70. +# Dungeon levels 81 and beyond (4050'-)
  71. +sound:AMBIENT_DNG5:amb_door_doom amb_gong_chinese amb_gong_low
  72. +
  73. +#
  74. +# Store sounds
  75. +#
  76. +
  77. +# The shopkeep bought a worthless item.
  78. +sound:STORE1:sto_man_hey
  79. +
  80. +# The shopkeep paid too much for an item.
  81. +sound:STORE2:id_bad_dang
  82. +
  83. +# The shopkeep got away with a good bargain.
  84. +sound:STORE3:sto_man_haha
  85. +
  86. +# The shopkeep got away with a great bargain.
  87. +sound:STORE4:sto_man_whoohaha
  88. +
  89. +# You make a normal transaction (buying or selling).
  90. +sound:STORE5:sto_coins_countertop sto_bell_register1 sto_bell_register2
  91. +
  92. +# You enter a store.
  93. +sound:STORE_ENTER:sto_bell_desk sto_bell_ding sto_bell_dingaling sto_bell_jingles sto_bell_ringing sto_bell_shop
  94. +
  95. +# You enter your home.
  96. +STORE_HOME:plm_door_entrance
  97. +
  98. +# You leave a store.
  99. +STORE_LEAVE:plm_door_bolt
  100. +
  101. +#
  102. +# Player sounds - combat
  103. +#
  104. +
  105. +# You succeed in a melee attack against a monster.
  106. +sound:HIT:plc_hit_hay plc_hit_body
  107. +
  108. +# It was a good hit!
  109. +MDG_HIT_GOOD:plc_hit_anvil
  110. +
  111. +# It was a great hit!
  112. +sound:HIT_GREAT:plc_hit_groan
  113. +
  114. +# It was a superb hit!
  115. +sound:HIT_SUPERB:plc_hit_grunt
  116. +
  117. +# It was a *GREAT* hit!
  118. +sound:HIT_HI_GREAT:plc_hit_grunt2
  119. +
  120. +# It was a *SUPERB* hit!
  121. +sound:HIT_HI_SUPERB:plc_hit_anvil2
  122. +
  123. +# You miss a melee attack against a monster.
  124. +sound:MISS:plc_miss_arrow2
  125. +
  126. +# You fire a missile.
  127. +sound:SHOOT:plc_miss_arrow
  128. +
  129. +# You hit something with a missile.
  130. +sound:SHOOT_HIT:plc_hit_arrow
  131. +
  132. +# You receive a hitpoint warning.
  133. +sound:HITPOINT_WARN:plc_bell_warn
  134. +
  135. +# You die.
  136. +sound:DEATH:plc_die_laugh
  137. +
  138. +#
  139. +# Player sounds - status changes
  140. +#
  141. +
  142. +# You become blind.
  143. +sound:BLIND:pls_tone_conk
  144. +
  145. +# You become confused.
  146. +sound:CONFUSED:pls_man_ugh
  147. +
  148. +# You become poisoned.
  149. +sound:POISONED:pls_tone_guiro
  150. +
  151. +# You become afraid.
  152. +sound:AFRAID:pls_man_yell
  153. +
  154. +# You become paralyzed.
  155. +sound:PARALYZED:pls_man_gulp_new
  156. +
  157. +# You feel drugged (chaos effects).
  158. +sound:DRUGGED:pls_breathe_in
  159. +
  160. +# You become slower.
  161. +sound:SLOW:pls_man_sigh
  162. +
  163. +# You become stunned.
  164. +sound:STUN:pls_bell_mute
  165. +
  166. +# You suffer a cut.
  167. +sound:CUT:pls_man_argoh
  168. +
  169. +# A stat is drained
  170. +sound:DRAIN_STAT:pls_tone_headstock
  171. +
  172. +# You recover from a condition (blind, confused, etc.)
  173. +sound:RECOVER:pls_bell_chime_new
  174. +
  175. +# You become faster.
  176. +sound:SPEED:pls_bell_sustain
  177. +
  178. +# You attain a mystic shield.
  179. +sound:SHIELD:pls_bell_bowl
  180. +
  181. +# You become blessed.
  182. +sound:BLESSED:sum_angel_song
  183. +
  184. +# You feel heroic.
  185. +sound:HERO:pls_tone_goblet
  186. +
  187. +# You are bold.
  188. +sound:BOLD:pls_bell_hibell_soft
  189. +
  190. +# You become berserk.
  191. +sound:BERSERK:pls_man_scream2
  192. +
  193. +# You feel protected from evil.
  194. +sound:PROT_EVIL:pls_bell_glass
  195. +
  196. +# You feel invulnerable. (does any item/spell do this anymore?)
  197. +sound:INVULN:pls_tone_blurk
  198. +
  199. +# You can see invisible things.
  200. +sound:SEE_INVIS:pls_tone_clave6
  201. +
  202. +# You can see the infrared spectrum
  203. +sound:INFRARED:pls_tone_clavelo8
  204. +
  205. +# You become resistant to acid.
  206. +sound:RES_ACID:pls_man_sniff
  207. +
  208. +# You become resistant to electricity.
  209. +sound:RES_ELEC:pls_tone_elec
  210. +
  211. +# You become resistant to fire.
  212. +sound:RES_FIRE:pls_tone_scrape
  213. +
  214. +# You become resistant to cold.
  215. +sound:RES_COLD:pls_tone_stick
  216. +
  217. +# You become resistant to poison.
  218. +sound:RES_POIS:pls_man_spit
  219. +
  220. +# You become hungry.
  221. +sound:HUNGRY:pls_man_sob
  222. +
  223. +#
  224. +# Player sounds - misc.
  225. +#
  226. +
  227. +# You pick up money worth less than 200 au.
  228. +sound:MONEY1:plm_coins_light plm_coins_shake
  229. +
  230. +# You pick up money worth between 200 and 600 au.
  231. +sound:MONEY2:plm_chain_light plm_coins_pour
  232. +
  233. +# You pick up money worth 600 au or more.
  234. +sound:MONEY3:plm_coins_dump
  235. +
  236. +# You (or a monster) drop something on the ground.
  237. +sound:DROP:plm_drop_boot
  238. +
  239. +# You gain (or regain) a level.
  240. +sound:LEVEL:plm_levelup
  241. +
  242. +# You successfully study a spell or prayer.
  243. +sound:STUDY:plm_book_pageturn
  244. +
  245. +# You teleport or phase door.
  246. +sound:TELEPORT:plm_chimes_jangle
  247. +
  248. +# You quaff a potion.
  249. +sound:QUAFF:plm_bottle_clinks plm_cork_pop plm_cork_squeak
  250. +
  251. +# You zap a rod.
  252. +sound:ZAP_ROD:plm_zap_rod
  253. +
  254. +# You take a step.  (unimplemented)
  255. +# walk:
  256. +
  257. +# You teleport someone else away.
  258. +sound:TPOTHER:plm_chimes_jangle
  259. +
  260. +# You bump into a wall or door.
  261. +sound:HITWALL:plm_wood_thud
  262. +
  263. +# You eat something.
  264. +sound:EAT:plm_eat_bite
  265. +
  266. +# You successfully dig through something.
  267. +sound:DIG:plm_metal_clank
  268. +
  269. +# You open a door.
  270. +sound:OPENDOOR:plm_door_bolt plm_door_creak plm_door_dungeon plm_door_entrance plm_door_open plm_door_opening plm_door_rusty plm_door_squeaky
  271. +
  272. +# You shut a door.
  273. +sound:SHUTDOOR:plm_bang_dumpster plm_cabinet_shut plm_close_hatch plm_door_creakshut plm_door_latch plm_door_shut plm_door_slam
  274. +
  275. +# You teleport from a level (including via recall).
  276. +sound:TPLEVEL:sum_bell_crystal
  277. +
  278. +# Default "bell" sound for system messages.
  279. +sound:BELL:plm_jar_ding
  280. +
  281. +# You try to open something that's not a door.
  282. +sound:NOTHING_TO_OPEN:plm_click_switch2 plm_door_knob
  283. +
  284. +# You fail to pick a lock.
  285. +sound:LOCKPICK_FAIL:plm_click_dry plm_click_switch plm_click_wood plm_door_echolock plm_door_wooden
  286. +
  287. +# You pick a lock.
  288. +sound:LOCKPICK:plm_break_wood plm_cabinet_open plm_chest_unlatch plm_lock_case plm_lock_distant plm_open_case
  289. +
  290. +# You disarm a trap.
  291. +sound:DISARM:plm_bang_ceramic plm_chest_latch plm_click_switch3
  292. +
  293. +# You go up stairs.
  294. +sound:STAIRS_UP:plm_floor_creak2
  295. +
  296. +# You go down stairs.
  297. +sound:STAIRS_DOWN:plm_floor_creak
  298. +
  299. +# You activate an artifact.
  300. +sound:ACT_ARTIFACT:plm_aim_wand
  301. +
  302. +# You use a staff.
  303. +sound:USE_STAFF:plm_use_staff
  304. +
  305. +# An object is destroyed.
  306. +sound:DESTROY:plm_bang_metal plm_break_canister plm_break_glass plm_break_glass2 plm_break_plates plm_break_shatter plm_break_smash plm_glass_breaking plm_glass_break plm_glass_smashing
  307. +
  308. +# You wield or take off something.
  309. +sound:WIELD:plm_metal_sharpen
  310. +
  311. +# You take something in or out of your quiver.
  312. +sound:QUIVER:plc_miss_swish
  313. +
  314. +# You wield a cursed item.
  315. +sound:CURSED:pls_man_oooh
  316. +
  317. +# You notice something (generic notice)
  318. +sound:NOTICE:id_bad_hmm
  319. +
  320. +# You notice something about your equipment or inventory.
  321. +sound:PSEUDOID:id_good_hmm
  322. +
  323. +# You successfully cast a spell.
  324. +sound:SPELL:plm_spell1 plm_spell2 plm_spell3
  325. +
  326. +# You successfully pray a prayer.
  327. +sound:PRAYER:sum_angel_song
  328. +
  329. +#
  330. +# Monster Sounds - combat
  331. +#
  332. +
  333. +# A monster flees in terror.
  334. +sound:FLEE:mco_creature_yelp
  335. +
  336. +# A monster is killed.
  337. +sound:KILL:mco_howl_croak mco_howl_deep mco_howl_distressed mco_howl_high mco_howl_long
  338. +
  339. +# A unique is killed.
  340. +sound:KILL_UNIQUE:sum_ghost_wail
  341. +
  342. +# Morgoth, Lord of Darkness is killed.
  343. +sound:KILL_KING:amb_guitar_chord
  344. +
  345. +# Attack - hit
  346. +sound:MON_HIT:mco_hit_whip
  347. +
  348. +# Attack - touch
  349. +sound:MON_TOUCH:mco_click_vibra
  350. +
  351. +# Attack - punch
  352. +sound:MON_PUNCH:mco_squish_snap
  353. +
  354. +# Attack - kick
  355. +sound:MON_KICK:mco_rubber_thud
  356. +
  357. +# Attack - claw
  358. +sound:MON_CLAW:mco_ceramic_trill mco_scurry_dry
  359. +
  360. +# Attack - bite
  361. +sound:MON_BITE:mco_snarl_short mco_bite_soft mco_bite_munch mco_bite_long mco_bite_short mco_bite_gnash mco_bite_chomp mco_bite_regular mco_bite_small mco_bite_dainty mco_bite_hard mco_bite_chew
  362. +
  363. +# Attack - sting
  364. +sound:MON_STING:mco_castanet_trill mco_tube_hit
  365. +
  366. +# Attack - butt
  367. +sound:MON_BUTT:mco_cuica_rubbing mco_thud_crash
  368. +
  369. +# Attack - crush
  370. +sound:MON_CRUSH:mco_dino_low mco_squish_hit
  371. +
  372. +# Attack - engulf
  373. +sound:MON_ENGULF:mco_dino_talk mco_dino_yawn
  374. +
  375. +# Attack - crawl
  376. +sound:MON_CRAWL:mco_card_shuffle mco_shake_roll
  377. +
  378. +# Attack - drool
  379. +sound:MON_DROOL:mco_creature_choking mco_liquid_squirt
  380. +
  381. +# Attack - spit
  382. +sound:MON_SPIT:mco_attack_spray
  383. +
  384. +# Attack - gaze
  385. +sound:MON_GAZE:mco_thoing_backwards
  386. +
  387. +# Attack - wail
  388. +sound:MON_WAIL:mco_dino_low
  389. +
  390. +# Attack - release spores
  391. +sound:MON_SPORE:mco_dub_wobble mco_spray_long
  392. +
  393. +# Attack - beg for money
  394. +sound:MON_BEG:mco_man_mumble
  395. +
  396. +# Attack - insult
  397. +sound:MON_INSULT:mco_strange_thwoink
  398. +
  399. +# Attack - moan
  400. +sound:MON_MOAN:mco_strange_music
  401. +
  402. +# Attack - shriek
  403. +sound:SHRIEK:mco_mouse_squeaks
  404. +
  405. +# Spell - create traps
  406. +sound:CREATE_TRAP:mco_thoing_deep
  407. +
  408. +# Spell - cause fear
  409. +sound:CAST_FEAR:mco_creature_groan mco_dino_slur
  410. +
  411. +# Multiply (breed explosively)
  412. +sound:MULTIPLY:mco_frog_trill
  413. +
  414. +#
  415. +# Summons
  416. +#
  417. +
  418. +# Summon one or more monsters.
  419. +sound:SUM_MONSTER:sum_chime_jangle
  420. +
  421. +# Summon angels.
  422. +sound:SUM_AINU:sum_angel_song
  423. +
  424. +# Summon undead.
  425. +sound:SUM_UNDEAD:sum_ghost_oooo
  426. +
  427. +# Summon animals.
  428. +sound:SUM_ANIMAL:sum_lion_growl
  429. +
  430. +# Summon spiders.
  431. +sound:SUM_SPIDER:sum_piano_scrape
  432. +
  433. +# Summon hounds.
  434. +sound:SUM_HOUND:sum_lion_growl
  435. +
  436. +# Summon hydras.
  437. +sound:SUM_HYDRA:sum_piano_scrape
  438. +
  439. +# Summon demons.
  440. +sound:SUM_DEMON:sum_ghost_wail sum_laugh_evil2
  441. +
  442. +# Summon dragon.
  443. +sound:SUM_DRAGON:sum_piano_scrape
  444. +
  445. +# Summon greater undead.
  446. +sound:SUM_HI_UNDEAD:sum_ghost_moan
  447. +
  448. +# Summon greater dragons.
  449. +sound:SUM_HI_DRAGON:sum_gong_temple
  450. +
  451. +# Summon greater demons.
  452. +sound:SUM_HI_DEMON:sum_ghost_moan
  453. +
  454. +# Summon Ringwraiths.
  455. +sound:SUM_WRAITH:sum_bell_hand
  456. +
  457. +# Summon uniques.
  458. +sound:SUM_UNIQUE:sum_bell_tone
  459. +
  460. +#
  461. +# Breath weapons
  462. +#
  463. +
  464. +# Breathe frost.
  465. +sound:BR_FROST:mco_attack_breath
  466. +
  467. +# Breathe electricity.
  468. +MST_BR_ELEC:mco_attack_breath
  469. +
  470. +# Breathe acid.
  471. +sound:BR_ACID:mco_attack_breath
  472. +
  473. +# Breathe gas.
  474. +sound:BR_GAS:mco_attack_breath
  475. +
  476. +# Breathe fire.
  477. +sound:BR_FIRE:mco_attack_breath
  478. +
  479. +# Breathe disenchantment.
  480. +sound:BR_DISEN:mco_attack_breath
  481. +
  482. +# Breathe chaos.
  483. +sound:BR_CHAOS:mco_attack_breath
  484. +
  485. +# Breathe shards.
  486. +sound:BR_SHARDS:mco_attack_breath
  487. +
  488. +# Breathe sound.
  489. +sound:BR_SOUND:mco_attack_breath
  490. +
  491. +# Breathe light.
  492. +sound:BR_LIGHT:mco_attack_breath
  493. +
  494. +# Breathe darkness.
  495. +sound:BR_DARK:mco_attack_breath
  496. +
  497. +# Breathe nether.
  498. +sound:BR_NETHER:mco_attack_breath
  499. +
  500. +# Breathe nexus.
  501. +sound:BR_NEXUS:mco_attack_breath
  502. +
  503. +# Breathe time.
  504. +sound:BR_TIME:mco_attack_breath
  505. +
  506. +# Breathe inertia.
  507. +sound:BR_INERTIA:mco_attack_breath
  508. +
  509. +# Breathe gravity.
  510. +sound:BR_GRAVITY:mco_attack_breath
  511. +
  512. +# Breathe plasma.
  513. +sound:BR_PLASMA:mco_attack_breath
  514. +
  515. +# Breathe force.
  516. +sound:BR_FORCE:mco_attack_breath
  517. +
  518. +# Breathe the elements (power dragon scale mail).
  519. +sound:BR_ELEMENTS:mco_attack_breath
  520. +
  521. +#
  522. +# Identifying Items
  523. +#
  524. +
  525. +# Identify a bad item (including bad ego items and artifacts).
  526. +sound:IDENT_BAD:id_bad_aww id_bad_dang id_bad_hmm id_bad_hmph id_bad_ohh
  527. +
  528. +# Identify a good ego item.
  529. +sound:IDENT_EGO:id_ego_whoa id_ego_woohoo id_ego_yeah id_ego_yeah2 id_ego_yes
  530. +
  531. +# Identify a good artifact.
  532. +sound:IDENT_ART:id_good_hey id_good_hey2 id_good_hmm id_good_huh id_good_ooh id_good_ooo id_good_wow
  533. +
  534. diff --git a/src/Makefile.src b/src/Makefile.src
  535. index 5d4a738..c4296f9 100644
  536. --- a/src/Makefile.src
  537. +++ b/src/Makefile.src
  538. @@ -158,6 +158,7 @@ ANGFILES = \
  539.     score.o \
  540.     save.o \
  541.     savefile.o \
  542. +   sound-core.o \
  543.     store.o \
  544.     target.o \
  545.     trap.o \
  546. diff --git a/src/avltree.h b/src/avltree.h
  547. new file mode 100644
  548. index 0000000..f3c5977
  549. --- /dev/null
  550. +++ b/src/avltree.h
  551. @@ -0,0 +1,212 @@
  552. +/* tree.h -- AVL trees (in the spirit of BSD's 'queue.h')  -*- C -*-   */
  553. +
  554. +/* Copyright (c) 2005 Ian Piumarta
  555. + *
  556. + * All rights reserved.
  557. + *
  558. + * Permission is hereby granted, free of charge, to any person obtaining a copy
  559. + * of this software and associated documentation files (the 'Software'), to deal
  560. + * in the Software without restriction, including without limitation the rights
  561. + * to use, copy, modify, merge, publish, distribute, and/or sell copies of the
  562. + * Software, and to permit persons to whom the Software is furnished to do so,
  563. + * provided that the above copyright notice(s) and this permission notice appear
  564. + * in all copies of the Software and that both the above copyright notice(s) and
  565. + * this permission notice appear in supporting documentation.
  566. + *
  567. + * THE SOFTWARE IS PROVIDED 'AS IS'.  USE ENTIRELY AT YOUR OWN RISK.
  568. + */
  569. +
  570. +/* This file defines an AVL balanced binary tree [Georgii M. Adelson-Velskii and
  571. + * Evgenii M. Landis, 'An algorithm for the organization of information',
  572. + * Doklady Akademii Nauk SSSR, 146:263-266, 1962 (Russian).  Also in Myron
  573. + * J. Ricci (trans.), Soviet Math, 3:1259-1263, 1962 (English)].
  574. + *
  575. + * An AVL tree is headed by pointers to the root node and to a function defining
  576. + * the ordering relation between nodes.  Each node contains an arbitrary payload
  577. + * plus three fields per tree entry: the depth of the subtree for which it forms
  578. + * the root and two pointers to child nodes (singly-linked for minimum space, at
  579. + * the expense of direct access to the parent node given a pointer to one of the
  580. + * children).  The tree is rebalanced after every insertion or removal.  The
  581. + * tree may be traversed in two directions: forward (in-order left-to-right) and
  582. + * reverse (in-order, right-to-left).
  583. + *
  584. + * Because of the recursive nature of many of the operations on trees it is
  585. + * necessary to define a number of helper functions for each type of tree node.
  586. + * The macro TREE_DEFINE(node_tag, entry_name) defines these functions with
  587. + * unique names according to the node_tag.  This macro should be invoked,
  588. + * thereby defining the necessary functions, once per node tag in the program.
  589. + *
  590. + * For details on the use of these macros, see the tree(3) manual page.
  591. + */
  592. +
  593. +#ifndef __tree_h
  594. +#define __tree_h
  595. +
  596. +
  597. +#define TREE_DELTA_MAX 1
  598. +
  599. +#define TREE_ENTRY(type)           \
  600. +  struct {                 \
  601. +    struct type    *avl_left;          \
  602. +    struct type    *avl_right;         \
  603. +    int         avl_height;            \
  604. +  }
  605. +
  606. +#define TREE_HEAD(name, type)              \
  607. +  struct name {                        \
  608. +    struct type *th_root;              \
  609. +    int  (*th_cmp)(struct type *lhs, struct type *rhs);    \
  610. +  }
  611. +
  612. +#define TREE_INITIALIZER(cmp) { 0, cmp }
  613. +
  614. +#define TREE_DELTA(self, field)                                \
  615. +  (( (((self)->field.avl_left)  ? (self)->field.avl_left->field.avl_height  : 0))  \
  616. +   - (((self)->field.avl_right) ? (self)->field.avl_right->field.avl_height : 0))
  617. +
  618. +/* Recursion prevents the following from being defined as macros. */
  619. +
  620. +#define TREE_DEFINE(node, field)                                   \
  621. +                                                   \
  622. +  struct node *TREE_BALANCE_##node##_##field(struct node *);                       \
  623. +                                                   \
  624. +  struct node *TREE_ROTL_##node##_##field(struct node *self)                       \
  625. +  {                                                    \
  626. +    struct node *r= self->field.avl_right;                             \
  627. +    self->field.avl_right= r->field.avl_left;                              \
  628. +    r->field.avl_left= TREE_BALANCE_##node##_##field(self);                        \
  629. +    return TREE_BALANCE_##node##_##field(r);                               \
  630. +  }                                                    \
  631. +                                                   \
  632. +  struct node *TREE_ROTR_##node##_##field(struct node *self)                       \
  633. +  {                                                    \
  634. +    struct node *l= self->field.avl_left;                              \
  635. +    self->field.avl_left= l->field.avl_right;                              \
  636. +    l->field.avl_right= TREE_BALANCE_##node##_##field(self);                       \
  637. +    return TREE_BALANCE_##node##_##field(l);                               \
  638. +  }                                                    \
  639. +                                                   \
  640. +  struct node *TREE_BALANCE_##node##_##field(struct node *self)                        \
  641. +  {                                                    \
  642. +    int delta= TREE_DELTA(self, field);                                    \
  643. +                                                   \
  644. +    if (delta < -TREE_DELTA_MAX)                                   \
  645. +      {                                                    \
  646. +   if (TREE_DELTA(self->field.avl_right, field) > 0)                       \
  647. +     self->field.avl_right= TREE_ROTR_##node##_##field(self->field.avl_right);         \
  648. +   return TREE_ROTL_##node##_##field(self);                            \
  649. +      }                                                    \
  650. +    else if (delta > TREE_DELTA_MAX)                                   \
  651. +      {                                                    \
  652. +   if (TREE_DELTA(self->field.avl_left, field) < 0)                        \
  653. +     self->field.avl_left= TREE_ROTL_##node##_##field(self->field.avl_left);           \
  654. +   return TREE_ROTR_##node##_##field(self);                            \
  655. +      }                                                    \
  656. +    self->field.avl_height= 0;                                     \
  657. +    if (self->field.avl_left && (self->field.avl_left->field.avl_height > self->field.avl_height)) \
  658. +      self->field.avl_height= self->field.avl_left->field.avl_height;                  \
  659. +    if (self->field.avl_right && (self->field.avl_right->field.avl_height > self->field.avl_height))   \
  660. +      self->field.avl_height= self->field.avl_right->field.avl_height;                 \
  661. +    self->field.avl_height += 1;                                   \
  662. +    return self;                                           \
  663. +  }                                                    \
  664. +                                                   \
  665. +  struct node *TREE_INSERT_##node##_##field                                \
  666. +    (struct node *self, struct node *elm, int (*compare)(struct node *lhs, struct node *rhs))      \
  667. +  {                                                    \
  668. +    if (!self)                                             \
  669. +      return elm;                                          \
  670. +    if (compare(elm, self) < 0)                                        \
  671. +      self->field.avl_left= TREE_INSERT_##node##_##field(self->field.avl_left, elm, compare);      \
  672. +    else                                               \
  673. +      self->field.avl_right= TREE_INSERT_##node##_##field(self->field.avl_right, elm, compare);        \
  674. +    return TREE_BALANCE_##node##_##field(self);                                \
  675. +  }                                                    \
  676. +                                                   \
  677. +  struct node *TREE_FIND_##node##_##field                              \
  678. +    (struct node *self, struct node *elm, int (*compare)(struct node *lhs, struct node *rhs))      \
  679. +  {                                                    \
  680. +    if (!self)                                             \
  681. +      return 0;                                                \
  682. +    if (compare(elm, self) == 0)                                   \
  683. +      return self;                                         \
  684. +    if (compare(elm, self) < 0)                                        \
  685. +      return TREE_FIND_##node##_##field(self->field.avl_left, elm, compare);               \
  686. +    else                                               \
  687. +      return TREE_FIND_##node##_##field(self->field.avl_right, elm, compare);              \
  688. +  }                                                    \
  689. +                                                   \
  690. +  struct node *TREE_MOVE_RIGHT_##node##_##field(struct node *self, struct node *rhs)                   \
  691. +  {                                                    \
  692. +    if (!self)                                             \
  693. +      return rhs;                                          \
  694. +    self->field.avl_right= TREE_MOVE_RIGHT_##node##_##field(self->field.avl_right, rhs);                   \
  695. +    return TREE_BALANCE_##node##_##field(self);                                \
  696. +  }                                                    \
  697. +                                                   \
  698. +  struct node *TREE_REMOVE_##node##_##field                                \
  699. +    (struct node *self, struct node *elm, int (*compare)(struct node *lhs, struct node *rhs))      \
  700. +  {                                                    \
  701. +    if (!self) return 0;                                       \
  702. +                                                   \
  703. +    if (compare(elm, self) == 0)                                   \
  704. +      {                                                    \
  705. +   struct node *tmp= TREE_MOVE_RIGHT_##node##_##field(self->field.avl_left, self->field.avl_right);            \
  706. +   self->field.avl_left= 0;                                    \
  707. +   self->field.avl_right= 0;                                   \
  708. +   return tmp;                                         \
  709. +      }                                                    \
  710. +    if (compare(elm, self) < 0)                                        \
  711. +      self->field.avl_left= TREE_REMOVE_##node##_##field(self->field.avl_left, elm, compare);      \
  712. +    else                                               \
  713. +      self->field.avl_right= TREE_REMOVE_##node##_##field(self->field.avl_right, elm, compare);        \
  714. +    return TREE_BALANCE_##node##_##field(self);                                \
  715. +  }                                                    \
  716. +                                                   \
  717. +  void TREE_FORWARD_APPLY_ALL_##node##_##field                             \
  718. +    (struct node *self, void (*function)(struct node *node, void *data), void *data)           \
  719. +  {                                                    \
  720. +    if (self)                                              \
  721. +      {                                                    \
  722. +   TREE_FORWARD_APPLY_ALL_##node##_##field(self->field.avl_left, function, data);          \
  723. +   function(self, data);                                       \
  724. +   TREE_FORWARD_APPLY_ALL_##node##_##field(self->field.avl_right, function, data);         \
  725. +      }                                                    \
  726. +  }                                                    \
  727. +                                                   \
  728. +  void TREE_REVERSE_APPLY_ALL_##node##_##field                             \
  729. +    (struct node *self, void (*function)(struct node *node, void *data), void *data)           \
  730. +  {                                                    \
  731. +    if (self)                                              \
  732. +      {                                                    \
  733. +   TREE_REVERSE_APPLY_ALL_##node##_##field(self->field.avl_right, function, data);         \
  734. +   function(self, data);                                       \
  735. +   TREE_REVERSE_APPLY_ALL_##node##_##field(self->field.avl_left, function, data);          \
  736. +      }                                                    \
  737. +  }
  738. +
  739. +#define TREE_INSERT(head, node, field, elm)                        \
  740. +  ((head)->th_root= TREE_INSERT_##node##_##field((head)->th_root, (elm), (head)->th_cmp))
  741. +
  742. +#define TREE_FIND(head, node, field, elm)              \
  743. +  (TREE_FIND_##node##_##field((head)->th_root, (elm), (head)->th_cmp))
  744. +
  745. +#define TREE_REMOVE(head, node, field, elm)                        \
  746. +  ((head)->th_root= TREE_REMOVE_##node##_##field((head)->th_root, (elm), (head)->th_cmp))
  747. +
  748. +#define TREE_DEPTH(head, field)            \
  749. +  ((head)->th_root->field.avl_height)
  750. +
  751. +#define TREE_FORWARD_APPLY(head, node, field, function, data)  \
  752. +  TREE_FORWARD_APPLY_ALL_##node##_##field((head)->th_root, function, data)
  753. +
  754. +#define TREE_REVERSE_APPLY(head, node, field, function, data)  \
  755. +  TREE_REVERSE_APPLY_ALL_##node##_##field((head)->th_root, function, data)
  756. +
  757. +#define TREE_INIT(head, cmp) do {      \
  758. +    (head)->th_root= 0;                \
  759. +    (head)->th_cmp= (cmp);         \
  760. +  } while (0)
  761. +
  762. +
  763. +#endif /* __tree_h */
  764. diff --git a/src/main.c b/src/main.c
  765. index 6717e0e..3392129 100644
  766. --- a/src/main.c
  767. +++ b/src/main.c
  768. @@ -43,6 +43,8 @@
  769.  
  770.  #include "main.h"
  771.  
  772. +#include "sound.h"
  773. +
  774.  /**
  775.   * List of the available modules in the order they are tried.
  776.   */
  777. @@ -69,22 +71,6 @@ static const struct module modules[] =
  778.  #endif /* USE_STATS */
  779.  };
  780.  
  781. -static int init_sound_dummy(int argc, char *argv[]) {
  782. -   return 0;
  783. -}
  784. -
  785. -/**
  786. - * List of sound modules in the order they should be tried.
  787. - */
  788. -static const struct module sound_modules[] =
  789. -{
  790. -#ifdef SOUND_SDL
  791. -   { "sdl", "SDL_mixer sound module", init_sound_sdl },
  792. -#endif /* SOUND_SDL */
  793. -
  794. -   { "none", "No sound", init_sound_dummy },
  795. -};
  796. -
  797.  /**
  798.   * A hook for "quit()".
  799.   *
  800. @@ -467,9 +453,7 @@ int main(int argc, char *argv[])
  801.                 }
  802.                 puts("                 Multiple -d options are allowed.");
  803.                 puts("  -s<mod>        Use sound module <sys>:");
  804. -               for (i = 0; i < (int)N_ELEMENTS(sound_modules); i++)
  805. -                   printf("     %s   %s\n", sound_modules[i].name,
  806. -                          sound_modules[i].help);
  807. +               print_sound_help();
  808.                 puts("  -m<sys>        Use module <sys>, where <sys> can be:");
  809.  
  810.                 /* Print the name and help for each available module */
  811. @@ -532,12 +516,6 @@ int main(int argc, char *argv[])
  812.  
  813.  #endif /* UNIX */
  814.  
  815. -   /* Try the modules in the order specified by sound_modules[] */
  816. -   for (i = 0; i < (int)N_ELEMENTS(sound_modules); i++)
  817. -       if (!soundstr || streq(soundstr, sound_modules[i].name))
  818. -           if (0 == sound_modules[i].init(argc, argv))
  819. -               break;
  820. -
  821.     /* Catch nasty signals */
  822.     signals_init();
  823.  
  824. @@ -549,6 +527,16 @@ int main(int argc, char *argv[])
  825.     init_angband();
  826.     textui_init();
  827.  
  828. +   /*
  829. +    * We needed to wait until the prefs files where loaded before we
  830. +    * initialise the sound sub-system because some fool moved the
  831. +    * sound config from a random 'config' file to a properly formatted
  832. +    * 'pref' file and stuck it in the 'customize' directory so it could
  833. +    * be chain-loaded from pref.prf
  834. +    */
  835. +   if (0 != init_sound(soundstr, argc, argv))
  836. +       plog("Failed to initialize sound!");    /* Non-fatal */
  837. +
  838.     /* Wait for response */
  839.     pause_line(Term);
  840.  
  841. diff --git a/src/main.h b/src/main.h
  842. index 70c11e0..39d442b 100644
  843. --- a/src/main.h
  844. +++ b/src/main.h
  845. @@ -23,9 +23,6 @@
  846.  #include "angband.h"
  847.  #include "ui-term.h"
  848.  
  849. -extern errr init_sound_sdl(int argc, char **argv);
  850. -
  851. -
  852.  extern errr init_lfb(int argc, char **argv);
  853.  extern errr init_x11(int argc, char **argv);
  854.  extern errr init_xpj(int argc, char **argv);
  855. diff --git a/src/message.h b/src/message.h
  856. index d08a8e6..1474fa3 100644
  857. --- a/src/message.h
  858. +++ b/src/message.h
  859. @@ -34,7 +34,7 @@ enum {
  860.  /* Functions */
  861.  void messages_init(void);
  862.  void messages_free(void);
  863. -u16b messages_num(void);  
  864. +u16b messages_num(void);
  865.  void message_add(const char *str, u16b type);
  866.  const char *message_str(u16b age);
  867.  u16b message_count(u16b age);
  868. diff --git a/src/snd-sdl.c b/src/snd-sdl.c
  869. index afce53f..75b0ca8 100644
  870. --- a/src/snd-sdl.c
  871. +++ b/src/snd-sdl.c
  872. @@ -19,86 +19,52 @@
  873.   */
  874.  #include "angband.h"
  875.  #include "init.h"
  876. -
  877. +#include "sound.h"
  878. +
  879.  #ifdef SOUND_SDL
  880.  
  881.  
  882.  #include "SDL.h"
  883.  #include "SDL_mixer.h"
  884.  
  885. -
  886. -/**
  887. - * Don't cache audio
  888. - */
  889. -static bool no_cache_audio = false;
  890. -
  891. -/**
  892. - * Using mp3s
  893. - */
  894. -static bool use_mp3 = false;
  895. -
  896. -/**
  897. - * Arbitary limit on number of samples per event
  898. - */
  899. -#define MAX_SAMPLES      16
  900. +typedef enum sdl_sample_type {
  901. +   SDL_CHUNK,
  902. +   SDL_MUSIC,
  903. +   SDL_NULL
  904. +} sdl_sample_type;
  905.  
  906.  /**
  907.   * Struct representing all data about an event sample
  908.   */
  909.  typedef struct
  910.  {
  911. -   int num;                        /* Number of samples for this event */
  912. -   Mix_Chunk *wavs[MAX_SAMPLES];   /* Sample array */
  913. -   Mix_Music *mp3s[MAX_SAMPLES];   /* Sample array */
  914. -   char *paths[MAX_SAMPLES]; /* Relative pathnames for samples */
  915. -} sample_list;
  916. -
  917. -
  918. -/**
  919. - * Just need an array of SampInfos
  920. - */
  921. -static sample_list samples[MSG_MAX];
  922. -
  923. -
  924. -/**
  925. - * Shut down the sound system and free resources.
  926. - */
  927. -static void close_audio(void)
  928. -{
  929. -   size_t i;
  930. -   int j;
  931. -
  932. -   /* Free all the sample data*/
  933. -   for (i = 0; i < MSG_MAX; i++) {
  934. -       sample_list *smp = &samples[i];
  935. -
  936. -       /* Nuke all samples */
  937. -       for (j = 0; j < smp->num; j++) {
  938. -           if (use_mp3)
  939. -               Mix_FreeMusic(smp->mp3s[j]);
  940. -           else
  941. -               Mix_FreeChunk(smp->wavs[j]);
  942. -           string_free(smp->paths[j]);
  943. -       }
  944. -   }
  945. -
  946. -   /* Close the audio */
  947. -   Mix_CloseAudio();
  948. -
  949. -   /* XXX This may conflict with the SDL port */
  950. -   SDL_Quit();
  951. -}
  952. -
  953. -
  954. +   union {
  955. +       Mix_Chunk *chunk;   /* Sample in WAVE format */
  956. +       Mix_Music *music;   /* Sample in MP3 format */
  957. +   };
  958. +
  959. +   sdl_sample_type sample_type;
  960. +   char *path;         /* Relative pathnames for samples */
  961. +} sdl_sample;
  962. +
  963. +typedef struct sdl_file_type {
  964. +   const char *extension;
  965. +   sdl_sample_type type;
  966. +} sdl_file_type_t;
  967. +
  968. +/* List of supported file types */
  969. +static const sdl_file_type_t supported_file_types[] = { {".mp3", SDL_MUSIC},
  970. +                           {".ogg", SDL_CHUNK},
  971. +                           {"", SDL_NULL} };
  972.  /**
  973.   * Initialise SDL and open the mixer
  974.   */
  975. -static bool open_audio(void)
  976. +static bool open_audio_sdl(int argc, char **argv)
  977.  {
  978.     int audio_rate;
  979.     Uint16 audio_format;
  980.     int audio_channels;
  981. -  
  982. +
  983.     /* Initialize variables */
  984.     audio_rate = 22050;
  985.     audio_format = AUDIO_S16;
  986. @@ -106,13 +72,13 @@ static bool open_audio(void)
  987.  
  988.     /* Initialize the SDL library */
  989.     if (SDL_Init(SDL_INIT_AUDIO) < 0) {
  990. -       plog_fmt("Couldn't initialize SDL: %s", SDL_GetError());
  991. +       plog_fmt("SDL: Couldn't initialize SDL: %s", SDL_GetError());
  992.         return false;
  993.     }
  994.  
  995.     /* Try to open the audio */
  996.     if (Mix_OpenAudio(audio_rate, audio_format, audio_channels, 4096) < 0) {
  997. -       plog_fmt("Couldn't open mixer: %s", SDL_GetError());
  998. +       plog_fmt("SDL: Couldn't open mixer: %s", SDL_GetError());
  999.         return false;
  1000.     }
  1001.  
  1002. @@ -120,228 +86,191 @@ static bool open_audio(void)
  1003.     return true;
  1004.  }
  1005.  
  1006. -
  1007. -
  1008. -/**
  1009. - * Read sound.cfg and map events to sounds; then load all the sounds into
  1010. - * memory to avoid I/O latency later.
  1011. - */
  1012. -static bool sound_sdl_init(bool no_cache)
  1013. +static bool load_sample_sdl(sdl_sample *sample)
  1014.  {
  1015. -   char path[2048];
  1016. -   char buffer[2048];
  1017. -   ang_file *fff;
  1018. +   switch (sample->sample_type) {
  1019. +       case SDL_CHUNK:
  1020. +           sample->chunk = Mix_LoadWAV(sample->path);
  1021. +
  1022. +           if (!sample->chunk) {
  1023. +               plog_fmt("SDL: Failed to load %s (%s: %s)", sample->path, SDL_GetError(), strerror(errno));
  1024. +           }
  1025. +           else {
  1026. +               plog_fmt("SDL: Successfully loaded %s", sample->path);
  1027. +               return true;
  1028. +           }
  1029.  
  1030. +           break;
  1031.  
  1032. -   /* Initialise the mixer  */
  1033. -   if (!open_audio())
  1034. -       return false;
  1035. +       case SDL_MUSIC:
  1036. +           sample->music = Mix_LoadMUS(sample->path);
  1037.  
  1038. +           if (!sample->music) {
  1039. +               plog_fmt("SDL: Failed to load %s (%s: %s)", sample->path, SDL_GetError(), strerror(errno));
  1040. +           } else {
  1041. +               plog_fmt("SDL: Successfully loaded %s", sample->path);
  1042. +               return true;
  1043. +           }
  1044.  
  1045. -   /* Find and open the config file */
  1046. -   path_build(path, sizeof(path), ANGBAND_DIR_SOUNDS, "sound.cfg");
  1047. -   fff = file_open(path, MODE_READ, -1);
  1048. +           break;
  1049.  
  1050. -   /* Handle errors */
  1051. -   if (!fff) {
  1052. -       plog_fmt("Failed to open sound config (%s):\n    %s",
  1053. -                 path, strerror(errno));
  1054. -       return false;
  1055. +       default:
  1056. +           plog_fmt("SDL: Oops - Unsupported file type");
  1057. +           break;
  1058.     }
  1059.  
  1060. -   /* Parse the file */
  1061. -   /* Lines are always of the form "name = sample [sample ...]" */
  1062. -   while (file_getl(fff, buffer, sizeof(buffer))) {
  1063. -       char *msg_name;
  1064. -       char *sample_list;
  1065. -       char *search;
  1066. -       char *cur_token;
  1067. -       char *next_token;
  1068. -       int event;
  1069. -
  1070. -       /* Skip anything not beginning with an alphabetic character */
  1071. -       if (!buffer[0] || !isalpha((unsigned char)buffer[0])) continue;
  1072. -
  1073. -       /* Split the line into two: message name, and the rest */
  1074. -       search = strchr(buffer, ' ');
  1075. -       sample_list = strchr(search + 1, ' ');
  1076. -       if (!search) continue;
  1077. -       if (!sample_list) continue;
  1078. -
  1079. -       /* Set the message name, and terminate at first space */
  1080. -       msg_name = buffer;
  1081. -       search[0] = '\0';
  1082. -
  1083. -
  1084. -       /* Make sure this is a valid event name */
  1085. -       event = message_lookup_by_sound_name(msg_name);
  1086. -       if (event < 0) continue;
  1087. -
  1088. -       /* Advance the sample list pointer so it's at the beginning of text */
  1089. -       sample_list++;
  1090. -       if (!sample_list[0]) continue;
  1091. -
  1092. -       /* Terminate the current token */
  1093. -       cur_token = sample_list;
  1094. -       search = strchr(cur_token, ' ');
  1095. -       if (search) {
  1096. -           search[0] = '\0';
  1097. -           next_token = search + 1;
  1098. -       } else {
  1099. -           next_token = NULL;
  1100. -       }
  1101. +   return false;
  1102. +}
  1103.  
  1104. -        /*
  1105. -         * Now we find all the sample names and add them one by one
  1106. -         */
  1107. -        while (cur_token) {
  1108. -           int num = samples[event].num;
  1109. -           bool got_file_type = false;
  1110. -
  1111. -           /* Don't allow too many samples */
  1112. -           if (num >= MAX_SAMPLES) break;
  1113. -
  1114. -           /* Build the path to the sample */
  1115. -           path_build(path, sizeof(path), ANGBAND_DIR_SOUNDS, cur_token);
  1116. -           if (!file_exists(path)) goto next_token;
  1117. -
  1118. -           if (!got_file_type) {
  1119. -                   if (streq(path + strlen(path) - 3, "mp3")) {
  1120. -                       use_mp3 = true;
  1121. -                   got_file_type = true;
  1122. -               }
  1123. -           }
  1124. +static bool load_sound_sdl(const char *sound_name, void *data)
  1125. +{
  1126. +   char path[2048];
  1127. +   char *filename_buf;
  1128. +   size_t filename_buf_size;
  1129. +   sdl_sample *sample = NULL;
  1130. +   int i = 0;
  1131. +   bool loaded = false;
  1132. +
  1133. +   /* Build the path to the sample */
  1134. +   path_build(path, sizeof(path), ANGBAND_DIR_SOUNDS, sound_name);
  1135. +
  1136. +   /*
  1137. +    * Create a buffer to store the filename plus three character
  1138. +    * extension (5 = '.' + 3 character extension + '\0'
  1139. +    */
  1140. +   filename_buf_size = strlen(path) + 5;
  1141. +   filename_buf = mem_alloc(filename_buf_size);
  1142. +
  1143. +   while ((SDL_NULL != supported_file_types[i].type) && (!loaded)) {
  1144. +       my_strcpy(filename_buf, path, filename_buf_size);
  1145. +       filename_buf = string_append(filename_buf,
  1146. +                        supported_file_types[i].extension);
  1147. +
  1148. +       if (file_exists(filename_buf)) {
  1149. +           if (!sample)
  1150. +               sample = mem_zalloc(sizeof(*sample));
  1151. +
  1152. +           if (sample) {
  1153. +               sample->sample_type = supported_file_types[i].type;
  1154. +               sample->path = string_make(filename_buf);
  1155. +
  1156. +               /* Try and load the sample file */
  1157. +               if (!load_sample_sdl(sample))
  1158. +                   mem_free(sample->path);
  1159. +               else
  1160. +                   loaded = true;
  1161.  
  1162. -           /* Don't load now if we're not caching */
  1163. -           if (no_cache) {
  1164. -               /* Just save the path for later */
  1165. -               samples[event].paths[num] = string_make(path);
  1166.             } else {
  1167. -               /* Load the file now */
  1168. -               if (use_mp3) {
  1169. -                   samples[event].mp3s[num] = Mix_LoadMUS(path);
  1170. -                   if (!samples[event].mp3s[num]) {
  1171. -                       plog_fmt("%s: %s", SDL_GetError(), strerror(errno));
  1172. -                       goto next_token;
  1173. -                   }
  1174. -               } else {
  1175. -                   samples[event].wavs[num] = Mix_LoadWAV(path);
  1176. -                   if (!samples[event].wavs[num]) {
  1177. -                           plog_fmt("%s: %s", SDL_GetError(), strerror(errno));
  1178. -                       goto next_token;
  1179. -                   }
  1180. -               }
  1181. -           }
  1182. -
  1183. -           /* Imcrement the sample count */
  1184. -           samples[event].num++;
  1185. -
  1186. -       next_token:
  1187. -
  1188. -           /* Figure out next token */
  1189. -           cur_token = next_token;
  1190. -           if (next_token) {
  1191. -               /* Try to find a space */
  1192. -               search = strchr(cur_token, ' ');
  1193. -
  1194. -               /* If we can find one, terminate, and set new "next" */
  1195. -               if (search) {
  1196. -                   search[0] = '\0';
  1197. -                   next_token = search + 1;
  1198. -               } else {
  1199. -                   /* Otherwise prevent infinite looping */
  1200. -                   next_token = NULL;
  1201. -               }
  1202. +               /* Out of memory */
  1203. +               mem_free(filename_buf);
  1204. +               data = NULL;
  1205. +               return false;
  1206.             }
  1207. +       } else {
  1208. +           i++;
  1209.         }
  1210.     }
  1211.  
  1212. -   /* Close the file */
  1213. -   file_close(fff);
  1214. +   mem_free(filename_buf);
  1215.  
  1216. +   if (!loaded) {
  1217. +       mem_free(sample);
  1218. +       sample = NULL;
  1219. +   }
  1220.  
  1221. -   /* Success */
  1222. -   return true;
  1223. +   data = (void *)sample;
  1224. +
  1225. +   return (NULL != sample);
  1226.  }
  1227.  
  1228.  /**
  1229.   * Play a sound of type "event".
  1230.   */
  1231. -static void play_sound(game_event_type type, game_event_data *data, void *user)
  1232. +static bool play_sound_sdl(void *data)
  1233.  {
  1234. -   Mix_Chunk *wave = NULL;
  1235. -   Mix_Music *mp3 = NULL;
  1236. -   int s;
  1237. -
  1238. -   int event = data->message.type;
  1239. -
  1240. -   /* Paranoia */
  1241. -   if (event < 0 || event >= MSG_MAX) return;
  1242. -
  1243. -   /* Check there are samples for this event */
  1244. -   if (!samples[event].num) return;
  1245. -
  1246. -   /* Choose a random event */
  1247. -   s = randint0(samples[event].num);
  1248. -   if (use_mp3)
  1249. -           mp3 = samples[event].mp3s[s];
  1250. -   else
  1251. -           wave = samples[event].wavs[s];
  1252. -
  1253. -   /* Try loading it, if it's not cached */
  1254. -   if (!(wave || mp3)) {
  1255. -       /* Verify it exists */
  1256. -       const char *filename = samples[event].paths[s];
  1257. -       if (!file_exists(filename)) return;
  1258. -
  1259. -       /* Load */
  1260. -       if (use_mp3)
  1261. -               mp3 = Mix_LoadMUS(filename);
  1262. -       else
  1263. -               wave = Mix_LoadWAV(filename);
  1264. +   sdl_sample *sample = (sdl_sample *)data;
  1265. +
  1266. +   if (sample) {
  1267. +       switch (sample->sample_type) {
  1268. +           case SDL_CHUNK:
  1269. +               if (sample->chunk)
  1270. +                   return (0 == Mix_PlayChannel(-1, sample->chunk, 0));
  1271. +               break;
  1272. +
  1273. +           case SDL_MUSIC:
  1274. +               if (sample->music)
  1275. +                   return (0 == Mix_PlayMusic(sample->music, 1));
  1276. +               break;
  1277. +
  1278. +           default:
  1279. +               break;
  1280. +       }
  1281.     }
  1282.  
  1283. -   /* Check to see if we have a sound again */
  1284. -   if (!(wave || mp3)) {
  1285. -       plog("SDL sound load failed.");
  1286. -       return;
  1287. +   return false;
  1288. +}
  1289. +
  1290. +static bool unload_sound_sdl(void *data)
  1291. +{
  1292. +   sdl_sample *sample = (sdl_sample *)data;
  1293. +
  1294. +   if (sample) {
  1295. +       switch (sample->sample_type) {
  1296. +           case SDL_CHUNK:
  1297. +               if (sample->chunk)
  1298. +                    Mix_FreeChunk(sample->chunk);
  1299. +
  1300. +               break;
  1301. +
  1302. +           case SDL_MUSIC:
  1303. +               if (sample->music)
  1304. +                   Mix_FreeMusic(sample->music);
  1305. +
  1306. +               break;
  1307. +
  1308. +           default:
  1309. +               break;
  1310. +       }
  1311. +
  1312. +       if (sample->path)
  1313. +           mem_free(sample->path);
  1314. +
  1315. +       mem_free(sample);
  1316.     }
  1317.  
  1318. -   /* Actually play the thing */
  1319. -   if (use_mp3)
  1320. -           Mix_PlayMusic(mp3, 1);
  1321. -   else
  1322. -           Mix_PlayChannel(-1, wave, 0);
  1323. +   return true;
  1324.  }
  1325.  
  1326. -
  1327.  /**
  1328. - * Init the SDL sound "module".
  1329. + * Shut down the sound system and free resources.
  1330.   */
  1331. -errr init_sound_sdl(int argc, char **argv)
  1332. +static bool close_audio_sdl(void)
  1333.  {
  1334. -   int i;
  1335. -
  1336. -   /* Parse args */
  1337. -   for (i = 1; i < argc; i++) {
  1338. -       if (prefix(argv[i], "-c")) {
  1339. -           no_cache_audio = true;
  1340. -           plog("Audio cache disabled.");
  1341. -           continue;
  1342. -       }
  1343. -   }
  1344. +   /*
  1345. +    * Close the audio.
  1346. +    *
  1347. +    * NOTE: All samples will have been free'd by the sound subsystem
  1348. +    * calling unload_sound_sdl() for every sample that was loaded.
  1349. +    */
  1350. +   Mix_CloseAudio();
  1351.  
  1352. -   /* Load sound preferences if requested */
  1353. -   if (!sound_sdl_init(no_cache_audio)) {
  1354. -       plog("Failed to load sound config");
  1355. +   /* XXX This may conflict with the SDL port */
  1356. +   SDL_Quit();
  1357.  
  1358. -       /* Failure */
  1359. -       return (1);
  1360. -   }
  1361. +   return true;
  1362. +}
  1363. +
  1364. +/**
  1365. + * Init the SDL sound "module".
  1366. + */
  1367. +errr init_sound_sdl(struct sound_hooks *hooks, int argc, char **argv)
  1368. +{
  1369. +   hooks->open_audio_hook = open_audio_sdl;
  1370. +   hooks->close_audio_hook = close_audio_sdl;
  1371.  
  1372. -   /* Enable sound */
  1373. -   event_add_handler(EVENT_SOUND, play_sound, NULL);
  1374. -   atexit(close_audio);
  1375. +   hooks->load_sound_hook = load_sound_sdl;
  1376. +   hooks->unload_sound_hook = unload_sound_sdl;
  1377. +   hooks->play_sound_hook = play_sound_sdl;
  1378.  
  1379.     /* Success */
  1380.     return (0);
  1381. diff --git a/src/sound-core.c b/src/sound-core.c
  1382. new file mode 100644
  1383. index 0000000..d43b8e5
  1384. --- /dev/null
  1385. +++ b/src/sound-core.c
  1386. @@ -0,0 +1,388 @@
  1387. +/**
  1388. + * \file sound-core.c
  1389. + * \brief core sound support
  1390. + *
  1391. + * Copyright (c) 2004 Brendon Oliver <brendon.oliver@gmail.com>
  1392. + * Copyright (c) 2007 Andi Sidwell <andi@takkaria.org>
  1393. + * A large chunk of this file was taken and modified from main-ros.
  1394. + *
  1395. + * This work is free software; you can redistribute it and/or modify it
  1396. + * under the terms of either:
  1397. + *
  1398. + * a) the GNU General Public License as published by the Free Software
  1399. + *    Foundation, version 2, or
  1400. + *
  1401. + * b) the "Angband licence":
  1402. + *    This software may be copied and distributed for educational, research,
  1403. + *    and not for profit purposes provided that this copyright and statement
  1404. + *    are included in all such copies.  Other copyrights may also apply.
  1405. + */
  1406. +#include "angband.h"
  1407. +#include "init.h"
  1408. +#include "sound.h"
  1409. +#include "avltree.h"
  1410. +#include "main.h"
  1411. +
  1412. +/**
  1413. + * SDL needs a look-in
  1414. + */
  1415. +#ifdef SOUND_SDL
  1416. +# include "SDL.h"
  1417. +
  1418. +/* HACK */
  1419. +errr init_sound_sdl(struct sound_hooks *hooks, int argc, char **argv);
  1420. +#endif
  1421. +
  1422. +static int init_sound_dummy(struct sound_hooks *hooks, int argc, char *argv[]) {
  1423. +   return 0;
  1424. +}
  1425. +
  1426. +/**
  1427. + * List of sound modules in the order they should be tried.
  1428. + */
  1429. +const struct sound_module sound_modules[] =
  1430. +{
  1431. +#ifdef SOUND_SDL
  1432. +   { "sdl", "SDL_mixer sound module", init_sound_sdl },
  1433. +#endif /* SOUND_SDL */
  1434. +
  1435. +   { "none", "No sound", init_sound_dummy },
  1436. +};
  1437. +
  1438. +/*
  1439. + * We will need two trees:
  1440. + * - A mapping of 'sound names' to 'sound ids' - this is only used during
  1441. + *   the initial parsing of the sound configuration file to ensure we don't
  1442. + *   load the same sounds multiple times (if a sound is mapped to more than
  1443. + *   one message)
  1444. + * - A mapping of 'message ids' to 'sound ids' - In the past, we have used a
  1445. + *   static array of size [MAX_MESSAGES][MAX_SOUND_PER_MESSAGE] which results
  1446. + *   in a horrendous waste of memory
  1447. + */
  1448. +
  1449. +
  1450. +/*****************************************************************************
  1451. + * Structures to map sound names to ids
  1452. + *****************************************************************************/
  1453. +typedef struct _sound_node sound_node;
  1454. +
  1455. +struct _sound_node
  1456. +{
  1457. +   char *sound_name;
  1458. +   u16b sound_id;
  1459. +
  1460. +   TREE_ENTRY(_sound_node) sound_tree;
  1461. +};
  1462. +
  1463. +static sound_node *sound_node_new(char *sound_name, u16b sound_id)
  1464. +{
  1465. +   sound_node *self = mem_alloc(sizeof *self);
  1466. +
  1467. +   self->sound_name = string_make(sound_name);
  1468. +   self->sound_id = sound_id;
  1469. +   return self;
  1470. +}
  1471. +
  1472. +static int sound_node_compare(sound_node *lhs, sound_node *rhs)
  1473. +{
  1474. +   return (int)strcmp(lhs->sound_name, rhs->sound_name);
  1475. +}
  1476. +
  1477. +typedef TREE_HEAD(_sound_tree, _sound_node) tree_sound;
  1478. +
  1479. +TREE_DEFINE(_sound_node, sound_tree)
  1480. +
  1481. +static tree_sound sounds = TREE_INITIALIZER(sound_node_compare);
  1482. +
  1483. +static u16b next_sound_id;
  1484. +/*****************************************************************************/
  1485. +
  1486. +/*****************************************************************************
  1487. + * Structures to map message ids to sound ids
  1488. + *****************************************************************************/
  1489. +typedef struct _msg_sound msg_sound;
  1490. +
  1491. +struct _msg_sound
  1492. +{
  1493. +   int sound_id;
  1494. +   msg_sound *next;
  1495. +};
  1496. +
  1497. +typedef struct _message_node message_node;
  1498. +
  1499. +struct _message_node
  1500. +{
  1501. +   u16b message_id;
  1502. +   int num_sounds;
  1503. +   msg_sound *first;
  1504. +
  1505. +   TREE_ENTRY(_message_node) message_tree;
  1506. +};
  1507. +
  1508. +static message_node *message_node_new(u16b message_id)
  1509. +{
  1510. +   message_node *self = mem_alloc(sizeof *self);
  1511. +
  1512. +   self->message_id = message_id;
  1513. +
  1514. +   return self;
  1515. +}
  1516. +
  1517. +static int message_node_compare(message_node *lhs, message_node *rhs)
  1518. +{
  1519. +   return (rhs->message_id - lhs->message_id);
  1520. +}
  1521. +
  1522. +typedef TREE_HEAD(_message_tree, _message_node) tree_message;
  1523. +
  1524. +TREE_DEFINE(_message_node, message_tree)
  1525. +
  1526. +static tree_message messages = TREE_INITIALIZER(message_node_compare);
  1527. +/*****************************************************************************/
  1528. +
  1529. +///*
  1530. +// * HACK: Structure to allow the platform's sound module to store platform
  1531. +// * specific data for each sound. Typically 'plat_data' will be a structure
  1532. +// * containing information such as the format of the sound (wav, mp3, ogg, etc)
  1533. +// * and the actual sound data. plat_data is created when we call
  1534. +// * load_sound_hook() and passed to unload_sound_hook() in order for the
  1535. +// * platform's sound module to safely de-allocate resources
  1536. +// */
  1537. +//typedef struct {
  1538. +// void *plat_data;
  1539. +//} sound_plat_data;
  1540. +
  1541. +/*
  1542. + * After processing the preference files, the 'sounds' AVL Tree will contain
  1543. + * next_sound_id nodes - each representing a sound that needs to be loaded.
  1544. + * We create the sound_data array once we know this information, and then
  1545. + * populate it by calling load_sound_hook() for each node in the tree
  1546. + */
  1547. +static void **sound_data;
  1548. +
  1549. +static struct sound_hooks hooks;
  1550. +
  1551. +void message_sound_define(u16b message_id, const char *sounds_str)
  1552. +{
  1553. +   char *search;
  1554. +   char *str;
  1555. +   char *cur_token;
  1556. +   char *next_token;
  1557. +
  1558. +   sound_node sound_search_node;
  1559. +   sound_node *existing_sound;
  1560. +   sound_node *new_sound;
  1561. +   u16b sound_id;
  1562. +
  1563. +   message_node message_search_node;
  1564. +   message_node *message_map;
  1565. +   msg_sound *new_message_sound;
  1566. +
  1567. +   str = cur_token = string_make(sounds_str);
  1568. +
  1569. +   search = strchr(cur_token, ' ');
  1570. +   if (search) {
  1571. +       search[0] = '\0';
  1572. +       next_token = search++;
  1573. +   } else {
  1574. +       next_token = NULL;
  1575. +   }
  1576. +
  1577. +   if (cur_token) {
  1578. +       /* Do we already have a message->sounds mapping? */
  1579. +       message_search_node.message_id = message_id;
  1580. +
  1581. +       message_map = TREE_FIND(&messages, _message_node, message_tree, &message_search_node);
  1582. +
  1583. +       if (!message_map) {
  1584. +           message_map = message_node_new(message_id);
  1585. +           TREE_INSERT(&messages, _message_node, message_tree, message_map);
  1586. +       }
  1587. +   }
  1588. +
  1589. +   /* Find all the sample names and add them one by one */
  1590. +   while (cur_token) {
  1591. +       /* Have we already processed this sound name? */
  1592. +       sound_search_node.sound_name = cur_token;
  1593. +
  1594. +       existing_sound = TREE_FIND(&sounds, _sound_node, sound_tree, &sound_search_node);
  1595. +
  1596. +       if (existing_sound) {
  1597. +           /* Yep - Just need to get the ID */
  1598. +           sound_id = existing_sound->sound_id;
  1599. +       } else {
  1600. +           /* Nope - Create a new node to store this sound's ID */
  1601. +           sound_id = next_sound_id;
  1602. +           new_sound = sound_node_new(cur_token, sound_id);
  1603. +           TREE_INSERT(&sounds, _sound_node, sound_tree, new_sound);
  1604. +
  1605. +           next_sound_id++;
  1606. +       }
  1607. +
  1608. +       /* Add this sound (by id) to the message->sounds map */
  1609. +       new_message_sound = mem_alloc(sizeof *new_message_sound);
  1610. +       new_message_sound->sound_id = sound_id;
  1611. +       new_message_sound->next = message_map->first;
  1612. +       message_map->first = new_message_sound;
  1613. +       message_map->num_sounds++;
  1614. +
  1615. +       /* Figure out next token */
  1616. +       cur_token = next_token;
  1617. +
  1618. +       if (next_token) {
  1619. +           /* Try to find a space */
  1620. +           search = strchr(cur_token, ' ');
  1621. +
  1622. +           /* If we can find one, terminate, and set new "next" */
  1623. +           if (search) {
  1624. +               search[0] = '\0';
  1625. +               next_token = search + 1;
  1626. +           } else {
  1627. +               /* Otherwise prevent infinite looping */
  1628. +               next_token = NULL;
  1629. +           }
  1630. +       }
  1631. +   }
  1632. +
  1633. +   string_free(str);
  1634. +}
  1635. +
  1636. +/**
  1637. + * Play a sound of type "event".
  1638. + */
  1639. +static void play_sound(game_event_type type, game_event_data *data, void *user)
  1640. +{
  1641. +   int s, i, sound_id;
  1642. +   message_node message_search_node;
  1643. +   message_node *message_map;
  1644. +   msg_sound *message_sound;
  1645. +
  1646. +   int event = data->message.type;
  1647. +
  1648. +   /* Paranoia */
  1649. +   assert(event >= 0);
  1650. +
  1651. +   message_search_node.message_id = (u16b)event;
  1652. +
  1653. +   message_map = TREE_FIND(&messages, _message_node, message_tree, &message_search_node);
  1654. +
  1655. +   if (!message_map)
  1656. +       return; /* No sounds for this message */
  1657. +
  1658. +
  1659. +   /* Choose a random event */
  1660. +   message_sound = message_map->first;
  1661. +
  1662. +   if (!message_sound)
  1663. +       return; /* Oops */
  1664. +
  1665. +   s = randint0(message_map->num_sounds);
  1666. +
  1667. +   /*
  1668. +    * Walk the list - possibly inefficient if you define LOTS of sounds
  1669. +    * for LOTS of messages. Not worth using a more 'efficient' data
  1670. +    * structure
  1671. +    */
  1672. +   for (i = 0; i < s; i++)
  1673. +       if (message_sound->next)
  1674. +           message_sound = message_sound->next;
  1675. +
  1676. +   sound_id = message_sound->sound_id;
  1677. +
  1678. +
  1679. +   assert((sound_id >= 0) && (sound_id < next_sound_id));
  1680. +
  1681. +   hooks.play_sound_hook(sound_data[sound_id]);
  1682. +}
  1683. +
  1684. +static void load_sound(sound_node *self, void *ignore)
  1685. +{
  1686. +   void *plat_data;
  1687. +
  1688. +   if (hooks.load_sound_hook) {
  1689. +       if(!hooks.load_sound_hook(self->sound_name, &plat_data))
  1690. +           plog_fmt("Failed to load sound: %s", self->sound_name);
  1691. +       else
  1692. +           sound_data[self->sound_id] = plat_data;
  1693. +   }
  1694. +}
  1695. +
  1696. +/*
  1697. + * Shut down the sound system and free resources.
  1698. + */
  1699. +static void close_audio(void)
  1700. +{
  1701. +   int i;
  1702. +
  1703. +   if (0 == next_sound_id)
  1704. +       return; /* Never opened */
  1705. +
  1706. +   /*
  1707. +    * Ask the platforms sound module to free resources for each
  1708. +    * sound
  1709. +    */
  1710. +   if (hooks.unload_sound_hook)
  1711. +       for (i = 0; i < next_sound_id; i++)
  1712. +           hooks.unload_sound_hook(sound_data[i]);
  1713. +
  1714. +   mem_free(sound_data);
  1715. +
  1716. +   /* TODO: Kill the trees */
  1717. +
  1718. +   /* Close the platform's sound module */
  1719. +   if (hooks.close_audio_hook)
  1720. +       hooks.close_audio_hook();
  1721. +}
  1722. +
  1723. +
  1724. +/**
  1725. + * Init the sound "module".
  1726. + */
  1727. +errr init_sound(const char *soundstr, int argc, char **argv)
  1728. +{
  1729. +   int i;
  1730. +   bool done;
  1731. +
  1732. +   /* Only initialise the sound sub-system if we have sounds to play */
  1733. +   if (0 == next_sound_id)
  1734. +       return 0;   /* It's not a fail if no sounds defined */
  1735. +
  1736. +   /* Try the modules in the order specified by sound_modules[] */
  1737. +   for (i = 0; i < (int)N_ELEMENTS(sound_modules); i++)
  1738. +       if (!soundstr || streq(soundstr, sound_modules[i].name))
  1739. +           if (0 == sound_modules[i].init(&hooks, argc, argv)) {
  1740. +               done = true;
  1741. +               break;
  1742. +           }
  1743. +
  1744. +   /* Check that we have a sound module to use */
  1745. +   if (!done)
  1746. +       return 1;
  1747. +
  1748. +   /* Open the platform specific sound system */
  1749. +   if (!hooks.open_audio_hook)
  1750. +       return 1;
  1751. +
  1752. +   if (!hooks.open_audio_hook(argc, argv))
  1753. +       return 1;
  1754. +
  1755. +   sound_data = mem_zalloc(sizeof(void *) * next_sound_id);
  1756. +
  1757. +   TREE_FORWARD_APPLY(&sounds, _sound_node, sound_tree, load_sound, NULL);
  1758. +
  1759. +   /* Enable sound */
  1760. +   event_add_handler(EVENT_SOUND, play_sound, NULL);
  1761. +   atexit(close_audio);
  1762. +
  1763. +   /* Success */
  1764. +   return (0);
  1765. +}
  1766. +
  1767. +void print_sound_help(void)
  1768. +{
  1769. +   int i;
  1770. +
  1771. +   for (i = 0; i < (int)N_ELEMENTS(sound_modules); i++)
  1772. +       printf("     %s   %s\n", sound_modules[i].name,
  1773. +              sound_modules[i].help);
  1774. +}
  1775. diff --git a/src/sound.h b/src/sound.h
  1776. new file mode 100644
  1777. index 0000000..4b73c4d
  1778. --- /dev/null
  1779. +++ b/src/sound.h
  1780. @@ -0,0 +1,45 @@
  1781. +/**
  1782. + * \file sound.h
  1783. + * \brief Sound handling
  1784. + *
  1785. + * Copyright (c) 2016 Graeme Russ
  1786. + *
  1787. + * Redistribution and use in source and binary forms, with or without
  1788. + * modification, are permitted provided that the following conditions are met:
  1789. + *
  1790. + *  * Redistributions of source code must retain the above copyright notice,
  1791. + *    this list of conditions and the following disclaimer.
  1792. + *
  1793. + *  * Redistributions in binary form must reproduce the above copyright notice,
  1794. + *    this list of conditions and the following disclaimer in the documentation
  1795. + *    and/or other materials provided with the distribution.
  1796. + */
  1797. +
  1798. +#ifndef INCLUDED_Z_SOUND_H
  1799. +#define INCLUDED_Z_SOUND_H
  1800. +
  1801. +struct sound_hooks
  1802. +{
  1803. +   bool (*open_audio_hook)(int argc, char **argv);
  1804. +   bool (*close_audio_hook)(void);
  1805. +
  1806. +   /* 'data' is a sound module specific struct */
  1807. +   bool (*load_sound_hook)(const char *sound_name, void *data);
  1808. +   bool (*unload_sound_hook)(void *data);
  1809. +   bool (*play_sound_hook)(void *data);
  1810. +};
  1811. +
  1812. +struct sound_module
  1813. +{
  1814. +   const char *name;
  1815. +   const char *help;
  1816. +   errr (*init)(struct sound_hooks *hooks, int argc, char **argv);
  1817. +};
  1818. +
  1819. +errr init_sound(const char *soundstr, int argc, char **argv);
  1820. +
  1821. +void message_sound_define(u16b type, const char *sounds);
  1822. +
  1823. +void print_sound_help(void);
  1824. +
  1825. +#endif /* !INCLUDED_Z_SOUND_H */
  1826. diff --git a/src/ui-prefs.c b/src/ui-prefs.c
  1827. index cff07cf..e32ba72 100644
  1828. --- a/src/ui-prefs.c
  1829. +++ b/src/ui-prefs.c
  1830. @@ -34,6 +34,7 @@
  1831.  #include "ui-keymap.h"
  1832.  #include "ui-prefs.h"
  1833.  #include "ui-term.h"
  1834. +#include "sound.h"
  1835.  
  1836.  int arg_graphics;          /* Command arg -- Request graphics mode */
  1837.  bool arg_graphics_nice;        /* Command arg -- Request nice graphics mode */
  1838. @@ -1047,6 +1048,29 @@ static enum parser_error parse_prefs_window(struct parser *p)
  1839.     return PARSE_ERROR_NONE;
  1840.  }
  1841.  
  1842. +static enum parser_error parse_prefs_sound(struct parser *p)
  1843. +{
  1844. +   int msg_index;
  1845. +   const char *type;
  1846. +   const char *sounds;
  1847. +
  1848. +   struct prefs_data *d = parser_priv(p);
  1849. +   assert(d != NULL);
  1850. +   if (d->bypass) return PARSE_ERROR_NONE;
  1851. +
  1852. +   type = parser_getsym(p, "type");
  1853. +   sounds = parser_getstr(p, "sounds");
  1854. +
  1855. +   msg_index = message_lookup_by_name(type);
  1856. +
  1857. +   if (msg_index < 0)
  1858. +       return PARSE_ERROR_INVALID_MESSAGE;
  1859. +
  1860. +   message_sound_define(msg_index, sounds);
  1861. +
  1862. +   return PARSE_ERROR_NONE;
  1863. +}
  1864. +
  1865.  static struct parser *init_parse_prefs(bool user)
  1866.  {
  1867.     struct parser *p = parser_new();
  1868. @@ -1074,6 +1098,7 @@ static struct parser *init_parse_prefs(bool user)
  1869.     parser_reg(p, "message sym type sym attr", parse_prefs_message);
  1870.     parser_reg(p, "color uint idx int k int r int g int b", parse_prefs_color);
  1871.     parser_reg(p, "window int window uint flag uint value", parse_prefs_window);
  1872. +   parser_reg(p, "sound sym type str sounds", parse_prefs_sound);
  1873.  
  1874.     return p;
  1875.  }
RAW Paste Data
We use cookies for various purposes including analytics. By continuing to use Pastebin, you agree to our use of cookies as described in the Cookies Policy. OK, I Understand
 
Top