dofile_once( "data/scripts/lib/coroutines.lua" ) dofile_once( "data/scripts/lib/utilities.lua" ) -- Description of overall boss behavior: -- Boss waits for player to pick up item. -- When item is collected, combat starts. -- During combat if player is nearby, boss performs attacks and mauneuvers randomly (next_phase() sets phase variable). -- Some attacks are performed several times in a row (phase_repeats). -- If boss suffers enough damage it enters "aggro mode" with a different set of attacks. -- If player moves away from the arena, boss gains cell eating ability and starts chasing. -- Boss health and abilities vary based on how many orbs player has collected (search for "orbcount"). -- enum for changing C++ logic state. keep this in sync with the values in limbboss_system.cpp local states = { MoveAroundNest = 0, FollowPlayer = 1, Escape = 2, DontMove = 3, MoveTo = 4, MoveDirectlyTowardsPlayer = 5, } local is_dead = false local boss_chase = 0 local is_eye_open = false local is_aggro = false local orbcount = 0 local shield_enabled = false local did_wait = false local death_sound_started = false function init_boss() local entity = GetUpdatedEntityID() local pos_x, pos_y = EntityGetTransform( entity ) local init_comp = get_variable_storage_component(entity, "initialized") local orbcount_comp = get_variable_storage_component(entity, "orbcount") -- init boss only once if init_comp and ComponentGetValue2(init_comp, "value_bool") == false then ComponentSetValue2(init_comp, "value_bool", true) -- Get the amount of orbs to adjust boss difficulty -- orbcount = orbcount + new game plus count local newgame_n = tonumber( SessionNumbersGetValue("NEW_GAME_PLUS_COUNT") ) orbcount = GameGetOrbCountThisRun() orbcount = orbcount + newgame_n ComponentSetValue2(orbcount_comp, "value_int", orbcount) -- store orbcount for savegames -- Set boss HP based on orbs local boss_hp = 46.0 + ( 2.0 ^ (orbcount + 1.3) ) + (orbcount*15.5) local comp = EntityGetFirstComponent( entity, "DamageModelComponent" ) if( comp ~= nil ) then ComponentSetValue( comp, "max_hp", tostring(boss_hp) ) ComponentSetValue( comp, "hp", tostring(boss_hp) ) end -- no orbs = weaker shield if orbcount == 0 then EntityAddChild( entity, EntityLoad("data/entities/animals/boss_centipede/boss_centipede_shield_weak.xml", pos_x, pos_y) ) else EntityAddChild( entity, EntityLoad("data/entities/animals/boss_centipede/boss_centipede_shield_strong.xml", pos_x, pos_y) ) end -- orbs boost damage resistances local damagemodel_comp = EntityGetFirstComponent( entity, "DamageModelComponent" ) if damagemodel_comp ~= nil then if orbcount >= 3 then ComponentObjectSetValue2(damagemodel_comp, "damage_multipliers", "melee", 1.5) ComponentObjectSetValue2(damagemodel_comp, "damage_multipliers", "drill", 0.25) ComponentObjectSetValue2(damagemodel_comp, "damage_multipliers", "projectile", 0.2) ComponentObjectSetValue2(damagemodel_comp, "damage_multipliers", "fire", 0) ComponentObjectSetValue2(damagemodel_comp, "damage_multipliers", "ice", 0) ComponentObjectSetValue2(damagemodel_comp, "damage_multipliers", "electricity", 0) end if( orbcount >= 4 ) then EntitySetDamageFromMaterial( entity, "acid", 0.01) end if orbcount >= 5 then ComponentObjectSetValue2(damagemodel_comp, "damage_multipliers", "melee", 1.0) ComponentObjectSetValue2(damagemodel_comp, "damage_multipliers", "drill", 0.01) end if orbcount >= 7 then EntitySetDamageFromMaterial( entity, "acid", 0.0) end if orbcount >= 9 then ComponentObjectSetValue2(damagemodel_comp, "damage_multipliers", "slice", 0.5) ComponentObjectSetValue2(damagemodel_comp, "damage_multipliers", "physics_hit", 0.5) ComponentObjectSetValue2(damagemodel_comp, "damage_multipliers", "radioactive", 0.5) ComponentObjectSetValue2(damagemodel_comp, "damage_multipliers", "poison", 0.5) end if( orbcount >= 11 ) then ComponentObjectSetValue2(damagemodel_comp, "damage_multipliers", "melee", 0.5) end end -- orbs determine material damages if( orbcount > 0 ) then -- material weaknesses based on orb count if( orbcount == 12 ) then EntitySetDamageFromMaterial( entity, "magic_liquid_polymorph", 0.35) end if( orbcount == 13 ) then EntitySetDamageFromMaterial( entity, "magic_liquid_random_polymorph", 0.35) end if( orbcount == 14 ) then EntitySetDamageFromMaterial( entity, "magic_liquid_teleportation", 0.35) end if( orbcount == 15 ) then EntitySetDamageFromMaterial( entity, "magic_liquid_movement_faster", 0.35) end if( orbcount == 16 ) then EntitySetDamageFromMaterial( entity, "material_confusion", 0.35) end end -- over 30 orbs immunity to touch spells if( orbcount > 30 ) then EntityAddTag( entity, "touchmagic_immunity") end else -- make sure orbcount is not lost on game load orbcount = ComponentGetValue2(orbcount_comp, "value_int") end -- Turn on the limbs local children = EntityGetAllChildren( entity ) if children ~= nil then for _,it in ipairs(children) do EntitySetComponentsWithTagEnabled( it, "disabled_at_start", true ) end end -- check if boss was in aggro mode is_aggro = get_variable_storage_component(entity, "aggro") ~= nil end init_boss() -- gather some data we're gonna reuse -------------- local herd_id = get_herd_id( GetUpdatedEntityID() ) local subphase = 0 local phase_repeats = 0 -- Phase logic function phase_chase_slow() close_eye() set_logic_state( states.FollowPlayer ) --boss_wait(2 * 60) boss_wait(60) next_phase() end function phase_chase() close_eye() set_logic_state( states.FollowPlayer ) boss_wait(140) next_phase() end function phase_chase_direct() close_eye() set_logic_state( states.MoveDirectlyTowardsPlayer ) boss_wait(2 * 80) next_phase() end function phase_circleshot() move_to_reference() boss_wait(50) -- a brief pause if shield was previously on shield_on() boss_wait(10) open_eye() GameEntityPlaySound( GetUpdatedEntityID(), "phase_circleshot_start" ) local shot_count = 10 + math.floor(orbcount / 3) local frame = GameGetFrameNum() local r = ProceduralRandomf(frame, frame) local spiral_speed = 25 * (r*2-1) -- random turn speed & direction with each attack for i=1,shot_count do circleshot(r * 180 + i*spiral_speed) boss_wait(12) end close_eye() shield_off() boss_wait(60) set_logic_state( states.FollowPlayer ) next_phase() end function phase_spawn_minion() set_logic_state( states.FollowPlayer ) local spawn_count = 1 + math.floor(orbcount / 2) for i=1,spawn_count do if not minion_check_maxcount() then open_eye() GameEntityPlaySound( GetUpdatedEntityID(), "spawn_minion" ) spawn_minion() boss_wait(30) end end close_eye() next_phase() end function phase_firepillar() move_to_reference() boss_wait(50) -- a brief pause if shield was previously on shield_on() boss_wait(10) open_eye() GameEntityPlaySound( GetUpdatedEntityID(), "shoot_fire" ) firepillar() close_eye() boss_wait(40) --shield_off() --boss_wait(20) set_logic_state( states.FollowPlayer ) next_phase() end function phase_explosion() set_logic_state( states.FollowPlayer ) open_eye() GameEntityPlaySound( GetUpdatedEntityID(), "shoot_explosion" ) if (orbcount < 6) then explode() else explode(true) end boss_wait(20) close_eye() set_logic_state( states.FollowPlayer ) next_phase() end function phase_homingshot() open_eye() local shot_count = 4 + math.floor(orbcount * 0.5) for i=1,shot_count do homingshot() GameEntityPlaySound( GetUpdatedEntityID(), "shoot_homingshot" ) boss_wait(20) end close_eye() next_phase() end function phase_polymorph() open_eye() boss_wait(30) polymorphshot() GameEntityPlaySound( GetUpdatedEntityID(), "shoot_homingshot" ) boss_wait(20) close_eye() next_phase() end function phase_melee() local this = GetUpdatedEntityID() local pos_x, pos_y = EntityGetTransform( this ) open_eye() explosion_attack() GameEntityPlaySound( GetUpdatedEntityID(), "phase_rush_start" ) -- flinch away so boss won't hang around on top of player local dir_x = 0 local dir_y = -70 dir_x, dir_y = vec_rotate(dir_x, dir_y, ProceduralRandomf(pos_x, GameGetFrameNum(), -math.pi * 0.5, math.pi * 0.5)) set_force_coeff_mult(20) move_to(pos_x + dir_x, pos_y + dir_y) boss_wait(50) set_force_coeff_mult(1) close_eye() next_phase() end function phase_clean_materials() set_logic_state( states.FollowPlayer ) boss_wait(25) GameEntityPlaySound( GetUpdatedEntityID(), "shoot_clean_materials" ) clear_materials() next_phase() end function phase_aggro() set_force_coeff_mult(5) set_main_animation("aggro", "aggro") boss_wait(60) -- circle shots to random directions local shot_count = 12 + math.floor(orbcount / 3) local frame = GameGetFrameNum() for i=1,shot_count do circleshot_aggro() boss_wait(12) end boss_wait(20) explosion_attack() boss_wait(60) set_logic_state( states.FollowPlayer ) next_phase() end function next_phase() shield_off() -- set a new phase local entity_id = GetUpdatedEntityID() local players = EntityGetWithTag( "player_unit" ) if #players > 0 then local player_id = players[1] local xe,ye = EntityGetTransform( entity_id ) local xp,yp = EntityGetTransform( player_id ) local dist = get_distance(xp,yp,xe,ye) local phases = -- { phase, repeat amount } { { phase_chase_slow, 0 }, { phase_circleshot, 1 }, { phase_spawn_minion, 0 }, { phase_firepillar, 2 }, } -- additional attack mode on higher orbcount if orbcount >= 2 then phases[#phases+1] = { phase_homingshot, 0 } end if is_aggro then -- aggro mode, replace the usual phases with a more difficult selection phases = { --{ phase_chase, 0 }, { phase_aggro, 0 }, } end -- polymorph shots if orbcount >= 11 then phases[#phases+1] = { phase_polymorph, 0 } end if dist < 65 and not is_aggro then -- do a melee attack phase = phase_melee phase_repeats = 0 elseif dist < 700 then -- use attack phases -- see if phase has repeats queued before picking a new one if phase_repeats > 0 then phase_repeats = phase_repeats - 1 return end -- Every phase increases a 'subphase' variable, and at 6 subphase forces the boss to use the clean_materials phase if subphase < 6 then SetRandomSeed(xe+xp+subphase, ye+yp) local next_phase = random_from_array(phases) phase = next_phase[1] phase_repeats = next_phase[2] subphase = subphase + 1 else subphase = 0 phase_repeats = 0 phase = phase_clean_materials end else -- further away: start chasin' phase = phase_chase_direct end -- If player is way too far, boss assumes they have left the arena entirely and sets up phase 2 if (dist > 1300) and (boss_chase == 0) then boss_chase = 1 local celleater = EntityGetFirstComponent( GetUpdatedEntityID(), "CellEaterComponent" ) if (celleater ~= nil) then ComponentSetValue( celleater, "eat_probability", tostring(100.0) ) ComponentSetValue( celleater, "radius", tostring(64.0) ) end set_force_coeff_mult(5) phase = phase_chase_direct end --print("Boss distance: " .. tostring(dist)) end end -- actual boss attacks ----------------- function circleshot(angle) local this = GetUpdatedEntityID() local pos_x, pos_y = EntityGetTransform( this ) local branches = 6 + orbcount - phase_repeats local space = math.floor(360 / branches) local speed = 80 -- spawn projectiles on each branch for i=1,branches do local vel_x = math.cos( math.rad(angle) ) * speed local vel_y = math.sin( math.rad(angle) ) * speed shoot_projectile( this, "data/entities/animals/boss_centipede/orb_circleshot.xml", pos_x, pos_y, vel_x, vel_y ) angle = angle + space end -- muzzle flash & audio EntityLoad( "data/entities/particles/muzzle_flashes/muzzle_flash_circular_pink.xml", pos_x, pos_y) GamePlaySound( "data/audio/Desktop/projectiles.bank", "projectiles/magic/create", pos_x, pos_y ) end function circleshot_aggro() local this = GetUpdatedEntityID() local pos_x, pos_y = EntityGetTransform( this ) local branches = 4 + orbcount local speed = 120 local frame = GameGetFrameNum() -- spawn projectiles to random directions for i=1,branches do local r = ProceduralRandomf(frame + i, frame) local angle = r * 360 local vel_x = math.cos( math.rad(angle) ) * speed local vel_y = math.sin( math.rad(angle) ) * speed shoot_projectile( this, "data/entities/animals/boss_centipede/orb_circleshot.xml", pos_x, pos_y, vel_x, vel_y ) end GameCreateParticle( "slime_green", pos_x, pos_y, 50, 0, -20, true, false ) -- muzzle flash & audio EntityLoad( "data/entities/particles/muzzle_flashes/muzzle_flash_circular_pink.xml", pos_x, pos_y) GamePlaySound( "data/audio/Desktop/projectiles.bank", "projectiles/magic/create", pos_x, pos_y ) end function homingshot() local this = GetUpdatedEntityID() local pos_x, pos_y = EntityGetTransform( this ) local vel_x = 0 local vel_y = ProceduralRandomf(pos_x, pos_y + GameGetFrameNum(), -200, 50) shoot_projectile( this, "data/entities/animals/boss_centipede/orb_homing.xml", pos_x, pos_y, vel_x, vel_y ) end function polymorphshot() local this = GetUpdatedEntityID() local pos_x, pos_y = EntityGetTransform( this ) -- triangular launch shape shoot_projectile( this, "data/entities/animals/boss_centipede/orb_polymorph.xml", pos_x, pos_y - 10, 0, -50 ) shoot_projectile( this, "data/entities/animals/boss_centipede/orb_polymorph.xml", pos_x - 5, pos_y, -30, 20 ) shoot_projectile( this, "data/entities/animals/boss_centipede/orb_polymorph.xml", pos_x - 5, pos_y, -30, 20 ) end function firepillar() local this = GetUpdatedEntityID() local pos_x, pos_y = EntityGetTransform( this ) local amount = 10 + orbcount - phase_repeats * 2 local space = math.floor(180 / amount) local speed = 150 local angle = space * 0.5 for i=1,amount do local vel_x = math.cos( math.rad(angle) ) * speed local vel_y = math.sin( math.rad(angle) ) * speed vel_y = vel_y - 200 shoot_projectile( this, "data/entities/animals/boss_centipede/firepillar.xml", pos_x, pos_y, vel_x, vel_y ) angle = angle + space end -- muzzle flash & audio EntityLoad( "data/entities/particles/muzzle_flashes/muzzle_flash_circular.xml", pos_x, pos_y) GamePlaySound( "data/audio/Desktop/projectiles.bank", "projectiles/magic/create", pos_x, pos_y ) end function explode(big_explosion_) local big_explosion = big_explosion_ or false local this = GetUpdatedEntityID() local pos_x, pos_y = EntityGetTransform( this ) if big_explosion then shoot_projectile( this, "data/entities/animals/boss_centipede/boss_centipede_explosion_large.xml", pos_x, pos_y, 0, 0 ) else shoot_projectile( this, "data/entities/animals/boss_centipede/boss_centipede_explosion.xml", pos_x, pos_y, 0, 0 ) end end function explosion_attack() local this = GetUpdatedEntityID() local pos_x, pos_y = EntityGetTransform( this ) local attack = shoot_projectile( this, "data/entities/animals/boss_centipede/melee.xml", pos_x, pos_y, 0, 0 ) end function clear_materials() local this = GetUpdatedEntityID() local pos_x, pos_y = EntityGetTransform( this ) shoot_projectile( this, "data/entities/animals/boss_centipede/clear_materials.xml", pos_x, pos_y, 0, 0 ) end function minion_check_maxcount() return #EntityGetWithTag("boss_centipede_minion") >= 3 + orbcount end function spawn_minion() -- check that we only have less than N minions --if minion_check_maxcount() then return end -- spawn local x, y = EntityGetTransform( GetUpdatedEntityID() ) EntityLoad( "data/entities/animals/boss_centipede/boss_centipede_minion.xml", x, y ) EntityLoad( "data/entities/particles/muzzle_flashes/muzzle_flash_circular_blue.xml", x, y) end function shield_on() if shield_enabled then return end -- avoid playing unnecessary transitions local entity_id = GetUpdatedEntityID() local children = EntityGetAllChildren(entity_id) if children == nil then return end for _,v in ipairs(children) do if EntityGetName(v) == "shield_entity" then EntitySetComponentsWithTagEnabled( v, "shield", true ) -- muzzle flash local x, y = EntityGetTransform(entity_id) EntityLoad( "data/entities/particles/muzzle_flashes/muzzle_flash_circular_large_pink_reverse.xml", x, y) GameEntityPlaySound( v, "activate" ) shield_enabled = true return end end end function shield_off() if not shield_enabled then return end -- avoid playing unnecessary transitions local entity_id = GetUpdatedEntityID() local children = EntityGetAllChildren(entity_id) if children == nil then return end for _,v in ipairs(children) do if EntityGetName(v) == "shield_entity" then EntitySetComponentsWithTagEnabled( v, "shield", false ) -- muzzle flash local x, y = EntityGetTransform(entity_id) EntityLoad( "data/entities/particles/muzzle_flashes/muzzle_flash_circular_large_pink.xml", x, y) GameEntityPlaySound( v, "deactivate" ) shield_enabled = false return end end end function chase_start() set_force_coeff_mult(5) local celleater = EntityGetFirstComponent( GetUpdatedEntityID(), "CellEaterComponent" ) if (celleater ~= nil) then --ComponentSetValue( celleater, "eat_probability", tostring(100.0) ) end end function chase_stop() set_force_coeff_mult(1) local celleater = EntityGetFirstComponent( GetUpdatedEntityID(), "CellEaterComponent" ) if (celleater ~= nil) then --ComponentSetValue( celleater, "eat_probability", tostring(0.0) ) end end -- Setting the boss movement logic state function set_logic_state( state ) edit_component( GetUpdatedEntityID(), "LimbBossComponent", function(comp,vars) vars.state = state end) -- DEBUG: local ai = EntityGetFirstComponent( GetUpdatedEntityID(), "LimbBossComponent" ) local old = 0 if (ai ~= nil) then old = tonumber(ComponentGetValue( ai, "state" )) end local on,nn = "","" for i,v in pairs(states) do if (v == old) then on = i end if (v == state) then nn = i end end --print("Changing state from " .. tostring(on) .. " to " .. tostring(nn)) end -- Special code for moving to a set position function move_to_reference() if ( boss_chase == 0 ) then local reference = EntityGetWithTag( "reference" ) if ( #reference > 0 ) then local reference_id = reference[1] local x,y = EntityGetTransform( reference_id ) move_to( x, y ) else print("Boss - NO REFERENCE FOUND!!!") end else set_logic_state( states.FollowPlayer ) end end function move_to( x, y ) set_logic_state( states.MoveTo ) edit_component( GetUpdatedEntityID(), "LimbBossComponent", function(comp,vars) vars.mMoveToPositionX = x vars.mMoveToPositionY = y end) end function open_eye() if is_eye_open then return end set_main_animation( "open", "opened" ) GameEntityPlaySound( GetUpdatedEntityID(), "open_mouth" ) is_eye_open = true boss_wait(55) end function close_eye() -- don't close eye if there's still attacks lined up if not is_eye_open or phase_repeats > 0 then return end set_main_animation("close", get_idle_animation_name()) GameEntityPlaySound( GetUpdatedEntityID(), "close_mouth" ) is_eye_open = false boss_wait(50) end -- The boss can't die normally; if their HP is zero, this does stuff instead function check_death() if is_dead then return end local entity_id = GetUpdatedEntityID() SetRandomSeed( GameGetFrameNum(), GameGetFrameNum() ) local comp = EntityGetFirstComponent( entity_id, "DamageModelComponent" ) if( comp ~= nil ) then local hp = ComponentGetValueFloat( comp, "hp" ) -- check aggro if not is_aggro then local max_hp = ComponentGetValueInt( comp, "max_hp") is_aggro = hp <= clamp(max_hp * 0.1, 9, 40) --print("hp/max: " .. hp .. " / " .. max_hp) -- enter aggro mode if is_aggro then -- store aggro to entity EntityAddComponent( entity_id, "VariableStorageComponent", { name = "aggro", }) set_main_animation("aggro", "aggro") -- spawn body chunks GameEntityPlaySound( entity_id, "destroy_face" ) local x,y = EntityGetTransform( entity_id ) local o = EntityLoad( "data/entities/animals/boss_centipede/body_chunks.xml", x, y) PhysicsApplyForce( o, 0, -600) PhysicsApplyTorque( o, 200) GameCreateParticle( "slime_green", x+20, y, 250, 0, -20, true, false ) phase_repeats = 0 next_phase() end end -- check death if ( hp <= 0.0 ) then move_to_reference() GameTriggerMusicFadeOutAndDequeueAll() if death_sound_started == false then GameEntityPlaySound( GetUpdatedEntityID(), "dying" ) death_sound_started = true end local o = EntityLoad( "data/entities/animals/boss_centipede/body_chunks.xml", x, y) PhysicsApplyForce( o, 0, -600) PhysicsApplyTorque( o, 200) for i = 1,40 do local rand = function() return Random( -10, 10 ) end local x,y = EntityGetTransform( entity_id ) GameScreenshake( i * 1, x, y ) GameCreateParticle( "slime_green", x + rand(), y + rand(), 10, i * 5.5, i * 5.5, true, false ) if i > 20 then GameCreateParticle( "gunpowder_unstable", x + rand(), y + rand(), 3, 40.0, 40.0, true, false ) end wait( 3 ) end local reference = EntityGetWithTag( "reference" ) local x_portal,y_portal = EntityGetTransform( GetUpdatedEntityID() ) if ( #reference > 0 ) then local ref_id = reference[1] x_portal,y_portal = EntityGetTransform( ref_id ) EntityKill( ref_id ) end -- fix for spider legs, looks visually quite bad (what? how's this related to spider legs) -- 150 puts it right under the bridge, which kinda cool y_portal = y_portal + 50 EntityLoad( "data/entities/buildings/teleport_ending_victory_delay.xml", x_portal, y_portal ) -- kill comp = EntityGetFirstComponent( GetUpdatedEntityID(), "DamageModelComponent" ) if( comp ~= nil ) then ComponentSetValue( comp, "kill_now", "1" ) end GlobalsSetValue( "FINAL_BOSS_ACTIVE", "0" ) local boss_kill_count = tonumber( GlobalsGetValue( "GLOBAL_BOSS_KILL_COUNT", "0" ) ) boss_kill_count = boss_kill_count + 1 print( "boss_kill_count: " .. boss_kill_count ) GlobalsSetValue( "GLOBAL_BOSS_KILL_COUNT", tostring( boss_kill_count ) ) AddFlagPersistent( "boss_centipede" ) StatsLogPlayerKill( GetUpdatedEntityID() ) -- this is needed because otherwise the boss kill doesn't get registered as a kill for the player is_dead = true return end end end -- Basic idle function function boss_wait( frames ) check_death() wait( frames ) check_death() did_wait = true end function animate_sprite( sprite, current_name, next_name ) GamePlayAnimation( GetUpdatedEntityID(), current_name, 0, next_name, 0 ) end function get_idle_animation_name() return "stand" end function set_main_animation( current_name, next_name ) local sprite = EntityGetFirstComponent( GetUpdatedEntityID(), "SpriteComponent" ) if ( sprite ~= nil ) then if not is_aggro then animate_sprite( sprite, current_name, next_name ) else -- aggro overrides animations animate_sprite( sprite, "aggro", "aggro" ) end end end function set_force_coeff_mult( mult ) local entity_id = GetUpdatedEntityID() local physics_ai = EntityGetFirstComponent( entity_id, "PhysicsAIComponent" ) if (physics_ai ~= nil) then -- use a hardcoded value instead of getting from comp to avoid varying the value across save/load serialization -- remember to update value here if changed in the component local force_coeff_orig = 14.0 ComponentSetValue( physics_ai, "force_coeff", tostring( force_coeff_orig * mult ) ) end end -- run phase state machine ----------------- next_phase() -- always start combat with circle shots --if get_initialized() then -- phase = phase_circleshot -- phase_repeats = 2 --end async_loop(function() if is_dead then wait(60 * 10) else did_wait = false phase() if did_wait == false then -- ensure the coroutine doesn't get stuck in an infinite loop if the states never wait boss_wait(1) end end end)