• There is NO official Otland's Discord server and NO official Otland's server list. The Otland's Staff does not manage any Discord server or server list. Moderators or administrator of any Discord server or server lists have NO connection to the Otland's Staff. Do not get scammed!

Enhanced sound module

tarjei

Necronian Engineer
Joined
May 25, 2008
Messages
505
Reaction score
126
Location
Poland
Hello!

This weekend I was trying to enhance the sound module originaly posted by Shawak (origina post here: [Mod] Sound System . As I mentioned in there, it had one significat flaw I didn't like -> it was iterating table of sound zones, which were rectangles. That's cool if you don't want to define many zones, however sooner or later it stops beeing scalable.
Therefore, I implemented kd-tree which is able to locate nearby zones within few steps, even if you have 100k sound zones defined :)
It still has some flaws and areas to improve however, it brings a nice optimization, I wanted to share, so here we go :D
First grab this from my repository, and put in client main folder :
GitHub - Tarjei400/lua-tools

Great half way done. Now add this preferable to init.lua
I removed some gui stuff from there, but you can restore it from Shawak's script if you want to ;)
[code/lua]dofile('lua-tools/main.lua')[/code]

And here is the modified file:
rcsound.lua:

Lua:
Polygon.polygons = {}
local CONQUERIA = Polygon()
CONQUERIA:addPoint(1528, 1547)
CONQUERIA:addPoint(1537, 1547)
CONQUERIA:addPoint(1537, 1557)
CONQUERIA:addPoint(1528, 1557)
CONQUERIA.sound = "Fairy Tail - Main.ogg"
CONQUERIA.fadeIn = 3
CONQUERIA.priority = 1
CONQUERIA:normalize()

for i = 1, 100 do
    local CONQUERIA2 = CONQUERIA:move(30*(i-1),30*i)
    CONQUERIA2.sound = "Fairy Tail - Main.ogg"
    CONQUERIA2.priority = 1
    CONQUERIA2.fadeIn = 3
end
local centroids = Polygon.calculateAllCentroids();
local SoundZoneTree = KDTree(centroids);

SOUNDS_CONFIG = {
    soundChannel = 1,
    checkInterval = 1000,
    folder = 'music/',
    noSound = 'No sound file for this area.',
}


-- Sound
local rcSoundChannel
local showPosEvent
local playingSound

-- Design
soundWindow = nil

function init()
    for k, v in pairs(Polygon.polygons) do
        v.sound = SOUNDS_CONFIG.folder .. v.sound
    end
 
    connect(g_game, { onGameStart = onGameStart,
                    onGameEnd = onGameEnd })
 
    rcSoundChannel = g_sounds.getChannel(SOUNDS_CONFIG.soundChannel)

    if(g_game.isOnline()) then
        onGameStart()
    end
end

function terminate()
    disconnect(g_game, { onGameStart = onGameStart,
                       onGameEnd = onGameEnd })
    onGameEnd()
end

function onGameStart()
    stopSound()
    toggleSoundEvent = addEvent(toggleSound, SOUNDS_CONFIG.checkInterval)
end

function onGameEnd()
    stopSound()
    removeEvent(toggleSoundEvent)
end

local SongFadingOut = false;
local CurrentZone = nil
function toggleSound()

    local player = g_game.getLocalPlayer()
    if not player then return end
 
    local pos = player:getPosition()
    local toPlay = nil

    local searchPos = Point(pos.x, pos.y)

    if CurrentZone ~= nil then
        if CurrentZone:contains(searchPos) then
               toggleSoundEvent = scheduleEvent(toggleSound, SOUNDS_CONFIG.checkInterval)
               return
        else
            CurrentZone = nil
        end
    end
    local zones = {}
    local p = SoundZoneTree:nearestTo(searchPos, function(lNorm, rNorm, node)
            local poly = node.point.polygon
            table.insert(zones, poly)
            return lNorm < rNorm
    end)


    playingSound = playingSound or {sound='', priority=0, fadeIn = 0}

        local inZones = 0
        for k, zone in pairs(zones)do
            if zone:contains(searchPos) then
                toPlay = zone
                inZones = inZones + 1
                if(toPlay~=nil and playingSound.sound~=toPlay.sound) then
                    g_logger.info("RC Sounds: New sound area detected:")
                    g_logger.info("  Position: {x=" .. pos.x .. ", y=" .. pos.y .. ", z=" .. pos.z .. "}")
                    g_logger.info("  Music: " .. toPlay.sound)
                    stopSound(toPlay.fadeIn)
                    playSound(toPlay.sound, toPlay.fadeIn)
                    playingSound = toPlay
                    CurrentZone = zone
                    break
                end
            end
        end
        if(inZones == 0 and not (SongFadingOut) and playingSound ~= nil) then
             g_logger.info("RC Sounds: New sound area detected:")
             g_logger.info("  Left music area.")
             SongFadingOut = true
             scheduleEvent(function()
                SongFadingOut = false
             end, 1000*playingSound.fadeIn)
             stopSound(playingSound.fadeIn)
        end

    toggleSoundEvent = scheduleEvent(toggleSound, SOUNDS_CONFIG.checkInterval)
end


function playSound(sound, fadeIn)
    rcSoundChannel:enqueue(sound, fadeIn)
end

function clearName(soundName)
    local explode = string.explode(soundName, "/")
    soundName = explode[#explode]
    explode = string.explode(soundName, ".ogg")
    soundName = ''
    for i = 1, #explode-1 do
        soundName = soundName .. explode[i]
    end
    return soundName
end

function stopSound(fadeIn)
    rcSoundChannel:stop(fadeIn)
    playingSound = nil
end
 
Last edited:
Anyone has any idea how does this system work? Original one is by setting map coords, and here I can't seem to figure out how it's supposed to be specified
 
Back
Top