indexing description: "Our hero!" deferred class STOOGE -- Bridge stuff added 3/23/97 -- Some people had the Water piece manage the new bridge piece. This -- is nice as it's 1-1. Might make sense to change to that approach? -- Either way, currently we're setting up a potentially fragile situation as a -- new bridge piece does not always replace a complete water piece. Instead -- sometimes replaces some parts of a water piece. This is done by having -- the cells remove their water pieces, so a water piece may think it still -- occupies four cells when only two of the cells agree. -- This class is getting bigger and bigger as Stooge obtains more powers. Need to -- subdivide in some fashion? inherit MOBILE redefine will_accept, try_west, try_east, try_north, try_south, restart, win, clear, build_record, customized_init end feature -- save/restore build_record is -- 1,2,3 from GAME_PIECE -- 4,5 from MOBILE -- 6 number of axes -- 7 number of bridges -- 8 number if bullets -- 9 number of magnets -- 10 number of mirrors -- 11 dead -- 12 facing -- 13 left foot -- 14 spoor -- 15 if locked or unlock -- 16 if locked then col of box -- 17 if locked then row of box -- 18 if teleporting -- 19 if teleporting, frame_index -- 20 if teleporting, frame_scan_forward -- 21 if teleporting, teleported -- 22 if teleporting, vulnerable_while_teleporting -- note that we need to save/restore vulnerable_while_teleporting because -- it is determine after the room reacts -- 23 bridge list count -- 24 if bridges bridge col -- 25 if bridges bridge row -- ... -- 26 + 2 * bridge list count - 1 if bridges bridge col -- 26 + 2 * bridge list count if bridges bridge row do precursor record.extend( axes ) record.extend( bridges ) record.extend( bullets ) record.extend( magnets ) record.extend( mirrors ) if dead then record.extend( 1 ) else record.extend( 0 ) end record.extend( facing ) -- Left foot if left then record.extend( 1 ) else record.extend( 0 ) end record.extend( spoor ) if locked then record.extend( 1 ) record.extend( locked_box.northwest.column ) record.extend( locked_box.northwest.row ) else record.extend( 0 ) end if teleporting then record.extend( 1 ) record.extend( get_tele_frame_num ) if frame_scan_forward then record.extend( 1 ) else record.extend( 0 ) end if teleported then record.extend( 1 ) else record.extend( 0 ) end if vulnerable_while_teleporting then record.extend( 1 ) else record.extend( 0 ) end else record.extend( 0 ) end record.extend( bridge_list.count ) from bridge_list.start until bridge_list.exhausted loop record.extend( bridge_list.item.northwest.column ) record.extend( bridge_list.item.northwest.row ) bridge_list.forth end -- lb code -- this adds stoogies invinciblity state to the sip record. if invincible then record.extend( 1 ) else record.extend( 0 ) end -- end lb code ensure then proper_num_rec: record.count > 16 end finish_restoring is -- Complete my restoration, rebuild my bridges, etc. do saved_record.forth if saved_record.item = 1 then relock end saved_record.forth teleporting := ( saved_record.item = 1 ) if teleporting then saved_record.forth tele_frame_number := saved_record.item saved_record.forth frame_scan_forward := ( saved_record.item = 1 ) saved_record.forth teleported := ( saved_record.item = 1 ) saved_record.forth vulnerable_while_teleporting := ( saved_record.item = 1 ) end saved_record.forth if saved_record.item > 0 then restore_bridges end -- Undead Stooge problem if dead then die end if teleporting then -- kick off the teleportation animation restore_teleportation end -- lb code add -- this restores stoogies invincibility state from the sip record. saved_record.forth invincible := ( saved_record.item = 1 ) -- lb code end end feature{NONE} -- save/restore saved_record : like record customized_init( r : like room ; pr : like record ) is do precursor( r, pr ) visit( northwest ) restore_powers( pr ) pr.forth -- Undead Stooge problem dead := ( pr.item = 1 ) pr.forth facing := pr.item -- The Left Foot Enigma -- Note that left gets notted in "face_NSEW" of V_STOOGE pr.forth left := ( pr.item = 0 ) pr.forth spoor := pr.item face( facing ) saved_record := clone( pr ) end relock is -- Re-lock onto locked box local c : like northwest locked_box_col, locked_box_row : INTEGER do saved_record.forth locked_box_col := saved_record.item saved_record.forth locked_box_row := saved_record.item c := room.room_cell( locked_box_col, locked_box_row ) locked_box ?= c.visitor locked_box.lock locked := True end restore_bridges is -- Restore my previously built bridges. local c : like northwest bridge_col, bridge_row : INTEGER do from saved_record.forth variant ( saved_record.count - saved_record.index + 1 ) until saved_record.exhausted loop bridge_col := saved_record.item saved_record.forth bridge_row := saved_record.item saved_record.forth c := room.room_cell( bridge_col, bridge_row ) really_build_bridge( c ) end end restore_powers( pr : like record ) is -- Restore my axes and other powers. do pr.forth change_axes( pr.item ) pr.forth change_bridges( pr.item ) pr.forth change_bullets( pr.item ) pr.forth change_magnets( pr.item ) pr.forth change_mirrors( pr.item ) end feature{NONE} -- Telportation dancing, teleporting, teleported, frame_scan_forward, vulnerable_while_teleporting : BOOLEAN -- used when restoring Stooge while teleporting tele_frame_number : INTEGER -- Percentage of frames at which stooge remains/becomes vulnerable while teleporting -- For instance, frames numbers 1 2 3 4 5 6 7 6 5 4 3 2 1 -- Stooge is in 7 * 0.6 = 4 ^vuln ^ invul ^ vuln -- The larger the number, the less frames stooge is invulnerable while teleporting vulnerable_percent : REAL is 0.6 vulnerable_index : INTEGER -- gives STOOGE access to feature in V_STOOGE teleport_display( gc : like northwest ) is deferred end restore_teleport_display( gc : like northwest ) is deferred end -- Stooge used up her last pair of glasses while teleporting switch_anim_to_normal is deferred end get_tele_frame_num : INTEGER is -- get the teleportation animation frame number deferred end set_tele_frame_num( num : INTEGER ) is -- set the teleportation animation frame number deferred end -- Return void if Stooge is not fully on the portal -- or the portal is not linked get_portal_mate : GAME_PORTAL is local nw_c, ne_c, sw_c, se_c : like northwest p : GAME_PORTAL do -- Here are the four cells for which Stooge is occupying nw_c := stooge.northwest sw_c := stooge.southwest se_c := stooge.southeast ne_c := stooge.northeast p ?= ne_c.occupant if p /= Void and then p.is_linked then -- The portal is linked. Now check if Stooge is on all four portal cells if p = se_c.occupant and p = sw_c.occupant and p = nw_c.occupant then Result := p.link_mate end end end restore_teleportation is local mate : GAME_PORTAL cell : V_GAME_CELL do mate := get_portal_mate if mate /= Void then cell ?= mate.northwest if cell /= Void then restore_teleport_display( cell ) end end end feature{NONE} left : BOOLEAN -- Do I have my left foot forward? face( d : INTEGER ) is do if facing = south then face_south elseif facing = north then face_north elseif facing = east then face_east elseif facing = west then face_west end end face_north, face_south, face_east, face_west is deferred end visitor : MOBILE -- Somebody I might try to move out of my way. common_visitor( c1, c2 : like northwest ) : MOBILE is -- If 'c1' and 'c2' are both being visited by the same visitor then -- Result is that visitor. Else Result is Void. do if c1.visited and c2.visited and then c1.visitor = c2.visitor then Result := c1.visitor end end display_bullets is -- Display number of bullets. deferred end display_bridges is -- Display number of bridges. deferred end display_mirrors is -- Display number of mirrors. deferred end display_axes is -- Display number of axes. deferred end display_magnets is -- Display number of mirrors. deferred end display_win is -- Visually celebrate my glorious victory. deferred end display_initial is -- Display myself in my initial configuration. deferred end display_dead is -- Display my sad remains. deferred end -- Ought to be some clever way to combine these "shoot" routines. Ditto -- for build bridge stuff. shoot_north is -- Shoot a bullet north, 'attack' whoever stops the bullet. require bullets > 0 local c1, c2 : GAME_CELL do from c1 := northwest.north c2 := northeast.north until c1.blocks_shots or c2.blocks_shots loop c1 := c1.north c2 := c2.north end attack( c1, c2 ) end shoot_south is -- Shoot a bullet south, 'attack' whoever stops the bullet. require bullets > 0 local c1, c2 : GAME_CELL do from c1 := southwest.south c2 := southeast.south until c1.blocks_shots or c2.blocks_shots loop c1 := c1.south c2 := c2.south end attack( c1, c2 ) end shoot_east is -- Shoot a bullet east, 'attack' whoever stops the bullet. require bullets > 0 local c1, c2 : GAME_CELL do from c1 := southeast.east c2 := northeast.east until c1.blocks_shots or c2.blocks_shots loop c1 := c1.east c2 := c2.east end attack( c1, c2 ) end shoot_west is -- Shoot a bullet west, 'attack' whoever stops the bullet. require bullets > 0 local c1, c2 : GAME_CELL do from c1 := northwest.west c2 := southwest.west until c1.blocks_shots or c2.blocks_shots loop c1 := c1.west c2 := c2.west end attack( c1, c2 ) end attack( c1, c2 : GAME_CELL ) is -- If these two cells have a common occupant and/or visitor, shoot same. local o, v : GAME_PIECE do -- This is tricky. Since a bullet may turn an occupant into a -- visitor or vice versa, we need to save the old visitor/occupant -- and make sure the shot only affects them. Probably a better way -- to do this. if c1.visited and c2.visited and then c1.visitor = c2.visitor then -- kludge to handle FAKE_CELL case. v := c1.visitor end if c1.occupied and c2.occupied and then c1.occupant = c2.occupant then -- kludge to handle FAKE_CELL case. o := c1.occupant end if o /= Void then o.receive_bullet end if v /= Void then v.receive_bullet end end facing_medusa( m : MEDUSA ) : BOOLEAN is -- Am I facing `m'? require aligned: m.northwest.row = northwest.row or m.northwest.column = northwest.column do if facing = North then Result := m.northwest.row < northwest.row elseif facing = South then Result := m.northwest.row > northwest.row elseif facing = East then Result := m.northwest.column > northwest.column else Result := m.northwest.column < northwest.column end end facing_tree : PUZZLE_TREE is -- Tree directly in front of me. Void if no such tree. do if facing_cell_1.occupied and then facing_cell_2.occupied and then facing_cell_1.occupant = facing_cell_2.occupant then Result ?= facing_cell_1.occupant end end facing_box : PUZZLE_BOX is -- Box directly in front of me. Void if no such box. do if facing_cell_1.visited and then facing_cell_2.visited and then facing_cell_1.visitor = facing_cell_2.visitor then Result ?= facing_cell_1.visitor end end facing_cell_1 : like northwest is -- Northwesternmost cell I'm facing do if facing = North then Result := northwest.north elseif facing = East then Result := northeast.east elseif facing = South then Result := southwest.south elseif facing = West then Result := northwest.west end end facing_cell_2 : like northwest is -- Southeasternmost cell I'm facing do if facing = North then Result := northeast.north elseif facing = East then Result := southeast.east elseif facing = South then Result := southeast.south elseif facing = West then Result := southwest.west end end spoor : INTEGER leave_spoor is -- Leave a trace of myself in my cells. do northwest.set_spoor( spoor ) northeast.set_spoor( spoor ) southwest.set_spoor( spoor ) southeast.set_spoor( spoor ) end feature North, East, South, West : INTEGER is unique facing : INTEGER -- My current direction. This is important in case I shoot, build a bridge, -- reglect glare, etc. blocks_glare : BOOLEAN is True blocks_shots : BOOLEAN is True -- begin rob add -- Flag to see if the stooge is invincible invincible : BOOLEAN -- end Rob add dead : BOOLEAN -- Say it ain't so! receive_glare( m : MEDUSA ) is -- Uh oh, I've been spotted! do -- begin Rob add -- if not invincible then -- End Rob add if mirrors > 0 and facing_medusa( m ) then mirrors := mirrors - 1 -- Stooge used up her last pair of glasses during teleportation -- Switch the animation if teleporting and mirrors = 0 then switch_anim_to_normal elseif not teleporting then display_mirrors end reflect( m ) else -- lb add if not invincible then die end end -- begin rob add --end -- end rob add end reflect( m : MEDUSA ) is -- Reflect glare back at medusa. do m.receive_own_glare end die is -- Aaaaaaaggggghhhhh! do if not teleporting or vulnerable_while_teleporting then dead := True -- frozen := True if locked then unlock end display_dead end ensure ( not teleporting or vulnerable_while_teleporting ) implies dead end restart is do precursor -- frozen := False bullets := 0 clear_bridges mirrors := 0 axes := 0 magnets := 0 bridges := 0 invincible := False dead := False display_bullets display_bridges display_mirrors display_axes display_magnets if locked then unlock end display_initial spoor := 1 leave_spoor facing := south dancing := False ensure then not dancing spoor = 1 facing = south end clear_bridges is do from bridge_list.start until bridge_list.after loop bridge_list.item.clear bridge_list.remove end end bullets : INTEGER change_bullets( b : INTEGER ) is -- Change my number of bullets and display the new value. do bullets := b display_bullets ensure bullets = b end shoot is -- If I have any bullets, shoot one in the direction I'm facing. require not dead do if bullets > 0 then if facing = North then shoot_north elseif facing = East then shoot_east elseif facing = West then shoot_west elseif facing = south then shoot_south end bullets := bullets - 1 display_bullets end ensure old bullets > 0 implies bullets = old bullets - 1 end bridges : INTEGER change_bridges( b : INTEGER ) is -- Change my number of bridgesand display the new value. do bridges := b display_bridges ensure bridges = b end build_bridge is -- If I have any bridges, try to build one in the direction I'm facing. require not dead do if bridges > 0 then check_for_water if all_water then really_build_bridge( nw ) change_bridges( bridges - 1 ) end end end chop is -- If I have any axes, try to chop a tree down. require not dead local t : PUZZLE_TREE do t := facing_tree if axes > 0 and t /= Void then t.chop change_axes( axes - 1 ) end end locked : BOOLEAN locked_box : PUZZLE_BOX magnetize is -- Toggle locked box status. That is, detach from -- the box if I'm locked onto one, otherwise -- try to lock onto the one I'm facing. require not dead do if locked then unlock else try_lock end end mirrors : INTEGER change_mirrors( m : INTEGER ) is -- Change my number of mirrors and display the new value. do mirrors := m display_mirrors ensure mirrors = m end change_invincible() is -- this toggles stooges invincibliliy when she collect an invincible heart. do if(invincible) then invincible := False else invincible := True end ensure invincible = not(old invincible) end magnets : INTEGER change_magnets( m : INTEGER ) is -- Change my number of magnets and display the new value. do magnets := m display_magnets ensure magnets = m end axes : INTEGER change_axes( a : INTEGER ) is -- Change my number of axes and display the new value. do axes := a display_axes ensure axes = a end feature{NONE} all_water : BOOLEAN check_for_water is do if facing = North then check_water( northwest.north.north ) elseif facing = West then check_water( northwest.west.west ) elseif facing = east then check_water( northeast.east ) else check_water( southwest.south ) end end check_water( cll : like northwest ) is do nw := cll all_water := is_water( nw ) and is_water( nw.east ) and is_water( nw.south.east ) and is_water( nw.south ) end nw : like northwest is_water( cll : like northwest) : BOOLEAN is local water : WATER do if cll.occupied then water ?= cll.occupant Result := ( water /= Void ) end end bridge : DECORATION bridge_list : LINKED_LIST[ like bridge ] really_build_bridge( c : like northwest ) is do bridge := new_bridge( room, c ) bridge_list.extend( bridge ) c.vacate c.south.vacate c.east.vacate c.south.east.vacate end factory : PIECE_FACTORY new_bridge( r : like room ; c : like northwest ) : like bridge is do Result := factory.new_bridge( r, c ) end unlock is -- Detach myself from `locked_box' require locked do locked_box.unlock locked := False ensure not locked end try_lock is -- Attach myself to the box in front of me, -- if any. require not locked do locked_box := facing_box if magnets > 0 and locked_box /= Void then locked_box.lock locked := True end end check_locked_box is -- If locked box moved with me then I lose -- a magnet, otherwise I lose the box. require locked do if locked_box.success then change_magnets( magnets - 1 ) if magnets = 0 then unlock end else unlock end end feature will_accept( c1, c2 : like northwest ) : BOOLEAN is -- Will both these cells welcome me? do Result := c1.will_accept_stooge and c2.will_accept_stooge end start( c : like northwest ) is -- Make 'c' the northwest corner of my home. do visit( c ) starting_cell := c spoor := 1 leave_spoor ensure starting_cell = c end can_move_north : BOOLEAN is -- All the 'can_move' routines need work. Not using them currently to -- move the Stooge. do -- Result := m_can_move_north and then mobile_will_move_north end mobile_will_move_north : BOOLEAN is do -- Result := no_mobile or else same_mobile and mobile.can_move_north end -- This 'try' code is not pretty. Better way? try_teleport is local mate : GAME_PORTAL cell : V_GAME_CELL do -- not teleporting prevents a the user from teleporting -- during the frame display if not dead and not teleporting then success := False -- Is Stooge completely on the portal? mate := get_portal_mate if mate /= Void then cell ?= mate.northwest if cell /= Void then teleport_display( cell ) success := True end end end end try_north is do -- Can not move when teleporting if not dead and not teleporting then facing := North face_north success := False if will_accept( northwest.north, northeast.north ) then if no_visitors( northwest.north, northeast.north ) then move_north spoor := spoor + 1 leave_spoor success := True if locked then locked_box.try_north check_locked_box end else visitor := common_visitor( northwest.north, northeast.north ) if visitor /= Void and ( not locked or else visitor = locked_box ) then visitor.try_north if visitor.success then move_north spoor := spoor + 1 leave_spoor success := True end end end end end ensure then not old dead and not teleporting implies facing = North end try_south is do -- Can not move when teleporting if not dead and not teleporting then facing := South face_south success := False if will_accept( southwest.south, southeast.south ) then if no_visitors( southwest.south, southeast.south ) then move_south spoor := spoor + 1 leave_spoor success := True if locked then locked_box.try_south check_locked_box end else visitor := common_visitor( southwest.south, southeast.south ) if visitor /= Void and ( not locked or else visitor = locked_box ) then visitor.try_south if visitor.success then move_south spoor := spoor + 1 leave_spoor success := True end end end end end ensure then not old dead and not teleporting implies facing = South end try_west is do -- Can not move when teleporting if not dead and not teleporting then facing := West face_west success := False if will_accept( northwest.west, southwest.west ) then if no_visitors( northwest.west, southwest.west ) then move_west spoor := spoor + 1 leave_spoor success := True if locked then locked_box.try_west check_locked_box end else visitor := common_visitor( northwest.west, southwest.west ) if visitor /= Void and ( not locked or else visitor = locked_box ) then visitor.try_west if visitor.success then move_west spoor := spoor + 1 leave_spoor success := True end end end end end ensure then not old dead and not teleporting implies facing = West end try_east is do -- Can not move when teleporting if not dead and not teleporting then facing := East face_east success := False if will_accept( northeast.east, southeast.east ) then if no_visitors( northeast.east, southeast.east ) then move_east spoor := spoor + 1 leave_spoor success := True if locked then locked_box.try_east check_locked_box end else visitor := common_visitor( northeast.east, southeast.east ) if visitor /= Void and ( not locked or else visitor = locked_box ) then visitor.try_east if visitor.success then move_east spoor := spoor + 1 leave_spoor success := True end end end end end ensure then not old dead and not teleporting implies facing = East end win is -- Celebrate! do bullets := 0 bridges := 0 magnets := 0 axes := 0 if locked then unlock end facing := South face_south display_win ensure then facing = South end clear is -- Clear myself and my bridges. do precursor bullets := 0 display_bullets clear_bridges bridges := 0 display_bridges magnets := 0 display_magnets spoor := 1 if locked then unlock end ensure then bullets = 0 bridges = 0 not locked end invariant -- dead or else -- ( facing = south or facing = east or -- facing = west or facing = north ) end