diff --git a/core/config.d b/core/config.d index de5f5ebd5..8c0f877e4 100644 --- a/core/config.d +++ b/core/config.d @@ -28,6 +28,7 @@ import std.file; import std.path; import std.stdio; +import monster.monster; import monster.util.string; import core.inifile; @@ -38,10 +39,6 @@ import sound.audio; import input.keys; import input.ois; -//import sdl.Keysym; - -//import input.events : updateMouseSensitivity; - ConfigManager config; /* @@ -52,20 +49,25 @@ ConfigManager config; * from Morrowind.ini and for configuring OGRE. It doesn't currently * DO all of this, but it is supposed to in the future. */ + struct ConfigManager { + MonsterObject *mo; + IniWriter iniWriter; // Sound setting + /* float musicVolume; float sfxVolume; float mainVolume; bool useMusic; + //*/ // Mouse sensitivity - float mouseSensX; - float mouseSensY; - bool flipMouseY; + float *mouseSensX; + float *mouseSensY; + bool *flipMouseY; // Ogre configuration bool showOgreConfig; // The configuration setting @@ -97,50 +99,31 @@ struct ConfigManager // Cell to load at startup char[] defaultCell; - // Check that a given volume is within sane limits (0.0-1.0) - private static float saneVol(float vol) - { - if(!(vol >= 0)) vol = 0; - else if(!(vol <= 1)) vol = 1; - return vol; - } - // These set the volume to a new value and updates all sounds to // take notice. void setMusicVolume(float vol) { - musicVolume = saneVol(vol); - - jukebox.updateVolume(); - battleMusic.updateVolume(); + stack.pushFloat(vol); + mo.call("setMusicVolume"); } + float getMusicVolume() + { return mo.getFloat("musicVolume"); } void setSfxVolume(float vol) { - sfxVolume = saneVol(vol); - - // TODO: Call some sound manager here to adjust all active sounds + stack.pushFloat(vol); + mo.call("setSfxVolume"); } + float getSfxVolume() + { return mo.getFloat("sfxVolume"); } void setMainVolume(float vol) { - mainVolume = saneVol(vol); - - // Update the sound managers - setMusicVolume(musicVolume); - setSfxVolume(sfxVolume); - } - - // These calculate the "effective" volumes. - float calcMusicVolume() - { - return musicVolume * mainVolume; - } - - float calcSfxVolume() - { - return sfxVolume * mainVolume; + stack.pushFloat(vol); + mo.call("setMainVolume"); } + float getMainVolume() + { return mo.getFloat("mainVolume"); } // Initialize the config manager. Send a 'true' parameter to reset // all keybindings to the default. A lot of this stuff will be moved @@ -149,6 +132,12 @@ struct ConfigManager // all setup and control should be handled in script code. void initialize(bool reset = false) { + // Initialize variables from Monster. + assert(mo !is null); + mouseSensX = mo.getFloatPtr("mouseSensX"); + mouseSensY = mo.getFloatPtr("mouseSensY"); + flipMouseY = mo.getBoolPtr("flipMouseY"); + // Initialize the key binding manager keyBindings.initKeys(); @@ -189,14 +178,19 @@ struct ConfigManager ini.readFile(confFile); screenShotNum = ini.getInt("General", "Screenshots", 0); - mainVolume = saneVol(ini.getFloat("Sound", "Main Volume", 0.7)); - musicVolume = saneVol(ini.getFloat("Sound", "Music Volume", 0.5)); - sfxVolume = saneVol(ini.getFloat("Sound", "SFX Volume", 0.5)); - useMusic = ini.getBool("Sound", "Enable Music", true); + float mainVolume = saneVol(ini.getFloat("Sound", "Main Volume", 0.7)); + float musicVolume = saneVol(ini.getFloat("Sound", "Music Volume", 0.5)); + float sfxVolume = saneVol(ini.getFloat("Sound", "SFX Volume", 0.5)); + bool useMusic = ini.getBool("Sound", "Enable Music", true); + + *mouseSensX = ini.getFloat("Controls", "Mouse Sensitivity X", 0.2); + *mouseSensY = ini.getFloat("Controls", "Mouse Sensitivity Y", 0.2); + *flipMouseY = ini.getBool("Controls", "Flip Mouse Y Axis", false); - mouseSensX = ini.getFloat("Controls", "Mouse Sensitivity X", 0.2); - mouseSensY = ini.getFloat("Controls", "Mouse Sensitivity Y", 0.2); - flipMouseY = ini.getBool("Controls", "Flip Mouse Y Axis", false); + mo.setFloat("mainVolume", mainVolume); + mo.setFloat("musicVolume", musicVolume); + mo.setFloat("sfxVolume", sfxVolume); + mo.setBool("useMusic", useMusic); defaultCell = ini.getString("General", "Default Cell", "Assu"); @@ -356,9 +350,9 @@ struct ConfigManager writeBool("First Run", false); section("Controls"); - writeFloat("Mouse Sensitivity X", mouseSensX); - writeFloat("Mouse Sensitivity Y", mouseSensY); - writeBool("Flip Mouse Y Axis", flipMouseY); + writeFloat("Mouse Sensitivity X", *mouseSensX); + writeFloat("Mouse Sensitivity Y", *mouseSensY); + writeBool("Flip Mouse Y Axis", *flipMouseY); section("Bindings"); comment("Key bindings. The strings must match exactly."); @@ -370,10 +364,10 @@ struct ConfigManager } section("Sound"); - writeFloat("Main Volume", mainVolume); - writeFloat("Music Volume", musicVolume); - writeFloat("SFX Volume", sfxVolume); - writeBool("Enable Music", useMusic); + writeFloat("Main Volume", mo.getFloat("mainVolume")); + writeFloat("Music Volume", mo.getFloat("musicVolume")); + writeFloat("SFX Volume", mo.getFloat("sfxVolume")); + writeBool("Enable Music", mo.getBool("useMusic")); section("Game Files"); foreach(int i, ref s; gameFiles) diff --git a/core/resource.d b/core/resource.d index b9ceaab90..abe149197 100644 --- a/core/resource.d +++ b/core/resource.d @@ -152,8 +152,8 @@ struct ResourceManager return res; } - jukebox.setPlaylist(getDir(config.musDir)); - battleMusic.setPlaylist(getDir(config.musDir2)); + Music.setPlaylists(getDir(config.musDir), + getDir(config.musDir2)); meshLookup.reset(); textureLookup.reset(); diff --git a/input/events.d b/input/events.d index 60077de78..59aeceb32 100644 --- a/input/events.d +++ b/input/events.d @@ -50,50 +50,9 @@ import input.ois; // TODO: Jukebox controls and other state-related data will later be // handled entirely in script code, as will some of the key bindings. -// Are we currently playing battle music? -bool battle = false; - // Pause? bool pause = false; -// Temporarily store volume while muted -float muteVolume = -1; - -void toggleMute() -{ - if(muteVolume < 0) - { - muteVolume = config.mainVolume; - config.setMainVolume(0); - writefln("Muted"); - } - else - { - config.setMainVolume(muteVolume); - muteVolume = -1; - writefln("Mute off"); - } -} - -// Switch between normal and battle music -void toggleBattle() -{ - if(battle) - { - writefln("Changing to normal music"); - jukebox.resume(); - battleMusic.pause(); - battle=false; - } - else - { - writefln("Changing to battle music"); - jukebox.pause(); - battleMusic.resume(); - battle=true; - } -} - void toggleFullscreen() { ogre_toggleFullscreen(); @@ -105,24 +64,24 @@ void musVolume(bool increase) { float diff = -volDiff; if(increase) diff = -diff; - config.setMusicVolume(diff + config.musicVolume); - writefln(increase?"Increasing":"Decreasing", " music volume to ", config.musicVolume); + config.setMusicVolume(diff + config.getMusicVolume); + writefln(increase?"Increasing":"Decreasing", " music volume to ", config.getMusicVolume); } void sfxVolume(bool increase) { float diff = -volDiff; if(increase) diff = -diff; - config.setSfxVolume(diff + config.sfxVolume); - writefln(increase?"Increasing":"Decreasing", " sound effect volume to ", config.sfxVolume); + config.setSfxVolume(diff + config.getSfxVolume); + writefln(increase?"Increasing":"Decreasing", " sound effect volume to ", config.getSfxVolume); } void mainVolume(bool increase) { float diff = -volDiff; if(increase) diff = -diff; - config.setMainVolume(diff + config.mainVolume); - writefln(increase?"Increasing":"Decreasing", " main volume to ", config.mainVolume); + config.setMainVolume(diff + config.getMainVolume); + writefln(increase?"Increasing":"Decreasing", " main volume to ", config.getMainVolume); } void takeScreenShot() @@ -137,9 +96,9 @@ float effMX, effMY; void updateMouseSensitivity() { - effMX = config.mouseSensX; - effMY = config.mouseSensY; - if(config.flipMouseY) effMY = -effMY; + effMX = *config.mouseSensX; + effMY = *config.mouseSensY; + if(*config.flipMouseY) effMY = -effMY; } void togglePause() @@ -212,7 +171,9 @@ extern(C) void d_handleKey(KC keycode, dchar text = 0) if(k) switch(k) { - case Keys.ToggleBattleMusic: toggleBattle(); break; + case Keys.ToggleBattleMusic: + Music.toggle(); + break; case Keys.MainVolUp: mainVolume(true); break; case Keys.MainVolDown: mainVolume(false); break; @@ -220,7 +181,7 @@ extern(C) void d_handleKey(KC keycode, dchar text = 0) case Keys.MusVolDown: musVolume(false); break; case Keys.SfxVolUp: sfxVolume(true); break; case Keys.SfxVolDown: sfxVolume(false); break; - case Keys.Mute: toggleMute(); break; + case Keys.Mute: Music.toggleMute(); break; case Keys.Fullscreen: toggleFullscreen(); break; case Keys.PhysMode: bullet_nextMode(); break; @@ -298,8 +259,7 @@ extern(C) int d_frameStarted(float time) musCumTime += time; if(musCumTime > musRefresh) { - jukebox.updateBuffers(); - battleMusic.updateBuffers(); + Music.updateBuffers(); musCumTime -= musRefresh; } diff --git a/mscripts/cellobject.mn b/mscripts/cellobject.mn new file mode 100644 index 000000000..25873997f --- /dev/null +++ b/mscripts/cellobject.mn @@ -0,0 +1,60 @@ +/* + OpenMW - The completely unofficial reimplementation of Morrowind + Copyright (C) 2008 Nicolay Korslund + Email: < korslund@gmail.com > + WWW: http://openmw.snaptoad.com/ + + This file (cellobject.mn) is part of the OpenMW package. + + OpenMW is distributed as free software: you can redistribute it + and/or modify it under the terms of the GNU General Public License + version 3, as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + version 3 along with this program. If not, see + http://www.gnu.org/licenses/ . + + */ + +// An object that exists inside a cell. All cell objects must have a +// position in space. +class CellObject : Object; + +// Position and rotation in space +float x, y, z; +float r1, r2, r3; + +float scale; + +// Various variables that are currently unused. Most of the strings +// will be replaced by object references at some point. + +// Owner of an object / activator +char[] owner; + +// A global variable? Don't know what it's used for. +char[] global; + +// Reference to a soul trapped creature? +char[] soul; + +// Faction owner? Rank? +char[] cnam; +int indx; + +// Magic value / health / uses of an item? +float xchg; + +// ?? See comment below +int intv, nam9; + +// ?? +int fltv; +int unam; + +// TODO: Scripts diff --git a/mscripts/config.mn b/mscripts/config.mn new file mode 100644 index 000000000..524d3ddf2 --- /dev/null +++ b/mscripts/config.mn @@ -0,0 +1,61 @@ +/* + OpenMW - The completely unofficial reimplementation of Morrowind + Copyright (C) 2008 Nicolay Korslund + Email: < korslund@gmail.com > + WWW: http://openmw.snaptoad.com/ + + This file (config.mn) is part of the OpenMW package. + + OpenMW is distributed as free software: you can redistribute it + and/or modify it under the terms of the GNU General Public License + version 3, as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + version 3 along with this program. If not, see + http://www.gnu.org/licenses/ . + + */ + +// TODO: Should be a singleton +class Config : Object; + +// Only some config options have been moved into Monster. Key bindings +// and other low-level settings are still handled in D. + +float musicVolume; +float sfxVolume; +float mainVolume; +bool useMusic; + +float mouseSensX; +float mouseSensY; +bool flipMouseY; + +// TODO: This could be replaced by some sort of hook placed on +// mainVolume. Writing to the variable would automatically update +// everything. +setMainVolume(float f) +{ + mainVolume = f; + music().updateVolume(); +} + +setMusicVolume(float f) +{ + musicVolume = f; + music().updateVolume(); +} + +setSfxVolume(float f) +{ + sfxVolume = f; + // TODO: Update something here +} + +// Returns the "real" music volume +float calcMusicVolume() { return mainVolume * musicVolume; } diff --git a/mscripts/door.mn b/mscripts/door.mn new file mode 100644 index 000000000..c30dd95be --- /dev/null +++ b/mscripts/door.mn @@ -0,0 +1,32 @@ +/* + OpenMW - The completely unofficial reimplementation of Morrowind + Copyright (C) 2008 Nicolay Korslund + Email: < korslund@gmail.com > + WWW: http://openmw.snaptoad.com/ + + This file (door.mn) is part of the OpenMW package. + + OpenMW is distributed as free software: you can redistribute it + and/or modify it under the terms of the GNU General Public License + version 3, as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + version 3 along with this program. If not, see + http://www.gnu.org/licenses/ . + + */ + +class Door : LockedObject; + +// Does this door transport you to another cell? +bool teleport; + +// Door destination +float destx, desty, destz; +float destr1, destr2, destr3; +char[] destCell; diff --git a/mscripts/gamesettings.mn b/mscripts/gamesettings.mn index 70c803dea..062f053d0 100644 --- a/mscripts/gamesettings.mn +++ b/mscripts/gamesettings.mn @@ -2096,12 +2096,12 @@ test() // lost in a see of output from OGRE, run openmw with the -n switch // to disable rendering. print(); - print("Some random GSMT variables:"); - print("sThief: ", sThief); - print("iAlchemyMod: ", iAlchemyMod); - print("sBribe_100_Gold: ", sBribe_100_Gold); - print("fMaxWalkSpeed: ", fMaxWalkSpeed); - print("fWereWolfMagicka: ", fWereWolfMagicka); - print("sEffectSummonFabricant: ", sEffectSummonFabricant); + print("Some random GMST variables:"); + print("sThief:", sThief); + print("iAlchemyMod:", iAlchemyMod); + print("sBribe_100_Gold:", sBribe_100_Gold); + print("fMaxWalkSpeed:", fMaxWalkSpeed); + print("fWereWolfMagicka:", fWereWolfMagicka); + print("sEffectSummonFabricant:", sEffectSummonFabricant); print(); } diff --git a/mscripts/jukebox.mn b/mscripts/jukebox.mn index e2c93c412..e191bd414 100644 --- a/mscripts/jukebox.mn +++ b/mscripts/jukebox.mn @@ -41,12 +41,15 @@ float fadeInterval = 0.2; // List of sounds to play char[][] playlist; +// Name used for error messages +char[] name; + // Index of current song int index; // The music volume, set by the user. Does NOT change to adjust for -// fading, etc. TODO: This should be stored in a configuration class, -// not here. +// fading, it is only updated when the user changes the volume +// settings. Updated from Config through updateVolume(). float musVolume; bool isPlaying; // Is a song currently playing? @@ -69,6 +72,8 @@ pause() resume() { + if(!config().useMusic) return; + if(isPaused) playSound(); else next(); @@ -89,10 +94,13 @@ stop() play() { + if(!config().useMusic) return; + if(index >= playlist.length) return; setSound(playlist[index]); + setVolume(musVolume*fadeLevel); playSound(); isPlaying = true; @@ -104,6 +112,8 @@ play() // Play the next song in the playlist next() { + if(!config().useMusic) return; + if(isPlaying) stop(); @@ -119,11 +129,10 @@ next() play(); } -// Set the new music volume setting. TODO: This should be read from a -// config object instead. -updateVolume(float vol) +// Set the new music volume setting. +updateVolume(float f) { - musVolume = vol; + musVolume = f; if(isPlaying) setVolume(musVolume*fadeLevel); } diff --git a/mscripts/light.mn b/mscripts/light.mn new file mode 100644 index 000000000..fd2a5007d --- /dev/null +++ b/mscripts/light.mn @@ -0,0 +1,30 @@ +/* + OpenMW - The completely unofficial reimplementation of Morrowind + Copyright (C) 2008 Nicolay Korslund + Email: < korslund@gmail.com > + WWW: http://openmw.snaptoad.com/ + + This file (light.mn) is part of the OpenMW package. + + OpenMW is distributed as free software: you can redistribute it + and/or modify it under the terms of the GNU General Public License + version 3, as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + version 3 along with this program. If not, see + http://www.gnu.org/licenses/ . + + */ + +class Light : CellObject; + +// Time left in seconds (for carried lights) +float lifetime; + +// Is this a carryable light? +bool carry; diff --git a/mscripts/lockedobject.mn b/mscripts/lockedobject.mn new file mode 100644 index 000000000..0fccdd9a8 --- /dev/null +++ b/mscripts/lockedobject.mn @@ -0,0 +1,30 @@ +/* + OpenMW - The completely unofficial reimplementation of Morrowind + Copyright (C) 2008 Nicolay Korslund + Email: < korslund@gmail.com > + WWW: http://openmw.snaptoad.com/ + + This file (lockedobject.mn) is part of the OpenMW package. + + OpenMW is distributed as free software: you can redistribute it + and/or modify it under the terms of the GNU General Public License + version 3, as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + version 3 along with this program. If not, see + http://www.gnu.org/licenses/ . + + */ + +// Objects that can have a lock level and a trap +class LockedObject : CellObject; + +// ID of key and trap type. +char[] key, trap; + +int lockLevel; diff --git a/mscripts/music.mn b/mscripts/music.mn new file mode 100644 index 000000000..713e782ea --- /dev/null +++ b/mscripts/music.mn @@ -0,0 +1,104 @@ +/* + OpenMW - The completely unofficial reimplementation of Morrowind + Copyright (C) 2008 Nicolay Korslund + Email: < korslund@gmail.com > + WWW: http://openmw.snaptoad.com/ + + This file (jukebox.mn) is part of the OpenMW package. + + OpenMW is distributed as free software: you can redistribute it + and/or modify it under the terms of the GNU General Public License + version 3, as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + version 3 along with this program. If not, see + http://www.gnu.org/licenses/ . + + */ + +// This class controls all the music. +class Music : Object; + +// Create one jukebox for normal music, and one for battle music. This +// way we can pause / fade out one while the other resumes / fades in. +Jukebox jukebox, battle; + +bool isBattle; +bool isMuted; + +// Toggle between normal and battle music +toggle() +{ + if(isBattle) + { + print("Switching to normal music"); + battle.pause(); + jukebox.resume(); + isBattle = false; + } + else + { + print("Switching to battle music"); + jukebox.pause(); + battle.resume(); + isBattle = true; + } +} + +toggleMute() +{ + if(!isMuted) + { + jukebox.updateVolume(0); + battle.updateVolume(0); + print("Muted"); + isMuted = true; + } + else + { + updateVolume(); + isMuted = false; + print("Mute off"); + } +} + +setup() +{ + jukebox = new Jukebox; + battle = new Jukebox; + + jukebox.name = "Main"; + battle.name = "Battle"; + + isBattle = false; + + updateVolume(); +} + +play() +{ + if(isBattle) battle.play(); + else jukebox.play(); +} + +// Called at startup, listing the files in the "explore" and "battle" +// music directories respectively. +setPlaylists(char[][] normal, char[][] battlelist) +{ + jukebox.setPlaylist(normal); + battle.setPlaylist(battlelist); +} + +// Called whenever the volume settings (music volume or main volume) +// have been changed by the user. +updateVolume() +{ + float v = config().calcMusicVolume(); + jukebox.updateVolume(v); + battle.updateVolume(v); +} diff --git a/mscripts/object.d b/mscripts/object.d index ac4e6ca81..79c6b10df 100644 --- a/mscripts/object.d +++ b/mscripts/object.d @@ -27,6 +27,8 @@ import monster.monster; import std.stdio; import std.date; import core.resource : rnd; +import core.config; +import sound.music; // Set up the base Monster classes we need in OpenMW void initMonsterScripts() @@ -37,6 +39,10 @@ void initMonsterScripts() // Make sure the Object class is loaded auto mc = new MonsterClass("Object", "object.mn"); + // Create the config object too (only needed here because Object + // refers to Config. This will change.) + config.mo = (new MonsterClass("Config")).createObject; + // Bind various functions mc.bind("print", { print(); }); mc.bind("randInt", @@ -44,6 +50,10 @@ void initMonsterScripts() (stack.popInt,stack.popInt));}); mc.bind("sleep", new IdleSleep); + // Temporary hacks + mc.bind("config", { stack.pushObject(config.mo); }); + mc.bind("music", { stack.pushObject(Music.controlM); }); + // Load and run the test script mc = new MonsterClass("Test"); mc.createObject().call("test"); diff --git a/mscripts/object.mn b/mscripts/object.mn index cfc9634b4..6a7798e64 100644 --- a/mscripts/object.mn +++ b/mscripts/object.mn @@ -24,6 +24,11 @@ // This is the base class of all OpenMW Monster classes. class Object; +// TODO: These are temporary hacks. A more elegant solution will be +// used once the language supports it. +native Config config(); +native Music music(); + // Sleeps a given amount of time idle sleep(float seconds); diff --git a/mscripts/test.mn b/mscripts/test.mn index 587a8c129..929645da0 100644 --- a/mscripts/test.mn +++ b/mscripts/test.mn @@ -10,8 +10,11 @@ state printMessage { // This state code will run as long as the object is in this state. begin: - sleep(15); + sleep(10); + + loop: print("Howdy from the world of Monster scripts!"); print("This script is located in mscripts/test.mn. Check it out!"); - goto begin; + sleep(60); + goto loop; } diff --git a/openmw.d b/openmw.d index 553ce6e05..7e86c9fbb 100644 --- a/openmw.d +++ b/openmw.d @@ -260,11 +260,11 @@ void main(char[][] args) // Insert the meshes of statics into the scene foreach(ref LiveStatic ls; cd.statics) - putObject(ls.m.model, &ls.base.pos, ls.base.scale, true); + putObject(ls.m.model, ls.getPos(), ls.getScale(), true); // Inventory lights foreach(ref LiveLight ls; cd.lights) { - NodePtr n = putObject(ls.m.model, &ls.base.pos, ls.base.scale); + NodePtr n = putObject(ls.m.model, ls.getPos(), ls.getScale()); ls.lightNode = attachLight(n, ls.m.data.color, ls.m.data.radius); if(!noSound) { @@ -274,16 +274,19 @@ void main(char[][] args) writefln("Dynamic light %s has sound %s", ls.m.id, s.id); ls.loopSound = soundScene.insert(s, true); if(ls.loopSound) - ls.loopSound.setPos(ls.base.pos.position[0], - ls.base.pos.position[1], - ls.base.pos.position[2]); + { + auto p = ls.getPos(); + ls.loopSound.setPos(p.position[0], + p.position[1], + p.position[2]); + } } } } // Static lights foreach(ref LiveLight ls; cd.statLights) { - NodePtr n = putObject(ls.m.model, &ls.base.pos, ls.base.scale, true); + NodePtr n = putObject(ls.m.model, ls.getPos(), ls.getScale(), true); ls.lightNode = attachLight(n, ls.m.data.color, ls.m.data.radius); if(!noSound) { @@ -293,56 +296,59 @@ void main(char[][] args) writefln("Static light %s has sound %s", ls.m.id, s.id); ls.loopSound = soundScene.insert(s, true); if(ls.loopSound) - ls.loopSound.setPos(ls.base.pos.position[0], - ls.base.pos.position[1], - ls.base.pos.position[2]); + { + auto p = ls.getPos(); + ls.loopSound.setPos(p.position[0], + p.position[1], + p.position[2]); + } } } } // Misc items foreach(ref LiveMisc ls; cd.miscItems) - putObject(ls.m.model, &ls.base.pos, ls.base.scale); + putObject(ls.m.model, ls.getPos(), ls.getScale()); /* // NPCs (these are complicated, usually do not have normal meshes) foreach(ref LiveNPC ls; cd.npcs) - putObject(ls.m.model, &ls.base.pos, ls.base.scale); + putObject(ls.m.model, ls.getPos(), ls.getScale()); */ // Containers foreach(ref LiveContainer ls; cd.containers) - putObject(ls.m.model, &ls.base.pos, ls.base.scale, true); + putObject(ls.m.model, ls.getPos(), ls.getScale(), true); // Doors foreach(ref LiveDoor ls; cd.doors) - putObject(ls.m.model, &ls.base.pos, ls.base.scale); + putObject(ls.m.model, ls.getPos(), ls.getScale()); // Activators (including beds etc) foreach(ref LiveActivator ls; cd.activators) - putObject(ls.m.model, &ls.base.pos, ls.base.scale, true); + putObject(ls.m.model, ls.getPos(), ls.getScale(), true); // Potions foreach(ref LivePotion ls; cd.potions) - putObject(ls.m.model, &ls.base.pos, ls.base.scale); + putObject(ls.m.model, ls.getPos(), ls.getScale()); // Apparatus foreach(ref LiveApparatus ls; cd.appas) - putObject(ls.m.model, &ls.base.pos, ls.base.scale); + putObject(ls.m.model, ls.getPos(), ls.getScale()); // Ingredients foreach(ref LiveIngredient ls; cd.ingredients) - putObject(ls.m.model, &ls.base.pos, ls.base.scale); + putObject(ls.m.model, ls.getPos(), ls.getScale()); // Armors foreach(ref LiveArmor ls; cd.armors) - putObject(ls.m.model, &ls.base.pos, ls.base.scale); + putObject(ls.m.model, ls.getPos(), ls.getScale()); // Weapons foreach(ref LiveWeapon ls; cd.weapons) - putObject(ls.m.model, &ls.base.pos, ls.base.scale); + putObject(ls.m.model, ls.getPos(), ls.getScale()); // Books foreach(ref LiveBook ls; cd.books) - putObject(ls.m.model, &ls.base.pos, ls.base.scale); + putObject(ls.m.model, ls.getPos(), ls.getScale()); // Clothes foreach(ref LiveClothing ls; cd.clothes) - putObject(ls.m.model, &ls.base.pos, ls.base.scale); + putObject(ls.m.model, ls.getPos(), ls.getScale()); // Tools foreach(ref LiveTool ls; cd.tools) - putObject(ls.m.model, &ls.base.pos, ls.base.scale); + putObject(ls.m.model, ls.getPos(), ls.getScale()); // Creatures (not displayed very well yet) foreach(ref LiveCreature ls; cd.creatures) - putObject(ls.m.model, &ls.base.pos, ls.base.scale); + putObject(ls.m.model, ls.getPos(), ls.getScale()); // Initialize the internal input and event manager. The // lower-level input system (OIS) is initialized by the @@ -350,7 +356,8 @@ void main(char[][] args) initializeInput(); // Start swangin' - if(!noSound) jukebox.play(); + if(!noSound) + Music.play(); // Run it until the user tells us to quit startRendering(); diff --git a/scene/celldata.d b/scene/celldata.d index ea65511df..6fcb01e82 100644 --- a/scene/celldata.d +++ b/scene/celldata.d @@ -28,6 +28,7 @@ import std.stdio; public import esm.esmmain; import core.memory; +import monster.monster; import util.reglist; @@ -38,71 +39,26 @@ import sound.audio; import scene.player; -// Base properties common to all live objects. Currently extremely -// sketchy. TODO: This will all be handled in Monster script at some -// point. -struct LiveObjectBase -{ - // Should this stuff be in here? - bool disabled; // Disabled in game - bool deleted; // Deleted relative to plugin file - - // Used for objects created in-game, like custom potions or - // enchanted items. These can be completely deleted. It is also used - // for creatures created from leveled lists. - bool transient; - - // Is this a door that teleports to another cell? - bool teleport; - - // Scale, 1.0 is normal. - float scale; - - // Owner of an object / activator - char[] owner; - - // A global variable? Don't know what it's used for. - char[] global; - - // Reference to a soul trapped creature? - char[] soul; - - // Faction owner? Rank? - char[] cnam; - int indx; - - // Magic value / health / uses of an item? - float xchg; - - // ?? See comment below - int intv, nam9; - - // Destination for a door - Placement destPos; - char[] destCell; - - // Lock level? - int fltv; - - // For locked doors and containers - char[] key, trap; - - // Position in 3D world - Placement pos; - - // ?? - byte unam; - - // TODO: Scripts -} - // Generic version of a "live" object struct GenLive(T) { - // This HAS to be a pointer, since we load the LOB after copying the - // LiveWhatever into the linked list. - LiveObjectBase *base; + // Instance of class CellObject or a derived class (depending on + // object type) + MonsterObject *obj; T *m; + + Placement *getPos() + { + assert(obj !is null); + // This belongs in HACK-land + return cast(Placement*)obj.getFloatPtr("x"); + } + + float getScale() + { + assert(obj !is null); + return obj.getFloat("scale"); + } } alias GenLive!(Static) LiveStatic; @@ -121,16 +77,27 @@ alias GenLive!(Door) LiveDoor; alias GenLive!(Misc) LiveMisc; alias GenLive!(Container) LiveContainer; +// TODO: This is sort of redundant. Eliminate or rework it later. struct LiveLight { - LiveObjectBase *base; + MonsterObject *obj; Light *m; + Placement *getPos() + { + assert(obj !is null); + // This belongs in HACK-land + return cast(Placement*)obj.getFloatPtr("x"); + } + + float getScale() + { + assert(obj !is null); + return obj.getFloat("scale"); + } + NodePtr lightNode; SoundInstance *loopSound; - - // Lifetime left, in seconds? - float time; } class CellData @@ -172,6 +139,9 @@ class CellData { reg = r; killCell(); // Make sure all data is initialized. + + // Set up the Monster classes if it's not done already + setup(); } // Kills all data and initialize the object for reuse. @@ -286,7 +256,22 @@ class CellData loadReferences(); } - private void loadReferences() + private: + + static + MonsterClass cellObjC, doorC, lightC, lockedC; + + void setup() + { + if(cellObjC !is null) return; + + cellObjC = new MonsterClass("CellObject"); + doorC = new MonsterClass("Door"); + lightC = new MonsterClass("Light"); + lockedC = new MonsterClass("LockedObject"); + } + + void loadReferences() { with(esFile) { @@ -315,19 +300,18 @@ class CellData Item itm = cellRefs.lookup(refr); ItemT it = ItemT(itm); - // Create a new base object that holds all our reference - // data. - LiveObjectBase *base = reg.newT!(LiveObjectBase)(); + MonsterObject *mo; // These should be ordered according to how commonly they - // occur and how large the reference lists are. + // occur. - // Static mesh - probably the most common + // Static mesh - probably the most common object type if(Static *s = it.getStatic()) { LiveStatic ls; ls.m = s; - ls.base = base; + ls.obj = cellObjC.createObject; + mo = ls.obj; statics.insert(ls); stat = true; } @@ -336,7 +320,8 @@ class CellData { LiveMisc ls; ls.m = m; - ls.base = base; + ls.obj = cellObjC.createObject; + mo = ls.obj; miscItems.insert(ls); } // Lights and containers too @@ -344,20 +329,25 @@ class CellData { LiveLight ls; ls.m = m; - ls.base = base; + ls.obj = lightC.createObject; + mo = ls.obj; - ls.time = m.data.time; + mo.setFloat("lifetime", m.data.time); + bool carry = (m.data.flags&Light.Flags.Carry) != 0; + mo.setBool("carry", carry); - if(m.data.flags&Light.Flags.Carry) + if(carry) lights.insert(ls); else statLights.insert(ls); } + else if(Container *c = it.getContainer()) { LiveContainer ls; ls.m = c; - ls.base = base; + ls.obj = lockedC.createObject; + mo = ls.obj; containers.insert(ls); container = true; } @@ -366,7 +356,8 @@ class CellData { LiveDoor ls; ls.m = d; - ls.base = base; + ls.obj = doorC.createObject; + mo = ls.obj; doors.insert(ls); door = true; } @@ -375,7 +366,8 @@ class CellData { LiveActivator ls; ls.m = a; - ls.base = base; + ls.obj = cellObjC.createObject; + mo = ls.obj; activators.insert(ls); activator = true; } @@ -384,84 +376,96 @@ class CellData { LiveNPC ls; ls.m = n; - ls.base = base; + ls.obj = cellObjC.createObject; + mo = ls.obj; npcs.insert(ls); } else if(Potion *p = it.getPotion()) { LivePotion ls; ls.m = p; - ls.base = base; + ls.obj = cellObjC.createObject; + mo = ls.obj; potions.insert(ls); } else if(Apparatus *m = it.getApparatus()) { LiveApparatus ls; ls.m = m; - ls.base = base; + ls.obj = cellObjC.createObject; + mo = ls.obj; appas.insert(ls); } else if(Ingredient *m = it.getIngredient()) { LiveIngredient ls; ls.m = m; - ls.base = base; + ls.obj = cellObjC.createObject; + mo = ls.obj; ingredients.insert(ls); } else if(Armor *m = it.getArmor()) { LiveArmor ls; ls.m = m; - ls.base = base; + ls.obj = cellObjC.createObject; + mo = ls.obj; armors.insert(ls); } else if(Weapon *m = it.getWeapon()) { LiveWeapon ls; ls.m = m; - ls.base = base; + ls.obj = cellObjC.createObject; + mo = ls.obj; weapons.insert(ls); } else if(Book *m = it.getBook()) { LiveBook ls; ls.m = m; - ls.base = base; + ls.obj = cellObjC.createObject; + mo = ls.obj; books.insert(ls); } else if(Clothing *m = it.getClothing()) { LiveClothing ls; ls.m = m; - ls.base = base; + ls.obj = cellObjC.createObject; + mo = ls.obj; clothes.insert(ls); } else if(Tool *m = it.getPick()) { LiveTool ls; ls.m = m; - ls.base = base; + ls.obj = cellObjC.createObject; + mo = ls.obj; tools.insert(ls); } else if(Tool *m = it.getProbe()) { LiveTool ls; ls.m = m; - ls.base = base; + ls.obj = cellObjC.createObject; + mo = ls.obj; tools.insert(ls); } else if(Tool *m = it.getRepair()) { LiveTool ls; ls.m = m; - ls.base = base; + ls.obj = cellObjC.createObject; + mo = ls.obj; tools.insert(ls); } else if(Creature *c = it.getCreature()) { LiveCreature ls; ls.m = c; - ls.base = base; + ls.obj = cellObjC.createObject; + mo = ls.obj; creatures.insert(ls); } else if(LeveledCreatures *l = it.getCreatureList) @@ -471,7 +475,7 @@ class CellData ls.m = l.instCreature(playerData.level); if(ls.m != null) { - ls.base = base; + ls.obj = cellObjC.createObject; mo = ls.obj; creatures.insert(ls); } } @@ -480,16 +484,10 @@ class CellData // Now that the object has found it's place, load data // into base. - with(*base) + with(*mo) { - // ALL variables must be initialized here - disabled = false; - deleted = false; - transient = false; - teleport = false; - // Scale - scale = getHNOFloat("XSCL", 1.0); + setFloat("scale", getHNOFloat("XSCL", 1.0)); // Statics only need the position data. Skip the // unneeded calls to isNextSub() as an optimization. @@ -497,25 +495,28 @@ class CellData // An NPC that owns this object (and will get angry if // you steal it) - owner = getHNOString("ANAM"); + setString8("owner", getHNOString("ANAM")); - // ??? I have no idea, link to a global variable - global = getHNOString("BNAM"); + // I have no idea, link to a global variable perhaps? + setString8("global", getHNOString("BNAM")); // ID of creature trapped in a soul gem (?) - soul = getHNOString("XSOL"); + setString8("soul", getHNOString("XSOL")); // ?? CNAM has a faction name, might be for // objects/beds etc belonging to a faction. - cnam = getHNOString("CNAM"); + { + char[] cnam = getHNOString("CNAM"); + setString8("cnam", cnam); - // INDX might be PC faction rank required to use the - // item? Sometimes is -1. - if(cnam.length) indx = getHNInt("INDX"); + // INDX might be PC faction rank required to use the + // item? Sometimes is -1. + if(cnam.length) setInt("indx", getHNInt("INDX")); + } // Possibly weapon health, number of uses left or // weapon magic charge? - xchg = getHNOFloat("XCHG", 0.0); + setFloat("xchg", getHNOFloat("XCHG", 0.0)); // I have no idea, these are present some times, often // along with owner (ANAM) and sometimes otherwise. Is @@ -523,57 +524,71 @@ class CellData // lights. Perhaps something to do with remaining // light "charge". I haven't tried reading it as a // float in those cases. - intv = getHNOInt("INTV", 0); - nam9 = getHNOInt("NAM9", 0); + setInt("intv", getHNOInt("INTV", 0)); + setInt("nam9", getHNOInt("NAM9", 0)); // Present for doors that teleport you to another // cell. if(door && isNextSub("DODT")) { - teleport = true; - readHExact(&destPos, destPos.sizeof); + setBool("teleport", true); + + // Warning, HACK! Will be fixed when we implement + // structs in Monster. + Placement *p = cast(Placement*)getFloatPtr("destx"); + readHExact(p, Placement.sizeof); - // Destination cell (optitional?) - destCell = getHNOString("DNAM"); + // Destination cell (optional?) + setString8("destCell", getHNOString("DNAM")); } if(door || container) { // Lock level (I think) - fltv = getHNOInt("FLTV", 0); + setInt("lockLevel", getHNOInt("FLTV", 0)); // For locked doors and containers - key = getHNOString("KNAM"); - trap = getHNOString("TNAM"); + setString8("key", getHNOString("KNAM")); + setString8("trap", getHNOString("TNAM")); } if(activator) { // Occurs ONCE in Morrowind.esm, for an activator. - unam = getHNOByte("UNAM", 0); + setInt("unam", getHNOByte("UNAM", 0)); // Occurs in Tribunal.esm, eg. in the cell // "Mournhold, Plaza Brindisi Dorom", where it has // the value 100. - fltv = getHNOInt("FLTV", 0); + setInt("fltv", getHNOInt("FLTV", 0)); } readpos: - // Position of this object within the cell - readHNExact(&pos, Placement.sizeof, "DATA"); + + // Position and rotation of this object within the + // cell + + // TODO: This is a HACK. It assumes the class variable + // floats are placed consecutively in memory in the + // right order. This is true, but is a very bug prone + // method of doing this. Will fix when Monster gets + // structs. (See the DODT record above also.) + Placement *pos = cast(Placement*)getFloatPtr("x"); + readHNExact(pos, Placement.sizeof, "DATA"); // TODO/FIXME: Very temporary. Set player position at // the first door we find. if(door && !playerData.posSet) { playerData.posSet = true; - playerData.position = pos; + playerData.position = *pos; } - } - } + } + } // End of while(hasMoreSubs) } - } -} + + } // End of loadReferences() +} // End of class CellData CellFreelist cellList; diff --git a/sound/audio.d b/sound/audio.d index 4b3544081..546479b68 100644 --- a/sound/audio.d +++ b/sound/audio.d @@ -37,9 +37,6 @@ class SoundException : Exception this(char[] caller, char[] msg) { super(caller ~ " SoundException: " ~ msg); } } -MusicManager jukebox; -MusicManager battleMusic; - ALCdevice *Device = null; ALCcontext *Context = null; @@ -54,16 +51,12 @@ void initializeSound() alcMakeContextCurrent(Context); - MusicManager.sinit(); - - jukebox.initialize("Main"); - battleMusic.initialize("Battle"); + Music.init(); } void shutdownSound() { - jukebox.shutdown(); - battleMusic.shutdown(); + Music.shutdown(); alcMakeContextCurrent(null); if(Context) alcDestroyContext(Context); @@ -72,10 +65,17 @@ void shutdownSound() Device = null; } -void checkALError(char[] what = "") +float saneVol(float vol) +{ + if(!(vol >= 0)) vol = 0; + else if(!(vol <= 1)) vol = 1; + return vol; +} + +void checkALError(char[] what) { ALenum err = alGetError(); - if(what.length) what = " while " ~ what; + what = " while " ~ what; if(err != AL_NO_ERROR) throw new Exception(format("OpenAL error%s: (%x) %s", what, err, toString(alGetString(err)))); diff --git a/sound/music.d b/sound/music.d index fac3a9677..72fb19c40 100644 --- a/sound/music.d +++ b/sound/music.d @@ -42,30 +42,121 @@ class Idle_waitUntilFinished : IdleFunction bool hasFinished(MonsterObject *mo) { - MusicManager *mgr = cast(MusicManager*)mo.extra; + Jukebox mgr = cast(Jukebox)mo.extra; // Return when the music is no longer playing return !mgr.isPlaying(); } } -// Simple music player, has a playlist and can pause/resume music. -struct MusicManager +struct Music +{ + private: + static: + + // The Monster classes and objects + MonsterClass jukeC, controlC; + + public: + + MonsterObject *controlM; + + void init() + { + assert(jukeC is null); + assert(controlC is null); + assert(controlM is null); + + jukeC = MonsterClass.get("Jukebox"); + jukeC.bind("waitUntilFinished", + new Idle_waitUntilFinished); + + jukeC.bind("setSound", { Jukebox.get().setSound(); }); + jukeC.bind("setVolume", { Jukebox.get().setVolume(); }); + jukeC.bind("playSound", { Jukebox.get().playSound(); }); + jukeC.bind("stopSound", { Jukebox.get().stopSound(); }); + + jukeC.bindConst({new Jukebox(params.obj()); }); + + controlC = MonsterClass.get("Music"); + controlM = controlC.createObject; + controlM.call("setup"); + } + + private void pushSArray(char[][] strs) + { + AIndex arr[]; + arr.length = strs.length; + + // Create the array indices for each element string + foreach(i, ref elm; arr) + elm = arrays.create(strs[i]).getIndex(); + + // Push the final array + stack.pushArray(arr); + } + + void setPlaylists(char[][] normal, char[][] battle) + { + pushSArray(normal); + pushSArray(battle); + controlM.call("setPlaylists"); + } + + void play() + { + if(controlM !is null) + controlM.call("play"); + } + + void toggle() + { + if(controlM !is null) + controlM.call("toggle"); + } + + void toggleMute() + { + if(controlM !is null) + controlM.call("toggleMute"); + } + + void updateBuffers() + { + foreach(ref MonsterObject b; jukeC) + Jukebox.get(b).updateBuffers(); + } + + void shutdown() + { + foreach(ref MonsterObject b; jukeC) + Jukebox.get(b).shutdown(); + } +} + +// Simple music player, has a playlist and can pause/resume +// music. Most of the high-level code is in mscripts/jukebox.mn. +class Jukebox { private: // Maximum buffer length, divided up among OpenAL buffers const uint bufLength = 128*1024; + const uint numBufs = 4; - char[] name; + char[] getName() + { + if(mo is null) return "(no name)"; + else return mo.getString8("name"); + } void fail(char[] msg) { - throw new SoundException(name ~ " Jukebox", msg); + throw new SoundException(getName() ~ " Jukebox", msg); } ALuint sID; // Sound id - ALuint bIDs[4]; // Buffers + ALuint bIDs[numBufs]; // Buffers ALenum bufFormat; ALint bufRate; @@ -75,82 +166,61 @@ struct MusicManager static ubyte[] outData; - // The Jukebox class - static MonsterClass mc; + static this() + { + outData.length = bufLength / numBufs; + } // The jukebox Monster object MonsterObject *mo; public: - static MusicManager *get() - { return cast(MusicManager*)params.obj().extra; } - - static void sinit() + this(MonsterObject *m) { - assert(mc is null); - mc = new MonsterClass("Jukebox", "jukebox.mn"); - mc.bind("waitUntilFinished", - new Idle_waitUntilFinished); - - mc.bind("setSound", { get().setSound(); }); - mc.bind("setVolume", { get().setVolume(); }); - mc.bind("playSound", { get().playSound(); }); - mc.bind("stopSound", { get().stopSound(); }); + mo = m; + m.extra = cast(void*)this; - outData.length = bufLength / bIDs.length; - } - - // Initialize the jukebox - void initialize(char[] name) - { - this.name = name; sID = 0; bIDs[] = 0; - fileHandle = null; - - mo = mc.createObject(); - mo.extra = this; } - // Called whenever the volume configuration values are changed by - // the user. - void updateVolume() - { - stack.pushFloat(config.calcMusicVolume()); - mo.call("updateVolume"); - } + static Jukebox get(MonsterObject *m) + { + auto j = cast(Jukebox)m.extra; + assert(j !is null); + assert(j.mo == m); + return j; + } - // Give a music play list - void setPlaylist(char[][] pl) - { - AIndex arr[]; - arr.length = pl.length; + static Jukebox get(ref MonsterObject m) + { return get(&m); } - // Create the array indices for each element string - foreach(i, ref elm; arr) - elm = arrays.create(pl[i]).getIndex(); + static Jukebox get() + { return get(params.obj()); } - // Push the final array - stack.pushArray(arr); + private: - mo.call("setPlaylist"); - } + // Disable music + void shutdown() + { + mo.call("stop"); - // Pause current track - void pause() { mo.call("pause"); } + if(fileHandle) avc_closeAVFile(fileHandle); + fileHandle = null; + audioHandle = null; - // Resume. Starts playing sound, with fade in - void resume() - { - if(!config.useMusic) return; - mo.call("resume"); - } + if(sID) + { + alSourceStop(sID); + alDeleteSources(1, &sID); + checkALError("disabling music"); + sID = 0; - void play() - { - if(!config.useMusic) return; - mo.call("play"); + alDeleteBuffers(bIDs.length, bIDs.ptr); + checkALError("deleting buffers"); + bIDs[] = 0; + } } void setSound() @@ -158,7 +228,7 @@ struct MusicManager char[] fname = stack.popString8(); // Generate a source to play back with if needed - if(!sID) + if(sID == 0) { alGenSources(1, &sID); checkALError("generating buffers"); @@ -167,17 +237,17 @@ struct MusicManager alSourcei(sID, AL_SOURCE_RELATIVE, AL_TRUE); alGenBuffers(bIDs.length, bIDs.ptr); - - updateVolume(); } else { // Kill current track, but keep the sID source. alSourceStop(sID); + checkALError("stopping current track"); + alSourcei(sID, AL_BUFFER, 0); //alDeleteBuffers(bIDs.length, bIDs.ptr); //bIDs[] = 0; - checkALError("killing current track"); + checkALError("resetting buffer"); } if(fileHandle) avc_closeAVFile(fileHandle); @@ -230,7 +300,8 @@ struct MusicManager } if(bufFormat == 0) - fail(format("Unhandled format (%d channels, %d bits) for music track %s", ch, bits, fname)); + fail(format("Unhandled format (%d channels, %d bits) for music track %s", + ch, bits, fname)); // Fill the buffers foreach(int i, ref b; bIDs) @@ -257,14 +328,15 @@ struct MusicManager { float volume = stack.popFloat(); + volume = saneVol(volume); + // Set the new volume if(sID) alSourcef(sID, AL_GAIN, volume); } void playSound() { - if(!sID || !config.useMusic) - return; + if(!sID) return; alSourcePlay(sID); checkALError("starting music"); @@ -280,6 +352,7 @@ struct MusicManager { ALint state; alGetSourcei(sID, AL_SOURCE_STATE, &state); + checkALError("getting status"); return state == AL_PLAYING; } @@ -293,7 +366,7 @@ struct MusicManager ALint count; alGetSourcei(sID, AL_BUFFERS_PROCESSED, &count); - checkALError(); + checkALError("getting number of unprocessed buffers"); for(int i = 0;i < count;i++) { @@ -307,30 +380,8 @@ struct MusicManager { alBufferData(bid, bufFormat, outData.ptr, length, bufRate); alSourceQueueBuffers(sID, 1, &bid); - checkALError(); + checkALError("queueing buffers"); } } } - - // Disable music - void shutdown() - { - mo.call("stop"); - - if(fileHandle) avc_closeAVFile(fileHandle); - fileHandle = null; - audioHandle = null; - - if(sID) - { - alSourceStop(sID); - alDeleteSources(1, &sID); - checkALError("disabling music"); - sID = 0; - } - - alDeleteBuffers(bIDs.length, bIDs.ptr); - checkALError(); - bIDs[] = 0; - } } diff --git a/util/reglist.d b/util/reglist.d index 111c405f0..ccbc59370 100644 --- a/util/reglist.d +++ b/util/reglist.d @@ -72,7 +72,6 @@ struct RegionList(Value) public: - alias Node* Iterator; // Equivalent to calling remove() on all elements