diff --git a/core/src/avm1/globals/movie_clip.rs b/core/src/avm1/globals/movie_clip.rs index 8b6ad0d6a..ef56bc285 100644 --- a/core/src/avm1/globals/movie_clip.rs +++ b/core/src/avm1/globals/movie_clip.rs @@ -176,6 +176,7 @@ pub fn create_proto<'gc>( "getBounds" => get_bounds, "getBytesLoaded" => get_bytes_loaded, "getBytesTotal" => get_bytes_total, + "getInstanceAtDepth" => get_instance_at_depth, "getNextHighestDepth" => get_next_highest_depth, "getRect" => get_rect, "getURL" => get_url, @@ -818,6 +819,41 @@ fn get_bytes_total<'gc>( .unwrap_or(Value::Undefined)) } +fn get_instance_at_depth<'gc>( + movie_clip: MovieClip<'gc>, + activation: &mut Activation<'_, 'gc, '_>, + args: &[Value<'gc>], +) -> Result, Error<'gc>> { + if activation.current_swf_version() >= 7 { + let depth = if let Some(depth) = args.get(0) { + depth + .coerce_to_i32(activation)? + .wrapping_add(AVM_DEPTH_BIAS) + } else { + avm_error!( + activation, + "MovieClip.get_instance_at_depth: Too few parameters" + ); + return Ok(Value::Undefined); + }; + match movie_clip.child_by_depth(depth) { + Some(child) => { + // If the child doesn't have a corresponding AVM object, return mc itself. + // NOTE: this behavior was guessed from observing behavior for Text and Graphic; + // I didn't test other variants like Bitmap, MorphSpahe, Video + // or objects that weren't fully initialized yet. + match child.object() { + Value::Undefined => Ok(movie_clip.object()), + obj => Ok(obj), + } + } + None => Ok(Value::Undefined), + } + } else { + Ok(Value::Undefined) + } +} + fn get_next_highest_depth<'gc>( movie_clip: MovieClip<'gc>, activation: &mut Activation<'_, 'gc, '_>, diff --git a/core/tests/regression_tests.rs b/core/tests/regression_tests.rs index 6c023246b..74cce7d09 100644 --- a/core/tests/regression_tests.rs +++ b/core/tests/regression_tests.rs @@ -163,6 +163,7 @@ swf_tests! { (lessthan2_swf7, "avm1/lessthan2_swf7", 1), (logical_ops_swf4, "avm1/logical_ops_swf4", 1), (logical_ops_swf8, "avm1/logical_ops_swf8", 1), + (movieclip_get_instance_at_depth, "avm1/movieclip_get_instance_at_depth", 1), (movieclip_depth_methods, "avm1/movieclip_depth_methods", 3), (get_variable_in_scope, "avm1/get_variable_in_scope", 1), (movieclip_init_object, "avm1/movieclip_init_object", 1), diff --git a/core/tests/swfs/avm1/movieclip_get_instance_at_depth/output.txt b/core/tests/swfs/avm1/movieclip_get_instance_at_depth/output.txt new file mode 100644 index 000000000..1998772ab --- /dev/null +++ b/core/tests/swfs/avm1/movieclip_get_instance_at_depth/output.txt @@ -0,0 +1,28 @@ +//_root.getInstanceAtDepth(-16384) +undefined +//_root.getInstanceAtDepth(-16384).getDepth() +undefined +//_root.getInstanceAtDepth(-16383) +_level0 +//_root.getInstanceAtDepth(-16383).getDepth() +-16384 +//_root.getInstanceAtDepth(-16382) +_level0.instance1 +//_root.getInstanceAtDepth(-16382).getDepth() +-16382 +//_root.getInstanceAtDepth(-16381) +undefined +//_root.getInstanceAtDepth(-16381).getDepth() +undefined +//_root.getInstanceAtDepth(-16380) +_level0 +//_root.getInstanceAtDepth(-16380).getDepth() +-16384 +//_root.getInstanceAtDepth(-16379) +_level0.instance2 +//_root.getInstanceAtDepth(-16379).getDepth() +-16379 +//this.getInstanceAtDepth(123) +_level0.fromscript +//_root.getInstanceAtDepth(123).getDepth() +123 diff --git a/core/tests/swfs/avm1/movieclip_get_instance_at_depth/test.fla b/core/tests/swfs/avm1/movieclip_get_instance_at_depth/test.fla new file mode 100644 index 000000000..c0b92878f Binary files /dev/null and b/core/tests/swfs/avm1/movieclip_get_instance_at_depth/test.fla differ diff --git a/core/tests/swfs/avm1/movieclip_get_instance_at_depth/test.swf b/core/tests/swfs/avm1/movieclip_get_instance_at_depth/test.swf new file mode 100644 index 000000000..995d6c917 Binary files /dev/null and b/core/tests/swfs/avm1/movieclip_get_instance_at_depth/test.swf differ