-- The visual version of the STOOGE. Since the Stooge can move in
-- several directions and since we want her feet moving, we need lots
-- of pictures of her. Also need pictures with mirrors. May want more
-- that represent her other powers.

class V_STOOGE

inherit

  TM_CLIENT

  V_MOBILE
  rename
    make as vm_make, make_customized as vm_make_customized
  undefine
    restart, win, will_accept,
    try_west, try_east, try_north, try_south,
    create_record, build_record, customized_init
  redefine
    room, northwest, clear
  end

  STOOGE
  redefine
    northwest, room, restart, bridge, clear, factory
  end

creation

  make, make_customized

feature{NONE}

  make( s : STRING ; vgr : V_GAME_ROOM ; c : V_GAME_CELL ) is
  do
    facing := south
    vm_make( s, vgr, c )
    display_bullets
    display_bridges
    display_mirrors
    display_axes
    display_magnets
    !!bridge_list.make
    !!factory
    clock := room.clock
    create dance_event.make_periodic( Current, configuration.dance_interval )
    create teleport_event.make_periodic( Current, configuration.teleport_interval )
  end

  make_customized( s : STRING ; vgr : V_GAME_ROOM ; pr : LINKED_LIST[ INTEGER ] ) is
  do
    facing := south
    vm_make_customized( s, vgr, pr )
    display_bullets
    display_bridges
    display_mirrors
    display_axes
    display_magnets
    !!bridge_list.make
    !!factory
    clock := room.clock
    create dance_event.make_periodic( Current, configuration.dance_interval )
    create teleport_event.make_periodic( Current, configuration.teleport_interval )
  end

  bridge : V_DECORATION
  factory : V_PIECE_FACTORY

  display_win is
  -- Celebrate!
  do
    dance
  end

  step : INTEGER
  -- To count my dance steps.

--  sounds : expanded SOUNDS
  -- To vocalize my death rattle.

  dance is
  -- Celebrate!
  do
    dancing := True -- Tele Animation
    step := 0
    clock.register( dance_event )
  end

  display_bullets is
  -- Have the room display my quantity of bullets.
  do
    room.display_bullets( bullets )
  end

  display_bridges is
  -- Have the room display my quantity of bridges.
  do
    room.display_bridges ( bridges )
  end

  display_mirrors is
  -- Have the room display my quantity of mirrors.
  do
    room.display_mirrors ( mirrors )
    if mirrors > 0 then 
      bitmaps := mirrored
    else
      bitmaps := normal
    end
    bitmap := bitmaps.item( bitmap_index )
    invalidate
  end

  display_axes is
  -- Have the room display my quantity of mirrors.
  do
    room.display_axes ( axes )
  end

  display_magnets is
  -- Have the room display my quantity of mirrors.
  do
    room.display_magnets ( magnets )
  end

  normal, mirrored, bitmaps : ARRAY[ WEL_BITMAP ]
  teleportation_anim_normal : ARRAY[ LINKED_LIST [ WEL_BITMAP ] ]
  teleportation_anim_mirror : ARRAY[ LINKED_LIST [ WEL_BITMAP ] ]
  bitmap_index : INTEGER

  winning, south_right, north_right, east_right, west_right,
  west_left, north_left, south_left, east_left, killed : INTEGER is unique

  get_bitmaps is
  do
    make_normal
    make_mirrored
    make_teleportation_animation_normal
    make_teleportation_animation_mirror
    bitmaps := normal
    bitmap := bitmaps.item( south_right )
    bitmap_index := south_right
  end

-- Teleportation Animation

  make_teleportation_animation_normal is
  do
    create teleportation_anim_normal.make( south_right, east_left )
    teleportation_anim_normal.put( configuration.game_stooge_s_r_pixmaps( Current ), south_right )
    teleportation_anim_normal.put( configuration.game_stooge_n_r_pixmaps( Current ), north_right )
    teleportation_anim_normal.put( configuration.game_stooge_e_r_pixmaps( Current ), east_right )
    teleportation_anim_normal.put( configuration.game_stooge_w_r_pixmaps( Current ), west_right )
    teleportation_anim_normal.put( configuration.game_stooge_w_l_pixmaps( Current ), west_left )
    teleportation_anim_normal.put( configuration.game_stooge_n_l_pixmaps( Current ), north_left )
    teleportation_anim_normal.put( configuration.game_stooge_s_l_pixmaps( Current ), south_left )
    teleportation_anim_normal.put( configuration.game_stooge_e_l_pixmaps( Current ), east_left )
  end

  make_teleportation_animation_mirror is
  do
    create teleportation_anim_mirror.make( south_right, east_left )
    teleportation_anim_mirror.put( configuration.mirror_s_r_pixmaps( Current ), south_right )
    teleportation_anim_mirror.put( configuration.mirror_n_r_pixmaps( Current ), north_right )
    teleportation_anim_mirror.put( configuration.mirror_e_r_pixmaps( Current ), east_right )
    teleportation_anim_mirror.put( configuration.mirror_w_r_pixmaps( Current ), west_right )
    teleportation_anim_mirror.put( configuration.mirror_w_l_pixmaps( Current ), west_left )
    teleportation_anim_mirror.put( configuration.mirror_n_l_pixmaps( Current ), north_left )
    teleportation_anim_mirror.put( configuration.mirror_s_l_pixmaps( Current ), south_left )
    teleportation_anim_mirror.put( configuration.mirror_e_l_pixmaps( Current ), east_left )
  end

  make_mirrored is
  do
    !!mirrored.make( winning, killed )
    mirrored.put( configuration.mirror_win_pixmap( Current ), winning )
    mirrored.put( configuration.mirror_s_r_pixmap( Current ), south_right )
    mirrored.put( configuration.mirror_n_r_pixmap( Current ), north_right )
    mirrored.put( configuration.mirror_e_r_pixmap( Current ), east_right )
    mirrored.put( configuration.mirror_w_r_pixmap( Current ), west_right )
    mirrored.put( configuration.mirror_w_l_pixmap( Current ), west_left )
    mirrored.put( configuration.mirror_n_l_pixmap( Current ), north_left )
    mirrored.put( configuration.mirror_s_l_pixmap( Current ), south_left )
    mirrored.put( configuration.mirror_e_l_pixmap( Current ), east_left )
    mirrored.put( configuration.mirror_dead_pixmap( Current ), killed )
  end


  make_normal is
  do
    !!normal.make( winning, killed )
    normal.put( configuration.game_stooge_win_pixmap( Current ), winning )
    normal.put( configuration.game_stooge_s_r_pixmap( Current ), south_right )
    normal.put( configuration.game_stooge_n_r_pixmap( Current ), north_right )
    normal.put( configuration.game_stooge_e_r_pixmap( Current ), east_right )
    normal.put( configuration.game_stooge_w_r_pixmap( Current ), west_right )
    normal.put( configuration.game_stooge_w_l_pixmap( Current ), west_left )
    normal.put( configuration.game_stooge_n_l_pixmap( Current ), north_left )
    normal.put( configuration.game_stooge_s_l_pixmap( Current ), south_left )
    normal.put( configuration.game_stooge_e_l_pixmap( Current ), east_left )
    normal.put( configuration.game_stooge_dead_pixmap( Current ), killed )
  end

  get_id is
  do
    id := configuration.stooge_code
  end

  display_dead is
  -- Show my earthly remains and vocalize my death rattle.
  do
     bitmap := bitmaps.item( killed )
     bitmap_index := killed
 --   sounds.play( "splat.au" )
    invalidate
  end

  face_north is
  -- Look northward and change my front foot.
  do
    left := not left
    if left then
      bitmap :=  bitmaps.item( north_left )
      bitmap_index := north_left
    else
      bitmap :=  bitmaps.item( north_right )
      bitmap_index := north_right
    end
    invalidate
  end

  face_south is
  -- Look southward and change my front foot.
  do
    left := not left
    if left then
      bitmap := bitmaps.item( south_left )
      bitmap_index := south_left
    else
      bitmap := bitmaps.item( south_right )
      bitmap_index := south_right
    end
    invalidate
  end

  face_east is
  -- Look eastward and change my front foot.
  do
    left := not left
    if left then
      bitmap := bitmaps.item( east_left )
      bitmap_index := east_left
    else
      bitmap := bitmaps.item( east_right )
      bitmap_index := east_right
    end
    invalidate
  end

  face_west is
  -- Look westward and change my front foot.
  do
    left := not left
    if left then
      bitmap := bitmaps.item( west_left )
      bitmap_index := west_left
    else
      bitmap := bitmaps.item( west_right )
      bitmap_index := west_right
    end
    invalidate
  end

  display_initial is
  -- Display myself in my initial orientation.
  do
    left := False
    bitmaps := normal
    bitmap := bitmaps.item( south_right )
    bitmap_index := south_right
    invalidate
  end

  do_one_dance_step is
  -- Change my front foot and maybe my direction as well.
  local
    d : INTEGER
  do
    d := 4 * (step - 1) // configuration.dance_steps
    inspect d
    when 0 then face_west
    when 1 then face_north
    when 2 then face_east
    when 3 then face_south
    else
    end
  end
    
  dance_event : TM_EVENT

  wake_up_while_dancing is
  local
    win_evt : WIN_EVENT
  do
    step := step + 1
    if step <= configuration.dance_steps then
      do_one_dance_step
    else
      dancing := False -- Tele Animation
      clock.cancel( dance_event )
      bitmap := bitmaps.item( winning )
      bitmap_index := winning
      invalidate

      -- allow the room to inform its listeners that Stooge has won
      -- located here so that the HOF dialog box does not cover Stooge while dancing
      create win_evt.new_win_event( room.game_clock.time_value, room.puzzle.title ) -- RML HW4
      room.notify_win_listener( win_evt )                                           -- RML HW4
    end
  end


feature{NONE} -- Teleportation Animation

  teleport_anim : LINKED_LIST [ WEL_BITMAP ]
  teleport_event : TM_EVENT
  move_to_cell : like northwest
-- facilitates a fast switch of the animation list
  anim_array_index : INTEGER

  set_teleportation_animation is
  local
    index : INTEGER
  do
    anim_array_index := get_array_index
    if mirrors > 0 then 
      teleport_anim := teleportation_anim_mirror.item( anim_array_index )
    else
      teleport_anim := teleportation_anim_normal.item( anim_array_index )
    end
    vulnerable_index := (teleport_anim.count * vulnerable_percent).rounded
  end

  get_array_index : INTEGER is
  do
    if facing = south and left then
      Result := south_left
    elseif facing = south and not left then
      Result := south_right
    elseif facing = north and left then
      Result := north_left
    elseif facing = north and not left then
      Result := north_right
    elseif facing = east and left then
      Result := east_left
    elseif facing = east and not left then
      Result := east_right
    elseif facing = west and left then
      Result := west_left
    elseif facing = west and not left then
      Result := west_right
    end
  end

  teleport_display( gc : like northwest ) is
  -- Get ready to display a series of bitmaps during teleportation
  do

    -- Initial settings
    teleporting := True
    frame_scan_forward := True
    teleported := False
    vulnerable_while_teleporting := True
    move_to_cell := gc

    set_teleportation_animation
    
    if teleport_anim.empty then
      move_to( move_to_cell )
      clean_up_teleporting
    else
      clock.register( teleport_event )
    end
  end

  restore_teleport_display( gc : like northwest ) is
  -- Get ready to display a series of bitmaps during teleportation
  do
    move_to_cell := gc
    set_teleportation_animation
    set_tele_frame_num( tele_frame_number )
    clock.register( teleport_event ) 
  end

  get_tele_frame_num : INTEGER is
-- get the teleportation animation frame number
  do
    Result := teleport_anim.index
  end

  set_tele_frame_num( num : INTEGER ) is
-- set the teleportation animation frame number
  do
    teleport_anim.go_i_th( num )
  end
  do_one_teleport_frame is
  do
    bitmap := teleport_anim.item

    if vulnerable_while_teleporting then
    -- the room should react if Stooge is in the vulnerable stage of teleportation
      room.react
    end

    if frame_scan_forward then
      teleport_anim.forth
    else
      teleport_anim.back
    end

    if teleport_anim.index > vulnerable_index then
      vulnerable_while_teleporting := False
    else
      vulnerable_while_teleporting := True
    end

    invalidate
  end

  wake_up_while_teleporting is
  do
    if not dead then
      if frame_scan_forward then
        do_one_teleport_frame
        if teleport_anim.exhausted then
          -- start scanning back to the beginnning of the list
          frame_scan_forward := False
          teleport_anim.back
        end
      else
        -- This is were the actual teleportation takes place
        if not teleported then
          move_to( move_to_cell )
          teleported := True
        end
        do_one_teleport_frame
          if teleport_anim.before then
          -- No valid left cursor position
            clean_up_teleporting
            display_mirrors
          end
        end
    else
      -- Stooge was killed while vulnerable and teleporting
      -- Cancel the telportation event
      clean_up_teleporting
    end
  end

  clean_up_teleporting is
  do
    if teleport_anim /= Void then
      teleport_anim.start
    end
    teleporting := False
    frame_scan_forward := True
    teleported := False
    clock.cancel( teleport_event )
  end

-- Stooge used up her last pair of glasses while teleporting
-- Switch the list quickly
  switch_anim_to_normal is
  local
    frame : INTEGER
  do
    frame := teleport_anim.index
    teleport_anim := teleportation_anim_normal.item( anim_array_index )
    teleport_anim.go_i_th ( frame )
  end

feature

  room : V_GAME_ROOM
  northwest : V_GAME_CELL

  wake_up( e: TM_EVENT ) is
  -- Based on the number of steps taken, either do the next dance step 
  -- and reset timer or finish the dance.
  -- Also hanle telporting frames
  do
    if dancing then
      wake_up_while_dancing
    elseif teleporting then
      wake_up_while_teleporting -- Tele Animation
    end
  end

  restart is
  -- Do my parent's 'restart' then do my own.
  do
    {STOOGE}precursor  -- Bug in compiler? Shouldn't need {STOOGE}
--    precursor  -- Bug in compiler? Shouldn't need {STOOGE}
    clock.cancel( dance_event )
    clean_up_teleporting
  ensure then
    not teleporting
  end

  clear is
  do
    {STOOGE}precursor
    {V_MOBILE}precursor
  end

end 
