Guest User

Untitled

a guest
Mar 24th, 2016
647
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