diff --git a/strafe-client/src/physics.rs b/strafe-client/src/physics.rs index 956136f..fbf4d39 100644 --- a/strafe-client/src/physics.rs +++ b/strafe-client/src/physics.rs @@ -1441,7 +1441,7 @@ enum TeleportToSpawnError{ NoModel, } fn teleport_to_spawn( - stage:&gameplay_modes::Stage, + spawn_model_id:ModelId, move_state:&mut MoveState, body:&mut Body, touching:&mut TouchingState, @@ -1457,13 +1457,71 @@ fn teleport_to_spawn( time:Time, )->Result<(),TeleportToSpawnError>{ const EPSILON:Planar64=Planar64::raw((1<<32)/16); - let transform=models.get_model_transform(stage.spawn()).ok_or(TeleportToSpawnError::NoModel)?; + let transform=models.get_model_transform(spawn_model_id).ok_or(TeleportToSpawnError::NoModel)?; //TODO: transform.vertex.matrix3.col(1)+transform.vertex.translation let point=transform.vertex.transform_point3(vec3::Y).fix_1()+Planar64Vec3::new([Planar64::ZERO,style.hitbox.halfsize.y+EPSILON,Planar64::ZERO]); teleport(point,move_state,body,touching,run,mode_state,Some(mode),models,hitbox_mesh,bvh,style,camera,input_state,time); Ok(()) } +struct CheckpointCheckOutcome{ + set_stage:Option, + teleport_to_model:Option, +} + +fn checkpoint_check( + mode_state:&ModeState, + stage_element:&gameplay_modes::StageElement, + mode:&gameplay_modes::Mode, +)->CheckpointCheckOutcome{ + if mode_state.get_stage_id()if !stage.is_empty(){ + return CheckpointCheckOutcome{ + set_stage:Some(stage_id), + teleport_to_model:Some(stage.spawn()), + }; + }, + //no such stage! set to last existing stage + None=>return CheckpointCheckOutcome{ + set_stage:Some(StageId::new(stage_id.get()-1)), + teleport_to_model:None, + }, + } + }; + //notably you do not get teleported for touching ordered checkpoints in the wrong order within the same stage. + return CheckpointCheckOutcome{ + set_stage:Some(stage_element.stage_id()), + teleport_to_model:None, + }; + }else if stage_element.force(){ + //forced stage_element will set the stage_id even if the stage has already been passed + return CheckpointCheckOutcome{ + set_stage:Some(stage_element.stage_id()), + teleport_to_model:None, + }; + } + CheckpointCheckOutcome{ + set_stage:None, + teleport_to_model:None, + } +} + fn run_teleport_behaviour( model_id:ModelId, wormhole:Option<&gameplay_attributes::Wormhole>, @@ -1485,66 +1543,37 @@ fn run_teleport_behaviour( //Map makers are expected to use tools to prevent //multi-boosting on JumpLimit boosters such as spawning into a SetVelocity if let Some(mode)=mode{ - if let Some(stage_element)=mode.get_element(model_id){ - if let Some(stage)=mode.get_stage(stage_element.stage_id()){ - if mode_state.get_stage_id()if !stage.is_empty(){ - mode_state.set_stage_id(stage_id); - let _=teleport_to_spawn(stage,move_state,body,touching,run,mode_state,mode,models,hitbox_mesh,bvh,style,camera,input_state,time); - return; - }, - None=>{ - //no such stage! set to last existing stage and break loop - mode_state.set_stage_id(StageId::new(stage_id.get()-1)); - loop_unbroken=false; - break; - }, - } - }; - //notably you do not get teleported for touching ordered checkpoints in the wrong order within the same stage. - if loop_unbroken{ - mode_state.set_stage_id(stage_element.stage_id()); - } - }else if stage_element.force(){ - //forced stage_element will set the stage_id even if the stage has already been passed - mode_state.set_stage_id(stage_element.stage_id()); - } - match stage_element.behaviour(){ - gameplay_modes::StageElementBehaviour::SpawnAt=>(), - gameplay_modes::StageElementBehaviour::Trigger - |gameplay_modes::StageElementBehaviour::Teleport=>if let Some(mode_state_stage)=mode.get_stage(mode_state.get_stage_id()){ - //I guess this is correct behaviour when trying to teleport to a non-existent spawn but it's still weird - let _=teleport_to_spawn(mode_state_stage,move_state,body,touching,run,mode_state,mode,models,hitbox_mesh,bvh,style,camera,input_state,time); + if let Some(model_id)=teleport_to_model{ + let _=teleport_to_spawn(model_id,move_state,body,touching,run,mode_state,mode,models,hitbox_mesh,bvh,style,camera,input_state,time); return; - }, - gameplay_modes::StageElementBehaviour::Platform=>(), - gameplay_modes::StageElementBehaviour::Check=>(),//this is to run the checkpoint check behaviour without any other side effects - gameplay_modes::StageElementBehaviour::Checkpoint=>{ - //each of these checks if the model is actually a valid respective checkpoint object - //accumulate sequential ordered checkpoints - mode_state.accumulate_ordered_checkpoint(&stage,model_id); - //insert model id in accumulated unordered checkpoints - mode_state.accumulate_unordered_checkpoint(&stage,model_id); - }, + } + match stage_element.behaviour(){ + gameplay_modes::StageElementBehaviour::SpawnAt=>(), + gameplay_modes::StageElementBehaviour::Trigger + |gameplay_modes::StageElementBehaviour::Teleport=>if let Some(mode_state_stage)=mode.get_stage(mode_state.get_stage_id()){ + //I guess this is correct behaviour when trying to teleport to a non-existent spawn but it's still weird + let _=teleport_to_spawn(mode_state_stage.spawn(),move_state,body,touching,run,mode_state,mode,models,hitbox_mesh,bvh,style,camera,input_state,time); + return; + }, + gameplay_modes::StageElementBehaviour::Platform=>(), + gameplay_modes::StageElementBehaviour::Check=>(),//this is to run the checkpoint check behaviour without any other side effects + gameplay_modes::StageElementBehaviour::Checkpoint=>{ + //each of these checks if the model is actually a valid respective checkpoint object + //accumulate sequential ordered checkpoints + mode_state.accumulate_ordered_checkpoint(&stage,model_id); + //insert model id in accumulated unordered checkpoints + mode_state.accumulate_unordered_checkpoint(&stage,model_id); + }, + } } } } - } if let Some(&gameplay_attributes::Wormhole{destination_model})=wormhole{ if let (Some(origin),Some(destination))=(models.get_model_transform(model_id),models.get_model_transform(destination_model)){ let point=body.position-origin.vertex.translation+destination.vertex.translation; @@ -1914,7 +1943,7 @@ fn atomic_input_instruction(state:&mut PhysicsState,data:&PhysicsData,ins:TimedI if let Some(mode)=data.modes.get_mode(mode_id){ if let Some(stage)=mode.get_stage(stage_id){ let _=teleport_to_spawn( - stage, + stage.spawn(), &mut state.move_state,&mut state.body,&mut state.touching,&mut state.run,&mut state.mode_state, mode, &data.models,&data.hitbox_mesh,&data.bvh,&state.style,&state.camera,&state.input_state,state.time