I think scripting levels for forced scrolling shooters/shmups is a must IMO. Although compile it to a binary format first to save on processing time. I use macros and equates to directly write the simplified scripts for such levels. No custom script compiler needed. Here's a quick example:
Stage01:
_FuncLoff
_FuncLrst
_BG_OFF
_SPR_OFF
_SCROLL_OFF
_COL_OFF
_WAIT_FRM $0001
_MAP_PTR tile_map
_COL_PTR tile_col
_MAP_X 0, 29, tile_map
_COL_X 0, 29, tile_col
.DB MAP_Y,00,00
_MAP_SPD $0800
_MAP_RE
_COL_RE
_PAL_PTR tile_pal
_PAL_XFER 0, 255
_PAL_PTR status_pal
_PAL_XFER 160, 32
_VRAM_PTR $0780
_VXFER_PTR status_map
_VDC_XFER status_map
_VRAM_PTR $0800
_VXFER_PTR status_tile
_VDC_XFER status_tile
_VRAM_PTR $ab0
_VXFER_PTR tile_data
_VDC_XFER SIZEOF(tile_data)
_VRAM_PTR $6900
_VXFER_PTR ship_spr
_VDC_XFER $780
_PAL_PTR ship_pal
_PAL_XFER 256, 32
_BG_ON
_SPR_ON
;.DB PLYR_OFF
_COL_ON
_SCROLL_ON
_MAPaccel 80, 0, 3, -1, $0080
_WAIT_SEC 80
;_WAIT_SEC 340
;_MAPaccelREMOVE
;_MAP_X 50, 58, tile_map
;_MAP_RE
;_MAP_SPD $003f
;_WAIT_SEC 10
;_MAP_X 150, 58, tile_map
;_MAP_RE
;_MAP_SPD $0200
;_WAIT_SEC 10
;_MAP_X 250, 58, tile_map
;_MAP_RE
;_MAP_SPD $0100
;_WAIT_SEC 10
;_MAP_X 300, 58, tile_map
;_MAP_RE
;_MAP_SPD $008
;_WAIT_SEC 10
;_MAP_X 350, 58, tile_map
;_MAP_RE
;_STOP
_SCROLL_OFF
Enemies are done the same way. They are pretty much just timed events. I treat certain 'command' codes (which you don't see here, but you would if you saw the binary or hex version of this) as non terminating. That is to say, you can string multiple commands for that instance/time slice/etc together and add a terminator at the end. Other commands are self terminating, etc. It's pretty much just like a command-string music engine (think MML style sound engines instead of traditional trackers). Though mine (above) is a little more complicated in that it will push certain function pointers onto a function stack to be processed once a frame. The functions can remove themselves once they expire, or high priority functions can force remove them if need be (like resetting a stage point upon a continue, or mid stage change/transition, etc). I like the idea of a function stack that gets parsed once a frame. The primary function list itself is just a simple 256 byte table. The cpu quickly parses if a value is TRUE or FALSE (no terminator). Upon TRUE, it uses that place in the stack as an index into a 24bit pointer (bank:address) table, and JSRs to the function. Simply removing a function from the list is to change the value to FALSE. No re-ordering or removing a pointer or such.
Anyway, the macros end up creating ".DB" or data defines, with operand data as well. I agree with what others have said, have a set of predetermined paths that can be applied to enemy types.