A cast is a shift pair
Every narrowing you have seen so far was implied by a declaration - a u8 field, an s16 parameter, a narrow return type. Write the cast yourself and you get the same instructions, in the middle of an expression where you asked for them.
(u8)x is lsl #24 then lsr #24. (s16)x is lsl #16 then asr #16. The pattern is the one from the last few lessons: shift up by 32 minus the width, shift back with lsr for an unsigned target type or asr for a signed one.
What makes casts worth their own lesson is that the obvious alternative compiles to something else entirely. These two functions extract byte 1 of a value:
0 lsr r0, #8
2 lsl r0, #24
4 lsr r0, #24
6 bx lr
0 lsr r0, #8
2 mov r1, #255
4 and r0, r1
6 bx lr
The first wrote (u8)(x >> 8), the second wrote (x >> 8) & 255. Identical values, identical instruction counts, different instructions. agbcc never turns a cast into a mask or a mask into a shift pair, so the target tells you which one the original programmer typed. If you see mov and and, the source had a mask; if you see a shift pair, the source had a cast.
That distinction gets sharper with 16 bits, where the mask constant no longer fits in a mov at all and x & 0xFFFF drags a literal-pool word into the function while (u16)x still costs two shifts.
Your target has two shift pairs reading the same source register, and one add. Solve each pair on its own.
Your task
Write func_081da6b4 to reproduce the target assembly.