winning, losing, war2 music types

This commit is contained in:
Luke Hubmayer-Werner 2020-06-06 23:15:09 +09:30
parent c003e8f38b
commit 95b4e08ebd
1 changed files with 163 additions and 145 deletions

View File

@ -42,30 +42,56 @@ options = {
desc = "Music pauses with game", desc = "Music pauses with game",
noHotkey = true, noHotkey = true,
}, },
attritionRatioLosing = {
name = "Attrition Ratio: Losing",
type = "number",
value = 0.4,
min = 0.1,
max = 1.0,
step = 0.05,
desc = "Music switches to Losing when recent attrition ratio falls below this value",
noHotkey = true,
},
attritionRatioWinning = {
name = "Attrition Ratio: Winning",
type = "number",
value = 3.0,
min = 1.0,
max = 8.0,
step = 0.25,
desc = "Music switches to Winning when recent attrition ratio rises above this value",
noHotkey = true,
},
} }
local unitExceptions = include("Configs/snd_music_exception.lua") local unitExceptions = include("Configs/snd_music_exception.lua")
local windows = {} local windows = {}
local warThreshold = 5000 local moodPriorities = {peace=0, war=1, war2=2, winning=4, losing=4, briefing=10, victory=10, defeat=10} -- Determines which music moods will instantly interrupt others, and which will wait for playing track to finish
local peaceThreshold = 1000 local moodDynamic = {peace=true, war=true, war2=true, winning=true, losing=true, briefing=false, victory=false, defeat=false} -- Determines which music moods will instantly interrupt others, and which will wait for playing track to finish
local war2Threshold = 400000
local warThreshold = 50000
local peaceThreshold = 10000
local PLAYLIST_FILE = "sounds/music/playlist.lua" local PLAYLIST_FILE = "sounds/music/playlist.lua"
local LOOP_BUFFER = 0.015 -- if looping track is this close to the end, go ahead and loop local LOOP_BUFFER = 0.015 -- if looping track is this close to the end, go ahead and loop
local UPDATE_PERIOD = 1 local UPDATE_PERIOD = 1
local musicType = "peace" local musicType = "peace"
local warPointsIter = 1 -- Position in circular buffer. 1-indexed because L[ew]a local warPointsIter = 1 -- Position in circular buffer. 1-indexed because L[ew]a
local warPointsSize = 30 -- Size of circular buffer. Sampling is currently hardcoded but might change later. local warPointsSize = 90 -- Size of circular buffer. Sampling is currently hardcoded but might change later.
local warPointsFriendly = {} -- keeps track of the number of doods killed in each time frame local dmgPointsFriendly = {} -- keeps track of the number of doods killed in each time frame
local warPointsHostile = {} local dmgPointsHostile = {}
local deathPointsFriendly = {} -- metal costs of destroyed units
local deathPointsHostile = {}
local warPointsRollover = 4000000000 -- Roll back to zero after this many have accumulated local warPointsRollover = 4000000000 -- Roll back to zero after this many have accumulated
local timeframetimer = 0 local timeframetimer = 0
local timeframetimer_short = 0 local timeframetimer_short = 0
local loopTrack = "" local loopTrack = ""
local previousTrack = "" local previousTrack = ""
local previousTrackType = "" local prevMusicType = ""
local newTrackWait = 1000 local newTrackWait = 1000
local numVisibleFriendly = 0
local numVisibleEnemy = 0 local numVisibleEnemy = 0
local fadeVol local fadeVol
local curTrac = "no name" local curTrac = "no name"
@ -120,7 +146,7 @@ local function StartTrack(track)
local newTrack = previousTrack local newTrack = previousTrack
if musicType == "custom" then if musicType == "custom" then
previousTrackType = "peace" prevMusicType = "peace"
musicType = "peace" musicType = "peace"
end end
if (not gameStarted) then if (not gameStarted) then
@ -139,20 +165,10 @@ local function StartTrack(track)
end end
end end
-- for key, val in pairs(oggInfo) do
-- Spring.Echo(key, val)
-- end
firstFade = false firstFade = false
previousTrack = newTrack previousTrack = newTrack
-- if (oggInfo.comments.TITLE and oggInfo.comments.TITLE) then
-- Spring.Echo("Song changed to: " .. oggInfo.comments.TITLE .. " By: " .. oggInfo.comments.ARTIST)
-- else
-- Spring.Echo("Song changed but unable to get the artist and title info")
-- end
Spring.Echo ("game_message: Changing music to " .. newTrack)
curTrack = newTrack curTrack = newTrack
Spring.PlaySoundStream(newTrack,WG.music_volume or 0.5) Spring.PlaySoundStream(newTrack, WG.music_volume or 0.5)
WG.music_start_volume = WG.music_volume WG.music_start_volume = WG.music_volume
end end
@ -197,131 +213,156 @@ function InitializeTracks()
local vfsMode = (options.useIncludedTracks.value and VFS.RAW_FIRST) or VFS.RAW local vfsMode = (options.useIncludedTracks.value and VFS.RAW_FIRST) or VFS.RAW
tracks.war = tracks.war or VFS.DirList("sounds/music/war/", "*.ogg", vfsMode) tracks.war = tracks.war or VFS.DirList("sounds/music/war/", "*.ogg", vfsMode)
tracks.war2 = tracks.war2 or VFS.DirList("sounds/music/war2/", "*.ogg", vfsMode)
tracks.winning = tracks.winning or VFS.DirList("sounds/music/winning/", "*.ogg", vfsMode)
tracks.losing = tracks.losing or VFS.DirList("sounds/music/losing/", "*.ogg", vfsMode)
tracks.peace = tracks.peace or VFS.DirList("sounds/music/peace/", "*.ogg", vfsMode) tracks.peace = tracks.peace or VFS.DirList("sounds/music/peace/", "*.ogg", vfsMode)
tracks.briefing = tracks.briefing or VFS.DirList("sounds/music/briefing/", "*.ogg", vfsMode) tracks.briefing = tracks.briefing or VFS.DirList("sounds/music/briefing/", "*.ogg", vfsMode)
tracks.victory = tracks.victory or VFS.DirList("sounds/music/victory/", "*.ogg", vfsMode) tracks.victory = tracks.victory or VFS.DirList("sounds/music/victory/", "*.ogg", vfsMode)
tracks.defeat = tracks.defeat or VFS.DirList("sounds/music/defeat/", "*.ogg", vfsMode) tracks.defeat = tracks.defeat or VFS.DirList("sounds/music/defeat/", "*.ogg", vfsMode)
end end
function widget:Update(dt) function CheckLoop()
if gameOver then local playedTime, totalTime = Spring.GetSoundStreamTime()
return paused = (playedTime == lastTrackTime)
lastTrackTime = playedTime
if looping then
if looping == 0.5 then
looping = 1
elseif playedTime >= totalTime - LOOP_BUFFER then
Spring.StopSoundStream()
Spring.PlaySoundStream(loopTrack, WG.music_volume or 0.5)
end
end end
end
function EvaluateMood()
-- (Spring.GetGameRulesParam("recentNukeLaunch") == 1) -- Might need this for superweapon music later
newTrackWait = newTrackWait + 1
numVisibleFriendly = 0
numVisibleEnemy = 0
local doods = Spring.GetVisibleUnits(-1, nil, true)
for i=1,#doods do
if Spring.IsUnitAllied(doods[i]) then
numVisibleFriendly = numVisibleFriendly + 1
else
numVisibleEnemy = numVisibleEnemy + 1
end
end
local totalKilled, friendliesKilled, hostilesKilled = 0, 0, 0
local totalDmg, friendlyDmg, hostileDmg = 0, 0, 0
local iLast = ((warPointsIter-16) % warPointsSize) + 1 -- Look back 15 periods.
local iLast2 = ((warPointsIter-61) % warPointsSize) + 1 -- Look back 60 periods.
-- Last 10 seconds count for double
friendliesKilled = friendliesKilled + ((deathPointsFriendly[warPointsIter] - deathPointsFriendly[iLast]) % warPointsRollover)
friendliesKilled = friendliesKilled + ((deathPointsFriendly[warPointsIter] - deathPointsFriendly[iLast2]) % warPointsRollover)
hostilesKilled = hostilesKilled + ((deathPointsHostile[warPointsIter] - deathPointsHostile[iLast]) % warPointsRollover)
hostilesKilled = hostilesKilled + ((deathPointsHostile[warPointsIter] - deathPointsHostile[iLast2]) % warPointsRollover)
friendlyDmg = friendlyDmg + ((dmgPointsFriendly[warPointsIter] - dmgPointsFriendly[iLast]) % warPointsRollover)
friendlyDmg = friendlyDmg + ((dmgPointsFriendly[warPointsIter] - dmgPointsFriendly[iLast2]) % warPointsRollover)
hostileDmg = hostileDmg + ((dmgPointsHostile[warPointsIter] - dmgPointsHostile[iLast]) % warPointsRollover)
hostileDmg = hostileDmg + ((dmgPointsHostile[warPointsIter] - dmgPointsHostile[iLast2]) % warPointsRollover)
totalKilled = friendliesKilled + hostilesKilled
local attritionRatio = (hostilesKilled+1)/(friendliesKilled+1) -- 1 metal is virtually nothing in the ratio, but this simplifies edge cases
totalDmg = friendlyDmg + hostileDmg
-- Roll to next index in the circular buffers, continue cumulative sum
local iNext = (warPointsIter % warPointsSize) + 1
dmgPointsFriendly[iNext] = dmgPointsFriendly[warPointsIter] % warPointsRollover
dmgPointsHostile[iNext] = dmgPointsHostile[warPointsIter] % warPointsRollover
deathPointsFriendly[iNext] = deathPointsFriendly[warPointsIter] % warPointsRollover
deathPointsHostile[iNext] = deathPointsHostile[warPointsIter] % warPointsRollover
warPointsIter = iNext
if moodDynamic[musicType] then
if (totalKilled >= warThreshold) then
musicType = "war"
if (totalKilled >= war2Threshold) then musicType = "war2" end
if attritionRatio < options.attritionRatioLosing then
musicType = "losing"
elseif attritionRatio > options.attritionRatioWinning then
musicType = "winning"
end
else --if (totalKilled <= peaceThreshold) then
musicType = "peace"
end
end
if (not firstTime) then
StartTrack()
firstTime = true
end
local playedTime, totalTime = Spring.GetSoundStreamTime()
-- playedTime = math.floor(playedTime)
-- totalTime = math.floor(totalTime)
--Spring.Echo(playedTime, totalTime, newTrackWait)
--if((totalTime - playedTime) <= 6 and (totalTime >= 1) ) then
--Spring.Echo("time left:", (totalTime - playedTime))
--Spring.Echo("volume:", (totalTime - playedTime)/6)
--if ((totalTime - playedTime)/6 >= 0) then
-- Spring.SetSoundStreamVolume((totalTime - playedTime)/6)
--else
-- Spring.SetSoundStreamVolume(0.1)
--end
--elseif(playedTime <= 5 )then--and not firstFade
--Spring.Echo("time playing:", playedTime)
--Spring.Echo("volume:", playedTime/5)
--Spring.SetSoundStreamVolume( playedTime/5)
--end
--Spring.Echo(prevMusicType, musicType)
if (prevMusicType ~= musicType and moodPriorities[musicType] >= moodPriorities[prevMusicType])
or (playedTime >= totalTime) -- both zero means track stopped
and not(haltMusic or looping) then
prevMusicType = musicType
StartTrack()
newTrackWait = 0
end
local _, _, paused = Spring.GetGameSpeed()
if (paused ~= wasPaused) and options.pausemusic.value then
Spring.PauseSoundStream()
wasPaused = paused
end
end
function widget:Update(dt)
if gameOver then return end
if not initialized then if not initialized then
math.randomseed(os.clock()* 100) math.randomseed(os.clock()* 100)
initialized=true initialized=true
-- these are here to give epicmenu time to set the values properly -- these are here to give epicmenu time to set the values properly (else it's always default at startup)
-- (else it's always default at startup)
InitializeTracks() InitializeTracks()
end end
timeframetimer_short = timeframetimer_short + dt timeframetimer_short = timeframetimer_short + dt
if timeframetimer_short > 0.03 then if timeframetimer_short > 0.03 then
local playedTime, totalTime = Spring.GetSoundStreamTime() CheckLoop()
playedTime = tonumber( ("%.2f"):format(playedTime) )
paused = (playedTime == lastTrackTime)
lastTrackTime = playedTime
if looping then
if looping == 0.5 then
looping = 1
elseif playedTime >= totalTime - LOOP_BUFFER then
Spring.StopSoundStream()
Spring.PlaySoundStream(loopTrack, WG.music_volume or 0.5)
end
end
timeframetimer_short = 0 timeframetimer_short = 0
end end
-- (Spring.GetGameRulesParam("recentNukeLaunch") == 1) -- Might need this for superweapon music later
timeframetimer = timeframetimer + dt timeframetimer = timeframetimer + dt
if (timeframetimer > UPDATE_PERIOD) then -- every second if (timeframetimer > UPDATE_PERIOD) then -- every second
EvaluateMood()
timeframetimer = 0 timeframetimer = 0
newTrackWait = newTrackWait + 1
numVisibleEnemy = 0
local doods = Spring.GetVisibleUnits(-1, nil, true)
for i=1,#doods do
if (Spring.IsUnitAllied(doods[i]) ~= true) then
numVisibleEnemy = numVisibleEnemy + 1
end
end
local totalKilled, friendliesKilled, hostilesKilled = 0, 0, 0
local iLast = ((warPointsIter-11) % warPointsSize) + 1 -- Look back 10 periods.
local iLast2 = ((warPointsIter-21) % warPointsSize) + 1 -- Look back 20 periods.
-- Last 10 seconds count for double
friendliesKilled = friendliesKilled + ((warPointsFriendly[warPointsIter] - warPointsFriendly[iLast]) % warPointsRollover)
friendliesKilled = friendliesKilled + ((warPointsFriendly[warPointsIter] - warPointsFriendly[iLast2]) % warPointsRollover)
hostilesKilled = hostilesKilled + ((warPointsHostile[warPointsIter] - warPointsHostile[iLast]) % warPointsRollover)
hostilesKilled = hostilesKilled + ((warPointsHostile[warPointsIter] - warPointsHostile[iLast2]) % warPointsRollover)
totalKilled = (friendliesKilled * 1.5) + hostilesKilled
-- Roll to next index in the circular buffers, continue cumulative sum
local iNext = (warPointsIter % warPointsSize) + 1
warPointsFriendly[iNext] = warPointsFriendly[warPointsIter] % warPointsRollover
warPointsHostile[iNext] = warPointsHostile[warPointsIter] % warPointsRollover
warPointsIter = iNext
if (musicType == "war" or musicType == "peace") then
if (totalKilled >= warThreshold) then
musicType = "war"
elseif (totalKilled <= peaceThreshold) then
musicType = "peace"
end
end
if (not firstTime) then
StartTrack()
firstTime = true
end
local playedTime, totalTime = Spring.GetSoundStreamTime()
playedTime = math.floor(playedTime)
totalTime = math.floor(totalTime)
--Spring.Echo(playedTime, totalTime)
--Spring.Echo(playedTime, totalTime, newTrackWait)
--if((totalTime - playedTime) <= 6 and (totalTime >= 1) ) then
--Spring.Echo("time left:", (totalTime - playedTime))
--Spring.Echo("volume:", (totalTime - playedTime)/6)
--if ((totalTime - playedTime)/6 >= 0) then
-- Spring.SetSoundStreamVolume((totalTime - playedTime)/6)
--else
-- Spring.SetSoundStreamVolume(0.1)
--end
--elseif(playedTime <= 5 )then--and not firstFade
--Spring.Echo("time playing:", playedTime)
--Spring.Echo("volume:", playedTime/5)
--Spring.SetSoundStreamVolume( playedTime/5)
--end
--Spring.Echo(previousTrackType, musicType)
if ( previousTrackType == "peace" and musicType == "war" )
or (playedTime >= totalTime) -- both zero means track stopped
and not(haltMusic or looping) then
previousTrackType = musicType
StartTrack()
--Spring.Echo("Track: " .. newTrack)
newTrackWait = 0
end
local _, _, paused = Spring.GetGameSpeed()
if (paused ~= wasPaused) and options.pausemusic.value then
Spring.PauseSoundStream()
wasPaused = paused
end
end end
end end
function widget:GameStart() function widget:GameStart()
if not gameStarted then if not gameStarted then
gameStarted = true gameStarted = true
previousTrackType = musicType prevMusicType = musicType
musicType = "peace" musicType = "peace"
StartTrack() StartTrack()
end end
--Spring.Echo("Track: " .. newTrack)
newTrackWait = 0 newTrackWait = 0
end end
@ -333,46 +374,24 @@ end
function widget:UnitDamaged(unitID, unitDefID, unitTeam, damage, paralyzer) function widget:UnitDamaged(unitID, unitDefID, unitTeam, damage, paralyzer)
if unitExceptions[unitDefID] then return end if unitExceptions[unitDefID] then return end
if (damage < 1.5) then return end
if (UnitDefs[unitDefID] == nil) then return end if (UnitDefs[unitDefID] == nil) then return end
if paralyzer then return end if paralyzer then return end
local multifactor = 1
if (numVisibleEnemy > 3) then
multifactor = math.log(numVisibleEnemy)
end
if (teamID == myTeam) then if (teamID == myTeam) then
warPointsFriendly[warPointsIter] = warPointsFriendly[warPointsIter] + (damage * multifactor); dmgPointsFriendly[warPointsIter] = dmgPointsFriendly[warPointsIter] + damage
else else
warPointsHostile[warPointsIter] = warPointsHostile[warPointsIter] + (damage * multifactor); dmgPointsHostile[warPointsIter] = dmgPointsHostile[warPointsIter] + damage
end end
end end
function widget:UnitDestroyed(unitID, unitDefID, teamID) function widget:UnitDestroyed(unitID, unitDefID, teamID)
if unitExceptions[unitDefID] then return end if unitExceptions[unitDefID] then return end
local unitCost = UnitDefs[unitDefID].metalCost
local unitWorth = 50
if (UnitDefs[unitDefID].metalCost > 500) then
unitWorth = 200
end
if (UnitDefs[unitDefID].metalCost > 1000) then
unitWorth = 300
end
if (UnitDefs[unitDefID].metalCost > 3000) then
unitWorth = 500
end
if (UnitDefs[unitDefID].metalCost > 8000) then
unitWorth = 700
end
local multifactor = 1
if (numVisibleEnemy > 3) then
multifactor = math.log(numVisibleEnemy)
end
if (teamID == myTeam) then if (teamID == myTeam) then
warPointsFriendly[warPointsIter] = warPointsFriendly[warPointsIter] + (unitWorth*multifactor); deathPointsFriendly[warPointsIter] = deathPointsFriendly[warPointsIter] + unitCost
else else
warPointsHostile[warPointsIter] = warPointsHostile[warPointsIter] + (unitWorth*multifactor); deathPointsHostile[warPointsIter] = deathPointsHostile[warPointsIter] + unitCost
end end
end end
@ -413,9 +432,6 @@ function widget:Initialize()
WG.Music.GetMusicType = GetMusicType WG.Music.GetMusicType = GetMusicType
WG.Music.PlayGameOverMusic = PlayGameOverMusic WG.Music.PlayGameOverMusic = PlayGameOverMusic
-- Spring.Echo(math.random(), math.random())
-- Spring.Echo(os.clock())
-- for TrackName,TrackDef in pairs(tracks.peace) do -- for TrackName,TrackDef in pairs(tracks.peace) do
-- Spring.Echo("Track: " .. TrackDef) -- Spring.Echo("Track: " .. TrackDef)
-- end -- end
@ -423,8 +439,10 @@ function widget:Initialize()
-- for i=1,20 do Spring.Echo(math.random()) end -- for i=1,20 do Spring.Echo(math.random()) end
for i = 1, warPointsSize do for i = 1, warPointsSize do
warPointsFriendly[i] = 0 dmgPointsFriendly[i] = 0
warPointsHostile[i] = 0 dmgPointsHostile[i] = 0
deathPointsFriendly[i] = 0
deathPointsHostile[i] = 0
end end
end end