Guest User

Untitled

a guest
Mar 24th, 2016
113
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..3595a03
  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. +sound:STORE_HOME:plm_door_entrance
  97. +
  98. +# You leave a store.
  99. +sound: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. +sound: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..948a852 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,10 @@ int main(int argc, char *argv[])
  825. init_angband();
  826. textui_init();
  827.  
  828. + /* Initialise sound */
  829. + if (0 != init_sound(soundstr, argc, argv))
  830. + plog("Failed to initialize sound!"); /* Non-fatal */
  831. +
  832. /* Wait for response */
  833. pause_line(Term);
  834.  
  835. diff --git a/src/main.h b/src/main.h
  836. index 70c11e0..39d442b 100644
  837. --- a/src/main.h
  838. +++ b/src/main.h
  839. @@ -23,9 +23,6 @@
  840. #include "angband.h"
  841. #include "ui-term.h"
  842.  
  843. -extern errr init_sound_sdl(int argc, char **argv);
  844. -
  845. -
  846. extern errr init_lfb(int argc, char **argv);
  847. extern errr init_x11(int argc, char **argv);
  848. extern errr init_xpj(int argc, char **argv);
  849. diff --git a/src/message.h b/src/message.h
  850. index d08a8e6..1474fa3 100644
  851. --- a/src/message.h
  852. +++ b/src/message.h
  853. @@ -34,7 +34,7 @@ enum {
  854. /* Functions */
  855. void messages_init(void);
  856. void messages_free(void);
  857. -u16b messages_num(void);
  858. +u16b messages_num(void);
  859. void message_add(const char *str, u16b type);
  860. const char *message_str(u16b age);
  861. u16b message_count(u16b age);
  862. diff --git a/src/snd-sdl.c b/src/snd-sdl.c
  863. index afce53f..de9c04d 100644
  864. --- a/src/snd-sdl.c
  865. +++ b/src/snd-sdl.c
  866. @@ -4,6 +4,7 @@
  867. *
  868. * Copyright (c) 2004 Brendon Oliver <brendon.oliver@gmail.com>
  869. * Copyright (c) 2007 Andi Sidwell <andi@takkaria.org>
  870. + * Copyright (c) 2016 Graeme Russ <graeme.russ@gmail.com>
  871. * A large chunk of this file was taken and modified from main-ros.
  872. *
  873. * This work is free software; you can redistribute it and/or modify it
  874. @@ -19,86 +20,52 @@
  875. */
  876. #include "angband.h"
  877. #include "init.h"
  878. -
  879. +#include "sound.h"
  880. +
  881. #ifdef SOUND_SDL
  882.  
  883.  
  884. #include "SDL.h"
  885. #include "SDL_mixer.h"
  886.  
  887. -
  888. -/**
  889. - * Don't cache audio
  890. - */
  891. -static bool no_cache_audio = false;
  892. -
  893. -/**
  894. - * Using mp3s
  895. - */
  896. -static bool use_mp3 = false;
  897. -
  898. -/**
  899. - * Arbitary limit on number of samples per event
  900. - */
  901. -#define MAX_SAMPLES 16
  902. +typedef enum sdl_sample_type {
  903. + SDL_CHUNK,
  904. + SDL_MUSIC,
  905. + SDL_NULL
  906. +} sdl_sample_type;
  907.  
  908. /**
  909. * Struct representing all data about an event sample
  910. */
  911. typedef struct
  912. {
  913. - int num; /* Number of samples for this event */
  914. - Mix_Chunk *wavs[MAX_SAMPLES]; /* Sample array */
  915. - Mix_Music *mp3s[MAX_SAMPLES]; /* Sample array */
  916. - char *paths[MAX_SAMPLES]; /* Relative pathnames for samples */
  917. -} sample_list;
  918. -
  919. -
  920. -/**
  921. - * Just need an array of SampInfos
  922. - */
  923. -static sample_list samples[MSG_MAX];
  924. -
  925. -
  926. -/**
  927. - * Shut down the sound system and free resources.
  928. - */
  929. -static void close_audio(void)
  930. -{
  931. - size_t i;
  932. - int j;
  933. -
  934. - /* Free all the sample data*/
  935. - for (i = 0; i < MSG_MAX; i++) {
  936. - sample_list *smp = &samples[i];
  937. -
  938. - /* Nuke all samples */
  939. - for (j = 0; j < smp->num; j++) {
  940. - if (use_mp3)
  941. - Mix_FreeMusic(smp->mp3s[j]);
  942. - else
  943. - Mix_FreeChunk(smp->wavs[j]);
  944. - string_free(smp->paths[j]);
  945. - }
  946. - }
  947. -
  948. - /* Close the audio */
  949. - Mix_CloseAudio();
  950. -
  951. - /* XXX This may conflict with the SDL port */
  952. - SDL_Quit();
  953. -}
  954. -
  955. -
  956. + union {
  957. + Mix_Chunk *chunk; /* Sample in WAVE format */
  958. + Mix_Music *music; /* Sample in MP3 format */
  959. + } sample_data;
  960. +
  961. + sdl_sample_type sample_type;
  962. + char *path; /* Relative pathnames for samples */
  963. +} sdl_sample;
  964. +
  965. +typedef struct sdl_file_type {
  966. + const char *extension;
  967. + sdl_sample_type type;
  968. +} sdl_file_type_t;
  969. +
  970. +/* List of supported file types */
  971. +static const sdl_file_type_t supported_file_types[] = { {".mp3", SDL_MUSIC},
  972. + {".ogg", SDL_CHUNK},
  973. + {"", SDL_NULL} };
  974. /**
  975. - * Initialise SDL and open the mixer
  976. + * Initialise SDL and open the mixer.
  977. */
  978. -static bool open_audio(void)
  979. +static bool open_audio_sdl(int argc, char **argv)
  980. {
  981. int audio_rate;
  982. Uint16 audio_format;
  983. int audio_channels;
  984. -
  985. +
  986. /* Initialize variables */
  987. audio_rate = 22050;
  988. audio_format = AUDIO_S16;
  989. @@ -106,13 +73,13 @@ static bool open_audio(void)
  990.  
  991. /* Initialize the SDL library */
  992. if (SDL_Init(SDL_INIT_AUDIO) < 0) {
  993. - plog_fmt("Couldn't initialize SDL: %s", SDL_GetError());
  994. + plog_fmt("SDL: Couldn't initialize SDL: %s", SDL_GetError());
  995. return false;
  996. }
  997.  
  998. /* Try to open the audio */
  999. if (Mix_OpenAudio(audio_rate, audio_format, audio_channels, 4096) < 0) {
  1000. - plog_fmt("Couldn't open mixer: %s", SDL_GetError());
  1001. + plog_fmt("SDL: Couldn't open mixer: %s", SDL_GetError());
  1002. return false;
  1003. }
  1004.  
  1005. @@ -120,228 +87,192 @@ static bool open_audio(void)
  1006. return true;
  1007. }
  1008.  
  1009. -
  1010. -
  1011. /**
  1012. - * Read sound.cfg and map events to sounds; then load all the sounds into
  1013. - * memory to avoid I/O latency later.
  1014. + * Load a sound from file.
  1015. */
  1016. -static bool sound_sdl_init(bool no_cache)
  1017. +static bool load_sample_sdl(sdl_sample *sample)
  1018. {
  1019. - char path[2048];
  1020. - char buffer[2048];
  1021. - ang_file *fff;
  1022. + switch (sample->sample_type) {
  1023. + case SDL_CHUNK:
  1024. + sample->sample_data.chunk = Mix_LoadWAV(sample->path);
  1025.  
  1026. + if (sample->sample_data.chunk)
  1027. + return true;
  1028.  
  1029. - /* Initialise the mixer */
  1030. - if (!open_audio())
  1031. - return false;
  1032. + break;
  1033.  
  1034. + case SDL_MUSIC:
  1035. + sample->sample_data.music = Mix_LoadMUS(sample->path);
  1036.  
  1037. - /* Find and open the config file */
  1038. - path_build(path, sizeof(path), ANGBAND_DIR_SOUNDS, "sound.cfg");
  1039. - fff = file_open(path, MODE_READ, -1);
  1040. + if (sample->sample_data.music)
  1041. + return true;
  1042.  
  1043. - /* Handle errors */
  1044. - if (!fff) {
  1045. - plog_fmt("Failed to open sound config (%s):\n %s",
  1046. - path, strerror(errno));
  1047. - return false;
  1048. + break;
  1049. +
  1050. + default:
  1051. + plog_fmt("SDL: Oops - Unsupported file type");
  1052. + break;
  1053. }
  1054.  
  1055. - /* Parse the file */
  1056. - /* Lines are always of the form "name = sample [sample ...]" */
  1057. - while (file_getl(fff, buffer, sizeof(buffer))) {
  1058. - char *msg_name;
  1059. - char *sample_list;
  1060. - char *search;
  1061. - char *cur_token;
  1062. - char *next_token;
  1063. - int event;
  1064. -
  1065. - /* Skip anything not beginning with an alphabetic character */
  1066. - if (!buffer[0] || !isalpha((unsigned char)buffer[0])) continue;
  1067. -
  1068. - /* Split the line into two: message name, and the rest */
  1069. - search = strchr(buffer, ' ');
  1070. - sample_list = strchr(search + 1, ' ');
  1071. - if (!search) continue;
  1072. - if (!sample_list) continue;
  1073. -
  1074. - /* Set the message name, and terminate at first space */
  1075. - msg_name = buffer;
  1076. - search[0] = '\0';
  1077. -
  1078. -
  1079. - /* Make sure this is a valid event name */
  1080. - event = message_lookup_by_sound_name(msg_name);
  1081. - if (event < 0) continue;
  1082. -
  1083. - /* Advance the sample list pointer so it's at the beginning of text */
  1084. - sample_list++;
  1085. - if (!sample_list[0]) continue;
  1086. -
  1087. - /* Terminate the current token */
  1088. - cur_token = sample_list;
  1089. - search = strchr(cur_token, ' ');
  1090. - if (search) {
  1091. - search[0] = '\0';
  1092. - next_token = search + 1;
  1093. - } else {
  1094. - next_token = NULL;
  1095. - }
  1096. + return false;
  1097. +}
  1098.  
  1099. - /*
  1100. - * Now we find all the sample names and add them one by one
  1101. - */
  1102. - while (cur_token) {
  1103. - int num = samples[event].num;
  1104. - bool got_file_type = false;
  1105. -
  1106. - /* Don't allow too many samples */
  1107. - if (num >= MAX_SAMPLES) break;
  1108. -
  1109. - /* Build the path to the sample */
  1110. - path_build(path, sizeof(path), ANGBAND_DIR_SOUNDS, cur_token);
  1111. - if (!file_exists(path)) goto next_token;
  1112. -
  1113. - if (!got_file_type) {
  1114. - if (streq(path + strlen(path) - 3, "mp3")) {
  1115. - use_mp3 = true;
  1116. - got_file_type = true;
  1117. - }
  1118. - }
  1119. +/**
  1120. + * Load a sound and return a pointer to the associated SDL Sound data
  1121. + * structure back to the core sound module.
  1122. + */
  1123. +static bool load_sound_sdl(const char *sound_name, void **data)
  1124. +{
  1125. + char path[2048];
  1126. + char *filename_buf;
  1127. + size_t filename_buf_size;
  1128. + sdl_sample *sample = NULL;
  1129. + int i = 0;
  1130. + bool loaded = false;
  1131. +
  1132. + /* Build the path to the sample */
  1133. + path_build(path, sizeof(path), ANGBAND_DIR_SOUNDS, sound_name);
  1134. +
  1135. + /*
  1136. + * Create a buffer to store the filename plus three character
  1137. + * extension (5 = '.' + 3 character extension + '\0'
  1138. + */
  1139. + filename_buf_size = strlen(path) + 5;
  1140. + filename_buf = mem_zalloc(filename_buf_size);
  1141. +
  1142. + while ((SDL_NULL != supported_file_types[i].type) && (!loaded)) {
  1143. + my_strcpy(filename_buf, path, filename_buf_size);
  1144. + filename_buf = string_append(filename_buf,
  1145. + supported_file_types[i].extension);
  1146. +
  1147. + if (file_exists(filename_buf)) {
  1148. + if (!sample)
  1149. + sample = mem_zalloc(sizeof(*sample));
  1150. +
  1151. + if (sample) {
  1152. + sample->sample_type = supported_file_types[i].type;
  1153. + sample->path = string_make(filename_buf);
  1154. +
  1155. + /* Try and load the sample file */
  1156. + if (!load_sample_sdl(sample))
  1157. + mem_free(sample->path);
  1158. + else
  1159. + loaded = true;
  1160.  
  1161. - /* Don't load now if we're not caching */
  1162. - if (no_cache) {
  1163. - /* Just save the path for later */
  1164. - samples[event].paths[num] = string_make(path);
  1165. } else {
  1166. - /* Load the file now */
  1167. - if (use_mp3) {
  1168. - samples[event].mp3s[num] = Mix_LoadMUS(path);
  1169. - if (!samples[event].mp3s[num]) {
  1170. - plog_fmt("%s: %s", SDL_GetError(), strerror(errno));
  1171. - goto next_token;
  1172. - }
  1173. - } else {
  1174. - samples[event].wavs[num] = Mix_LoadWAV(path);
  1175. - if (!samples[event].wavs[num]) {
  1176. - plog_fmt("%s: %s", SDL_GetError(), strerror(errno));
  1177. - goto next_token;
  1178. - }
  1179. - }
  1180. - }
  1181. -
  1182. - /* Imcrement the sample count */
  1183. - samples[event].num++;
  1184. -
  1185. - next_token:
  1186. -
  1187. - /* Figure out next token */
  1188. - cur_token = next_token;
  1189. - if (next_token) {
  1190. - /* Try to find a space */
  1191. - search = strchr(cur_token, ' ');
  1192. -
  1193. - /* If we can find one, terminate, and set new "next" */
  1194. - if (search) {
  1195. - search[0] = '\0';
  1196. - next_token = search + 1;
  1197. - } else {
  1198. - /* Otherwise prevent infinite looping */
  1199. - next_token = NULL;
  1200. - }
  1201. + /* Out of memory */
  1202. + mem_free(filename_buf);
  1203. + data = NULL;
  1204. + return false;
  1205. }
  1206. }
  1207. +
  1208. + i++;
  1209. }
  1210.  
  1211. - /* Close the file */
  1212. - file_close(fff);
  1213. + mem_free(filename_buf);
  1214.  
  1215. + if (!loaded) {
  1216. + plog_fmt("SDL: Failed to load sound '%s')", sound_name);
  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. + * Play the sound stored in the provided SDL Sound data structure.
  1231. */
  1232. -static void play_sound(game_event_type type, game_event_data *data, void *user)
  1233. +static bool play_sound_sdl(void *data)
  1234. {
  1235. - Mix_Chunk *wave = NULL;
  1236. - Mix_Music *mp3 = NULL;
  1237. - int s;
  1238. -
  1239. - int event = data->message.type;
  1240. -
  1241. - /* Paranoia */
  1242. - if (event < 0 || event >= MSG_MAX) return;
  1243. -
  1244. - /* Check there are samples for this event */
  1245. - if (!samples[event].num) return;
  1246. -
  1247. - /* Choose a random event */
  1248. - s = randint0(samples[event].num);
  1249. - if (use_mp3)
  1250. - mp3 = samples[event].mp3s[s];
  1251. - else
  1252. - wave = samples[event].wavs[s];
  1253. -
  1254. - /* Try loading it, if it's not cached */
  1255. - if (!(wave || mp3)) {
  1256. - /* Verify it exists */
  1257. - const char *filename = samples[event].paths[s];
  1258. - if (!file_exists(filename)) return;
  1259. -
  1260. - /* Load */
  1261. - if (use_mp3)
  1262. - mp3 = Mix_LoadMUS(filename);
  1263. - else
  1264. - wave = Mix_LoadWAV(filename);
  1265. - }
  1266. -
  1267. - /* Check to see if we have a sound again */
  1268. - if (!(wave || mp3)) {
  1269. - plog("SDL sound load failed.");
  1270. - return;
  1271. + sdl_sample *sample = (sdl_sample *)data;
  1272. +
  1273. + if (sample) {
  1274. + switch (sample->sample_type) {
  1275. + case SDL_CHUNK:
  1276. + if (sample->sample_data.chunk)
  1277. + return (0 == Mix_PlayChannel(-1, sample->sample_data.chunk, 0));
  1278. + break;
  1279. +
  1280. + case SDL_MUSIC:
  1281. + if (sample->sample_data.music)
  1282. + return (0 == Mix_PlayMusic(sample->sample_data.music, 1));
  1283. + break;
  1284. +
  1285. + default:
  1286. + break;
  1287. + }
  1288. }
  1289.  
  1290. - /* Actually play the thing */
  1291. - if (use_mp3)
  1292. - Mix_PlayMusic(mp3, 1);
  1293. - else
  1294. - Mix_PlayChannel(-1, wave, 0);
  1295. + return false;
  1296. }
  1297.  
  1298. -
  1299. /**
  1300. - * Init the SDL sound "module".
  1301. + * Free resources referenced in the provided SDL Sound data structure.
  1302. */
  1303. -errr init_sound_sdl(int argc, char **argv)
  1304. +static bool unload_sound_sdl(void *data)
  1305. {
  1306. - int i;
  1307. -
  1308. - /* Parse args */
  1309. - for (i = 1; i < argc; i++) {
  1310. - if (prefix(argv[i], "-c")) {
  1311. - no_cache_audio = true;
  1312. - plog("Audio cache disabled.");
  1313. - continue;
  1314. + sdl_sample *sample = (sdl_sample *)data;
  1315. +
  1316. + if (sample) {
  1317. + switch (sample->sample_type) {
  1318. + case SDL_CHUNK:
  1319. + if (sample->sample_data.chunk)
  1320. + Mix_FreeChunk(sample->sample_data.chunk);
  1321. +
  1322. + break;
  1323. +
  1324. + case SDL_MUSIC:
  1325. + if (sample->sample_data.music)
  1326. + Mix_FreeMusic(sample->sample_data.music);
  1327. +
  1328. + break;
  1329. +
  1330. + default:
  1331. + break;
  1332. }
  1333. - }
  1334.  
  1335. - /* Load sound preferences if requested */
  1336. - if (!sound_sdl_init(no_cache_audio)) {
  1337. - plog("Failed to load sound config");
  1338. + if (sample->path)
  1339. + mem_free(sample->path);
  1340.  
  1341. - /* Failure */
  1342. - return (1);
  1343. + mem_free(sample);
  1344. }
  1345.  
  1346. - /* Enable sound */
  1347. - event_add_handler(EVENT_SOUND, play_sound, NULL);
  1348. - atexit(close_audio);
  1349. + return true;
  1350. +}
  1351. +
  1352. +/**
  1353. + * Shut down the SDL sound module and free resources.
  1354. + */
  1355. +static bool close_audio_sdl(void)
  1356. +{
  1357. + /*
  1358. + * Close the audio.
  1359. + *
  1360. + * NOTE: All samples will have been free'd by the sound subsystem
  1361. + * calling unload_sound_sdl() for every sample that was loaded.
  1362. + */
  1363. + Mix_CloseAudio();
  1364. +
  1365. + /* XXX This may conflict with the SDL port */
  1366. + SDL_Quit();
  1367. +
  1368. + return true;
  1369. +}
  1370. +
  1371. +/**
  1372. + * Init the SDL sound module.
  1373. + */
  1374. +errr init_sound_sdl(struct sound_hooks *hooks, int argc, char **argv)
  1375. +{
  1376. + hooks->open_audio_hook = open_audio_sdl;
  1377. + hooks->close_audio_hook = close_audio_sdl;
  1378. + hooks->load_sound_hook = load_sound_sdl;
  1379. + hooks->unload_sound_hook = unload_sound_sdl;
  1380. + hooks->play_sound_hook = play_sound_sdl;
  1381.  
  1382. /* Success */
  1383. return (0);
  1384. diff --git a/src/snd-sdl.h b/src/snd-sdl.h
  1385. new file mode 100644
  1386. index 0000000..3700cea
  1387. --- /dev/null
  1388. +++ b/src/snd-sdl.h
  1389. @@ -0,0 +1,23 @@
  1390. +/**
  1391. + * \file sound.h
  1392. + * \brief Sound handling
  1393. + *
  1394. + * Copyright (c) 2016 Graeme Russ
  1395. + *
  1396. + * Redistribution and use in source and binary forms, with or without
  1397. + * modification, are permitted provided that the following conditions are met:
  1398. + *
  1399. + * * Redistributions of source code must retain the above copyright notice,
  1400. + * this list of conditions and the following disclaimer.
  1401. + *
  1402. + * * Redistributions in binary form must reproduce the above copyright notice,
  1403. + * this list of conditions and the following disclaimer in the documentation
  1404. + * and/or other materials provided with the distribution.
  1405. + */
  1406. +
  1407. +#ifndef INCLUDED_Z_SOUND_SDL_H
  1408. +#define INCLUDED_Z_SOUND_SDL_H
  1409. +
  1410. +errr init_sound_sdl(struct sound_hooks *hooks, int argc, char **argv);
  1411. +
  1412. +#endif /* !INCLUDED_Z_SOUND_H */
  1413. diff --git a/src/sound-core.c b/src/sound-core.c
  1414. new file mode 100644
  1415. index 0000000..fc6210c
  1416. --- /dev/null
  1417. +++ b/src/sound-core.c
  1418. @@ -0,0 +1,410 @@
  1419. +/**
  1420. + * \file sound-core.c
  1421. + * \brief core sound support
  1422. + *
  1423. + * Copyright (c) 2016 Graeme Russ <graeme.russ@gmail.com>
  1424. + *
  1425. + * This work is free software; you can redistribute it and/or modify it
  1426. + * under the terms of either:
  1427. + *
  1428. + * a) the GNU General Public License as published by the Free Software
  1429. + * Foundation, version 2, or
  1430. + *
  1431. + * b) the "Angband licence":
  1432. + * This software may be copied and distributed for educational, research,
  1433. + * and not for profit purposes provided that this copyright and statement
  1434. + * are included in all such copies. Other copyrights may also apply.
  1435. + */
  1436. +#include "angband.h"
  1437. +#include "init.h"
  1438. +#include "sound.h"
  1439. +#include "avltree.h"
  1440. +#include "main.h"
  1441. +
  1442. +#ifdef SOUND_SDL
  1443. +#include "snd-sdl.h"
  1444. +#endif
  1445. +
  1446. +struct sound_module
  1447. +{
  1448. + const char *name;
  1449. + const char *help;
  1450. + errr (*init)(struct sound_hooks *hooks, int argc, char **argv);
  1451. +};
  1452. +
  1453. +/**
  1454. + * List of sound modules in the order they should be tried.
  1455. + */
  1456. +static const struct sound_module sound_modules[] =
  1457. +{
  1458. +#ifdef SOUND_SDL
  1459. + { "sdl", "SDL_mixer sound module", init_sound_sdl },
  1460. +#endif /* SOUND_SDL */
  1461. +
  1462. + { "", "", NULL },
  1463. +};
  1464. +
  1465. +/*
  1466. + * Two trees are needed:
  1467. + * - A mapping of 'sound names' to 'sound ids' - this is used during the
  1468. + * initial parsing of the sound configuration file to ensure we don't
  1469. + * load the same sounds multiple times (if a sound is mapped to more than
  1470. + * one message). When the sound sub-system is initialised, this tree is
  1471. + * 'walked', with the sound name stored in each node passed to the platform
  1472. + * sound module which loads the sound
  1473. + * - A mapping of 'message ids' to 'sound ids' - In the past, a static array
  1474. + * of size [MAX_MESSAGES][MAX_SOUND_PER_MESSAGE] was used, which results
  1475. + * in a horrendous waste of memory
  1476. + */
  1477. +
  1478. +/*****************************************************************************
  1479. + * Structures to map sound names to ids
  1480. + *****************************************************************************/
  1481. +typedef struct _sound_node sound_node;
  1482. +
  1483. +struct _sound_node
  1484. +{
  1485. + char *sound_name;
  1486. + u16b sound_id;
  1487. +
  1488. + TREE_ENTRY(_sound_node) sound_tree;
  1489. +};
  1490. +
  1491. +static sound_node *sound_node_new(char *sound_name, u16b sound_id)
  1492. +{
  1493. + sound_node *self = mem_zalloc(sizeof *self);
  1494. +
  1495. + self->sound_name = string_make(sound_name);
  1496. + self->sound_id = sound_id;
  1497. + return self;
  1498. +}
  1499. +
  1500. +static int sound_node_compare(sound_node *lhs, sound_node *rhs)
  1501. +{
  1502. + return (int)strcmp(lhs->sound_name, rhs->sound_name);
  1503. +}
  1504. +
  1505. +typedef TREE_HEAD(_sound_tree, _sound_node) tree_sound;
  1506. +
  1507. +TREE_DEFINE(_sound_node, sound_tree)
  1508. +
  1509. +static tree_sound sounds = TREE_INITIALIZER(sound_node_compare);
  1510. +/*****************************************************************************/
  1511. +
  1512. +/*****************************************************************************
  1513. + * Structures to map message ids to sound ids
  1514. + *****************************************************************************/
  1515. +typedef struct _msg_sound msg_sound;
  1516. +
  1517. +struct _msg_sound
  1518. +{
  1519. + int sound_id;
  1520. + msg_sound *next;
  1521. +};
  1522. +
  1523. +typedef struct _message_node message_node;
  1524. +
  1525. +struct _message_node
  1526. +{
  1527. + u16b message_id;
  1528. + int num_sounds;
  1529. + msg_sound *first;
  1530. +
  1531. + TREE_ENTRY(_message_node) message_tree;
  1532. +};
  1533. +
  1534. +static message_node *message_node_new(u16b message_id)
  1535. +{
  1536. + message_node *self = mem_zalloc(sizeof *self);
  1537. +
  1538. + self->message_id = message_id;
  1539. +
  1540. + return self;
  1541. +}
  1542. +
  1543. +static int message_node_compare(message_node *lhs, message_node *rhs)
  1544. +{
  1545. + return (rhs->message_id - lhs->message_id);
  1546. +}
  1547. +
  1548. +typedef TREE_HEAD(_message_tree, _message_node) tree_message;
  1549. +
  1550. +TREE_DEFINE(_message_node, message_tree)
  1551. +
  1552. +static tree_message messages = TREE_INITIALIZER(message_node_compare);
  1553. +/*****************************************************************************/
  1554. +
  1555. +/*
  1556. + * After processing the preference files, the 'sounds' AVL Tree will contain
  1557. + * next_sound_id nodes - each representing a sound that needs to be loaded.
  1558. + * We create the sound_data array once we know this information, and then
  1559. + * populate it by calling load_sound_hook() for each node in the tree
  1560. + */
  1561. +static u16b next_sound_id;
  1562. +static void **sound_data;
  1563. +
  1564. +/* These are the hooks installed by the platform sound module */
  1565. +static struct sound_hooks hooks;
  1566. +
  1567. +/**
  1568. + * Parse a string of sound names provided by the preferences parser and:
  1569. + * - Add any new sounds to the 'sound names' tree and allocate them
  1570. + * unique 'sound ids'
  1571. + * - Add each sound assigned to a message type to that message types
  1572. + * 'sound map
  1573. + */
  1574. +void message_sound_define(u16b message_id, const char *sounds_str)
  1575. +{
  1576. + char *search;
  1577. + char *str;
  1578. + char *cur_token;
  1579. + char *next_token;
  1580. +
  1581. + sound_node sound_search_node;
  1582. + sound_node *existing_sound;
  1583. + sound_node *new_sound;
  1584. + u16b sound_id;
  1585. +
  1586. + message_node message_search_node;
  1587. + message_node *message_map;
  1588. + msg_sound *new_message_sound;
  1589. +
  1590. + /* sounds_str is a space separated list of sound names */
  1591. + str = cur_token = string_make(sounds_str);
  1592. +
  1593. + search = strchr(cur_token, ' ');
  1594. +
  1595. + if (search) {
  1596. + search[0] = '\0';
  1597. + next_token = search + 1;
  1598. + } else {
  1599. + next_token = NULL;
  1600. + }
  1601. +
  1602. + if (cur_token) {
  1603. + /* Do we already have a message->sounds mapping for this message ID? */
  1604. + message_search_node.message_id = message_id;
  1605. +
  1606. + message_map = TREE_FIND(&messages, _message_node, message_tree, &message_search_node);
  1607. +
  1608. + if (!message_map) {
  1609. + /* No - create one */
  1610. + message_map = message_node_new(message_id);
  1611. + TREE_INSERT(&messages, _message_node, message_tree, message_map);
  1612. + }
  1613. + }
  1614. +
  1615. + /* Find all the sample names and add them one by one */
  1616. + while (cur_token) {
  1617. + /* Have we already processed this sound name? */
  1618. + sound_search_node.sound_name = cur_token;
  1619. +
  1620. + existing_sound = TREE_FIND(&sounds, _sound_node, sound_tree, &sound_search_node);
  1621. +
  1622. + if (existing_sound) {
  1623. + /* Yep - Just need to get the ID */
  1624. + sound_id = existing_sound->sound_id;
  1625. + } else {
  1626. + /* Nope - Create a new node to store this sound's ID */
  1627. + sound_id = next_sound_id;
  1628. + new_sound = sound_node_new(cur_token, sound_id);
  1629. + TREE_INSERT(&sounds, _sound_node, sound_tree, new_sound);
  1630. +
  1631. + next_sound_id++;
  1632. + }
  1633. +
  1634. + /* Add this sound (by id) to the message->sounds map */
  1635. + new_message_sound = mem_zalloc(sizeof *new_message_sound);
  1636. + new_message_sound->sound_id = sound_id;
  1637. + new_message_sound->next = message_map->first;
  1638. + message_map->first = new_message_sound;
  1639. + message_map->num_sounds++;
  1640. +
  1641. + /* Figure out next token */
  1642. + cur_token = next_token;
  1643. +
  1644. + if (next_token) {
  1645. + /* Try to find a space */
  1646. + search = strchr(cur_token, ' ');
  1647. +
  1648. + /* If we can find one, terminate, and set new "next" */
  1649. + if (search) {
  1650. + search[0] = '\0';
  1651. + next_token = search + 1;
  1652. + } else {
  1653. + /* Otherwise prevent infinite looping */
  1654. + next_token = NULL;
  1655. + }
  1656. + }
  1657. + }
  1658. +
  1659. + string_free(str);
  1660. +}
  1661. +
  1662. +/**
  1663. + * Play a sound of type "event".
  1664. + */
  1665. +static void play_sound(game_event_type type, game_event_data *data, void *user)
  1666. +{
  1667. + int s, i, sound_id;
  1668. + message_node message_search_node;
  1669. + message_node *message_map;
  1670. + msg_sound *message_sound;
  1671. +
  1672. + int event = data->message.type;
  1673. +
  1674. + /* Paranoia */
  1675. + assert(event >= 0);
  1676. +
  1677. + message_search_node.message_id = (u16b)event;
  1678. +
  1679. + message_map = TREE_FIND(&messages, _message_node, message_tree, &message_search_node);
  1680. +
  1681. + if (!message_map)
  1682. + return; /* No sounds for this message */
  1683. +
  1684. + /* Choose a random event */
  1685. + message_sound = message_map->first;
  1686. +
  1687. + if (!message_sound)
  1688. + return; /* Oops */
  1689. +
  1690. + s = randint0(message_map->num_sounds);
  1691. +
  1692. + /*
  1693. + * Walk the list - possibly inefficient if you define LOTS of sounds
  1694. + * for LOTS of messages. Not worth using a more 'efficient' data
  1695. + * structure
  1696. + */
  1697. + for (i = 0; i < s; i++)
  1698. + if (message_sound->next)
  1699. + message_sound = message_sound->next;
  1700. +
  1701. + sound_id = message_sound->sound_id;
  1702. +
  1703. + assert((sound_id >= 0) && (sound_id < next_sound_id));
  1704. +
  1705. + hooks.play_sound_hook(sound_data[sound_id]);
  1706. +}
  1707. +
  1708. +/**
  1709. + * Call the platform sound modules 'load sound' function
  1710. + */
  1711. +static void load_sound(sound_node *self, void *ignore)
  1712. +{
  1713. + void *plat_data;
  1714. +
  1715. + if (hooks.load_sound_hook) {
  1716. + if(!hooks.load_sound_hook(self->sound_name, &plat_data))
  1717. + plog_fmt("Failed to load sound: %s", self->sound_name);
  1718. + else
  1719. + sound_data[self->sound_id] = plat_data;
  1720. + }
  1721. +}
  1722. +
  1723. +/*
  1724. + * Recursive function to delete sound id's from a node in the 'messages' tree
  1725. + */
  1726. +void delete_message_sound(msg_sound *sound)
  1727. +{
  1728. + assert(sound);
  1729. +
  1730. + if (sound->next)
  1731. + delete_message_sound(sound->next);
  1732. +
  1733. + mem_free(sound);
  1734. +}
  1735. +/*
  1736. + * Shut down the sound system and free resources.
  1737. + */
  1738. +static void close_audio(void)
  1739. +{
  1740. + int i;
  1741. +
  1742. + if (0 == next_sound_id)
  1743. + return; /* Never opened */
  1744. +
  1745. + /*
  1746. + * Ask the platforms sound module to free resources for each
  1747. + * sound
  1748. + */
  1749. + if (hooks.unload_sound_hook)
  1750. + for (i = 0; i < next_sound_id; i++)
  1751. + hooks.unload_sound_hook(sound_data[i]);
  1752. +
  1753. + mem_free(sound_data);
  1754. +
  1755. + /* Delete the 'sound names' tree */
  1756. + while (sounds.th_root) {
  1757. + mem_free(sounds.th_root->sound_name);
  1758. + TREE_REMOVE(&sounds, _sound_node, sound_tree, sounds.th_root);
  1759. + }
  1760. +
  1761. + /* Delete the 'message map' tree */
  1762. + while (messages.th_root) {
  1763. + delete_message_sound(messages.th_root->first);
  1764. + TREE_REMOVE(&messages, _message_node, message_tree, messages.th_root);
  1765. + }
  1766. +
  1767. + /* Close the platform's sound module */
  1768. + if (hooks.close_audio_hook)
  1769. + hooks.close_audio_hook();
  1770. +}
  1771. +
  1772. +
  1773. +/**
  1774. + * Init the sound "module".
  1775. + */
  1776. +errr init_sound(const char *soundstr, int argc, char **argv)
  1777. +{
  1778. + int i = 0;
  1779. + bool done = false;
  1780. +
  1781. + /* Only initialise the sound sub-system if we have sounds to play */
  1782. + if (0 == next_sound_id)
  1783. + return 0; /* It's not a fail if no sounds defined */
  1784. +
  1785. + /* Try the modules in the order specified by sound_modules[] */
  1786. + while (sound_modules[i].init && !done) {
  1787. + if (!soundstr || streq(soundstr, sound_modules[i].name))
  1788. + if (0 == sound_modules[i].init(&hooks, argc, argv))
  1789. + done = true;
  1790. + i++;
  1791. + }
  1792. +
  1793. + /* Check that we have a sound module to use */
  1794. + if (!done)
  1795. + return 1;
  1796. +
  1797. + /* Open the platform specific sound system */
  1798. + if (!hooks.open_audio_hook)
  1799. + return 1;
  1800. +
  1801. + if (!hooks.open_audio_hook(argc, argv))
  1802. + return 1;
  1803. +
  1804. + /* Allocate the array which stores the platform specific sound data */
  1805. + sound_data = mem_zalloc(sizeof(void *) * next_sound_id);
  1806. +
  1807. + /* Walk the 'sound names' tree, calling load_sound() for each node */
  1808. + TREE_FORWARD_APPLY(&sounds, _sound_node, sound_tree, load_sound, NULL);
  1809. +
  1810. + /* Enable sound */
  1811. + event_add_handler(EVENT_SOUND, play_sound, NULL);
  1812. + atexit(close_audio);
  1813. +
  1814. + /* Success */
  1815. + return (0);
  1816. +}
  1817. +
  1818. +/**
  1819. + * Print out the 'help' information for the sound module.
  1820. + */
  1821. +void print_sound_help(void)
  1822. +{
  1823. + int i;
  1824. +
  1825. + for (i = 0; i < (int)N_ELEMENTS(sound_modules); i++)
  1826. + printf(" %s %s\n", sound_modules[i].name,
  1827. + sound_modules[i].help);
  1828. +}
  1829. diff --git a/src/sound.h b/src/sound.h
  1830. new file mode 100644
  1831. index 0000000..cb49f0d
  1832. --- /dev/null
  1833. +++ b/src/sound.h
  1834. @@ -0,0 +1,38 @@
  1835. +/**
  1836. + * \file sound.h
  1837. + * \brief Sound handling
  1838. + *
  1839. + * Copyright (c) 2016 Graeme Russ
  1840. + *
  1841. + * Redistribution and use in source and binary forms, with or without
  1842. + * modification, are permitted provided that the following conditions are met:
  1843. + *
  1844. + * * Redistributions of source code must retain the above copyright notice,
  1845. + * this list of conditions and the following disclaimer.
  1846. + *
  1847. + * * Redistributions in binary form must reproduce the above copyright notice,
  1848. + * this list of conditions and the following disclaimer in the documentation
  1849. + * and/or other materials provided with the distribution.
  1850. + */
  1851. +
  1852. +#ifndef INCLUDED_SOUND_H
  1853. +#define INCLUDED_SOUND_H
  1854. +
  1855. +struct sound_hooks
  1856. +{
  1857. + bool (*open_audio_hook)(int argc, char **argv);
  1858. + bool (*close_audio_hook)(void);
  1859. +
  1860. + /* 'data' is a sound module specific struct */
  1861. + bool (*load_sound_hook)(const char *sound_name, void **data);
  1862. + bool (*unload_sound_hook)(void *data);
  1863. + bool (*play_sound_hook)(void *data);
  1864. +};
  1865. +
  1866. +errr init_sound(const char *soundstr, int argc, char **argv);
  1867. +
  1868. +void message_sound_define(u16b type, const char *sounds);
  1869. +
  1870. +void print_sound_help(void);
  1871. +
  1872. +#endif /* !INCLUDED_SOUND_H */
  1873. diff --git a/src/ui-prefs.c b/src/ui-prefs.c
  1874. index cff07cf..e32ba72 100644
  1875. --- a/src/ui-prefs.c
  1876. +++ b/src/ui-prefs.c
  1877. @@ -34,6 +34,7 @@
  1878. #include "ui-keymap.h"
  1879. #include "ui-prefs.h"
  1880. #include "ui-term.h"
  1881. +#include "sound.h"
  1882.  
  1883. int arg_graphics; /* Command arg -- Request graphics mode */
  1884. bool arg_graphics_nice; /* Command arg -- Request nice graphics mode */
  1885. @@ -1047,6 +1048,29 @@ static enum parser_error parse_prefs_window(struct parser *p)
  1886. return PARSE_ERROR_NONE;
  1887. }
  1888.  
  1889. +static enum parser_error parse_prefs_sound(struct parser *p)
  1890. +{
  1891. + int msg_index;
  1892. + const char *type;
  1893. + const char *sounds;
  1894. +
  1895. + struct prefs_data *d = parser_priv(p);
  1896. + assert(d != NULL);
  1897. + if (d->bypass) return PARSE_ERROR_NONE;
  1898. +
  1899. + type = parser_getsym(p, "type");
  1900. + sounds = parser_getstr(p, "sounds");
  1901. +
  1902. + msg_index = message_lookup_by_name(type);
  1903. +
  1904. + if (msg_index < 0)
  1905. + return PARSE_ERROR_INVALID_MESSAGE;
  1906. +
  1907. + message_sound_define(msg_index, sounds);
  1908. +
  1909. + return PARSE_ERROR_NONE;
  1910. +}
  1911. +
  1912. static struct parser *init_parse_prefs(bool user)
  1913. {
  1914. struct parser *p = parser_new();
  1915. @@ -1074,6 +1098,7 @@ static struct parser *init_parse_prefs(bool user)
  1916. parser_reg(p, "message sym type sym attr", parse_prefs_message);
  1917. parser_reg(p, "color uint idx int k int r int g int b", parse_prefs_color);
  1918. parser_reg(p, "window int window uint flag uint value", parse_prefs_window);
  1919. + parser_reg(p, "sound sym type str sounds", parse_prefs_sound);
  1920.  
  1921. return p;
  1922. }
RAW Paste Data