Repository: ruffle-rs/ruffle (language: rust)

Issue:
Regression in buttons
### Describe the bug

1. Enter the game: https://xarium.cc/playtest.php
2. Try to hover and click any of these objects:
![Image](https://github.com/user-attachments/assets/65d0b705-6361-4666-bd8f-141a916a2cc6)
![Image](https://github.com/user-attachments/assets/16ab73a3-0599-4d2c-bf44-b3736416ad34)
3. Nothing happens

### Expected behavior

Buttons respond to pointing and pressing:
![Image](https://github.com/user-attachments/assets/bc497312-53c6-4170-8b2f-8fee1020aa56)



### Content Location

https://xarium.cc/playtest.php

### Affected platform

Self-hosted version

### Operating system

Windows 11

### Browser

Google Chrome 131.0.6778.70

### Additional information

Probably due to #18434 - [nightly-2024-11-03](https://github.com/ruffle-rs/ruffle/releases/tag/nightly-2024-11-03) works fine, but starting with [nightly-2024-11-05](https://github.com/ruffle-rs/ruffle/releases/tag/nightly-2024-11-05) there are problems
Regression in buttons
### Describe the bug

1. Enter the game: https://xarium.cc/playtest.php
2. Try to hover and click any of these objects:
![Image](https://github.com/user-attachments/assets/65d0b705-6361-4666-bd8f-141a916a2cc6)
![Image](https://github.com/user-attachments/assets/16ab73a3-0599-4d2c-bf44-b3736416ad34)
3. Nothing happens

### Expected behavior

Buttons respond to pointing and pressing:
![Image](https://github.com/user-attachments/assets/bc497312-53c6-4170-8b2f-8fee1020aa56)



### Content Location

https://xarium.cc/playtest.php

### Affected platform

Self-hosted version

### Operating system

Windows 11

### Browser

Google Chrome 131.0.6778.70

### Additional information

Probably due to #18434 - [nightly-2024-11-03](https://github.com/ruffle-rs/ruffle/releases/tag/nightly-2024-11-03) works fine, but starting with [nightly-2024-11-05](https://github.com/ruffle-rs/ruffle/releases/tag/nightly-2024-11-05) there are problems


Discussion / hints:
CC @Toad06 
This game loads internal SWFs. One of the files contains the following code:
```as // child.swf
this.onRollOver = function() {
   mco.gotoAndStop("over_fr");
   ShowHint(this_mc);
};
this.onRollOut = this.onReleaseOutside = function() {
   mco.gotoAndStop("out_fr");
   RemoveHint();
};
```

If you open the file directly in Flash Player or Ruffle, this won't work because `this` refers to the root. For the same reason, this issue also occurs if you load it into a different level using `loadMovieNum`.

However, loading the file into a target movie clip that is part of the root works in Flash Player:
```as
this.createEmptyMovieClip("container", this.getNextHighestDepth());
loadMovie("child.swf", "container");
```

This doesn't work in Ruffle because `fn is_root` returns `true` in this situation, as this function actually indicates "whether this display object represents the root of loaded content". I misunderstood this...

So replacing the `is_root` check with `DisplayObject::ptr_eq(self.as_displayobject(), self.avm1_root_no_lock())` prevents the issue from occurring.

[test.zip](https://github.com/user-attachments/files/17780861/test.zip)
CC @Toad06 
This game loads internal SWFs. One of the files contains the following code:
```as // child.swf
this.onRollOver = function() {
   mco.gotoAndStop("over_fr");
   ShowHint(this_mc);
};
this.onRollOut = this.onReleaseOutside = function() {
   mco.gotoAndStop("out_fr");
   RemoveHint();
};
```

If you open the file directly in Flash Player or Ruffle, this won't work because `this` refers to the root. For the same reason, this issue also occurs if you load it into a different level using `loadMovieNum`.

However, loading the file into a target movie clip that is part of the root works in Flash Player:
```as
this.createEmptyMovieClip("container", this.getNextHighestDepth());
loadMovie("child.swf", "container");
```

This doesn't work in Ruffle because `fn is_root` returns `true` in this situation, as this function actually indicates "whether this display object represents the root of loaded content". I misunderstood this...

So replacing the `is_root` check with `DisplayObject::ptr_eq(self.as_displayobject(), self.avm1_root_no_lock())` prevents the issue from occurring.

[test.zip](https://github.com/user-attachments/files/17780861/test.zip)

Fix patch:
diff --git a/core/src/display_object/movie_clip.rs b/core/src/display_object/movie_clip.rs
index bd897797a220c..5a7703d0f2494 100644
--- a/core/src/display_object/movie_clip.rs
+++ b/core/src/display_object/movie_clip.rs
@@ -2373,7 +2373,7 @@ impl<'gc> MovieClip<'gc> {
                 .intersects(ClipEvent::BUTTON_EVENT_FLAGS)
         {
             true
-        } else if self.is_root() {
+        } else if self.avm1_parent().is_none() {
             false
         } else {
             let object = self.object();


Test patch:
diff --git a/tests/tests/swfs/avm1/root_button_mode/input.json b/tests/tests/swfs/avm1/root_button_mode/input.json
index 313d89bbf481d..05dd74b09a8d4 100644
--- a/tests/tests/swfs/avm1/root_button_mode/input.json
+++ b/tests/tests/swfs/avm1/root_button_mode/input.json
@@ -1,4 +1,7 @@
 [
+    {
+        "type": "Wait"
+    },
     {
         "type": "Wait"
     },
@@ -60,9 +63,6 @@
         "pos": [150.0, 150.0],
         "btn": "Left"
     },
-    {
-        "type": "Wait"
-    },
     {
         "type": "Wait"
     }
diff --git a/tests/tests/swfs/avm1/root_button_mode/output.txt b/tests/tests/swfs/avm1/root_button_mode/output.txt
index b5bbe40923faf..45409d6902545 100644
--- a/tests/tests/swfs/avm1/root_button_mode/output.txt
+++ b/tests/tests/swfs/avm1/root_button_mode/output.txt
@@ -1,4 +1,10 @@
+_level0.mc2.onMouseDown
 _level0.onMouseDown
+_level0.mc2.onMouseUp
 _level0.onMouseUp
+_level0.mc2.onMouseDown
 _level0.onMouseDown
+_level0.mc2.onPress
+_level0.mc2.onMouseUp
 _level0.onMouseUp
+_level0.mc2.onRelease
diff --git a/tests/tests/swfs/avm1/root_button_mode/source.as b/tests/tests/swfs/avm1/root_button_mode/source.as
index d0b87dead3f27..80e6bddb4dd78 100644
--- a/tests/tests/swfs/avm1/root_button_mode/source.as
+++ b/tests/tests/swfs/avm1/root_button_mode/source.as
@@ -1,7 +1,7 @@
 // Test made with JPEXS Free Flash Decompiler.
 
-function createMC(name, x, y) {
-	var mc = _root.createEmptyMovieClip(name, _root.getNextHighestDepth());
+function createMC(name, x, y, parent) {
+	var mc = parent.createEmptyMovieClip(name, parent.getNextHighestDepth());
 	mc._x = x;
 	mc._y = y;
 	mc.beginFill(0xFF0000);
@@ -28,5 +28,14 @@ function setFunctions(mc) {
 	};
 }
 
-createMC("square", 0, 0);
-setFunctions(_root);
+if(this === _level0) {
+	createMC("square", 0, 0, this);
+	setFunctions(this);
+	// Issue #18610.
+	this.createEmptyMovieClip("mc2", this.getNextHighestDepth());
+	loadMovie("test.swf", "mc2");
+} else {
+	this._lockroot = true;
+	createMC("square", 100, 100, this);
+	setFunctions(this);
+}
diff --git a/tests/tests/swfs/avm1/root_button_mode/test.swf b/tests/tests/swfs/avm1/root_button_mode/test.swf
index 2183686cfe1ec..be5e8a37853bf 100644
Binary files a/tests/tests/swfs/avm1/root_button_mode/test.swf and b/tests/tests/swfs/avm1/root_button_mode/test.swf differ