//* icsal.c - In-Code Sprite Automation Language (ICSAL) command processor module //* System library headers #include #include //debug #include //* Application headers #include "main.h" #include "procs.h" #include "preset.h" //* Static ISCAL function prototypes static void set_sprite_attr_all(struct SCTRL *scp); static void set_sprite_attr_brightness(struct SCTRL *scp); static void set_sprite_attr_clut_mode(struct SCTRL *scp); static void set_sprite_attr_rotation(struct SCTRL *scp); static void set_sprite_attr_trans_rate(struct SCTRL *scp); static void set_sprite_attr_transparency(struct SCTRL *scp); static void set_sprite_attr_display(struct SCTRL *scp); static void set_sprite_x(struct SCTRL *scp); static void set_sprite_y(struct SCTRL *scp); static void add_sprite_x(struct SCTRL *scp); static void add_sprite_y(struct SCTRL *scp); static void add_sprite_x_data(struct SCTRL *scp); static void add_sprite_y_data(struct SCTRL *scp); static void set_sprite_width(struct SCTRL *scp); static void set_sprite_height(struct SCTRL *scp); static void add_sprite_width(struct SCTRL *scp); static void add_sprite_height(struct SCTRL *scp); static void get_sprite_tpage(struct SCTRL *scp); static void set_sprite_texture_u(struct SCTRL *scp); static void set_sprite_texture_v(struct SCTRL *scp); static void add_sprite_texture_u(struct SCTRL *scp); static void add_sprite_texture_v(struct SCTRL *scp); static void get_sprite_clut_xy(struct SCTRL *scp); static void set_sprite_rgb(struct SCTRL *scp); static void add_sprite_rgb(struct SCTRL *scp); static void add_sprite_mx(struct SCTRL *scp); static void add_sprite_my(struct SCTRL *scp); static void set_sprite_rotation_xy(struct SCTRL *scp); static void set_sprite_scale_xy(struct SCTRL *scp); static void set_sprite_rotation_degree(struct SCTRL *scp); static void add_sprite_rotation_degree(struct SCTRL *scp); static void add_sprite_scale_x(struct SCTRL *scp); static void add_sprite_scale_y(struct SCTRL *scp); static void change_sprite_tim(struct SCTRL *scp); static void set_ctrl_wx(struct SCTRL *scp); static void set_ctrl_wy(struct SCTRL *scp); static void add_ctrl_wx(struct SCTRL *scp); static void add_ctrl_wy(struct SCTRL *scp); static void add_ctrl_wx_data(struct SCTRL *scp); static void add_ctrl_wy_data(struct SCTRL *scp); static void set_ctrl_accelX(struct SCTRL *scp); static void set_ctrl_accelY(struct SCTRL *scp); static void add_ctrl_accelXY(struct SCTRL *scp); static void set_ctrl_speed(struct SCTRL *scp); static void set_ctrl_repsPerFrame(struct SCTRL *scp); static void set_ctrl_frameCount(struct SCTRL *scp); static void set_ctrl_currFrame(struct SCTRL *scp); static void set_ctrl_alive(struct SCTRL *scp); static void set_ctrl_dir(struct SCTRL *scp); static void set_ctrl_locks(struct SCTRL *scp); static void set_ctrl_ID(struct SCTRL *scp); static void set_ctrl_bbXOff(struct SCTRL *scp); static void set_ctrl_bbYOff(struct SCTRL *scp); static void set_ctrl_bbW(struct SCTRL *scp); static void set_ctrl_bbH(struct SCTRL *scp); static void set_ctrl_high(struct SCTRL *scp); static void add_ctrl_high(struct SCTRL *scp); static void add_ctrl_high_data(struct SCTRL *scp); static void set_ctrl_isLight(struct SCTRL *scp); static void set_ctrl_unintICSAL(struct SCTRL *scp); static void set_ctrl_shadStat(struct SCTRL *scp); static void add_ctrl_shadBase(struct SCTRL *scp); static void set_ctrl_moveCount(struct SCTRL *scp); static void move_chasing_enemy(struct SCTRL *scp); static void move_enemy(struct SCTRL *scp); static void move_chasing_ufo(struct SCTRL *scp); static void move_mining_ufo(struct SCTRL *scp); static void move_ufo(struct SCTRL *scp); static void move_lost_baby(struct SCTRL *scp); static void move_following_baby(struct SCTRL *scp); static void move_centre_tv(struct SCTRL *scp); static void move_decoy_boy(struct SCTRL *scp); static void handle_sprite_over_wall(struct SCTRL *scp); static void handle_shadow_over_wall(struct SCTRL *scp); static void handle_heart_over_wall(struct SCTRL *scp); static void REP_tv_off(struct SCTRL *scp); static void REP_tv_on(struct SCTRL *scp); static void END_run_baby_wander(struct SCTRL *scp); static void END_beam(struct SCTRL *scp); static void REP_update_HUD_box(struct SCTRL *scp); static void REP_close_HUD_box(struct SCTRL *scp); static void REP_update_range_HUD(struct SCTRL *scp); static void REP_close_range_HUD(struct SCTRL *scp); static void REP_close_decoy_boy(struct SCTRL *scp); static void start_bullet_blur(struct SCTRL *scp); static void update_bullet_blur(struct SCTRL *scp); static void update_coin_fall(struct SCTRL *scp); static void update_fdrop_buildUp(struct SCTRL *scp); static void update_powflash_xy(struct SCTRL *scp); static void update_orbit(struct SCTRL *scp); static void update_ufo_crash(struct SCTRL *scp); static void update_ufo_fall(struct SCTRL *scp); static void goto_orbit(struct SCTRL *scp); static void set_spin_frame(struct SCTRL *scp); static void reset_moneybag(struct SCTRL *scp); static void check_landing_action(struct SCTRL *scp); static void set_loop_start(struct SCTRL *scp); static void repeat_loop(struct SCTRL *scp); static void set_data_start(struct SCTRL *scp); static void loop_while_data(struct SCTRL *scp); static void loop_repeat_data(struct SCTRL *scp); static void if_floor_hit_expire(struct SCTRL *scp); static void reuse_last_data(struct SCTRL *scp); static void do_nothing(struct SCTRL *scp); static void done_if_x_past(struct SCTRL *scp); static void play_sfx(struct SCTRL *scp); static void END_proc(struct SCTRL *scp); static void END_kill_sprite(struct SCTRL *scp); static void END_expire_bullet(struct SCTRL *scp); //* Initialize command array to hold pointers to the various ICSAL command functions static void (*command[]) (struct SCTRL *) = { //* GsSPRITE operation commands set_sprite_attr_all, set_sprite_attr_brightness, set_sprite_attr_clut_mode, set_sprite_attr_rotation, set_sprite_attr_trans_rate, set_sprite_attr_transparency, set_sprite_attr_display, set_sprite_x, set_sprite_y, add_sprite_x, add_sprite_y, add_sprite_x_data, add_sprite_y_data, set_sprite_width, set_sprite_height, add_sprite_width, add_sprite_height, get_sprite_tpage, set_sprite_texture_u, set_sprite_texture_v, add_sprite_texture_u, add_sprite_texture_v, get_sprite_clut_xy, set_sprite_rgb, add_sprite_rgb, add_sprite_mx, add_sprite_my, set_sprite_rotation_xy, set_sprite_scale_xy, set_sprite_rotation_degree, add_sprite_rotation_degree, add_sprite_scale_x, add_sprite_scale_y, change_sprite_tim, //* struct SCTRL operation instructions set_ctrl_wx, set_ctrl_wy, add_ctrl_wx, add_ctrl_wy, add_ctrl_wx_data, add_ctrl_wy_data, set_ctrl_accelX, set_ctrl_accelY, add_ctrl_accelXY, set_ctrl_speed, set_ctrl_repsPerFrame, set_ctrl_frameCount, set_ctrl_currFrame, set_ctrl_alive, set_ctrl_dir, set_ctrl_locks, set_ctrl_ID, set_ctrl_bbXOff, set_ctrl_bbYOff, set_ctrl_bbW, set_ctrl_bbH, set_ctrl_high, add_ctrl_high, add_ctrl_high_data, set_ctrl_isLight, set_ctrl_unintICSAL, set_ctrl_shadStat, add_ctrl_shadBase, set_ctrl_moveCount, //* Specialized operation functions move_chasing_enemy, move_enemy, move_chasing_ufo, move_mining_ufo, move_ufo, move_lost_baby, move_following_baby, move_centre_tv, move_decoy_boy, handle_sprite_over_wall, handle_shadow_over_wall, handle_heart_over_wall, start_bullet_blur, update_bullet_blur, update_coin_fall, update_fdrop_buildUp, update_powflash_xy, update_orbit, update_ufo_crash, update_ufo_fall, goto_orbit, set_spin_frame, reset_moneybag, check_landing_action, REP_tv_off, REP_tv_on, END_run_baby_wander, END_beam, REP_update_HUD_box, REP_close_HUD_box, REP_update_range_HUD, REP_close_range_HUD, REP_close_decoy_boy, //* General control operation instructions set_loop_start, repeat_loop, set_data_start, loop_while_data, loop_repeat_data, if_floor_hit_expire, reuse_last_data, do_nothing, done_if_x_past, play_sfx, END_proc, END_kill_sprite, END_expire_bullet }; static int lastCall; //* Last function call flag //*------------------------------------------------------------------------------------------ //* RunICSAL //*------------------------------------------------------------------------------------- void RunICSAL(register struct SCTRL *scp) { do { //* Set 'this is the last call' flag if requested lastCall = *scp->ICSALop & 0x100; //* Call required function by indexing into the function pointer array //* using op-code with any present 'last call' flag masked out (*command[*scp->ICSALop & 0xff]) (scp); } while (!lastCall); } //******************************************************************************************* //* //* struct SCTRL operation instructions start here: //* //******************************************************************************************* //*------------------------------------------------------------------------------------------ //* set_ctrl_wx //*------------------------------------------------------------------------------------- static void set_ctrl_wx(register struct SCTRL *scp) { ++scp->ICSALop; scp->wx = *scp->ICSALop; ++scp->ICSALop; } //*------------------------------------------------------------------------------------------ //* set_ctrl_wy //*------------------------------------------------------------------------------------- static void set_ctrl_wy(register struct SCTRL *scp) { ++scp->ICSALop; scp->wy = *scp->ICSALop; ++scp->ICSALop; } //*------------------------------------------------------------------------------------------ //* add_ctrl_wx //*------------------------------------------------------------------------------------- static void add_ctrl_wx(register struct SCTRL *scp) { ++scp->ICSALop; scp->wx += *scp->ICSALop; ++scp->ICSALop; } //*------------------------------------------------------------------------------------------ //* add_ctrl_wy //*------------------------------------------------------------------------------------- static void add_ctrl_wy(register struct SCTRL *scp) { ++scp->ICSALop; scp->wy += *scp->ICSALop; ++scp->ICSALop; } //*------------------------------------------------------------------------------------------ //* add_ctrl_wx_data //*------------------------------------------------------------------------------------- static void add_ctrl_wx_data(register struct SCTRL *scp) { ++scp->ICSALop; scp->wx += *scp->ICSALdata++; } //*------------------------------------------------------------------------------------------ //* add_ctrl_wy_data //*------------------------------------------------------------------------------------- static void add_ctrl_wy_data(register struct SCTRL *scp) { ++scp->ICSALop; scp->wy += *scp->ICSALdata++; } //*------------------------------------------------------------------------------------------ //* set_ctrl_accelX //*------------------------------------------------------------------------------------- static void set_ctrl_accelX(register struct SCTRL *scp) { ++scp->ICSALop; scp->accelX = *scp->ICSALop; ++scp->ICSALop; } //*------------------------------------------------------------------------------------------ //* set_ctrl_accelY //*------------------------------------------------------------------------------------- static void set_ctrl_accelY(register struct SCTRL *scp) { ++scp->ICSALop; scp->accelY = *scp->ICSALop; ++scp->ICSALop; } //*------------------------------------------------------------------------------------------ //* add_ctrl_accelXY //*------------------------------------------------------------------------------------- static void add_ctrl_accelXY(register struct SCTRL *scp) { ++scp->ICSALop; scp->wx += scp->accelX; scp->wy += scp->accelY; } //*------------------------------------------------------------------------------------------ //* set_ctrl_speed //*------------------------------------------------------------------------------------- static void set_ctrl_speed(register struct SCTRL *scp) { ++scp->ICSALop; scp->speed = *scp->ICSALop; ++scp->ICSALop; } //*------------------------------------------------------------------------------------------ //* set_ctrl_repsPerFrame //*------------------------------------------------------------------------------------- static void set_ctrl_repsPerFrame(register struct SCTRL *scp) { ++scp->ICSALop; scp->repsPerFrame = *scp->ICSALop; ++scp->ICSALop; } //*------------------------------------------------------------------------------------------ //* set_ctrl_frameCount //*------------------------------------------------------------------------------------- static void set_ctrl_frameCount(register struct SCTRL *scp) { ++scp->ICSALop; scp->frameCount = *scp->ICSALop; ++scp->ICSALop; } //*------------------------------------------------------------------------------------------ //* set_ctrl_currFrame //*------------------------------------------------------------------------------------- static void set_ctrl_currFrame(register struct SCTRL *scp) { ++scp->ICSALop; scp->currFrame = *scp->ICSALop; ++scp->ICSALop; } //*------------------------------------------------------------------------------------------ //* set_ctrl_alive //*------------------------------------------------------------------------------------- static void set_ctrl_alive(register struct SCTRL *scp) { ++scp->ICSALop; scp->alive = *scp->ICSALop; ++scp->ICSALop; } //*------------------------------------------------------------------------------------------ //* set_ctrl_dir //*------------------------------------------------------------------------------------- static void set_ctrl_dir(register struct SCTRL *scp) { ++scp->ICSALop; scp->dir = *scp->ICSALop; ++scp->ICSALop; } //*------------------------------------------------------------------------------------------ //* set_ctrl_locks //*------------------------------------------------------------------------------------- static void set_ctrl_locks(register struct SCTRL *scp) { ++scp->ICSALop; scp->frameLock = scp->currLock = *scp->ICSALop; ++scp->ICSALop; } //*------------------------------------------------------------------------------------------ //* set_ctrl_ID //*------------------------------------------------------------------------------------- static void set_ctrl_ID(register struct SCTRL *scp) { ++scp->ICSALop; scp->ID = *scp->ICSALop; ++scp->ICSALop; } //*------------------------------------------------------------------------------------------ //* set_ctrl_bbXOff //*------------------------------------------------------------------------------------- static void set_ctrl_bbXOff(register struct SCTRL *scp) { ++scp->ICSALop; scp->bbXOff = *scp->ICSALop; ++scp->ICSALop; } //*------------------------------------------------------------------------------------------ //* set_ctrl_bbYOff //*------------------------------------------------------------------------------------- static void set_ctrl_bbYOff(register struct SCTRL *scp) { ++scp->ICSALop; scp->bbYOff = *scp->ICSALop; ++scp->ICSALop; } //*------------------------------------------------------------------------------------------ //* set_ctrl_bbW //*------------------------------------------------------------------------------------- static void set_ctrl_bbW(register struct SCTRL *scp) { ++scp->ICSALop; scp->bbW = *scp->ICSALop; ++scp->ICSALop; } //*------------------------------------------------------------------------------------------ //* set_ctrl_bbH //*------------------------------------------------------------------------------------- static void set_ctrl_bbH(register struct SCTRL *scp) { ++scp->ICSALop; scp->bbH = *scp->ICSALop; ++scp->ICSALop; } //*------------------------------------------------------------------------------------------ //* set_ctrl_high //*------------------------------------------------------------------------------------- static void set_ctrl_high(register struct SCTRL *scp) { ++scp->ICSALop; scp->high = *scp->ICSALop; ++scp->ICSALop; } //*------------------------------------------------------------------------------------------ //* add_ctrl_high //*------------------------------------------------------------------------------------- static void add_ctrl_high(register struct SCTRL *scp) { ++scp->ICSALop; scp->high += *scp->ICSALop; ++scp->ICSALop; } //*------------------------------------------------------------------------------------------ //* add_ctrl_high_data //*------------------------------------------------------------------------------------- static void add_ctrl_high_data(register struct SCTRL *scp) { ++scp->ICSALop; scp->high += *scp->ICSALdata++; } //*------------------------------------------------------------------------------------------ //* set_ctrl_isLight //*------------------------------------------------------------------------------------- static void set_ctrl_isLight(register struct SCTRL *scp) { ++scp->ICSALop; //* Set sprites ground effect type if (scp->isLight = *scp->ICSALop) scp->shadLink->attribute = //* Reflected light (A_4BIT_CLUT + A_BRIGHT_ON + A_ROTATE_OFF + A_TRATE_2 + A_TRANS_ON + A_DISPLAY_ON); else scp->shadLink->attribute = //* Shadow (A_4BIT_CLUT + A_BRIGHT_OFF + A_ROTATE_OFF + A_TRATE_3 + A_TRANS_ON + A_DISPLAY_ON); ++scp->ICSALop; } //*------------------------------------------------------------------------------------------ //* set_ctrl_unintICSAL //*------------------------------------------------------------------------------------- static void set_ctrl_unintICSAL(register struct SCTRL *scp) { ++scp->ICSALop; scp->unintICSAL = *scp->ICSALop; ++scp->ICSALop; } //*------------------------------------------------------------------------------------------ //* set_ctrl_shadStat //*------------------------------------------------------------------------------------- static void set_ctrl_shadStat(register struct SCTRL *scp) { ++scp->ICSALop; scp->shadStat = *scp->ICSALop; ++scp->ICSALop; } //*------------------------------------------------------------------------------------------ //* add_ctrl_shadBase //*------------------------------------------------------------------------------------- static void add_ctrl_shadBase(register struct SCTRL *scp) { ++scp->ICSALop; scp->shadBase += *scp->ICSALop; ++scp->ICSALop; } //*------------------------------------------------------------------------------------------ //* set_ctrl_moveCount //*------------------------------------------------------------------------------------- static void set_ctrl_moveCount(register struct SCTRL *scp) { ++scp->ICSALop; scp->moveCount = *scp->ICSALop; ++scp->ICSALop; } //******************************************************************************************* //* //* GsSPRITE operation instructions start here: //* //******************************************************************************************* //*------------------------------------------------------------------------------------------ //* set_sprite_attr_all //*------------------------------------------------------------------------------------- static void set_sprite_attr_all(register struct SCTRL *scp) { ++scp->ICSALop; scp->spriteLink->attribute = *scp->ICSALop; ++scp->ICSALop; } //*------------------------------------------------------------------------------------------ //* set_sprite_attr_brightness //*------------------------------------------------------------------------------------- static void set_sprite_attr_brightness(register struct SCTRL *scp) { ++scp->ICSALop; scp->spriteLink->attribute = (scp->spriteLink->attribute & 0xffffffbf) | *scp->ICSALop; ++scp->ICSALop; } //*------------------------------------------------------------------------------------------ //* set_sprite_attr_clut_mode //*------------------------------------------------------------------------------------- static void set_sprite_attr_clut_mode(register struct SCTRL *scp) { ++scp->ICSALop; scp->spriteLink->attribute = (scp->spriteLink->attribute & 0xfcffffff) | *scp->ICSALop; ++scp->ICSALop; } //*------------------------------------------------------------------------------------------ //* set_sprite_attr_rotation //*------------------------------------------------------------------------------------- static void set_sprite_attr_rotation(register struct SCTRL *scp) { ++scp->ICSALop; scp->spriteLink->attribute = (scp->spriteLink->attribute & 0xf7ffffff) | *scp->ICSALop; ++scp->ICSALop; } //*------------------------------------------------------------------------------------------ //* set_sprite_attr_trans_rate //*------------------------------------------------------------------------------------- static void set_sprite_attr_trans_rate(register struct SCTRL *scp) { ++scp->ICSALop; scp->spriteLink->attribute = (scp->spriteLink->attribute & 0xcfffffff) | *scp->ICSALop; ++scp->ICSALop; } //*------------------------------------------------------------------------------------------ //* set_sprite_attr_transparency //*------------------------------------------------------------------------------------- static void set_sprite_attr_transparency(register struct SCTRL *scp) { ++scp->ICSALop; scp->spriteLink->attribute = (scp->spriteLink->attribute & 0xbfffffff) | *scp->ICSALop; ++scp->ICSALop; } //*------------------------------------------------------------------------------------------ //* set_sprite_attr_display //*------------------------------------------------------------------------------------- static void set_sprite_attr_display(register struct SCTRL *scp) { ++scp->ICSALop; scp->spriteLink->attribute = (scp->spriteLink->attribute & 0x7fffffff) | *scp->ICSALop; ++scp->ICSALop; } //*------------------------------------------------------------------------------------------ //* set_sprite_x //*------------------------------------------------------------------------------------- static void set_sprite_x(register struct SCTRL *scp) { ++scp->ICSALop; scp->spriteLink->x = *scp->ICSALop; ++scp->ICSALop; } //*------------------------------------------------------------------------------------------ //* set_sprite_y //*------------------------------------------------------------------------------------- static void set_sprite_y(register struct SCTRL *scp) { ++scp->ICSALop; scp->spriteLink->y = *scp->ICSALop; ++scp->ICSALop; } //*------------------------------------------------------------------------------------------ //* add_sprite_x //*------------------------------------------------------------------------------------- static void add_sprite_x(register struct SCTRL *scp) { ++scp->ICSALop; scp->spriteLink->x += *scp->ICSALop; ++scp->ICSALop; } //*------------------------------------------------------------------------------------------ //* add_sprite_y //*------------------------------------------------------------------------------------- static void add_sprite_y(register struct SCTRL *scp) { ++scp->ICSALop; scp->spriteLink->y += *scp->ICSALop; ++scp->ICSALop; } //*------------------------------------------------------------------------------------------ //* add_sprite_x_data //*------------------------------------------------------------------------------------- static void add_sprite_x_data(register struct SCTRL *scp) { ++scp->ICSALop; scp->spriteLink->x += *scp->ICSALdata++; } //*------------------------------------------------------------------------------------------ //* add_sprite_y_data //*------------------------------------------------------------------------------------- static void add_sprite_y_data(register struct SCTRL *scp) { ++scp->ICSALop; scp->spriteLink->y += *scp->ICSALdata++; } //*------------------------------------------------------------------------------------------ //* set_sprite_width //*------------------------------------------------------------------------------------- static void set_sprite_width(register struct SCTRL *scp) { ++scp->ICSALop; scp->spriteLink->w = *scp->ICSALop; ++scp->ICSALop; } //*------------------------------------------------------------------------------------------ //* set_sprite_height //*------------------------------------------------------------------------------------- static void set_sprite_height(register struct SCTRL *scp) { ++scp->ICSALop; scp->spriteLink->h = *scp->ICSALop; ++scp->ICSALop; } //*------------------------------------------------------------------------------------------ //* add_sprite_height //*------------------------------------------------------------------------------------- static void add_sprite_height(register struct SCTRL *scp) { ++scp->ICSALop; scp->spriteLink->h += *scp->ICSALop; ++scp->ICSALop; } //*------------------------------------------------------------------------------------------ //* add_sprite_width //*------------------------------------------------------------------------------------- static void add_sprite_width(register struct SCTRL *scp) { ++scp->ICSALop; scp->spriteLink->w += *scp->ICSALop; ++scp->ICSALop; } //*------------------------------------------------------------------------------------------ //* get_sprite_tpage //*------------------------------------------------------------------------------------- static void get_sprite_tpage(register struct SCTRL *scp) { int timID; ++scp->ICSALop; timID = *scp->ICSALop; scp->spriteLink->tpage = GetTPage(timData[timID].pmode & 0x07 ,0 ,timData[timID].px, timData[timID].py); ++scp->ICSALop; } //*------------------------------------------------------------------------------------------ //* set_sprite_texture_u //*------------------------------------------------------------------------------------- static void set_sprite_texture_u(register struct SCTRL *scp) { ++scp->ICSALop; scp->spriteLink->u = *scp->ICSALop; ++scp->ICSALop; } //*------------------------------------------------------------------------------------------ //* set_sprite_texture_v //*------------------------------------------------------------------------------------- static void set_sprite_texture_v(register struct SCTRL *scp) { ++scp->ICSALop; scp->spriteLink->v = *scp->ICSALop; ++scp->ICSALop; } //*------------------------------------------------------------------------------------------ //* add_sprite_texture_u //*------------------------------------------------------------------------------------- static void add_sprite_texture_u(register struct SCTRL *scp) { ++scp->ICSALop; scp->spriteLink->u += *scp->ICSALop; ++scp->ICSALop; } //*------------------------------------------------------------------------------------------ //* add_sprite_texture_v //*------------------------------------------------------------------------------------- static void add_sprite_texture_v(register struct SCTRL *scp) { ++scp->ICSALop; scp->spriteLink->v += *scp->ICSALop; ++scp->ICSALop; } //*------------------------------------------------------------------------------------------ //* get_sprite_clut_xy //*------------------------------------------------------------------------------------- static void get_sprite_clut_xy(register struct SCTRL *scp) { int timID; ++scp->ICSALop; timID = *scp->ICSALop; scp->spriteLink->cx = timData[timID].cx; scp->spriteLink->cy = timData[timID].cy; ++scp->ICSALop; } //*------------------------------------------------------------------------------------------ //* set_sprite_rgb //*------------------------------------------------------------------------------------- static void set_sprite_rgb(register struct SCTRL *scp) { ++scp->ICSALop; scp->spriteLink->r = *scp->ICSALop; ++scp->ICSALop; scp->spriteLink->g = *scp->ICSALop; ++scp->ICSALop; scp->spriteLink->b = *scp->ICSALop; ++scp->ICSALop; } //*------------------------------------------------------------------------------------------ //* add_sprite_rgb //*------------------------------------------------------------------------------------- static void add_sprite_rgb(register struct SCTRL *scp) { int temp; ++scp->ICSALop; scp->spriteLink->r += *scp->ICSALop; ++scp->ICSALop; scp->spriteLink->g += *scp->ICSALop; ++scp->ICSALop; scp->spriteLink->b += *scp->ICSALop; ++scp->ICSALop; } //*------------------------------------------------------------------------------------------ //* add_sprite_mx //*------------------------------------------------------------------------------------- static void add_sprite_mx(register struct SCTRL *scp) { ++scp->ICSALop; scp->spriteLink->mx += *scp->ICSALop; ++scp->ICSALop; } //*------------------------------------------------------------------------------------------ //* add_sprite_my //*------------------------------------------------------------------------------------- static void add_sprite_my(register struct SCTRL *scp) { ++scp->ICSALop; scp->spriteLink->my += *scp->ICSALop; ++scp->ICSALop; } //*------------------------------------------------------------------------------------------ //* set_sprite_rotation_xy //*------------------------------------------------------------------------------------- static void set_sprite_rotation_xy(register struct SCTRL *scp) { ++scp->ICSALop; scp->spriteLink->mx = *scp->ICSALop; ++scp->ICSALop; scp->spriteLink->my = *scp->ICSALop; ++scp->ICSALop; } //*------------------------------------------------------------------------------------------ //* set_sprite_scale_xy //*------------------------------------------------------------------------------------- static void set_sprite_scale_xy(register struct SCTRL *scp) { ++scp->ICSALop; scp->spriteLink->scalex = *scp->ICSALop; ++scp->ICSALop; scp->spriteLink->scaley = *scp->ICSALop; ++scp->ICSALop; } //*------------------------------------------------------------------------------------------ //* set_sprite_rotation_degree //*------------------------------------------------------------------------------------- static void set_sprite_rotation_degree(register struct SCTRL *scp) { ++scp->ICSALop; scp->spriteLink->rotate = (*scp->ICSALop<<12); //* = degrees * 4096(ONE) ++scp->ICSALop; } //*------------------------------------------------------------------------------------------ //* add_sprite_rotation_degree //*------------------------------------------------------------------------------------- static void add_sprite_rotation_degree(register struct SCTRL *scp) { ++scp->ICSALop; scp->spriteLink->rotate += (*scp->ICSALop<<12); //* = degrees * 4096(ONE) ++scp->ICSALop; } //*------------------------------------------------------------------------------------------ //* add_sprite_scale_x //*------------------------------------------------------------------------------------- static void add_sprite_scale_x(register struct SCTRL *scp) { ++scp->ICSALop; scp->spriteLink->scalex += *scp->ICSALop; ++scp->ICSALop; } //*------------------------------------------------------------------------------------------ //* add_sprite_scale_y //*------------------------------------------------------------------------------------- static void add_sprite_scale_y(register struct SCTRL *scp) { ++scp->ICSALop; scp->spriteLink->scaley += *scp->ICSALop; ++scp->ICSALop; } //*------------------------------------------------------------------------------------------ //* change_sprite_tim //*------------------------------------------------------------------------------------- static void change_sprite_tim(register struct SCTRL *scp) { register GsIMAGE *timp; register int pmode; ++scp->ICSALop; //* Point to 1st operand timp = &timData[*scp->ICSALop]; pmode = timp->pmode & 0x07; scp->spriteLink->tpage = GetTPage(pmode, 0, timp->px, timp->py); scp->spriteLink->u = ((timp->px<<(2-pmode)) % (256>>pmode)); scp->spriteLink->v = timp->py; ++scp->ICSALop; //* Point to 2nd operand if (*scp->ICSALop) { //* non-zero flags to change clut also scp->spriteLink->cx = timp->cx; scp->spriteLink->cy = timp->cy; } ++scp->ICSALop; } //******************************************************************************************* //* //* General control operation instructions start here: //* //******************************************************************************************* //*------------------------------------------------------------------------------------------ //* set_loop_start //*------------------------------------------------------------------------------------- static void set_loop_start(register struct SCTRL *scp) { ++scp->ICSALop; if ((scp->ICSALloopCount=*scp->ICSALop)==RANGE_LOOP) //* Initialize loop counter scp->ICSALloopCount = bullLoop; ++scp->ICSALop; scp->ICSALloopStart = scp->ICSALop; //* Set loop top to command after 'set_loop_start n' } //*------------------------------------------------------------------------------------------ //* repeat_loop //*------------------------------------------------------------------------------------- static void repeat_loop(register struct SCTRL *scp) { if (scp->ICSALloopCount==INFINITE_LOOP) scp->ICSALop = scp->ICSALloopStart; //* Infinite loop: always loop back else if (--scp->ICSALloopCount) scp->ICSALop = scp->ICSALloopStart; //* Loop back... else ++scp->ICSALop; //* Finished: Point to command after 'repeat_loop' } //*------------------------------------------------------------------------------------------ //* set_data_start //*------------------------------------------------------------------------------------- static void set_data_start(register struct SCTRL *scp) { scp->ICSALdata = scp->ICSALdataStart = ++scp->ICSALop; //* Set pointers to start of data while (*scp->ICSALop++!=DATA_END) //* Set op-code pointer to past data items ; scp->ICSALdataLoopStart = scp->ICSALop; } //*------------------------------------------------------------------------------------------ //* if_floor_hit_expire //*------------------------------------------------------------------------------------- static void if_floor_hit_expire(register struct SCTRL *scp) { register struct SCTRL *scp2; register GsSPRITE *sp; ++scp->ICSALop; if (scp->high<=0) { scp2 = GetSprite(1); //* Get a 'bullet expire' sprite sp = scp2->spriteLink; //* Point to actual sprite sp->attribute = (A_4BIT_CLUT + A_BRIGHT_ON + A_ROTATE_OFF + A_TRATE_2 + A_TRANS_ON + A_DISPLAY_ON); sp->w = sp->h = 16; sp->tpage = GetTPage(0, 1, timData[TIM_BULLBANG].px, timData[TIM_BULLBANG].py); sp->u = 0; sp->v = 16; sp->cx = timData[TIM_BULLBANG].cx; sp->cy = timData[TIM_BULLBANG].cy; scp2->shadStat = 0; //* Shadow off //scp2->frameLock = scp2->currLock = LOCK_ALTFRAMES; scp2->ICSALop = bulletExpire; scp2->wx = scp->wxMid - 8; scp2->wy = scp->wy; scp2->high = 0; AliveLinkIn(scp2); //* Activate 'expire' service sprite AliveLinkOut(scp); //* Kill actual bullet sprite lastCall = 0x100; //* Ensure this is last ICSAL call } } //*------------------------------------------------------------------------------------------ //* reuse_last_data //*------------------------------------------------------------------------------------- static void reuse_last_data(register struct SCTRL *scp) { if (*scp->ICSALdata==DATA_END) scp->ICSALdata = scp->ICSALdataStart; //* Point to start of last used data set ++scp->ICSALop; } //*------------------------------------------------------------------------------------------ //* loop_while_data - loop back until all data items have been used //*------------------------------------------------------------------------------------- static void loop_while_data(register struct SCTRL *scp) { if (*scp->ICSALdata==DATA_END) { ++scp->ICSALop; //* Finished: point to command after loop_while_data scp->ICSALdata = NULL; } else scp->ICSALop = scp->ICSALdataLoopStart; //* Loop back... } //*------------------------------------------------------------------------------------------ //* loop_repeat_data //*------------------------------------------------------------------------------------- static void loop_repeat_data(register struct SCTRL *scp) { if (scp->ICSALloopCount==INFINITE_LOOP) scp->ICSALop = scp->ICSALloopStart; //* Infinite loop: always loop back else if (--scp->ICSALloopCount) scp->ICSALop = scp->ICSALloopStart; //* Decrease counter and loop back else { ++scp->ICSALop; //* Finished: Point to command after 'loop_repeat_data' return; } if (*scp->ICSALdata==DATA_END) scp->ICSALdata = scp->ICSALdataStart; //* Reset pointer to 1st data item } //*------------------------------------------------------------------------------------------ //* END_proc //*------------------------------------------------------------------------------------- static void END_proc(register struct SCTRL *scp) { scp->ICSALop = NULL; } //*------------------------------------------------------------------------------------------ //* END_kill_sprite //*------------------------------------------------------------------------------------- static void END_kill_sprite(register struct SCTRL *scp) { AliveLinkOut(scp); } //*------------------------------------------------------------------------------------------ //* END_expire_bullet //*------------------------------------------------------------------------------------- static void END_expire_bullet(register struct SCTRL *scp) { register struct SCTRL *scp2; register GsSPRITE *sp; scp2 = GetSprite(1); //* Get a 'bullet expire' sprite sp = scp2->spriteLink; //* Point to actual sprite sp->attribute = (A_4BIT_CLUT + A_BRIGHT_ON + A_ROTATE_OFF + A_TRATE_2 + A_TRANS_ON + A_DISPLAY_ON); sp->w = sp->h = 16; sp->tpage = GetTPage(0, 1, timData[TIM_BULLBANG].px, timData[TIM_BULLBANG].py); sp->u = 0; sp->v = 16; sp->cx = timData[TIM_BULLBANG].cx; sp->cy = timData[TIM_BULLBANG].cy; scp2->shadStat = 0; //* Shadow off //scp2->frameLock = scp2->currLock = LOCK_ALTFRAMES; scp2->ICSALop = bulletExpire; scp2->wx = scp->wxMid - 8; scp2->wy = scp->wy + 1; //* +1 so is drawn over bullet scp2->high = scp->high-(8-(scp->spriteLink->h>>1))+1; AliveLinkIn(scp2); //* Activate 'expire' service sprite //* Kill both bullet blur sprites //* Note: the 3 linked bullet sprites MUST be destroyed in reverse //* order else the .freeLink chain would be broken AliveLinkOut(scp->freeLink->freeLink); AliveLinkOut(scp->freeLink); AliveLinkOut(scp); //* Kill actual bullet sprite lastCall = 0x100; //* Ensure this is last ICSAL call } //*------------------------------------------------------------------------------------------ //* do_nothing //*------------------------------------------------------------------------------------- static void do_nothing(register struct SCTRL *scp) { ++scp->ICSALop; } //*------------------------------------------------------------------------------------------ //* done_if_x_past //*------------------------------------------------------------------------------------- static void done_if_x_past(register struct SCTRL *scp) { ++scp->ICSALop; if (scp->spriteLink->x > *scp->ICSALop++) { scp->ICSALop = NULL; //* End ICSAL procedure lastCall = 0x100; //* Ensure this is last call } } //*------------------------------------------------------------------------------------------ //* play_sfx //*------------------------------------------------------------------------------------- static void play_sfx(register struct SCTRL *scp) { register int prog, note, fine, vol; prog = *++scp->ICSALop; note = *++scp->ICSALop; fine = (*++scp->ICSALop ? rand()%128 : 0); vol = *++scp->ICSALop; SsUtKeyOn(0, prog, 0, note, fine, vol, vol); ++scp->ICSALop; } //******************************************************************************************* //* //* Specialized operation functions start here: //* //******************************************************************************************* //* Functions to detect if sprite bounding box (representing the base size of //* the sprite) will hit a wall on the next movement #define BASE_HIT_LEFT_WALL (((scp->wx + moveX) + scp->bbXOff) < 22) #define BASE_HIT_RIGHT_WALL (((scp->wx + moveX) + scp->bbXOff + scp->bbW) > 490) #define BASE_HIT_TOP_WALL (((scp->wy + moveY) - scp->bbYOff) < 40) #define BASE_HIT_BOTTOM_WALL (((scp->wy + moveY) - scp->bbYOff + scp->bbH) > 512) //* Functions to detect if shadow/reflection should be displayed #define SHAD_OVER_LEFT_WALL ((scp->wx + scp->bbXOff) < 22) #define SHAD_OVER_RIGHT_WALL ((scp->wx + scp->bbXOff + scp->bbW) > 490) #define SHAD_OVER_TOP_WALL ((scp->wy - scp->bbYOff) < 40) #define SHAD_OVER_BOTTOM_WALL ((scp->wy - scp->bbYOff + scp->bbH) > 512) //* Functions to detect if sprite has hit a wall, taking into account off-ground //* height and attitude of wall (perspective of left/right walls) #define SPRT_HIT_LEFT_WALL ((scp->wx + scp->bbXOff) < (22-(scp->high>>1))) #define SPRT_HIT_RIGHT_WALL ((scp->wx + scp->bbXOff + scp->bbW) > (490+(scp->high>>1))) #define SPRT_HIT_TOP_WALL ((scp->wy - scp->bbYOff) < 40) #define SPRT_HIT_BOTTOM_WALL ((scp->wy - scp->bbYOff + scp->bbH) > (512+(scp->high>>1))) //*------------------------------------------------------------------------------------------ //* move_chasing_enemy //*------------------------------------------------------------------------------------- static void move_chasing_enemy(register struct SCTRL *scp) { register GsSPRITE *sp = scp->spriteLink; //* Pointer to actual monster sprite object register int xDist, yDist; //* x & y distances away from target sprite register int moveX, moveY; //* Needed for above macros ++scp->ICSALop; //* Calculate relative distances away from target sprite //* Note: -y = below target; -x = to right of target xDist = chaseTarget->wxMid - scp->wxMid; yDist = chaseTarget->wyMid - scp->wyMid; //* Sprite frame number control management if (!(--scp->frameCount)) { scp->frameCount = scp->repsPerFrame; scp->currFrame = ++scp->currFrame & 0x3; } //* TRY and keep moving in current direction if counter has not reached 0 //* Note: a new chase direction will be assigned if a wall is hit if (--scp->moveCount) { moveX = scp->accelX; moveY = scp->accelY; //* Set sprite's frame image switch (scp->dir) { case DIR_DOWN_RIGHT: sp->u = (scp->currFrame << 5); if (BASE_HIT_RIGHT_WALL || BASE_HIT_BOTTOM_WALL) { //* Wall hit so flag to set a new chase direction below scp->moveCount = 0; } break; case DIR_UP_RIGHT: sp->u = (scp->currFrame << 5); if (BASE_HIT_RIGHT_WALL || BASE_HIT_TOP_WALL) { //* Wall hit so flag to set a new chase direction below scp->moveCount = 0; } break; case DIR_RIGHT: sp->u = (scp->currFrame << 5); if (BASE_HIT_RIGHT_WALL) { //* Wall hit so flag to set a new chase direction below scp->moveCount = 0; } break; case DIR_DOWN_LEFT: sp->u = 128 + (scp->currFrame << 5); if (BASE_HIT_LEFT_WALL || BASE_HIT_BOTTOM_WALL) { //* Wall hit so flag to set a new chase direction below scp->moveCount = 0; } break; case DIR_UP_LEFT: sp->u = 128 + (scp->currFrame << 5); if (BASE_HIT_LEFT_WALL || BASE_HIT_TOP_WALL) { //* Wall hit so flag to set a new chase direction below scp->moveCount = 0; } break; case DIR_LEFT: sp->u = 128 + (scp->currFrame << 5); if (BASE_HIT_LEFT_WALL) { //* Wall hit so flag to set a new chase direction below scp->moveCount = 0; } break; case DIR_DOWN: sp->u = (scp->currFrame << 5); if (BASE_HIT_BOTTOM_WALL) { //* Wall hit so flag to set a new chase direction below scp->moveCount = 0; } break; case DIR_UP: sp->u = 128 + (scp->currFrame << 5); if (BASE_HIT_TOP_WALL) { //* Wall hit so flag to set a new chase direction below scp->moveCount = 0; } break; } } //* Time to set a new chase direction when counter has reached 0 //* or monster has exact x and/or y alignment with chase target if (!scp->moveCount || !xDist || !yDist) { scp->moveCount = scp->moveMax; //* Reset movement counter //* Calculate sprite's new direction, frame image etc. if (xDist > 0) { //* To left of target sprite... if (yDist > 0) { //* and above target sprite. moveX = scp->speed; moveY = scp->speed; if (BASE_HIT_RIGHT_WALL) { //* Move DOWN only SET_MOVE_DOWN } else if (BASE_HIT_BOTTOM_WALL) { //* Move RIGHT only SET_MOVE_RIGHT } else { //* OK to move DOWN_RIGHT SET_MOVE_DOWN_RIGHT } } else if (yDist < 0) { //* and below target sprite. moveX = scp->speed; moveY = -scp->speed; if (BASE_HIT_RIGHT_WALL) { //* Move UP only SET_MOVE_UP } else if (BASE_HIT_TOP_WALL) { //* Move RIGHT only SET_MOVE_RIGHT } else { //* OK to move UP_RIGHT SET_MOVE_UP_RIGHT } } else { //* exactly. SET_MOVE_RIGHT } } else if (xDist < 0) { //* To right of target sprite... if (yDist > 0) { //* and above target sprite. moveX = -scp->speed; moveY = scp->speed; if (BASE_HIT_LEFT_WALL) { //* Move DOWN only SET_MOVE_DOWN } else if (BASE_HIT_BOTTOM_WALL) { //* Move LEFT only SET_MOVE_LEFT } else { //* OK to move DOWN_LEFT SET_MOVE_DOWN_LEFT } } else if (yDist < 0) { //* and below target sprite. moveX = -scp->speed; moveY = -scp->speed; if (BASE_HIT_LEFT_WALL) { //* Move UP only SET_MOVE_UP } else if (BASE_HIT_TOP_WALL) { //* Move LEFT only SET_MOVE_LEFT } else { //* OK to move UP_LEFT SET_MOVE_UP_LEFT } } else { //* exactly. SET_MOVE_LEFT } } else { //* Directly... if (yDist > 0) { //* above target sprite. SET_MOVE_DOWN } else { //* below target sprite. SET_MOVE_UP } } } //* Centre enemy sprite on new central world coords //* only if TeleVator is not active if (tvStat==TV_OFF) { scp->wx = (scp->wxMid += scp->accelX) - (scp->bbXOff + (scp->bbW >> 1)); scp->wy = (scp->wyMid += scp->accelY) + (scp->bbYOff - (scp->bbH >> 1)); } else ++scp->moveCount; //* dont count this call - adjust movement counter } //*------------------------------------------------------------------------------------------ //* move_enemy //*------------------------------------------------------------------------------------- static void move_enemy(register struct SCTRL *scp) { register GsSPRITE *sp = scp->spriteLink; //* Pointer to actual sprite object register int moveX = scp->accelX; //* Used in macros register int moveY = scp->accelY; //* Used in macros ++scp->ICSALop; //* Sprite frame number control management if (!(--scp->frameCount)) { scp->frameCount = scp->repsPerFrame; scp->currFrame = ++scp->currFrame & 0x3; } //* Set sprite's frame image switch (scp->dir) { case DIR_DOWN_RIGHT: sp->u = (scp->currFrame << 5); sp->v = 96; if (BASE_HIT_RIGHT_WALL || BASE_HIT_BOTTOM_WALL) { scp->ICSALop = enemyChase; lastCall = 0x00; //* Ensure initialization of new ICSAL proc return; } break; case DIR_UP_RIGHT: sp->u = (scp->currFrame << 5); sp->v = 64; if (BASE_HIT_RIGHT_WALL || BASE_HIT_TOP_WALL) { scp->ICSALop = enemyChase; lastCall = 0x00; //* Ensure initialization of new ICSAL proc return; } break; case DIR_RIGHT: sp->u = (scp->currFrame << 5); sp->v = 32; if (BASE_HIT_RIGHT_WALL) { scp->ICSALop = enemyChase; lastCall = 0x00; //* Ensure initialization of new ICSAL proc return; } break; case DIR_DOWN_LEFT: sp->u = 128 + (scp->currFrame << 5); sp->v = 96; if (BASE_HIT_LEFT_WALL || BASE_HIT_BOTTOM_WALL) { scp->ICSALop = enemyChase; lastCall = 0x00; //* Ensure initialization of new ICSAL proc return; } break; case DIR_UP_LEFT: sp->u = 128 + (scp->currFrame << 5); sp->v = 64; if (BASE_HIT_LEFT_WALL || BASE_HIT_TOP_WALL) { scp->ICSALop = enemyChase; lastCall = 0x00; //* Ensure initialization of new ICSAL proc return; } break; case DIR_LEFT: sp->u = 128 + (scp->currFrame << 5); sp->v = 32; if (BASE_HIT_LEFT_WALL) { scp->ICSALop = enemyChase; lastCall = 0x00; //* Ensure initialization of new ICSAL proc return; } break; case DIR_DOWN: sp->u = (scp->currFrame << 5); sp->v = 0; if (BASE_HIT_BOTTOM_WALL) { scp->ICSALop = enemyChase; lastCall = 0x00; //* Ensure initialization of new ICSAL proc return; } break; case DIR_UP: sp->u = 128 + (scp->currFrame << 5); sp->v = 0; if (BASE_HIT_TOP_WALL) { scp->ICSALop = enemyChase; lastCall = 0x00; //* Ensure initialization of new ICSAL proc return; } break; } //* Set new world coords for this sprite //* only if TeleVator is not active if (tvStat==TV_OFF) { scp->wx += moveX; scp->wy += moveY; } else scp->ICSALloopCount++; //* dont count this call - adjust loop counter } //*------------------------------------------------------------------------------------------ //* move_chasing_ufo //*------------------------------------------------------------------------------------- static void move_chasing_ufo(register struct SCTRL *scp) { register GsSPRITE *sp = scp->spriteLink; //* Pointer to actual ufo sprite object register int xDist, yDist; //* x & y distances away from target sprite register int moveX, moveY; //* Needed for above macros register struct GRID_PAIR *gp; register struct SCTRL *mineScp; //* Reassign UFO to lay a mine when count falls below min... if (mineCount < mineMin) { scp->ICSALop = ufoLayMine; //* Set new ICSAL proc lastCall = 0x00; //* Ensure new ICSAL proc is run immediately //* Create mine sprite NOW at required world coords (to act as UFO target) //* BUT this wont be linked into the game until later! gp = GetRandGrid(); scp->target = mineScp = GetSprite(1); PresetSprite(mineScp, PRESET_MINE); mineScp->wx = 28 + (gp->c<<4) + ((gp->r & 0x00000001)<<3); mineScp->wy = 55 + (gp->r<<4); mineScp->wxMid = mineScp->wx + mineScp->bbXOff + (mineScp->bbW >> 1); mineScp->wyMid = mineScp->wy - mineScp->bbYOff + (mineScp->bbH >> 1); ++mineLaying; scp->moveCount = 0; //* Signals to move_mining_ufo that destination not reached yet return; } ++scp->ICSALop; //* Calculate relative distances away from target sprite //* Note: -y = below target; -x = to right of target xDist = chaseTarget->wxMid - scp->wxMid; yDist = chaseTarget->wyMid - scp->wyMid; //* Sprite frame number control management if (!(--scp->frameCount)) { scp->frameCount = scp->repsPerFrame; scp->currFrame = ++scp->currFrame & 0x3; } //* Set sprite's frame image sp->u = (scp->currFrame << 5); //* TRY and keep moving in current direction if counter has not reached 0 //* Note: a new chase direction will be assigned if a wall is hit if (--scp->moveCount) { moveX = scp->accelX; moveY = scp->accelY; switch (scp->dir) { case DIR_DOWN_RIGHT: if (BASE_HIT_RIGHT_WALL || BASE_HIT_BOTTOM_WALL) { //* Wall hit so flag to set a new chase direction below scp->moveCount = 0; } break; case DIR_UP_RIGHT: if (BASE_HIT_RIGHT_WALL || BASE_HIT_TOP_WALL) { //* Wall hit so flag to set a new chase direction below scp->moveCount = 0; } break; case DIR_RIGHT: if (BASE_HIT_RIGHT_WALL) { //* Wall hit so flag to set a new chase direction below scp->moveCount = 0; } break; case DIR_DOWN_LEFT: if (BASE_HIT_LEFT_WALL || BASE_HIT_BOTTOM_WALL) { //* Wall hit so flag to set a new chase direction below scp->moveCount = 0; } break; case DIR_UP_LEFT: if (BASE_HIT_LEFT_WALL || BASE_HIT_TOP_WALL) { //* Wall hit so flag to set a new chase direction below scp->moveCount = 0; } break; case DIR_LEFT: if (BASE_HIT_LEFT_WALL) { //* Wall hit so flag to set a new chase direction below scp->moveCount = 0; } break; case DIR_DOWN: if (BASE_HIT_BOTTOM_WALL) { //* Wall hit so flag to set a new chase direction below scp->moveCount = 0; } break; case DIR_UP: if (BASE_HIT_TOP_WALL) { //* Wall hit so flag to set a new chase direction below scp->moveCount = 0; } break; } } //* Time to set a new chase direction when counter has reached 0 //* or ufo has exact x and/or y alignment with chase target if (!scp->moveCount || !xDist || !yDist) { scp->moveCount = scp->moveMax; //* Reset movement counter //* Calculate sprite's new direction etc. if (xDist > 0) { //* To left of target sprite... if (yDist > 0) { //* and above target sprite. moveX = scp->speed; moveY = scp->speed; if (BASE_HIT_RIGHT_WALL) { //* Move DOWN only scp->accelX = 0; scp->accelY = scp->speed; scp->dir = DIR_DOWN; } else if (BASE_HIT_BOTTOM_WALL) { //* Move RIGHT only scp->accelX = scp->speed; scp->accelY = 0; scp->dir = DIR_RIGHT; } else { //* OK to move DOWN_RIGHT scp->accelX = scp->speed; scp->accelY = scp->speed; scp->dir = DIR_DOWN_RIGHT; } } else if (yDist < 0) { //* and below target sprite. moveX = scp->speed; moveY = -scp->speed; if (BASE_HIT_RIGHT_WALL) { //* Move UP only scp->accelX = 0; scp->accelY = -scp->speed; scp->dir = DIR_UP; } else if (BASE_HIT_TOP_WALL) { //* Move RIGHT only scp->accelX = scp->speed; scp->accelY = 0; scp->dir = DIR_RIGHT; } else { //* OK to move UP_RIGHT scp->accelX = scp->speed; scp->accelY = -scp->speed; scp->dir = DIR_UP_RIGHT; } } else { //* exactly. scp->accelX = scp->speed; scp->accelY = 0; scp->dir = DIR_RIGHT; } } else if (xDist < 0) { //* To right of target sprite... if (yDist > 0) { //* and above target sprite. moveX = -scp->speed; moveY = scp->speed; if (BASE_HIT_LEFT_WALL) { //* Move DOWN only scp->accelX = 0; scp->accelY = scp->speed; scp->dir = DIR_DOWN; } else if (BASE_HIT_BOTTOM_WALL) { //* Move LEFT only scp->accelX = -scp->speed; scp->accelY = 0; scp->dir = DIR_LEFT; } else { //* OK to move DOWN_LEFT scp->accelX = -scp->speed; scp->accelY = scp->speed; scp->dir = DIR_DOWN_LEFT; } } else if (yDist < 0) { //* and below target sprite. moveX = -scp->speed; moveY = -scp->speed; if (BASE_HIT_LEFT_WALL) { //* Move UP only scp->accelX = 0; scp->accelY = -scp->speed; scp->dir = DIR_UP; } else if (BASE_HIT_TOP_WALL) { //* Move LEFT only scp->accelX = -scp->speed; scp->accelY = 0; scp->dir = DIR_LEFT; } else { //* OK to move UP_LEFT scp->accelX = -scp->speed; scp->accelY = -scp->speed; scp->dir = DIR_UP_LEFT; } } else { //* exactly. scp->accelX = -scp->speed; scp->accelY = 0; scp->dir = DIR_LEFT; } } else { //* Directly... if (yDist > 0) { //* above target sprite. scp->accelX = 0; scp->accelY = scp->speed; scp->dir = DIR_DOWN; } else { //* below target sprite. scp->accelX = 0; scp->accelY = -scp->speed; scp->dir = DIR_UP; } } } //* Centre enemy sprite on new central world coords //* only if TeleVator is not active if (tvStat==TV_OFF) { scp->wx = (scp->wxMid += scp->accelX) - (scp->bbXOff + (scp->bbW >> 1)); scp->wy = (scp->wyMid += scp->accelY) + (scp->bbYOff - (scp->bbH >> 1)); } else ++scp->moveCount; //* dont count this call - adjust movement counter } //*------------------------------------------------------------------------------------------ //* move_mining_ufo //*------------------------------------------------------------------------------------- static void move_mining_ufo(register struct SCTRL *scp) { register GsSPRITE *sp = scp->spriteLink; //* Pointer to actual sprite object register int xDist, yDist; //* Relative x & y distances away from target register int xDistAbs, yDistAbs; //* Absolute x & y distances away from target register int moveX, moveY; //* Relative values to add to baby world coords register int speed=scp->speed; //* Maximum pixel increment per move ++scp->ICSALop; //* Sprite frame number control management if (!(--scp->frameCount)) { scp->frameCount = scp->repsPerFrame; scp->currFrame = ++scp->currFrame & 0x3; } //* Set sprite's frame image sp->u = (scp->currFrame << 5); //* Animate only, when TeleVator is active if (tvStat!=TV_OFF) { return; } //* Lay mine if UFO exactly in position (signalled by .moveCount)... if (scp->moveCount) { if (scp->moveCount > 1) { //* Hover a while before landing... --scp->moveCount; } else if (scp->target) { //* Mine not laid yet (still associated to UFO)... if (scp->high) { //* Land UFO --scp->high; } else { //* Now landed so lay mine AliveLinkIn(scp->target); --mineLaying; ++mineCount; scp->target = NULL; //* Signals mine has been laid! SsUtKeyOn(0, SFX_CART, 0, 67, 0, 127, 127); } } else { //* Mine has been laid... if (scp->high < UFO_HOVER_HEIGHT) { //* Raise UFO to hover height ++scp->high; } else { //* Mission complete: start chasing BB again scp->ICSALop = ufoChase; //* Set new ICSAL proc lastCall = 0x00; //* Ensure new ICSAL proc is run immediately } } return; } //* Calculate relative distance UFO is away from mine's CENTRAL coords //* Note: -y = below target; -x = to right of target xDist = scp->target->wxMid - scp->wxMid; yDist = scp->target->wyMid - scp->wyMid; if (!xDist && !yDist) { SsUtKeyOn(0, SFX_LASER, 0, 48, 0, 100, 100); scp->moveCount = 10; //* Signals destination reached! return; } xDistAbs = abs(xDist); //* Actual number of pixels away from target X coord yDistAbs = abs(yDist); //* Actual number of pixels away from target Y coord //* Set UFO's X movement if (xDistAbs<=speed) moveX = xDist; else if (xDistAbs>speed) { moveX = speed + (xDistAbs % speed); //* Ensure snap to X movement grid if (xDist<0) moveX = -moveX; } else moveX = 0; //* Set UFO's Y movement if (yDistAbs<=speed) moveY = yDist; else if (yDistAbs>speed) { moveY = speed + (yDistAbs % speed); //* Ensure snap to Y movement grid if (yDist < 0) moveY = -moveY; } else moveY = 0; //* Set sprite direction according to x,y movement if (moveX && moveY) { //* Is diagonal movement... if (moveX < 0) { if (moveY < 0) { //* and upwards scp->dir = DIR_UP_LEFT; } else { scp->dir = DIR_DOWN_LEFT; } } else { //* and downwards if (moveY < 0) { scp->dir = DIR_UP_RIGHT; } else { scp->dir = DIR_DOWN_RIGHT; } } } else { //* Is up, down, left or right movement if (moveX < 0) { scp->dir = DIR_LEFT; } else if (moveX > 0) { scp->dir = DIR_RIGHT; } else if (moveY < 0) { scp->dir = DIR_UP; } else { scp->dir = DIR_DOWN; } } //* Centre UFO on new central world coords scp->wx = (scp->wxMid += moveX) - (scp->bbXOff + (scp->bbW >> 1)); scp->wy = (scp->wyMid += moveY) + (scp->bbYOff - (scp->bbH >> 1)); } //*------------------------------------------------------------------------------------------ //* move_ufo //*------------------------------------------------------------------------------------- static void move_ufo(register struct SCTRL *scp) { register GsSPRITE *sp = scp->spriteLink; //* Pointer to actual sprite object register int moveX = scp->accelX; //* Used in macros register int moveY = scp->accelY; //* Used in macros ++scp->ICSALop; //* Sprite frame number control management if (!(--scp->frameCount)) { scp->frameCount = scp->repsPerFrame; scp->currFrame = ++scp->currFrame & 0x3; } //* Set sprite's frame image sp->u = (scp->currFrame << 5); //* Handle wall collisions switch (scp->dir) { case DIR_DOWN_RIGHT: if (BASE_HIT_RIGHT_WALL || BASE_HIT_BOTTOM_WALL) { scp->ICSALop = ufoChase; lastCall = 0x00; //* Ensure initialization of new ICSAL proc return; } break; case DIR_UP_RIGHT: if (BASE_HIT_RIGHT_WALL || BASE_HIT_TOP_WALL) { scp->ICSALop = ufoChase; lastCall = 0x00; //* Ensure initialization of new ICSAL proc return; } break; case DIR_RIGHT: if (BASE_HIT_RIGHT_WALL) { scp->ICSALop = ufoChase; lastCall = 0x00; //* Ensure initialization of new ICSAL proc return; } break; case DIR_DOWN_LEFT: if (BASE_HIT_LEFT_WALL || BASE_HIT_BOTTOM_WALL) { scp->ICSALop = ufoChase; lastCall = 0x00; //* Ensure initialization of new ICSAL proc return; } break; case DIR_UP_LEFT: if (BASE_HIT_LEFT_WALL || BASE_HIT_TOP_WALL) { scp->ICSALop = ufoChase; lastCall = 0x00; //* Ensure initialization of new ICSAL proc return; } break; case DIR_LEFT: if (BASE_HIT_LEFT_WALL) { scp->ICSALop = ufoChase; lastCall = 0x00; //* Ensure initialization of new ICSAL proc return; } break; case DIR_DOWN: if (BASE_HIT_BOTTOM_WALL) { scp->ICSALop = ufoChase; lastCall = 0x00; //* Ensure initialization of new ICSAL proc return; } break; case DIR_UP: if (BASE_HIT_TOP_WALL) { scp->ICSALop = ufoChase; lastCall = 0x00; //* Ensure initialization of new ICSAL proc return; } break; } //* Set new world coords for this sprite //* only if TeleVator is not active if (tvStat==TV_OFF) { scp->wx += moveX; scp->wy += moveY; } else scp->ICSALloopCount++; //* dont count this call - adjust loop counter } //*------------------------------------------------------------------------------------------ //* handle_sprite_over_wall //*------------------------------------------------------------------------------------- static void handle_sprite_over_wall(register struct SCTRL *scp) { register struct SCTRL *scp2; register GsSPRITE *sp; //* Handling is sprite movement direction specific switch (scp->dir) { case DIR_DOWN: if (SHAD_OVER_BOTTOM_WALL) scp->shadStat = 0; //* Shadow/reflection off while over wall else scp->shadStat = 1; //* Shadow/reflection on when not over wall //* Consider sprite hitting bottom wall if (SPRT_HIT_BOTTOM_WALL) break; ++scp->ICSALop; return; case DIR_DOWN_LEFT: if (SHAD_OVER_LEFT_WALL || SHAD_OVER_BOTTOM_WALL) scp->shadStat = 0; //* Shadow/reflection off while over wall else scp->shadStat = 1; //* Shadow/reflection on when not over wall //* Consider sprite hitting left or bottom wall if (SPRT_HIT_LEFT_WALL || SPRT_HIT_BOTTOM_WALL) break; ++scp->ICSALop; return; case DIR_LEFT: if (SHAD_OVER_LEFT_WALL) scp->shadStat = 0; //* Shadow/reflection off while over wall else scp->shadStat = 1; //* Shadow/reflection on when not over wall //* Consider sprite hitting left wall if (SPRT_HIT_LEFT_WALL) break; ++scp->ICSALop; return; case DIR_UP_LEFT: if (SHAD_OVER_LEFT_WALL || SHAD_OVER_TOP_WALL) scp->shadStat = 0; //* Shadow/reflection off while over wall else scp->shadStat = 1; //* Shadow/reflection on when not over wall //* Consider sprite hitting left or top wall if (SPRT_HIT_LEFT_WALL || SPRT_HIT_TOP_WALL) break; ++scp->ICSALop; return; case DIR_UP: if (SHAD_OVER_TOP_WALL) scp->shadStat = 0; //* Shadow/reflection off while over wall else scp->shadStat = 1; //* Shadow/reflection on when not over wall //* Consider sprite hitting top wall if (SPRT_HIT_TOP_WALL) break; ++scp->ICSALop; return; case DIR_UP_RIGHT: if (SHAD_OVER_RIGHT_WALL || SHAD_OVER_TOP_WALL) scp->shadStat = 0; //* Shadow/reflection off while over wall else scp->shadStat = 1; //* Shadow/reflection on when not over wall //* Consider sprite hitting right or top wall if (SPRT_HIT_RIGHT_WALL || SPRT_HIT_TOP_WALL) break; ++scp->ICSALop; return; case DIR_RIGHT: if (SHAD_OVER_RIGHT_WALL) scp->shadStat = 0; //* Shadow/reflection off while over wall else scp->shadStat = 1; //* Shadow/reflection on when not over wall //* Consider sprite hitting right wall if (SPRT_HIT_RIGHT_WALL) break; ++scp->ICSALop; return; case DIR_DOWN_RIGHT: if (SHAD_OVER_RIGHT_WALL || SHAD_OVER_BOTTOM_WALL) scp->shadStat = 0; //* Shadow/reflection off while over wall else scp->shadStat = 1; //* Shadow/reflection on when not over wall //* Consider sprite hitting right or bottom wall if (SPRT_HIT_RIGHT_WALL || SPRT_HIT_BOTTOM_WALL) break; ++scp->ICSALop; return; } //* Display 'expire' sprite to show where sprite has hit wall... scp2 = GetSprite(1); //* Get a 'bullet expire' sprite sp = scp2->spriteLink; //* Point to actual sprite sp->attribute = (A_4BIT_CLUT + A_BRIGHT_ON + A_ROTATE_OFF + A_TRATE_2 + A_TRANS_ON + A_DISPLAY_ON); sp->w = sp->h = 16; sp->tpage = GetTPage(0, 1, timData[TIM_BULLBANG].px, timData[TIM_BULLBANG].py); sp->u = 0; sp->v = 16; sp->cx = timData[TIM_BULLBANG].cx; sp->cy = timData[TIM_BULLBANG].cy; scp2->shadStat = 0; //* Shadow off //scp2->frameLock = scp2->currLock = LOCK_ALTFRAMES; scp2->ICSALop = bulletExpire; scp2->wx = scp->wxMid - 8; scp2->wy = scp->wy + 1; //* +1 so is drawn over bullet scp2->high = scp->high-(8-(scp->spriteLink->h>>1))+1; AliveLinkIn(scp2); //* Activate 'expire' service sprite if (scp->ID==ID_BULLET) { //* Bullet has hit wall... //* Kill both bullet blur sprites //* Note: the 3 linked bullet sprites MUST be destroyed in reverse //* order else the .freeLink chain would be broken if (scp->freeLink->alive) { //* The 2 bullet blur sprites are active... AliveLinkOut(scp->freeLink->freeLink); AliveLinkOut(scp->freeLink); } else { //* The 2 bullet blur sprites aren't active yet... PutSprite(scp->freeLink->freeLink); PutSprite(scp->freeLink); } } else if (scp->ID==ID_MOONBALL) { //* SFX for moonball only! SsUtKeyOn(0, SFX_ENEMY_EXPLODE1, 0, 93, 0, 127, 127); } AliveLinkOut(scp); //* Kill this sprite lastCall = 0x100; //* Ensure this is last ICSAL call } //*------------------------------------------------------------------------------------------ //* handle_shadow_over_wall //*------------------------------------------------------------------------------------- static void handle_shadow_over_wall(register struct SCTRL *scp) { //* Handling is sprite movement direction specific switch (scp->dir) { case DIR_DOWN: if (SHAD_OVER_BOTTOM_WALL) scp->shadStat = 0; //* Shadow/reflection off because it's over wall else scp->shadStat = 1; //* Shadow/reflection on when not over wall break; case DIR_DOWN_LEFT: if (SHAD_OVER_LEFT_WALL || SHAD_OVER_BOTTOM_WALL) scp->shadStat = 0; else scp->shadStat = 1; break; case DIR_LEFT: if (SHAD_OVER_LEFT_WALL) scp->shadStat = 0; else scp->shadStat = 1; break; case DIR_UP_LEFT: if (SHAD_OVER_LEFT_WALL || SHAD_OVER_TOP_WALL) scp->shadStat = 0; else scp->shadStat = 1; break; case DIR_UP: if (SHAD_OVER_TOP_WALL) scp->shadStat = 0; else scp->shadStat = 1; break; case DIR_UP_RIGHT: if (SHAD_OVER_RIGHT_WALL || SHAD_OVER_TOP_WALL) scp->shadStat = 0; else scp->shadStat = 1; break; case DIR_RIGHT: if (SHAD_OVER_RIGHT_WALL) scp->shadStat = 0; else scp->shadStat = 1; break; case DIR_DOWN_RIGHT: if (SHAD_OVER_RIGHT_WALL || SHAD_OVER_BOTTOM_WALL) scp->shadStat = 0; else scp->shadStat = 1; break; } ++scp->ICSALop; } //*------------------------------------------------------------------------------------------ //* handle_heart_over_wall //*------------------------------------------------------------------------------------- static void handle_heart_over_wall(register struct SCTRL *scp) { if (SHAD_OVER_LEFT_WALL || SHAD_OVER_RIGHT_WALL) scp->shadStat = 0; //* Shadow off because it's over wall else scp->shadStat = 1; ++scp->ICSALop; } static int babyCnt; //* Used to hold count of consecutive babies saved in move_centre_tv //*------------------------------------------------------------------------------------------ //* REP_tv_off //*------------------------------------------------------------------------------------- static void REP_tv_off(register struct SCTRL *scp) { short currVol; if (tvStat==TV_OFF) return; //* Ignore - TV is already off if (tvStat!=TV_TURNING_OFF) { SsUtKeyOff(tvVoice, 0, SFX_TELEVATOR, 0, 60); SsUtKeyOn(0, SFX_SPIN_SCREEN, 0, 84, 0, 127, 127); tvVoice = 0; tvLightLock = tvLightCLock = LOCK_ALTFRAMES; beamSpeed = 2; scp->wx = 236; scp->bbXOff = 1; scp->spriteLink->u = 0; scp->spriteLink->w = 40; } tvStat = TV_TURNING_OFF; //* Flag that TV is being turned off if (sprt[SPRT_TVBEAM].r) { sprt[SPRT_TVBEAM].r = sprt[SPRT_TVBEAM].g = sprt[SPRT_TVBEAM].b -= 2; } else { tvStat = TV_OFF; sCtrl->unintICSAL = 0; //* Allow BB to be hit by enemies again beamSpeed = 2; tvLightLock = tvLightCLock = LOCK_3FRAMES; babyCnt = 0; //* Reset saved consecutive baby count } } //*------------------------------------------------------------------------------------------ //* REP_tv_on //*------------------------------------------------------------------------------------- static void REP_tv_on(register struct SCTRL *scp) { register struct SCTRL *scp2; short currVol; if (tvStat==TV_ON) { //* TV is ready for beam-up... //* Set new TV beam frame every time switch (scp->currFrame = ++scp->currFrame & 0x3) { case 0: case 2: scp->wx = 236; scp->bbXOff = 1; scp->spriteLink->u = 0; scp->spriteLink->w = 40; break; case 1: scp->wx = 236; scp->bbXOff = 1; scp->spriteLink->u = 40; scp->spriteLink->w = 40; break; case 3: scp->wx = 233; scp->bbXOff = 4; scp->spriteLink->u = 80; scp->spriteLink->w = 46; break; } return; //* TV is already on } if (tvStat!=TV_TURNING_ON) { //* Is first time call SsUtKeyOn(0, SFX_SPIN_SCREEN, 0, 84, 0, 127, 127); tvLightLock = tvLightCLock = LOCK_ALTFRAMES; beamSpeed = 2; sCtrl->speed = BBtrueSpeed; sCtrl->repsPerFrame = 4; } tvStat = TV_TURNING_ON; //* Flag that TV is being turned on if (sprt[SPRT_TVBEAM].r<64) { sprt[SPRT_TVBEAM].r = sprt[SPRT_TVBEAM].g = sprt[SPRT_TVBEAM].b += 2; } else { tvVoice = SsUtKeyOn(0, SFX_TELEVATOR, 0, 60, 0, 100, 100); tvStat = TV_ON; beamSpeed = 4; tvLightLock = tvLightCLock = LOCK_NOFRAMES; scp->currFrame = 0; if (lastInLine!=sCtrl) { //* Set following baby to beam-up... //* Find baby that's following BB scp2 = lastInLine; while (scp2->target!=sCtrl) scp2 = scp2->target; scp2->target = &sCtrl[SPRT_TVBEAM]; scp2->ICSALop = gotoTV; //* Set baby to move into position for beam-up scp2->subID = BABY_GOTO_TV; } } } //*------------------------------------------------------------------------------------------ //* start_bullet_blur //*------------------------------------------------------------------------------------- static void start_bullet_blur(register struct SCTRL *scp) { AliveLinkIn(scp->freeLink); AliveLinkIn(scp->freeLink->freeLink); scp->freeLink->wx = scp->wx; scp->freeLink->wy = scp->wy; scp->freeLink->high = scp->high; ++scp->ICSALop; } //*------------------------------------------------------------------------------------------ //* update_bullet_blur //*------------------------------------------------------------------------------------- static void update_bullet_blur(register struct SCTRL *scp) { register struct SCTRL *blur1=scp->freeLink; register struct SCTRL *blur2=scp->freeLink->freeLink; blur2->wx = blur1->wx; blur2->wy = blur1->wy; blur2->high = blur1->high; blur1->wx = scp->wx; blur1->wy = scp->wy; blur1->high = scp->high; // scp2->wx = scp->wx; // scp2->wy = scp->wy; // scp2->high = scp->high; ++scp->ICSALop; } //*------------------------------------------------------------------------------------------ //* update_bullet_blur2 //*------------------------------------------------------------------------------------- //static void update_bullet_blur2(register struct SCTRL *scp) //{ //register struct SCTRL *scp1=scp->freeLink; //register struct SCTRL *scp2=scp->freeLink->freeLink; // // scp1->wx = scp->wx + ((scp2->wx - scp->wx)>>1); // scp1->wy = scp->wy + ((scp2->wy - scp->wy)>>1); // scp1->high = scp->high + ((scp2->high - scp->high)>>1); // ++scp->ICSALop; //} //*------------------------------------------------------------------------------------------ //* move_lost_baby //*------------------------------------------------------------------------------------- static void move_lost_baby(register struct SCTRL *scp) { register GsSPRITE *sp = scp->spriteLink; //* Pointer to actual sprite object register int moveX = scp->accelX; //* Used in macros register int moveY = scp->accelY; //* Used in macros ++scp->ICSALop; //* Sprite frame number control management if (!(--scp->frameCount)) { scp->frameCount = scp->repsPerFrame; scp->currFrame = ++scp->currFrame & 0x3; } //* Set sprite's frame image switch (scp->dir) { case DIR_DOWN_RIGHT: if (BASE_HIT_RIGHT_WALL) { //* Change direction... if (scp->wy & 0x01) { //* Move down-left (odd world Y coord) SET_MOVE_DOWN_LEFT BABY_BB_DOWN_LEFT } else { //* Move down (even world Y coord) SET_MOVE_DOWN BABY_BB_DOWN } } else if (BASE_HIT_BOTTOM_WALL) { //* Change direction (bottom wall ONLY hit)... if (scp->wx & 0x01) { //* Move right (odd world X coord) SET_MOVE_RIGHT BABY_BB_RIGHT } else { //* Move up-right (even world X coord) SET_MOVE_UP_RIGHT BABY_BB_UP_RIGHT } } else if (!(--scp->moveCount)) { //* Time for a direction change? scp->moveCount = scp->moveMax; switch (rand()%5) { case 0: SET_MOVE_UP_RIGHT BABY_BB_UP_RIGHT break; case 1: SET_MOVE_RIGHT BABY_BB_RIGHT break; case 2: SET_MOVE_DOWN_RIGHT //* No change! BABY_BB_DOWN_RIGHT break; case 3: SET_MOVE_DOWN BABY_BB_DOWN break; case 4: SET_MOVE_DOWN_LEFT BABY_BB_DOWN_LEFT break; } } else { //* Continue moving down-right sp->u = (scp->currFrame << 5); sp->v = 96; } break; case DIR_UP_RIGHT: if (BASE_HIT_RIGHT_WALL) { //* Change direction... if (scp->wy & 0x01) { //* Move up-left (odd world Y coord) SET_MOVE_UP_LEFT BABY_BB_UP_LEFT } else { //* Move up (even world Y coord) SET_MOVE_UP BABY_BB_UP } } else if (BASE_HIT_TOP_WALL) { //* Change direction (top wall ONLY hit)... if (scp->wx & 0x01) { //* Move right (odd world X coord) SET_MOVE_RIGHT BABY_BB_RIGHT } else { //* Move down-right (even world X coord) SET_MOVE_DOWN_RIGHT BABY_BB_DOWN_RIGHT } } else if (!(--scp->moveCount)) { //* Time for a direction change? scp->moveCount = scp->moveMax; switch (rand()%5) { case 0: SET_MOVE_UP_LEFT BABY_BB_UP_LEFT break; case 1: SET_MOVE_UP BABY_BB_UP break; case 2: SET_MOVE_UP_RIGHT //* No change! BABY_BB_UP_RIGHT break; case 3: SET_MOVE_RIGHT BABY_BB_RIGHT break; case 4: SET_MOVE_DOWN_RIGHT BABY_BB_DOWN_RIGHT break; } } else { //* Continue moving up-right sp->u = (scp->currFrame << 5); sp->v = 64; } break; case DIR_DOWN_LEFT: if (BASE_HIT_LEFT_WALL) { //* Change direction... if (scp->wy & 0x01) { //* Move down-right (odd world Y coord) SET_MOVE_DOWN_RIGHT BABY_BB_DOWN_RIGHT } else { //* Move down (even world Y coord) SET_MOVE_DOWN BABY_BB_DOWN } } else if (BASE_HIT_BOTTOM_WALL) { //* Change direction (bottom wall ONLY hit)... if (scp->wx & 0x01) { //* Move left (odd world X coord) SET_MOVE_LEFT BABY_BB_LEFT } else { //* Move up-left (even world X coord) SET_MOVE_UP_LEFT BABY_BB_UP_LEFT } } else if (!(--scp->moveCount)) { //* Time for a direction change? scp->moveCount = scp->moveMax; switch (rand()%5) { case 0: SET_MOVE_DOWN_RIGHT BABY_BB_DOWN_RIGHT break; case 1: SET_MOVE_DOWN BABY_BB_DOWN break; case 2: SET_MOVE_DOWN_LEFT //* No change! BABY_BB_DOWN_LEFT break; case 3: SET_MOVE_LEFT BABY_BB_LEFT break; case 4: SET_MOVE_UP_LEFT BABY_BB_UP_LEFT break; } } else { //* Continue moving down-left sp->u = 128 + (scp->currFrame << 5); sp->v = 96; } break; case DIR_UP_LEFT: if (BASE_HIT_LEFT_WALL) { //* Change direction... if (scp->wy & 0x01) { //* Move up-right (odd world Y coord) SET_MOVE_UP_RIGHT BABY_BB_UP_RIGHT } else { //* Move up (even world Y coord) SET_MOVE_UP BABY_BB_UP } } else if (BASE_HIT_TOP_WALL) { //* Change direction (top wall ONLY hit)... if (scp->wx & 0x01) { //* Move left (odd world X coord) SET_MOVE_LEFT BABY_BB_LEFT } else { //* Move down-left (even world X coord) SET_MOVE_DOWN_LEFT BABY_BB_DOWN_LEFT } } else if (!(--scp->moveCount)) { //* Time for a direction change? scp->moveCount = scp->moveMax; switch (rand()%5) { case 0: SET_MOVE_DOWN_LEFT BABY_BB_DOWN_LEFT break; case 1: SET_MOVE_LEFT BABY_BB_LEFT break; case 2: SET_MOVE_UP_LEFT //* No change! BABY_BB_UP_LEFT break; case 3: SET_MOVE_UP BABY_BB_UP break; case 4: SET_MOVE_UP_RIGHT BABY_BB_UP_RIGHT break; } } else { //* Continue moving up-left sp->u = 128 + (scp->currFrame << 5); sp->v = 64; } break; case DIR_RIGHT: if (BASE_HIT_RIGHT_WALL) { //* Change direction... if (scp->wy<255) { //* Move down SET_MOVE_DOWN BABY_BB_DOWN } else { //* Move up SET_MOVE_UP BABY_BB_UP } } else if (!(--scp->moveCount)) { //* Time for a direction change? scp->moveCount = scp->moveMax; switch (rand()%5) { case 0: SET_MOVE_UP BABY_BB_UP break; case 1: SET_MOVE_UP_RIGHT BABY_BB_UP_RIGHT break; case 2: SET_MOVE_RIGHT //* No change! BABY_BB_RIGHT break; case 3: SET_MOVE_DOWN_RIGHT BABY_BB_DOWN_RIGHT break; case 4: SET_MOVE_DOWN BABY_BB_DOWN break; } } else { //* Continue moving right sp->u = (scp->currFrame << 5); sp->v = 32; } break; case DIR_LEFT: if (BASE_HIT_LEFT_WALL) { //* Change direction... if (scp->wy<255) { //* Move down SET_MOVE_DOWN BABY_BB_DOWN } else { //* Move up SET_MOVE_UP BABY_BB_UP } } else if (!(--scp->moveCount)) { //* Time for a direction change? scp->moveCount = scp->moveMax; switch (rand()%5) { case 0: SET_MOVE_DOWN BABY_BB_DOWN break; case 1: SET_MOVE_DOWN_LEFT BABY_BB_DOWN_LEFT break; case 2: SET_MOVE_LEFT //* No change! BABY_BB_LEFT break; case 3: SET_MOVE_UP_LEFT BABY_BB_UP_LEFT break; case 4: SET_MOVE_UP BABY_BB_UP break; } } else { //* Continue moving left sp->u = 128 + (scp->currFrame << 5); sp->v = 32; } break; case DIR_DOWN: if (BASE_HIT_BOTTOM_WALL) { //* Change direction... if (scp->wx<255) { //* Move right SET_MOVE_RIGHT BABY_BB_RIGHT } else { //* Move left SET_MOVE_LEFT BABY_BB_LEFT } } else if (!(--scp->moveCount)) { //* Time for a direction change? scp->moveCount = scp->moveMax; switch (rand()%5) { case 0: SET_MOVE_LEFT BABY_BB_LEFT break; case 1: SET_MOVE_DOWN_LEFT BABY_BB_DOWN_LEFT break; case 2: SET_MOVE_DOWN //* No change! BABY_BB_DOWN break; case 3: SET_MOVE_DOWN_RIGHT BABY_BB_DOWN_RIGHT break; case 4: SET_MOVE_RIGHT BABY_BB_RIGHT break; } } else { //* Continue moving down sp->u = (scp->currFrame << 5); sp->v = 0; } break; case DIR_UP: if (BASE_HIT_TOP_WALL) { //* Change direction... if (scp->wx<255) { //* Move right SET_MOVE_RIGHT BABY_BB_RIGHT } else { //* Move left SET_MOVE_LEFT BABY_BB_LEFT } } else if (!(--scp->moveCount)) { //* Time for a direction change? scp->moveCount = scp->moveMax; switch (rand()%5) { case 0: SET_MOVE_LEFT BABY_BB_LEFT break; case 1: SET_MOVE_UP_LEFT BABY_BB_UP_LEFT break; case 2: SET_MOVE_UP //* No change! BABY_BB_UP break; case 3: SET_MOVE_UP_RIGHT BABY_BB_UP_RIGHT break; case 4: SET_MOVE_RIGHT BABY_BB_RIGHT break; } } else { //* Continue moving up sp->u = 128 + (scp->currFrame << 5); sp->v = 0; } break; } //* Centre baby sprite on new central world coords scp->wx = (scp->wxMid += scp->accelX) - (scp->bbXOff + (scp->bbW >> 1)); scp->wy = (scp->wyMid += scp->accelY) + (scp->bbYOff - (scp->bbH >> 1)); } //*------------------------------------------------------------------------------------------ //* move_following_baby //*------------------------------------------------------------------------------------- static void move_following_baby(register struct SCTRL *scp) { register GsSPRITE *sp = scp->spriteLink; //* Pointer to actual sprite object register int xDist, yDist; //* Relative x & y distances away from target register int xDistAbs, yDistAbs; //* Absolute x & y distances away from target register int moveX, moveY; //* Relative values to add to baby world coords register int speed=sCtrl->speed; //* Maximum pixel increment per move register struct SCTRL *target=scp->target; //* Pointer to the target sprite ++scp->ICSALop; //* Calculate relative distance baby is away from target's CENTRAL coords //* Note: -y = below target; -x = to right of target xDist = target->wxMid - scp->wxMid; yDist = target->wyMid - scp->wyMid; xDistAbs = abs(xDist); //* Actual number of pixels away from target X coord yDistAbs = abs(yDist); //* Actual number of pixels away from target Y coord //* Stay still if close enough to target if ((xDistAbs<=followDist) && (yDistAbs<=followDist)) return; //* Calculate distance away from true target coords //* Note: target coords are dependent on target's direction if (target->dir==DIR_UP || target->dir==DIR_DOWN) if (yDistAbs>followDist) yDist += (yDist<0 ? followDist : -followDist); else yDist = 0; //* No Y movement required else if (target->dir==DIR_LEFT || target->dir==DIR_RIGHT) if (xDistAbs>followDist) xDist += (xDist<0 ? followDist : -followDist); else xDist = 0; //* No X movement required else { if (yDistAbs>followDist) yDist += (yDist<0 ? followDist : -followDist); else yDist = 0; //* No Y movement required if (xDistAbs>followDist) xDist += (xDist<0 ? followDist : -followDist); else xDist = 0; //* No X movement required } xDistAbs = abs(xDist); //* Actual number of pixels away from target X coord yDistAbs = abs(yDist); //* Actual number of pixels away from target Y coord //* Set baby's X movement if (xDistAbs<=speed) moveX = xDist; else if (xDistAbs>speed) { moveX = speed + (xDistAbs % speed); //* Ensure snap to X movement grid if (xDist<0) moveX = -moveX; } else moveX = 0; //* Set baby's Y movement if (yDistAbs<=speed) moveY = yDist; else if (yDistAbs>speed) { moveY = speed + (yDistAbs % speed); //* Ensure snap to Y movement grid if (yDist < 0) moveY = -moveY; } else moveY = 0; //* Sprite frame number control management if (!(--scp->frameCount)) { scp->frameCount = scp->repsPerFrame; scp->currFrame = ++scp->currFrame & 0x3; } //* Set sprite frame and direction according to x,y movement if (moveX && moveY) { //* Is diagonal movement... if (moveX < 0) { if (moveY < 0) { //* and upwards SET_MOVE_UP_LEFT BABY_BB_UP_LEFT } else { SET_MOVE_DOWN_LEFT BABY_BB_DOWN_LEFT } } else { //* and downwards if (moveY < 0) { SET_MOVE_UP_RIGHT BABY_BB_UP_RIGHT } else { SET_MOVE_DOWN_RIGHT BABY_BB_DOWN_RIGHT } } } else { //* Is up, down, left or right movement if (moveX < 0) { SET_MOVE_LEFT BABY_BB_LEFT } else if (moveX > 0) { SET_MOVE_RIGHT BABY_BB_RIGHT } else if (moveY < 0) { SET_MOVE_UP BABY_BB_UP } else { SET_MOVE_DOWN BABY_BB_DOWN } } //* Centre baby sprite on new central world coords scp->wx = (scp->wxMid += moveX) - (scp->bbXOff + (scp->bbW >> 1)); scp->wy = (scp->wyMid += moveY) + (scp->bbYOff - (scp->bbH >> 1)); } //*------------------------------------------------------------------------------------------ //* move_centre_tv //*------------------------------------------------------------------------------------- static void move_centre_tv(register struct SCTRL *scp) { register int i; register GsSPRITE *sp = scp->spriteLink; //* Pointer to actual sprite object register int xDist, yDist; //* Relative x & y distances away from target register int xDistAbs, yDistAbs; //* Absolute x & y distances away from target register int moveX, moveY; //* Relative values to add to baby world coords register int speed=sCtrl->speed; //* Maximum pixel increment per move register struct SCTRL *target=scp->target; //* Target will be &sCtrl[SPRT_TVBEAM] register struct SCTRL *nextBaby; register struct SCTRL *scp2; register GsSPRITE *sp2; ++scp->ICSALop; //* Calculate relative distance baby/BB is away from target's CENTRAL coords //* Note: -y = below target; -x = to right of target xDist = target->wxMid - scp->wxMid; yDist = target->wyMid - scp->wyMid; //* Authorize beam-up if baby/BB exactly in position if (!xDist && !yDist) { lastCall = 0x100; //* Ensure this is last ICSAL call if (scp->ID==ID_BLITTER_BOY) { if (scp->subID==BOY_GAME_OVER) { //* GAME OVER beam up scp->ICSALop = boyLevEnd; scp2 = CentreText("GAME OVER_", 0, 4); for (i=4; scp2; scp2=scp2->freeLink, i^=4) { scp2->wy = 350; scp2->wx = (-bg1->x + scp2->spriteLink->x)+320; //* Off screen for now scp2->bbW = 16; scp2->bbH = 1; scp2->shadBase = 3; scp2->ICSALloopStart = (scp2->ICSALop = textGameOver) + 42; scp2->ICSALloopCount = 21>>i; //* Toggles 21 and 1 } if (gameType==MODE_MISSION) { scp2 = CentreText("MISSION ABORTED", 0, 4); for (i=1; scp2; scp2=scp2->freeLink, i++) { scp2->wy = 215; scp2->wx = (-bg1->x + scp2->spriteLink->x); scp2->bbW = (i==2 || i==5 ? 10 : 16); //* Fool shadow pos for narrow I's scp2->bbH = 1; scp2->shadBase = 3; scp2->high = 100; scp2->ICSALop = textMissAb; } } else { scp2 = CentreText("THAT'S IT, KID_", 0, 4); for (i=1; scp2; scp2=scp2->freeLink, i++) { scp2->wy = 215; scp2->wx = (-bg1->x + scp2->spriteLink->x); switch (i) { case 5: case 9: //* ' and , scp2->bbW = 6; break; case 7: case 11: //* i's scp2->bbW = 10; break; default: //* Normal chars scp2->bbW = 16; break; } scp2->bbH = 1; scp2->shadBase = 3; scp2->high = 100; scp2->ICSALop = textMissAb; } } } else { //* Level end beam up scp->ICSALop = boyLevEnd; scp2 = CentreText("LEVEL UP_", 0, 4); for (i=1; scp2; scp2=scp2->freeLink, i+=5) { scp2->wy = 350; scp2->wx = (-bg1->x + scp2->spriteLink->x)+320; //* Off screen for now scp2->bbW = 16; scp2->bbH = 1; scp2->shadBase = 3; scp2->ICSALop = scp2->ICSALloopStart = textLevup; scp2->ICSALloopCount = i; } scp2 = CentreText("AREA CLEARED", 0, 4); for (i=1; scp2; scp2=scp2->freeLink, i+=5) { scp2->wy = 215; scp2->wx = (-bg1->x + scp2->spriteLink->x)+320; //* Off screen for now scp2->bbW = 16; scp2->bbH = 1; scp2->shadBase = 3; scp2->ICSALop = scp2->ICSALloopStart = textCleared; scp2->ICSALloopCount = i; } } } else { //* scp is a baby... scp->ICSALop = beamMeUp; //* Set this baby for beam-up (dummyScp+babiesSaved)->ICSALop = dummyGo; //* Remove dummy OSD sprite //* Bring in message HUD if all babies have been saved if (++babiesSaved == 6) { sp2 = (messHudScp=GetSprite(2))->spriteLink; sp2->attribute = (A_BRIGHT_OFF + A_4BIT_CLUT + A_ROTATE_OFF + A_TRATE_1 + A_TRANS_OFF + A_DISPLAY_ON); sp2->x = 212; sp2->y = 6; sp2->w = 4; sp2->h = 16; sp2->tpage = GetTPage(0, 0, timData[TIM_MESS_HUD].px, timData[TIM_MESS_HUD].py); sp2->u = ((timData[TIM_MESS_HUD].px<<2) % 256); sp2->v = timData[TIM_MESS_HUD].py+16; sp2->cx = timData[TIM_MESS_HUD].cx; sp2->cy = timData[TIM_MESS_HUD].cy; messHudScp->ICSALop = messHudText; sp2 = messHudScp->freeLink->spriteLink; sp2->attribute = (A_BRIGHT_OFF + A_4BIT_CLUT + A_ROTATE_OFF + A_TRATE_1 + A_TRANS_ON + A_DISPLAY_ON); sp2->x = 212; sp2->y = 6; sp2->w = 0; sp2->h = 16; sp2->tpage = GetTPage(0, 0, timData[TIM_MESS_HUD].px, timData[TIM_MESS_HUD].py); sp2->u = ((timData[TIM_MESS_HUD].px<<2) % 256); sp2->v = timData[TIM_MESS_HUD].py; sp2->cx = timData[TIM_MESS_HUD].cx; sp2->cy = timData[TIM_MESS_HUD].cy; messHudScp->freeLink->ICSALop = messHudBlank; } currScore += bonusVal[bonusMulty][babyCnt]; scp2 = GetSprite(2); PresetSprite(scp2, PRESET_BONUS_SCORE); scp2->wx = target->wxMid-16; scp2->wy = target->wy+600; scp2->spriteLink->v += (babyCnt<<4); scp2->ICSALop = showBabyBonus; scp2->frameLock = scp2->currLock = LOCK_NOFRAMES; AliveLinkIn(scp2); scp2 = scp2->freeLink; PresetSprite(scp2, PRESET_BONUS_MULTY); scp2->wx = target->wxMid-16; scp2->wy = target->wy+600; scp2->spriteLink->v += (bonusMulty<<4)-(bonusMulty<<2); scp2->ICSALop = showBabyMulty; scp2->frameLock = scp2->currLock = LOCK_NOFRAMES; AliveLinkIn(scp2); babyCnt++; //* Consider any other following babies if ((nextBaby=lastInLine)!=scp) { //* There is a baby following this one while (nextBaby->target!=scp) //* Find baby that's following this one nextBaby = nextBaby->target; nextBaby->target = target; nextBaby->ICSALop = gotoTV; //* Set baby to move into position for beam-up nextBaby->subID = BABY_GOTO_TV; } } return; } xDistAbs = abs(xDist); //* Actual number of pixels away from target X coord yDistAbs = abs(yDist); //* Actual number of pixels away from target Y coord //* Set baby's/BB's X movement if (xDistAbs<=speed) moveX = xDist; else if (xDistAbs>speed) { moveX = speed + (xDistAbs % speed); //* Ensure snap to X movement grid if (xDist<0) moveX = -moveX; } else moveX = 0; //* Set baby's/BB's Y movement if (yDistAbs<=speed) moveY = yDist; else if (yDistAbs>speed) { moveY = speed + (yDistAbs % speed); //* Ensure snap to Y movement grid if (yDist < 0) moveY = -moveY; } else moveY = 0; //* Sprite frame number control management if (!(--scp->frameCount)) { scp->frameCount = scp->repsPerFrame; scp->currFrame = ++scp->currFrame & 0x3; } //* Set sprite frame and direction according to x,y movement if (scp->ID==ID_BABY) { //* scp is a baby... if (moveX && moveY) { //* Is diagonal movement... if (moveX < 0) { if (moveY < 0) { //* and upwards SET_MOVE_UP_LEFT BABY_BB_UP_LEFT } else { SET_MOVE_DOWN_LEFT BABY_BB_DOWN_LEFT } } else { //* and downwards if (moveY < 0) { SET_MOVE_UP_RIGHT BABY_BB_UP_RIGHT } else { SET_MOVE_DOWN_RIGHT BABY_BB_DOWN_RIGHT } } } else { //* Is up, down, left or right movement if (moveX < 0) { SET_MOVE_LEFT BABY_BB_LEFT } else if (moveX > 0) { SET_MOVE_RIGHT BABY_BB_RIGHT } else if (moveY < 0) { SET_MOVE_UP BABY_BB_UP } else { SET_MOVE_DOWN BABY_BB_DOWN } } //* Centre baby on new central world coords scp->wx = (scp->wxMid += moveX) - (scp->bbXOff + (scp->bbW >> 1)); scp->wy = (scp->wyMid += moveY) + (scp->bbYOff - (scp->bbH >> 1)); } else { //* scp is Blitter Boy... if (moveX && moveY) { //* Is diagonal movement... if (moveX < 0) { if (moveY < 0) { //* and upwards BOY_MOVE_UP_LEFT BOY_BB_UP_LEFT } else { BOY_MOVE_DOWN_LEFT BOY_BB_DOWN_LEFT } } else { //* and downwards if (moveY < 0) { BOY_MOVE_UP_RIGHT BOY_BB_UP_RIGHT } else { BOY_MOVE_DOWN_RIGHT BOY_BB_DOWN_RIGHT } } } else { //* Is up, down, left or right movement if (moveX < 0) { BOY_MOVE_LEFT BOY_BB_LEFT } else if (moveX > 0) { BOY_MOVE_RIGHT BOY_BB_RIGHT } else if (moveY < 0) { BOY_MOVE_UP BOY_BB_UP } else { BOY_MOVE_DOWN BOY_BB_DOWN } } //* Set BB's world X coord and BG sprites X coords scp->wx = (scp->wxMid += moveX) - (scp->bbXOff + (scp->bbW >> 1)); if (scp->wxMid < 160) { bg1->x = bg3->x = 0; bg2->x = bg4->x = 256; } else if (scp->wxMid > 352) { bg1->x = bg3->x = SCROLLX_MAX; bg2->x = bg4->x = SCROLLX_MAX + 256; } else { bg1->x = bg3->x = 160 - scp->wxMid; bg2->x = bg4->x = bg1->x + 256; } //* Set BB's world Y coord and BG sprites Y coords scp->wy = (scp->wyMid += moveY) + (scp->bbYOff - (scp->bbH >> 1)); if (scp->wyMid < 120) { bg1->y = bg2->y = 0; bg3->y = bg4->y = 256; } else if (scp->wyMid > 392) { bg1->y = bg2->y = SCROLLY_MAX; bg3->y = bg4->y = SCROLLY_MAX + 256; } else { bg1->y = bg2->y = 120 - scp->wyMid; bg3->y = bg4->y = bg1->y + 256; } } } //*------------------------------------------------------------------------------------------ //* move_decoy_boy - controls all 3 RGB decoy sprites (scp=RED) and HoloSphere sprite //*------------------------------------------------------------------------------------- static void move_decoy_boy(register struct SCTRL *scp) { register GsSPRITE *sp = scp->spriteLink; //* Pointer to actual sprite object register int moveX = scp->accelX; //* Used in macros register int moveY = scp->accelY; //* Used in macros register struct SCTRL *scpG = scp->freeLink; //* Green decoy sprite register struct SCTRL *scpB = scp->freeLink->freeLink; //* Blue decoy sprite register struct SCTRL *scpH = scp->freeLink->freeLink->freeLink; //* HoloSphere sprite ++scp->ICSALop; //* First, increase all 3 decoy projections to full height if (sp->h < 36) { --sp->v; --scpG->spriteLink->v; --scpB->spriteLink->v; ++sp->h; ++scpG->spriteLink->h; ++scpB->spriteLink->h; ++scpH->high; //* Raise HoloSphere into the air SsUtKeyOn(0, SFX_GUN_FDROP, 0, 84, 0, 127, 127); return; //* No more to be done yet! } //* Sprite frame number control management if (!(--scp->frameCount)) { scp->frameCount = scp->repsPerFrame; scp->currFrame = ++scp->currFrame & 0x3; } //* Set sprite's frame image switch (scp->dir) { case DIR_DOWN_RIGHT: if (BASE_HIT_RIGHT_WALL) { //* Change direction... if (scp->wy & 0x01) { //* Move down-left (odd world Y coord) BOY_MOVE_DOWN_LEFT BOY_BB_DOWN_LEFT } else { //* Move down (even world Y coord) BOY_MOVE_DOWN BOY_BB_DOWN } } else if (BASE_HIT_BOTTOM_WALL) { //* Change direction (bottom wall ONLY hit)... if (scp->wx & 0x01) { //* Move right (odd world X coord) BOY_MOVE_RIGHT BOY_BB_RIGHT } else { //* Move up-right (even world X coord) BOY_MOVE_UP_RIGHT BOY_BB_UP_RIGHT } } else if (!(--scp->moveCount)) { //* Time for a direction change? scp->moveCount = scp->moveMax; switch (rand()%5) { case 0: BOY_MOVE_UP_RIGHT BOY_BB_UP_RIGHT break; case 1: BOY_MOVE_RIGHT BOY_BB_RIGHT break; case 2: BOY_MOVE_DOWN_RIGHT //* No change! BOY_BB_DOWN_RIGHT break; case 3: BOY_MOVE_DOWN BOY_BB_DOWN break; case 4: BOY_MOVE_DOWN_LEFT BOY_BB_DOWN_LEFT break; } } else { //* Continue moving down-right sp->u = (scp->currFrame << 5); sp->v = 108; } break; case DIR_UP_RIGHT: if (BASE_HIT_RIGHT_WALL) { //* Change direction... if (scp->wy & 0x01) { //* Move up-left (odd world Y coord) BOY_MOVE_UP_LEFT BOY_BB_UP_LEFT } else { //* Move up (even world Y coord) BOY_MOVE_UP BOY_BB_UP } } else if (BASE_HIT_TOP_WALL) { //* Change direction (top wall ONLY hit)... if (scp->wx & 0x01) { //* Move right (odd world X coord) BOY_MOVE_RIGHT BOY_BB_RIGHT } else { //* Move down-right (even world X coord) BOY_MOVE_DOWN_RIGHT BOY_BB_DOWN_RIGHT } } else if (!(--scp->moveCount)) { //* Time for a direction change? scp->moveCount = scp->moveMax; switch (rand()%5) { case 0: BOY_MOVE_UP_LEFT BOY_BB_UP_LEFT break; case 1: BOY_MOVE_UP BOY_BB_UP break; case 2: BOY_MOVE_UP_RIGHT //* No change! BOY_BB_UP_RIGHT break; case 3: BOY_MOVE_RIGHT BOY_BB_RIGHT break; case 4: BOY_MOVE_DOWN_RIGHT BOY_BB_DOWN_RIGHT break; } } else { //* Continue moving up-right sp->u = (scp->currFrame << 5); sp->v = 72; } break; case DIR_DOWN_LEFT: if (BASE_HIT_LEFT_WALL) { //* Change direction... if (scp->wy & 0x01) { //* Move down-right (odd world Y coord) BOY_MOVE_DOWN_RIGHT BOY_BB_DOWN_RIGHT } else { //* Move down (even world Y coord) BOY_MOVE_DOWN BOY_BB_DOWN } } else if (BASE_HIT_BOTTOM_WALL) { //* Change direction (bottom wall ONLY hit)... if (scp->wx & 0x01) { //* Move left (odd world X coord) BOY_MOVE_LEFT BOY_BB_LEFT } else { //* Move up-left (even world X coord) BOY_MOVE_UP_LEFT BOY_BB_UP_LEFT } } else if (!(--scp->moveCount)) { //* Time for a direction change? scp->moveCount = scp->moveMax; switch (rand()%5) { case 0: BOY_MOVE_DOWN_RIGHT BOY_BB_DOWN_RIGHT break; case 1: BOY_MOVE_DOWN BOY_BB_DOWN break; case 2: BOY_MOVE_DOWN_LEFT //* No change! BOY_BB_DOWN_LEFT break; case 3: BOY_MOVE_LEFT BOY_BB_LEFT break; case 4: BOY_MOVE_UP_LEFT BOY_BB_UP_LEFT break; } } else { //* Continue moving down-left sp->u = 128 + (scp->currFrame << 5); sp->v = 108; } break; case DIR_UP_LEFT: if (BASE_HIT_LEFT_WALL) { //* Change direction... if (scp->wy & 0x01) { //* Move up-right (odd world Y coord) BOY_MOVE_UP_RIGHT BOY_BB_UP_RIGHT } else { //* Move up (even world Y coord) BOY_MOVE_UP BOY_BB_UP } } else if (BASE_HIT_TOP_WALL) { //* Change direction (top wall ONLY hit)... if (scp->wx & 0x01) { //* Move left (odd world X coord) BOY_MOVE_LEFT BOY_BB_LEFT } else { //* Move down-left (even world X coord) BOY_MOVE_DOWN_LEFT BOY_BB_DOWN_LEFT } } else if (!(--scp->moveCount)) { //* Time for a direction change? scp->moveCount = scp->moveMax; switch (rand()%5) { case 0: BOY_MOVE_DOWN_LEFT BOY_BB_DOWN_LEFT break; case 1: BOY_MOVE_LEFT BOY_BB_LEFT break; case 2: BOY_MOVE_UP_LEFT //* No change! BOY_BB_UP_LEFT break; case 3: BOY_MOVE_UP BOY_BB_UP break; case 4: BOY_MOVE_UP_RIGHT BOY_BB_UP_RIGHT break; } } else { //* Continue moving up-left sp->u = 128 + (scp->currFrame << 5); sp->v = 72; } break; case DIR_RIGHT: if (BASE_HIT_RIGHT_WALL) { //* Change direction... if (scp->wy<255) { //* Move down BOY_MOVE_DOWN BOY_BB_DOWN } else { //* Move up BOY_MOVE_UP BOY_BB_UP } } else if (!(--scp->moveCount)) { //* Time for a direction change? scp->moveCount = scp->moveMax; switch (rand()%5) { case 0: BOY_MOVE_UP BOY_BB_UP break; case 1: BOY_MOVE_UP_RIGHT BOY_BB_UP_RIGHT break; case 2: BOY_MOVE_RIGHT //* No change! BOY_BB_RIGHT break; case 3: BOY_MOVE_DOWN_RIGHT BOY_BB_DOWN_RIGHT break; case 4: BOY_MOVE_DOWN BOY_BB_DOWN break; } } else { //* Continue moving right sp->u = (scp->currFrame << 5); sp->v = 36; } break; case DIR_LEFT: if (BASE_HIT_LEFT_WALL) { //* Change direction... if (scp->wy<255) { //* Move down BOY_MOVE_DOWN BOY_BB_DOWN } else { //* Move up BOY_MOVE_UP BOY_BB_UP } } else if (!(--scp->moveCount)) { //* Time for a direction change? scp->moveCount = scp->moveMax; switch (rand()%5) { case 0: BOY_MOVE_DOWN BOY_BB_DOWN break; case 1: BOY_MOVE_DOWN_LEFT BOY_BB_DOWN_LEFT break; case 2: BOY_MOVE_LEFT //* No change! BOY_BB_LEFT break; case 3: BOY_MOVE_UP_LEFT BOY_BB_UP_LEFT break; case 4: BOY_MOVE_UP BOY_BB_UP break; } } else { //* Continue moving left sp->u = 128 + (scp->currFrame << 5); sp->v = 36; } break; case DIR_DOWN: if (BASE_HIT_BOTTOM_WALL) { //* Change direction... if (scp->wx<255) { //* Move right BOY_MOVE_RIGHT BOY_BB_RIGHT } else { //* Move left BOY_MOVE_LEFT BOY_BB_LEFT } } else if (!(--scp->moveCount)) { //* Time for a direction change? scp->moveCount = scp->moveMax; switch (rand()%5) { case 0: BOY_MOVE_LEFT BOY_BB_LEFT break; case 1: BOY_MOVE_DOWN_LEFT BOY_BB_DOWN_LEFT break; case 2: BOY_MOVE_DOWN //* No change! BOY_BB_DOWN break; case 3: BOY_MOVE_DOWN_RIGHT BOY_BB_DOWN_RIGHT break; case 4: BOY_MOVE_RIGHT BOY_BB_RIGHT break; } } else { //* Continue moving down sp->u = (scp->currFrame << 5); sp->v = 0; } break; case DIR_UP: if (BASE_HIT_TOP_WALL) { //* Change direction... if (scp->wx<255) { //* Move right BOY_MOVE_RIGHT BOY_BB_RIGHT } else { //* Move left BOY_MOVE_LEFT BOY_BB_LEFT } } else if (!(--scp->moveCount)) { //* Time for a direction change? scp->moveCount = scp->moveMax; switch (rand()%5) { case 0: BOY_MOVE_LEFT BOY_BB_LEFT break; case 1: BOY_MOVE_UP_LEFT BOY_BB_UP_LEFT break; case 2: BOY_MOVE_UP //* No change! BOY_BB_UP break; case 3: BOY_MOVE_UP_RIGHT BOY_BB_UP_RIGHT break; case 4: BOY_MOVE_RIGHT BOY_BB_RIGHT break; } } else { //* Continue moving up sp->u = 128 + (scp->currFrame << 5); sp->v = 0; } break; } //* Centre decoy BB sprite on new central world coords scp->wx = (scp->wxMid += scp->accelX) - (scp->bbXOff + (scp->bbW >> 1)); scp->wy = (scp->wyMid += scp->accelY) + (scp->bbYOff - (scp->bbH >> 1)); //* Set new (x offset) world coords for green and blue decoy images scpG->wx = scp->wx-2; scpB->wx = scp->wx+2; scpG->wy = scpB->wy = scp->wy; //* Set green and blue images to use same frame as main red image scpG->spriteLink->u = scpB->spriteLink->u = sp->u; scpG->spriteLink->v = scpB->spriteLink->v = sp->v; //* Centre HoloSphere sprite on main red decoy image scpH->wx = scp->wxMid - (scpH->bbXOff + (scpH->bbW >> 1)); scpH->wy = scp->wyMid + (scpH->bbYOff - (scpH->bbH >> 1)); } //*------------------------------------------------------------------------------------------ //* END_run_baby_wander //*------------------------------------------------------------------------------------- static void END_run_baby_wander(register struct SCTRL *scp) { register GsSPRITE *sp = scp->spriteLink; //* Pointer to actual sprite object scp->ICSALop = babyWander; scp->subID = BABY_WANDER; scp->unintICSAL = 0; //* Resume moving in original direction switch (scp->dir) { case DIR_DOWN: SET_MOVE_DOWN BABY_BB_DOWN break; case DIR_DOWN_LEFT: SET_MOVE_DOWN_LEFT BABY_BB_DOWN_LEFT break; case DIR_LEFT: SET_MOVE_LEFT BABY_BB_LEFT break; case DIR_UP_LEFT: SET_MOVE_UP_LEFT BABY_BB_UP_LEFT break; case DIR_UP: SET_MOVE_UP BABY_BB_UP break; case DIR_UP_RIGHT: SET_MOVE_UP_RIGHT BABY_BB_UP_RIGHT break; case DIR_RIGHT: SET_MOVE_RIGHT BABY_BB_RIGHT break; case DIR_DOWN_RIGHT: SET_MOVE_DOWN_RIGHT BABY_BB_DOWN_RIGHT break; } //* Centre baby sprite on central world coords scp->wx = scp->wxMid - (scp->bbXOff + (scp->bbW >> 1)); scp->wy = scp->wyMid + (scp->bbYOff - (scp->bbH >> 1)); } //*------------------------------------------------------------------------------------------ //* END_beam //*------------------------------------------------------------------------------------- static void END_beam(register struct SCTRL *scp) { if (scp->ID==ID_BABY) { if (lastInLine==scp) { lastInLine = sCtrl; sCtrl[SPRT_TVBEAM].ICSALop = turnOffTV; } AliveLinkOut(scp); //* Kill baby sprite GetSprite(1); //* Remove from pool so it cant be used for anything else! } else { if (scp->subID==BOY_GAME_OVER) gameStat = GAME_OVER; else gameStat = GAME_LEVEL_UP; } } //*------------------------------------------------------------------------------------------ //* REP_update_HUD_box //*------------------------------------------------------------------------------------- static void REP_update_HUD_box(register struct SCTRL *scp) { register struct HUDS *hp=&HUDbox[scp->subID]; //* Pointer to associated HUD controller register GsSPRITE *sp = scp->spriteLink; //* Pointer to actual sprite object register int chr; register int fontX=timData[TIM_POLYCART].px+4; if (sp->w<36) { //* First, open the box if (!sp->w) { //* This is 1st call... //* Reset (possibly) used HUD box to 'clean' image MoveImage(&hp->src, hp->tlX, hp->tlY); //* Reset .src for font copying hp->src.w = 1; //* 1 is 4 4bit pixels hp->src.h = 6; hp->src.x = timData[TIM_POLYCART].px+4; } sp->w += 2; //* Make HUD box wider } else if ((chr = *scp->ICSALdata) != DATA_END) { //* Then display text - one char at a time - and cursor if (!hp->charsDone) { scp->frameLock = scp->currLock = LOCK_3FRAMES; SsUtKeyOn(0, SFX_COMPUTER, 0, 60, 0, 100, 100); } else { SsUtKeyOn(0, SFX_BONUS, 0, 80, 0, 100, 100); } hp->src.x = fontX + (chr - 'A'); //* Point to char pattern MoveImage(&hp->src, hp->destX, hp->destY); //* Copy it onto sprite //* Find next char/cursor position if (*(++scp->ICSALdata) == '-') { scp->ICSALdata++; hp->charsDone = 6; } if (++hp->charsDone==7) { hp->destY += 6; hp->destX = hp->leftX; } else hp->destX++; hp->src.x = fontX + 27; //* Point to cursor pattern MoveImage(&hp->src, hp->destX, hp->destY); //* Copy it onto sprite } else { //* Blink cursor continuously if (hp->src.x == (fontX + 27)) hp->src.x--; else hp->src.x++; MoveImage(&hp->src, hp->destX, hp->destY); } } //*------------------------------------------------------------------------------------------ //* REP_close_HUD_box //*------------------------------------------------------------------------------------- static void REP_close_HUD_box(register struct SCTRL *scp) { register struct HUDS *hp=&HUDbox[scp->subID]; //* Pointer to associated HUD controller register GsSPRITE *sp = scp->spriteLink; //* Pointer to actual sprite object if (sp->w) { //* First, close the box if ((sp->w-=2) == 34) scp->frameLock = scp->currLock = LOCK_NOFRAMES; } else { //* Reset HUD box controller hp->src.x = timData[TIM_POLYCART].px+54; //* 54 is 216 4bit pixels hp->src.w = 9; //* 9 is 36 4bit pixels hp->src.h = 16; hp->destX = hp->leftX = (hp->tlX + 1); hp->destY = hp->tlY + 2; hp->charsDone = 0; PutHUDidx(scp->subID); //* Make HUD box available again AliveLinkOut(scp); } } //*------------------------------------------------------------------------------------------ //* REP_update_range_HUD //*------------------------------------------------------------------------------------- static void REP_update_range_HUD(register struct SCTRL *scp) { register GsSPRITE *sp = scp->spriteLink; //* Pointer to actual sprite object static int nextCnt; static int vRange; //* Place HUD above Blitter Boy scp->wx = sCtrl->wxMid-14; scp->wy = sCtrl->wyMid+594; if (sp->w<28) { //* First, open the box stopRange = 0; nextCnt = 240; sp->w += 2; //* Make HUD box wider } else { switch (nextCnt--) { //* Take action according to countdown... case 240: //* Set range to level 1 SsUtKeyOn(0, SFX_COMPUTER, 0, 60, 0, 127, 127); vRange = (sp->v += 16); bullLoop = ((bullRange=2)<<3); break; case 180: //* Set range to level 2 SsUtKeyOn(0, SFX_COMPUTER, 0, 61, 0, 127, 127); vRange = (sp->v += 16); bullLoop = ((bullRange=3)<<3); break; case 120: //* Set range to level 3 SsUtKeyOn(0, SFX_COMPUTER, 0, 62, 0, 127, 127); vRange = (sp->v += 16); bullLoop = ((bullRange=4)<<3); break; case 60: //* Set range to level 4 SsUtKeyOn(0, SFX_COMPUTER, 0, 63, 0, 127, 127); vRange = (sp->v += 16); bullLoop = ((bullRange=5)<<3); break; case 0: //* Set range to level 5 (max) SsUtKeyOn(0, SFX_COMPUTER, 0, 64, 0, 127, 127); vRange = (sp->v += 16); bullLoop = ((bullRange=6)<<3); stopRange = 1; break; case -5: case -15: case -25: case -35: //* Flash range off 4 times sp->v = 0; break; case -10: case -20: case -30: case -40: //* Flash range on 4 times sp->v = vRange; break; case -41: //* Set range HUD box to close ++scp->ICSALop; break; } if (stopRange && nextCnt>=-1) //* Fire pressed or max range reached nextCnt = -5; //* Signal range selection is complete } } //*------------------------------------------------------------------------------------------ //* REP_close_range_HUD //*------------------------------------------------------------------------------------- static void REP_close_range_HUD(register struct SCTRL *scp) { register GsSPRITE *sp = scp->spriteLink; //* Pointer to actual sprite object //* Place HUD above Blitter Boy scp->wx = sCtrl->wxMid-14; scp->wy = sCtrl->wyMid+594; //* Close then kill range HUD box sprite if (!(sp->w-=2)) { rangeScp = NULL; AliveLinkOut(scp); } } //*------------------------------------------------------------------------------------------ //* REP_close_decoy_boy //*------------------------------------------------------------------------------------- static void REP_close_decoy_boy(register struct SCTRL *scp) { register GsSPRITE *sp = scp->spriteLink; //* Pointer to actual sprite object register struct SCTRL *scpG = scp->freeLink; //* Green decoy sprite register struct SCTRL *scpB = scp->freeLink->freeLink; //* Blue decoy sprite register struct SCTRL *scpH = scp->freeLink->freeLink->freeLink; //* HoloSphere sprite register struct SCTRL *scp2; //* For expire sprite if (sp->h) { //* Decrease all 3 decoy projections to 0 height... ++sp->v; ++scpG->spriteLink->v; ++scpB->spriteLink->v; --sp->h; --scpG->spriteLink->h; --scpB->spriteLink->h; --scpH->high; } else { //* Finished, so expire HoloSphere... sp = (scp2=GetSprite(1))->spriteLink; sp->attribute = (A_4BIT_CLUT + A_BRIGHT_ON + A_ROTATE_OFF + A_TRATE_2 + A_TRANS_ON + A_DISPLAY_ON); sp->w = sp->h = 16; sp->tpage = GetTPage(0, 1, timData[TIM_BULLBANG].px, timData[TIM_BULLBANG].py); sp->u = 0; sp->v = 16; sp->cx = timData[TIM_BULLBANG].cx; sp->cy = timData[TIM_BULLBANG].cy; scp2->shadStat = 0; //* Shadow off scp2->ICSALop = bulletExpire; //* Same as an expiring bullet! scp2->wx = scpH->wx; scp2->wy = scpH->wy; scp2->high = scpH->high; AliveLinkIn(scp2); //* Activate 'expire' service sprite if (scp==decoyScp) { //* There isn't a decoy already active... decoyScp = NULL; chaseTarget = sCtrl; //* Make the real BB the chase target again } AliveLinkOut(scp); AliveLinkOut(scpG); AliveLinkOut(scpB); AliveLinkOut(scpH); } } //*------------------------------------------------------------------------------------------ //* update_coin_fall //*------------------------------------------------------------------------------------- static void update_coin_fall(register struct SCTRL *scp) { register GsSPRITE *sp = scp->spriteLink; //* Pointer to actual sprite object ++scp->ICSALop; //* Sprite frame number control management if (!(--scp->frameCount)) { scp->frameCount = scp->repsPerFrame; scp->currFrame = ++scp->currFrame & 0x7; } sp->u=(scp->currFrame<<4); if ((sp->y+=scp->accelY)>240) { //* Off bottom of screen - reset to top sp->y = -18; sp->x = -8 + (rand()%321); } } //*------------------------------------------------------------------------------------------ //* update_fdrop_buildUp //*------------------------------------------------------------------------------------- static void update_fdrop_buildUp(register struct SCTRL *scp) { register int action, posOff; register struct SCTRL *bp; action = *++scp->ICSALop; //* Get required action operand ++scp->ICSALop; if (action) { //* Fruit Drop bullet is still building up on end of gun... posOff = (action-1); //* Offset to move build-up bubble away from gun switch (scp->dir=sCtrl->dir) { //* Place build-up sprite on end of gun case DIR_DOWN: scp->wx = sCtrl->wx + 8; scp->wy = sCtrl->wy + 3 + (posOff<<1); break; case DIR_DOWN_LEFT: scp->wx = sCtrl->wx - 1 - posOff; scp->wy = sCtrl->wy + 4 + posOff; break; case DIR_LEFT: scp->wx = sCtrl->wx - 10 - (posOff<<1); scp->wy = sCtrl->wy - 3; break; case DIR_UP_LEFT: scp->wx = sCtrl->wx - 5 - posOff; scp->wy = sCtrl->wy - 12 - posOff; break; case DIR_UP: scp->wx = sCtrl->wx + 8; scp->wy = sCtrl->wy - 15 - (posOff<<1); break; case DIR_UP_RIGHT: scp->wx = sCtrl->wx + 19 + posOff; scp->wy = sCtrl->wy - 12 - posOff; break; case DIR_RIGHT: scp->wx = sCtrl->wx + 25 + (posOff<<1); scp->wy = sCtrl->wy - 3; break; case DIR_DOWN_RIGHT: scp->wx = sCtrl->wx + 16 + posOff; scp->wy = sCtrl->wy + 4 + posOff; break; } //* Set correct sprite frame image scp->spriteLink->u = ((timData[TIM_FDROP_FIRE].px<<2) % 256) + 128 + ((action-1)<<4); //* Set correct shadow size scp->shadBase = 6 - ((action-1)<<1); //* Set off-ground height for build-up sprite scp->high = sCtrl->high + 2; } else { //* Build-up complete - fire bullet in current direction... SsUtKeyOn(0, SFX_GUN_FDROP, 0, 60, rand()%128, 127, 127); bp = GetSprite(3); //* Bullet + 2 blur sprites //* Actual bullet sprite //* Make bullet and blur sprites same colour as build-up sprite preset[PRESET_FDROP_BULLET].sprite.cy = preset[PRESET_FDROP_BULLET_BLUR].sprite.cy = scp->spriteLink->cy; PresetSprite(bp, PRESET_FDROP_BULLET); //* Consider Blitter Boy's direction for firing //* Direction is needed for handle_sprite_over_wall & handle_shadow_over_wall switch (bp->dir = sCtrl->dir) { case DIR_DOWN: if (!(strafe & 0x00000001)) { //* Fire bullet forward (strafe is 0 or 2) bp->accelX = 0; bp->dir = DIR_DOWN; } else if (strafe==1) { //* Fire bullet to BB's right bp->accelX = -1; bp->dir = DIR_DOWN_LEFT; } else { //* Fire bullet to BB's left bp->accelX = 1; bp->dir = DIR_DOWN_RIGHT; } bp->accelY = bullSpeed; bp->spriteLink->u = 48; bp->wx = sCtrl->wx + 8; bp->wy = sCtrl->wy + 9; break; case DIR_DOWN_LEFT: if (!(strafe & 0x00000001)) { //* Fire bullet forward (strafe is 0 or 2) bp->accelX = -bullSpeed; bp->accelY = bullSpeed; } else if (strafe==1) { //* Fire bullet to BB's right bp->accelX = -(bullSpeed+1); bp->accelY = bullSpeed-1; } else { //* Fire bullet to BB's left bp->accelX = -(bullSpeed-1); bp->accelY = bullSpeed+1; } bp->dir = DIR_DOWN_LEFT; bp->spriteLink->u = 112; bp->wx = sCtrl->wx - 4; bp->wy = sCtrl->wy + 7; break; case DIR_LEFT: if (!(strafe & 0x00000001)) { //* Fire bullet forward (strafe is 0 or 2) bp->accelY = 0; bp->dir = DIR_LEFT; } else if (strafe==1) { //* Fire bullet to BB's right bp->accelY = -1; bp->dir = DIR_UP_LEFT; } else { //* Fire bullet to BB's left bp->accelY = 1; bp->dir = DIR_DOWN_LEFT; } bp->accelX = -bullSpeed; bp->spriteLink->u = 0; bp->wx = sCtrl->wx - 16; bp->wy = sCtrl->wy - 3; break; case DIR_UP_LEFT: if (!(strafe & 0x00000001)) { //* Fire bullet forward (strafe is 0 or 2) bp->accelX = -bullSpeed; bp->accelY = -bullSpeed; } else if (strafe==1) { //* Fire bullet to BB's right bp->accelX = -(bullSpeed-1); bp->accelY = -(bullSpeed+1); } else { //* Fire bullet to BB's left bp->accelX = -(bullSpeed+1); bp->accelY = -(bullSpeed-1); } bp->dir = DIR_UP_LEFT; bp->spriteLink->u = 64; bp->wx = sCtrl->wx - 8; bp->wy = sCtrl->wy - 15; break; case DIR_UP: if (!(strafe & 0x00000001)) { //* Fire bullet forward (strafe is 0 or 2) bp->accelX = 0; bp->dir = DIR_UP; } else if (strafe==1) { //* Fire bullet to BB's right bp->accelX = 1; bp->dir = DIR_UP_RIGHT; } else { //* Fire bullet to BB's left bp->accelX = -1; bp->dir = DIR_UP_LEFT; } bp->accelY = -bullSpeed; bp->spriteLink->u = 16; bp->wx = sCtrl->wx + 8; bp->wy = sCtrl->wy - 21; break; case DIR_UP_RIGHT: if (!(strafe & 0x00000001)) { //* Fire bullet forward (strafe is 0 or 2) bp->accelX = bullSpeed; bp->accelY = -bullSpeed; } else if (strafe==1) { //* Fire bullet to BB's right bp->accelX = bullSpeed+1; bp->accelY = -(bullSpeed-1); } else { //* Fire bullet to BB's left bp->accelX = bullSpeed-1; bp->accelY = -(bullSpeed+1); } bp->dir = DIR_UP_RIGHT; bp->spriteLink->u = 80; bp->wx = sCtrl->wx + 22; bp->wy = sCtrl->wy - 15; break; case DIR_RIGHT: if (!(strafe & 0x00000001)) { //* Fire bullet forward (strafe is 0 or 2) bp->accelY = 0; bp->dir = DIR_RIGHT; } else if (strafe==1) { //* Fire bullet to BB's right bp->accelY = 1; bp->dir = DIR_DOWN_RIGHT; } else { //* Fire bullet to BB's left bp->accelY = -1; bp->dir = DIR_UP_RIGHT; } bp->accelX = bullSpeed; bp->spriteLink->u = 32; bp->wx = sCtrl->wx + 31; bp->wy = sCtrl->wy - 3; break; case DIR_DOWN_RIGHT: if (!(strafe & 0x00000001)) { //* Fire bullet forward (strafe is 0 or 2) bp->accelX = bullSpeed; bp->accelY = bullSpeed; } else if (strafe==1) { //* Fire bullet to BB's right bp->accelX = bullSpeed-1; bp->accelY = bullSpeed+1; } else { //* Fire bullet to BB's left bp->accelX = bullSpeed+1; bp->accelY = bullSpeed-1; } bp->dir = DIR_DOWN_RIGHT; bp->spriteLink->u = 96; bp->wx = sCtrl->wx + 19; bp->wy = sCtrl->wy + 7; break; } //* Consider if bullet is starting over wall handle_shadow_over_wall(bp); --bp->ICSALop; //* Make blur preset frame same as bullet preset[PRESET_FDROP_BULLET_BLUR].sprite.u = bp->spriteLink->u; //* First motion-blur bullet PresetSprite(bp->freeLink, PRESET_FDROP_BULLET_BLUR); //sp = bp->freeLink->spriteLink; //sp->r = sp->g = sp->b = 32; //* Second motion-blur bullet PresetSprite(bp->freeLink->freeLink, PRESET_FDROP_BULLET_BLUR); //sp = bp->freeLink->freeLink->spriteLink; //sp->r = sp->g = sp->b = 16; //* Find initial central x,y world coords bp->wxMid = bp->wx + bp->bbXOff + (bp->bbW >> 1); bp->wyMid = bp->wy - bp->bbYOff + (bp->bbH >> 1); //* Set off-ground height for new bullet sprites bp->high = sCtrl->high + 2; AliveLinkIn(bp); } } //*------------------------------------------------------------------------------------------ //* update_powflash_xy //*------------------------------------------------------------------------------------- static void update_powflash_xy(register struct SCTRL *scp) { ++scp->ICSALop; scp->wx = scp->target->wx; scp->wy = scp->target->wy; scp->high = sCtrl->high; } //*------------------------------------------------------------------------------------------ //* update_orbit //*------------------------------------------------------------------------------------- static void update_orbit(register struct SCTRL *scp) { ++scp->ICSALop; scp->wx = sCtrl->wxMid - 4; scp->wy = sCtrl->wyMid + 1; } //*------------------------------------------------------------------------------------------ //* update_ufo_crash //*------------------------------------------------------------------------------------- static void update_ufo_crash(register struct SCTRL *scp) { register struct SCTRL *scp2; ++scp->ICSALop; if (scp->high<=0) { //* UFO has crashed... //* Bring preset coin/explosion sprites into game for (scp2=scp->freeLink; scp2; scp2=scp2->freeLink) AliveLinkIn(scp2); AliveLinkOut(scp); //* Kill actual UFO sprite lastCall = 0x100; //* Ensure this is last ICSAL call } } static long ufoSway[] = { ONE*20,ONE*30,ONE*30,ONE*20,0, -ONE*20,-ONE*30,-ONE*30,-ONE*20,0 }; //*------------------------------------------------------------------------------------------ //* update_ufo_fall //*------------------------------------------------------------------------------------- static void update_ufo_fall(register struct SCTRL *scp) { register GsSPRITE *sp = scp->spriteLink; //* Pointer to actual sprite object ++scp->ICSALop; if (scp->high) { if (--scp->high & 0x01) { scp->isLight = 0; sp->cx = timData[TIM_UFO].cx; sp->cy = timData[TIM_UFO].cy; scp->shadLink->attribute = //* Shadow (A_4BIT_CLUT + A_BRIGHT_OFF + A_ROTATE_OFF + A_TRATE_3 + A_TRANS_ON + A_DISPLAY_ON); } else { scp->isLight = 1; sp->r = sp->g =128; sp->b = 0; sp->cx = timData[TIM_MASKCLUT].cx; sp->cy = timData[TIM_MASKCLUT].cy; scp->shadLink->attribute = //* Reflected light (A_4BIT_CLUT + A_BRIGHT_ON + A_ROTATE_OFF + A_TRATE_2 + A_TRANS_ON + A_DISPLAY_ON); } sp->rotate = ufoSway[scp->dir]; if (++scp->dir==10) scp->dir = 0; } else { scp->isLight = 0; sp->cx = timData[TIM_UFO].cx; sp->cy = timData[TIM_UFO].cy; sp->rotate = 0; // SsUtKeyOn(0, SFX_LEV_SCREEN, 0, 84, 0, 127, 127); } } //*------------------------------------------------------------------------------------------ //* goto_orbit //*------------------------------------------------------------------------------------- static void goto_orbit(register struct SCTRL *scp) { //* Hand initialize main loop scp->ICSALloopCount = INFINITE_LOOP; scp->ICSALloopStart = scp->ICSALop+1; //* Jump to correct place in orbitBall ICSAL proc switch (scp->dir) { case DIR_DOWN: scp->ICSALop += 175; break; case DIR_DOWN_LEFT: scp->ICSALop += 146; break; case DIR_LEFT: scp->ICSALop += 117; break; case DIR_UP_LEFT: scp->ICSALop += 88; break; case DIR_UP: scp->ICSALop += 59; break; case DIR_UP_RIGHT: scp->ICSALop += 30; break; case DIR_RIGHT: scp->ICSALop += 1; break; case DIR_DOWN_RIGHT: scp->ICSALop += 204; break; } } //*------------------------------------------------------------------------------------------ //* set_spin_frame //*------------------------------------------------------------------------------------- static void set_spin_frame(register struct SCTRL *scp) { register GsSPRITE *sp = scp->spriteLink; //* Pointer to actual sprite object ++scp->ICSALop; if (!--scp->frameCount) { scp->frameCount = scp->repsPerFrame; //* Set frame to next clock-wise spin direction switch (scp->dir) { case DIR_DOWN: sp->u = 128; sp->v = (scp==sCtrl ? 108: 96); //* BB & baby sprites are different heights scp->dir = DIR_DOWN_LEFT; break; case DIR_DOWN_LEFT: sp->u = 128; sp->v = (scp==sCtrl ? 36: 32); scp->dir = DIR_LEFT; break; case DIR_LEFT: sp->u = 128; sp->v = (scp==sCtrl ? 72: 64); scp->dir = DIR_UP_LEFT; break; case DIR_UP_LEFT: sp->u = 128; sp->v = 0; scp->dir = DIR_UP; break; case DIR_UP: sp->u = 0; sp->v = (scp==sCtrl ? 72: 64); scp->dir = DIR_UP_RIGHT; break; case DIR_UP_RIGHT: sp->u = 0; sp->v = (scp==sCtrl ? 36: 32); scp->dir = DIR_RIGHT; break; case DIR_RIGHT: sp->u = 0; sp->v = (scp==sCtrl ? 108: 96); scp->dir = DIR_DOWN_RIGHT; break; case DIR_DOWN_RIGHT: sp->u = 0; sp->v = 0; scp->dir = DIR_DOWN; break; } } } //*------------------------------------------------------------------------------------------ //* reset_moneybag //*------------------------------------------------------------------------------------- static void reset_moneybag(register struct SCTRL *scp) { register GsSPRITE *sp = scp->spriteLink; //* Pointer to actual sprite object register int i; ++scp->ICSALop; i = (coinsInBag<<12)/FIX_COINS_PER_SCAN; sp->v = timData[TIM_MONEYBAG].py+(17-i); sp->h = i; sp->y = 6+(16-i); } //*------------------------------------------------------------------------------------------ //* check_landing_action //*------------------------------------------------------------------------------------- static void check_landing_action(register struct SCTRL *scp) { ++scp->ICSALop; if (scp->subID==BOY_GAME_OVER) { scp->ICSALop = boyGameOver; scp->target = &sCtrl[SPRT_TVBEAM]; lastCall = 0x100; //* Ensure this is last ICSAL call } else if (scp->subID==BOY_LEVEL_UP) { scp->target = &sCtrl[SPRT_TVBEAM]; scp->ICSALop = gotoTV; //* Set BB to move into position for beam-up lastCall = 0x100; //* Ensure this is last ICSAL call } }