Project

General

Profile

Bug #3823

[Mod] Animated Morrowind: a bard does not play music

Added by Andrei Kortunov 10 months ago. Updated about 1 month ago.

Status:
Resolved
Priority:
Normal
Category:
Scripting
Target version:
Start date:
04/10/2017
% Done:

100%

Reproducibility:
Always
Operating system:
Linux
Severity:
Normal

Description

Animated Morrowind 1.0 download link: http://mw.modhistory.com/download-55-6351

Animated bard (Der Juvas in "Mournhold, the Winged Guar") does not plays a music.

A console output shows:

Playing music/am\am_music2.mp3
Playing music/explore/mx_explore_1.mp3

i.e. the bard music starts, but immediately replaced by explore music.
I think there is a problem with StartScript - we should only register a script, but not run it until a next frame starts.

A problematic part of AM_Bard2_script:

if GetDisabled == 0
    if Reposition == 0
        if ( PLayonce == 0 )
            startScript AM_StopMusic_Script    ; <- the problem is here
            set Rand to random 10
            if Rand < 5
                StreamMusic,"AM\AM_music2.mp3" 
                set playonce to 2
                set timer to 0
            else
                StreamMusic,"AM\AM_music3.mp3" 
                set playonce to 3
                set timer to 0
            endif
        endif
    endif
endif

AM_StopMusic_Script:

begin AM_StopMusic_Script

short Rand

if cellchanged == 1
    set Rand to random 7
    if Rand == 0
        StreamMusic "Explore\MX_explore_1.mp3" 
    elseif Rand == 1
        StreamMusic "Explore\MX_explore_2.mp3" 
    elseif Rand == 2
        StreamMusic "Explore\MX_explore_3.mp3" 
    elseif Rand == 3
        StreamMusic "Explore\MX_explore_4.mp3" 
    elseif Rand == 4
        StreamMusic "Explore\MX_explore_5.mp3" 
    elseif Rand == 5
        StreamMusic "Explore\MX_explore_6.mp3" 
    elseif Rand == 6
        StreamMusic "Explore\MX_explore_7.mp3" 
    endif
    stopScript AM_StopMusic_Script
endif

end
Morrowind behaviour:
  1. PC enters a cell (cellchanged sets to 1)
  2. AM_Bard2_script starts a music and starts AM_StopMusic_Script (but this script is not executed on current frame)
  3. Next frame starts (cellchanged sets to 0)
  4. AM_StopMusic_Script runs, but doing nothing (because cellchanged = 0)
  5. PC leaves the cell (cellchanged sets to 1)
  6. AM_StopMusic_Script correctly stops the music and stops itself
OpenMW behaviour:
  1. PC enters a cell (cellchanged sets to 1)
  2. AM_Bard2_script starts a music and starts AM_StopMusic_Script
  3. AM_StopMusic_Script runs in current frame and stops a music and stops itself (because cellchanged = 1)

History

#1 Updated by scrawl . 4 months ago

  • Status changed from New to Confirmed

I think there is a problem with StartScript - we should only register a script, but not run it until a next frame starts.

I agree. Currently, whether or not a newly started script will be executed in the current frame basically depends on where it's inserted in the map respective to the currently running script, which depends on the name of the script. So because AM_StopMusic_Script is alphabetically higher than AM_Bard2_script, it will be executed (with opposite names, it wouldn't be executed). This makes absolutely no sense. We should either run or not run a newly started script, consistently.

Relevant code: https://github.com/OpenMW/openmw/blob/master/apps/openmw/mwscript/globalscripts.cpp#L73

Simplest solution I can think of is to make a copy of the map before iterating it, that way new scripts aren't run until the next frame.

This also applies, in a sense, to local scripts (i.e. when a new local script is started as a result of a 'PlaceAt' instruction in another local script).

#2 Updated by Chris Robinson 4 months ago

scrawl . wrote:

Simplest solution I can think of is to make a copy of the map before iterating it, that way new scripts aren't run until the next frame.

How should it behave with StopScript? Should a script still potentially run on the frame it was stopped, even if it hasn't run before the call? Or can it be assumed the stopped script will not run after the call?

An alternative option would be to have a temporary list of scripts that get started during script execution, and append them after all the scripts execute. That would avoid needing to copy the map every frame, and be very cheap when no new scripts are started (the temporary list wouldn't need to allocate any entries).

#3 Updated by scrawl . 4 months ago

Right, good point. We need to test how StopScript is supposed to behave. (I'd assume it stops right away)

#4 Updated by scrawl . 4 months ago

Note: in OpenMW's global script implementation, StopScript doesn't remove the script from the list of scripts, it just sets it to running=false. So the suggestion from comment # 1 should actually behave in the way that scripts immediately stop.

#5 Updated by Andrei Kortunov about 1 month ago

Simplest solution I can think of is to make a copy of the map before iterating it

Tried that, but it did not work: the AM_StopMusic_Script already has isRunning = true, when we run global scripts first time after entering the tavern.
I guess that we run global scripts after local ones, but vanilla game may run scripts in the opposite order.

#6 Updated by Andrei Kortunov about 1 month ago

Running local scripts after global ones (in the engine.cpp) solved this issue.

Is this order (local, then global) arbitrary, or it was done by design?

#7 Updated by Andrei Kortunov about 1 month ago

  • Status changed from Confirmed to Resolved
  • Assignee set to Andrei Kortunov
  • Target version set to openmw-0.44
  • % Done changed from 0 to 100

#8 Updated by Andrei Kortunov about 1 month ago

  • Subject changed from [Mod] Animated Morrowind: a bard does not plays music to [Mod] Animated Morrowind: a bard does not play music

Also available in: Atom PDF