2024-02-01 08:04:07 +00:00
|
|
|
const VALVE_SCALE:Planar64=Planar64::raw(1<<28);// 1/16
|
2024-02-04 00:04:09 +00:00
|
|
|
|
2024-08-27 20:33:50 +00:00
|
|
|
use crate::integer::{int,vec3::int as int3,Time,Ratio64,Planar64,Planar64Vec3};
|
2024-03-02 12:58:00 +00:00
|
|
|
use crate::controls_bitflag::Controls;
|
2024-01-30 06:38:43 +00:00
|
|
|
|
2024-03-02 12:58:00 +00:00
|
|
|
#[derive(Clone,Debug)]
|
2024-01-30 06:38:43 +00:00
|
|
|
pub struct StyleModifiers{
|
2024-03-02 12:58:00 +00:00
|
|
|
//controls which are allowed to pass into gameplay (usually all)
|
|
|
|
pub controls_mask:Controls,
|
|
|
|
//controls which are masked from control state (e.g. !jump in scroll style)
|
|
|
|
pub controls_mask_state:Controls,
|
|
|
|
//strafing
|
2024-02-01 08:04:07 +00:00
|
|
|
pub strafe:Option<StrafeSettings>,
|
2024-03-02 12:58:00 +00:00
|
|
|
//player gets a controllable rocket force
|
|
|
|
pub rocket:Option<PropulsionSettings>,
|
|
|
|
//flying
|
2024-07-22 21:55:03 +00:00
|
|
|
//pub move_type:MoveType::Fly(FlySettings)
|
2024-07-24 02:04:53 +00:00
|
|
|
//MoveType::Physics(PhysicsSettings) -> PhysicsSettings (strafe,rocket,jump,walk,ladder,swim,gravity)
|
2024-03-02 12:58:00 +00:00
|
|
|
//jumping is allowed
|
|
|
|
pub jump:Option<JumpSettings>,
|
|
|
|
//standing & walking is allowed
|
|
|
|
pub walk:Option<WalkSettings>,
|
|
|
|
//laddering is allowed
|
|
|
|
pub ladder:Option<LadderSettings>,
|
|
|
|
//water propulsion
|
|
|
|
pub swim:Option<PropulsionSettings>,
|
|
|
|
//maximum slope before sloped surfaces become frictionless
|
2024-02-01 08:04:07 +00:00
|
|
|
pub gravity:Planar64Vec3,
|
2024-03-02 12:58:00 +00:00
|
|
|
//hitbox
|
2024-02-01 08:04:07 +00:00
|
|
|
pub hitbox:Hitbox,
|
2024-03-02 12:58:00 +00:00
|
|
|
//camera location relative to the center (0,0,0) of the hitbox
|
2024-02-01 08:04:07 +00:00
|
|
|
pub camera_offset:Planar64Vec3,
|
2024-03-02 12:58:00 +00:00
|
|
|
//unused
|
|
|
|
pub mass:Planar64,
|
2024-01-30 06:38:43 +00:00
|
|
|
}
|
|
|
|
impl std::default::Default for StyleModifiers{
|
|
|
|
fn default()->Self{
|
|
|
|
Self::roblox_bhop()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-03-02 12:58:00 +00:00
|
|
|
#[derive(Clone,Debug)]
|
|
|
|
pub enum JumpCalculation{
|
2024-08-07 21:44:24 +00:00
|
|
|
Max,//Roblox: jumped_speed=max(velocity.boost(),velocity.jump())
|
|
|
|
BoostThenJump,//jumped_speed=velocity.boost().jump()
|
|
|
|
JumpThenBoost,//jumped_speed=velocity.jump().boost()
|
2024-03-02 12:58:00 +00:00
|
|
|
}
|
2024-01-30 06:38:43 +00:00
|
|
|
|
2024-03-02 12:58:00 +00:00
|
|
|
#[derive(Clone,Debug)]
|
|
|
|
pub enum JumpImpulse{
|
2024-08-07 21:44:24 +00:00
|
|
|
Time(Time),//jump time is invariant across mass and gravity changes
|
|
|
|
Height(Planar64),//jump height is invariant across mass and gravity changes
|
|
|
|
Linear(Planar64),//jump velocity is invariant across mass and gravity changes
|
|
|
|
Energy(Planar64),// :)
|
2024-03-02 12:58:00 +00:00
|
|
|
}
|
|
|
|
//Jumping acts on dot(walks_state.normal,body.velocity)
|
|
|
|
//Energy means it adds energy
|
|
|
|
//Linear means it linearly adds on
|
|
|
|
impl JumpImpulse{
|
2024-08-07 21:44:24 +00:00
|
|
|
pub fn jump(
|
|
|
|
&self,
|
|
|
|
velocity:Planar64Vec3,
|
|
|
|
jump_dir:Planar64Vec3,
|
|
|
|
gravity:&Planar64Vec3,
|
|
|
|
mass:Planar64,
|
|
|
|
)->Planar64Vec3{
|
|
|
|
match self{
|
2024-08-27 20:33:50 +00:00
|
|
|
&JumpImpulse::Time(time)=>velocity-(*gravity*time).map(|t|t.divide().fix_1()),
|
2024-08-07 21:44:24 +00:00
|
|
|
&JumpImpulse::Height(height)=>{
|
|
|
|
//height==-v.y*v.y/(2*g.y);
|
|
|
|
//use energy to determine max height
|
2024-08-27 20:33:50 +00:00
|
|
|
let gg=gravity.length_squared();
|
|
|
|
let g=gg.sqrt().fix_1();
|
|
|
|
let v_g=gravity.dot(velocity);
|
2024-08-07 21:44:24 +00:00
|
|
|
//do it backwards
|
2024-08-27 20:33:50 +00:00
|
|
|
let radicand=v_g*v_g+(g*height*2).fix_4();
|
|
|
|
velocity-(*gravity*(radicand.sqrt().fix_2()+v_g)/gg).divide().fix_1()
|
2024-08-07 21:44:24 +00:00
|
|
|
},
|
2024-08-27 20:33:50 +00:00
|
|
|
&JumpImpulse::Linear(jump_speed)=>velocity+(jump_dir*jump_speed/jump_dir.length()).divide().fix_1(),
|
2024-08-07 21:44:24 +00:00
|
|
|
&JumpImpulse::Energy(energy)=>{
|
|
|
|
//calculate energy
|
2024-08-27 20:33:50 +00:00
|
|
|
//let e=gravity.dot(velocity);
|
2024-08-07 21:44:24 +00:00
|
|
|
//add
|
|
|
|
//you get the idea
|
|
|
|
todo!()
|
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
//TODO: remove this and implement JumpCalculation properly
|
2024-03-02 12:58:00 +00:00
|
|
|
pub fn get_jump_deltav(&self,gravity:&Planar64Vec3,mass:Planar64)->Planar64{
|
|
|
|
//gravity.length() is actually the proper calculation because the jump is always opposite the gravity direction
|
|
|
|
match self{
|
2024-08-27 20:33:50 +00:00
|
|
|
&JumpImpulse::Time(time)=>(gravity.length().fix_1()*time/2).divide().fix_1(),
|
|
|
|
&JumpImpulse::Height(height)=>(gravity.length()*height*2).sqrt().fix_1(),
|
2024-08-07 21:44:24 +00:00
|
|
|
&JumpImpulse::Linear(deltav)=>deltav,
|
2024-08-27 20:33:50 +00:00
|
|
|
&JumpImpulse::Energy(energy)=>(energy.sqrt()*2/mass.sqrt()).divide().fix_1(),
|
2024-08-07 21:44:24 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Clone,Debug)]
|
|
|
|
pub struct JumpSettings{
|
|
|
|
//information used to calculate jump power
|
|
|
|
pub impulse:JumpImpulse,
|
|
|
|
//information used to calculate jump behaviour
|
|
|
|
pub calculation:JumpCalculation,
|
|
|
|
//limit the minimum jump power when combined with downwards momentum
|
|
|
|
//This is true in both roblox and source
|
|
|
|
pub limit_minimum:bool,
|
|
|
|
}
|
|
|
|
impl JumpSettings{
|
|
|
|
pub fn jumped_velocity(
|
|
|
|
&self,
|
|
|
|
style:&StyleModifiers,
|
|
|
|
jump_dir:Planar64Vec3,
|
|
|
|
rel_velocity:Planar64Vec3,
|
|
|
|
booster:Option<&crate::gameplay_attributes::Booster>,
|
|
|
|
)->Planar64Vec3{
|
|
|
|
let jump_speed=self.impulse.get_jump_deltav(&style.gravity,style.mass);
|
|
|
|
match (self.limit_minimum,&self.calculation){
|
|
|
|
(true,JumpCalculation::Max)=>{
|
|
|
|
//the roblox calculation
|
|
|
|
let boost_vel=match booster{
|
|
|
|
Some(booster)=>booster.boost(rel_velocity),
|
|
|
|
None=>rel_velocity,
|
|
|
|
};
|
|
|
|
let j=boost_vel.dot(jump_dir);
|
2024-08-27 20:33:50 +00:00
|
|
|
let js=jump_speed.fix_2();
|
|
|
|
if j<js{
|
2024-08-07 21:44:24 +00:00
|
|
|
//weak booster: just do a regular jump
|
2024-08-27 20:33:50 +00:00
|
|
|
boost_vel+jump_dir.with_length(js-j).divide().fix_1()
|
2024-08-07 21:44:24 +00:00
|
|
|
}else{
|
|
|
|
//activate booster normally, jump does nothing
|
|
|
|
boost_vel
|
|
|
|
}
|
|
|
|
},
|
|
|
|
(true,_)=>{
|
|
|
|
//the source calculation (?)
|
|
|
|
let boost_vel=match booster{
|
|
|
|
Some(booster)=>booster.boost(rel_velocity),
|
|
|
|
None=>rel_velocity,
|
|
|
|
};
|
|
|
|
let j=boost_vel.dot(jump_dir);
|
2024-08-27 20:33:50 +00:00
|
|
|
let js=jump_speed.fix_2();
|
|
|
|
if j<js{
|
2024-08-07 21:44:24 +00:00
|
|
|
//speed in direction of jump cannot be lower than amount
|
2024-08-27 20:33:50 +00:00
|
|
|
boost_vel+jump_dir.with_length(js-j).divide().fix_1()
|
2024-08-07 21:44:24 +00:00
|
|
|
}else{
|
|
|
|
//boost and jump add together
|
2024-08-27 20:33:50 +00:00
|
|
|
boost_vel+jump_dir.with_length(js).divide().fix_1()
|
2024-08-07 21:44:24 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
(false,JumpCalculation::Max)=>{
|
|
|
|
//??? calculation
|
|
|
|
//max(boost_vel,jump_vel)
|
|
|
|
let boost_vel=match booster{
|
|
|
|
Some(booster)=>booster.boost(rel_velocity),
|
|
|
|
None=>rel_velocity,
|
|
|
|
};
|
|
|
|
let boost_dot=boost_vel.dot(jump_dir);
|
2024-08-27 20:33:50 +00:00
|
|
|
let js=jump_speed.fix_2();
|
|
|
|
if boost_dot<js{
|
2024-08-07 21:44:24 +00:00
|
|
|
//weak boost is extended to jump speed
|
2024-08-27 20:33:50 +00:00
|
|
|
boost_vel+jump_dir.with_length(js-boost_dot).divide().fix_1()
|
2024-08-07 21:44:24 +00:00
|
|
|
}else{
|
|
|
|
//activate booster normally, jump does nothing
|
|
|
|
boost_vel
|
|
|
|
}
|
|
|
|
},
|
|
|
|
//the strafe client calculation
|
|
|
|
(false,_)=>{
|
|
|
|
let boost_vel=match booster{
|
|
|
|
Some(booster)=>booster.boost(rel_velocity),
|
|
|
|
None=>rel_velocity,
|
|
|
|
};
|
2024-08-27 20:33:50 +00:00
|
|
|
boost_vel+jump_dir.with_length(jump_speed).divide().fix_1()
|
2024-08-07 21:44:24 +00:00
|
|
|
},
|
2024-01-30 06:38:43 +00:00
|
|
|
}
|
|
|
|
}
|
2024-03-02 12:58:00 +00:00
|
|
|
}
|
2024-01-30 06:38:43 +00:00
|
|
|
|
2024-03-02 12:58:00 +00:00
|
|
|
#[derive(Clone,Debug)]
|
|
|
|
pub struct ControlsActivation{
|
|
|
|
//allowed keys
|
2024-08-07 21:43:34 +00:00
|
|
|
pub controls_mask:Controls,
|
2024-03-02 12:58:00 +00:00
|
|
|
//allow strafing only if any of the masked controls are held, eg W|S for shsw
|
2024-08-07 21:43:34 +00:00
|
|
|
pub controls_intersects:Controls,
|
2024-03-02 12:58:00 +00:00
|
|
|
//allow strafing only if all of the masked controls are held, eg W for hsw, w-only
|
2024-08-07 21:43:34 +00:00
|
|
|
pub controls_contains:Controls,
|
2024-03-02 12:58:00 +00:00
|
|
|
//Function(Box<dyn Fn(u32)->bool>),
|
|
|
|
}
|
|
|
|
impl ControlsActivation{
|
|
|
|
pub const fn mask(&self,controls:Controls)->Controls{
|
|
|
|
controls.intersection(self.controls_mask)
|
|
|
|
}
|
|
|
|
pub const fn activates(&self,controls:Controls)->bool{
|
|
|
|
(self.controls_intersects.is_empty()||controls.intersects(self.controls_intersects))
|
|
|
|
&&controls.contains(self.controls_contains)
|
|
|
|
}
|
|
|
|
pub const fn full_3d()->Self{
|
2024-01-30 06:38:43 +00:00
|
|
|
Self{
|
2024-03-02 12:58:00 +00:00
|
|
|
controls_mask:Controls::wasdqe(),
|
|
|
|
controls_intersects:Controls::wasdqe(),
|
|
|
|
controls_contains:Controls::empty(),
|
2024-01-30 06:38:43 +00:00
|
|
|
}
|
|
|
|
}
|
2024-03-02 12:58:00 +00:00
|
|
|
//classical styles
|
|
|
|
//Normal
|
|
|
|
pub const fn full_2d()->Self{
|
2024-01-30 06:38:43 +00:00
|
|
|
Self{
|
2024-03-02 12:58:00 +00:00
|
|
|
controls_mask:Controls::wasd(),
|
|
|
|
controls_intersects:Controls::wasd(),
|
|
|
|
controls_contains:Controls::empty(),
|
2024-01-30 06:38:43 +00:00
|
|
|
}
|
|
|
|
}
|
2024-03-02 12:58:00 +00:00
|
|
|
//Sideways
|
|
|
|
pub const fn sideways()->Self{
|
2024-01-30 06:38:43 +00:00
|
|
|
Self{
|
2024-03-02 12:58:00 +00:00
|
|
|
controls_mask:Controls::MoveForward.union(Controls::MoveBackward),
|
|
|
|
controls_intersects:Controls::MoveForward.union(Controls::MoveBackward),
|
|
|
|
controls_contains:Controls::empty(),
|
2024-01-30 06:38:43 +00:00
|
|
|
}
|
|
|
|
}
|
2024-03-02 12:58:00 +00:00
|
|
|
//Half-Sideways
|
|
|
|
pub const fn half_sideways()->Self{
|
2024-01-30 06:38:43 +00:00
|
|
|
Self{
|
2024-03-02 12:58:00 +00:00
|
|
|
controls_mask:Controls::MoveForward.union(Controls::MoveLeft).union(Controls::MoveRight),
|
|
|
|
controls_intersects:Controls::MoveLeft.union(Controls::MoveRight),
|
|
|
|
controls_contains:Controls::MoveForward,
|
2024-01-30 06:38:43 +00:00
|
|
|
}
|
|
|
|
}
|
2024-03-02 12:58:00 +00:00
|
|
|
//Surf Half-Sideways
|
|
|
|
pub const fn surf_half_sideways()->Self{
|
|
|
|
Self{
|
|
|
|
controls_mask:Controls::MoveForward.union(Controls::MoveBackward).union(Controls::MoveLeft).union(Controls::MoveRight),
|
|
|
|
controls_intersects:Controls::MoveForward.union(Controls::MoveBackward),
|
|
|
|
controls_contains:Controls::empty(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
//W-Only
|
|
|
|
pub const fn w_only()->Self{
|
|
|
|
Self{
|
|
|
|
controls_mask:Controls::MoveForward,
|
|
|
|
controls_intersects:Controls::empty(),
|
|
|
|
controls_contains:Controls::MoveForward,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
//A-Only
|
|
|
|
pub const fn a_only()->Self{
|
|
|
|
Self{
|
|
|
|
controls_mask:Controls::MoveLeft,
|
|
|
|
controls_intersects:Controls::empty(),
|
|
|
|
controls_contains:Controls::MoveLeft,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
//Backwards
|
2024-01-30 06:38:43 +00:00
|
|
|
}
|
|
|
|
|
2024-03-02 12:58:00 +00:00
|
|
|
#[derive(Clone,Debug)]
|
2024-02-01 08:04:07 +00:00
|
|
|
pub struct StrafeSettings{
|
2024-08-07 21:43:34 +00:00
|
|
|
pub enable:ControlsActivation,
|
|
|
|
pub mv:Planar64,
|
|
|
|
pub air_accel_limit:Option<Planar64>,
|
|
|
|
pub tick_rate:Ratio64,
|
2024-01-30 06:38:43 +00:00
|
|
|
}
|
2024-02-01 08:04:07 +00:00
|
|
|
impl StrafeSettings{
|
2024-03-02 12:58:00 +00:00
|
|
|
pub fn tick_velocity(&self,velocity:Planar64Vec3,control_dir:Planar64Vec3)->Option<Planar64Vec3>{
|
|
|
|
let d=velocity.dot(control_dir);
|
2024-08-27 20:33:50 +00:00
|
|
|
let mv=self.mv.fix_2();
|
|
|
|
match d<mv{
|
|
|
|
true=>Some(velocity+(control_dir*self.air_accel_limit.map_or(mv-d,|limit|limit.fix_2().min(mv-d))).fix_1()),
|
2024-03-02 12:58:00 +00:00
|
|
|
false=>None,
|
|
|
|
}
|
|
|
|
}
|
2024-02-01 08:04:07 +00:00
|
|
|
pub fn next_tick(&self,time:Time)->Time{
|
|
|
|
Time::from_nanos(self.tick_rate.rhs_div_int(self.tick_rate.mul_int(time.nanos())+1))
|
|
|
|
}
|
2024-03-02 12:58:00 +00:00
|
|
|
pub const fn activates(&self,controls:Controls)->bool{
|
|
|
|
self.enable.activates(controls)
|
|
|
|
}
|
|
|
|
pub const fn mask(&self,controls:Controls)->Controls{
|
|
|
|
self.enable.mask(controls)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Clone,Debug)]
|
|
|
|
pub struct PropulsionSettings{
|
2024-08-07 21:43:34 +00:00
|
|
|
pub magnitude:Planar64,
|
2024-03-02 12:58:00 +00:00
|
|
|
}
|
|
|
|
impl PropulsionSettings{
|
|
|
|
pub fn acceleration(&self,control_dir:Planar64Vec3)->Planar64Vec3{
|
2024-08-27 20:33:50 +00:00
|
|
|
(control_dir*self.magnitude).fix_1()
|
2024-03-02 12:58:00 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Clone,Debug)]
|
|
|
|
pub struct AccelerateSettings{
|
2024-08-07 21:43:34 +00:00
|
|
|
pub accel:Planar64,
|
|
|
|
pub topspeed:Planar64,
|
2024-07-24 02:04:53 +00:00
|
|
|
}
|
2024-03-02 12:58:00 +00:00
|
|
|
#[derive(Clone,Debug)]
|
|
|
|
pub struct WalkSettings{
|
2024-08-07 21:43:34 +00:00
|
|
|
pub accelerate:AccelerateSettings,
|
|
|
|
pub static_friction:Planar64,
|
|
|
|
pub kinetic_friction:Planar64,
|
2024-03-02 12:58:00 +00:00
|
|
|
//if a surf slope angle does not exist, then everything is slippery and walking is impossible
|
2024-08-07 21:43:34 +00:00
|
|
|
pub surf_dot:Planar64,//surf_dot<n.dot(up)/n.length()
|
2024-03-02 12:58:00 +00:00
|
|
|
}
|
|
|
|
impl WalkSettings{
|
|
|
|
pub fn accel(&self,target_diff:Planar64Vec3,gravity:Planar64Vec3)->Planar64{
|
|
|
|
//TODO: fallible walk accel
|
2024-08-27 20:33:50 +00:00
|
|
|
let diff_len=target_diff.length().fix_1();
|
2024-03-02 12:58:00 +00:00
|
|
|
let friction=if diff_len<self.accelerate.topspeed{
|
|
|
|
self.static_friction
|
|
|
|
}else{
|
|
|
|
self.kinetic_friction
|
|
|
|
};
|
2024-08-27 20:33:50 +00:00
|
|
|
self.accelerate.accel.min((-gravity.y*friction).fix_1())
|
2024-03-02 12:58:00 +00:00
|
|
|
}
|
|
|
|
pub fn get_walk_target_velocity(&self,control_dir:Planar64Vec3,normal:Planar64Vec3)->Planar64Vec3{
|
2024-08-27 20:33:50 +00:00
|
|
|
if control_dir==crate::integer::vec3::ZERO{
|
2024-03-02 12:58:00 +00:00
|
|
|
return control_dir;
|
|
|
|
}
|
2024-08-27 20:33:50 +00:00
|
|
|
let nn=normal.length_squared();
|
|
|
|
let mm=control_dir.length_squared();
|
|
|
|
let nnmm=nn*mm;
|
|
|
|
let d=normal.dot(control_dir);
|
|
|
|
let dd=d*d;
|
|
|
|
if dd<nnmm{
|
2024-03-02 12:58:00 +00:00
|
|
|
let cr=normal.cross(control_dir);
|
2024-08-27 20:33:50 +00:00
|
|
|
if cr==crate::integer::vec3::ZERO_2{
|
|
|
|
crate::integer::vec3::ZERO
|
2024-03-02 12:58:00 +00:00
|
|
|
}else{
|
2024-08-27 20:33:50 +00:00
|
|
|
(cr.cross(normal)*self.accelerate.topspeed/((nn*(nnmm-dd)).sqrt())).divide().fix_1()
|
2024-03-02 12:58:00 +00:00
|
|
|
}
|
|
|
|
}else{
|
2024-08-27 20:33:50 +00:00
|
|
|
crate::integer::vec3::ZERO
|
2024-03-02 12:58:00 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
pub fn is_slope_walkable(&self,normal:Planar64Vec3,up:Planar64Vec3)->bool{
|
|
|
|
//normal is not guaranteed to be unit length
|
|
|
|
let ny=normal.dot(up);
|
2024-08-27 20:33:50 +00:00
|
|
|
let h=normal.length().fix_1();
|
2024-03-02 12:58:00 +00:00
|
|
|
//remember this is a normal vector
|
2024-08-27 20:33:50 +00:00
|
|
|
ny.is_positive()&&h*self.surf_dot<ny
|
2024-03-02 12:58:00 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Clone,Debug)]
|
|
|
|
pub struct LadderSettings{
|
2024-08-07 21:43:34 +00:00
|
|
|
pub accelerate:AccelerateSettings,
|
2024-03-02 12:58:00 +00:00
|
|
|
//how close to pushing directly into/out of the ladder normal
|
|
|
|
//does your input need to be to redirect straight up/down the ladder
|
2024-08-07 21:43:34 +00:00
|
|
|
pub dot:Planar64,
|
2024-03-02 12:58:00 +00:00
|
|
|
}
|
|
|
|
impl LadderSettings{
|
2024-07-25 19:13:32 +00:00
|
|
|
pub const fn accel(&self,target_diff:Planar64Vec3,gravity:Planar64Vec3)->Planar64{
|
2024-03-02 12:58:00 +00:00
|
|
|
//TODO: fallible ladder accel
|
|
|
|
self.accelerate.accel
|
|
|
|
}
|
|
|
|
pub fn get_ladder_target_velocity(&self,mut control_dir:Planar64Vec3,normal:Planar64Vec3)->Planar64Vec3{
|
2024-08-27 20:33:50 +00:00
|
|
|
if control_dir==crate::integer::vec3::ZERO{
|
2024-03-02 12:58:00 +00:00
|
|
|
return control_dir;
|
|
|
|
}
|
2024-08-27 20:33:50 +00:00
|
|
|
let nn=normal.length_squared();
|
|
|
|
let mm=control_dir.length_squared();
|
|
|
|
let nnmm=nn*mm;
|
|
|
|
let d=normal.dot(control_dir);
|
|
|
|
let mut dd=d*d;
|
|
|
|
if (self.dot*self.dot*nnmm).fix_4()<dd{
|
|
|
|
if d.is_negative(){
|
|
|
|
control_dir=Planar64Vec3::new([Planar64::ZERO,mm.fix_1(),Planar64::ZERO]);
|
|
|
|
}else{
|
|
|
|
control_dir=Planar64Vec3::new([Planar64::ZERO,-mm.fix_1(),Planar64::ZERO]);
|
|
|
|
}
|
|
|
|
dd=(normal.y*normal.y).fix_4();
|
2024-03-02 12:58:00 +00:00
|
|
|
}
|
|
|
|
//n=d if you are standing on top of a ladder and press E.
|
|
|
|
//two fixes:
|
|
|
|
//- ladder movement is not allowed on walkable surfaces
|
|
|
|
//- fix the underlying issue
|
2024-08-27 20:33:50 +00:00
|
|
|
if dd<nnmm{
|
2024-03-02 12:58:00 +00:00
|
|
|
let cr=normal.cross(control_dir);
|
2024-08-27 20:33:50 +00:00
|
|
|
if cr==crate::integer::vec3::ZERO_2{
|
|
|
|
crate::integer::vec3::ZERO
|
2024-03-02 12:58:00 +00:00
|
|
|
}else{
|
2024-08-27 20:33:50 +00:00
|
|
|
(cr.cross(normal)*self.accelerate.topspeed/((nn*(nnmm-dd)).sqrt())).divide().fix_1()
|
2024-03-02 12:58:00 +00:00
|
|
|
}
|
|
|
|
}else{
|
2024-08-27 20:33:50 +00:00
|
|
|
crate::integer::vec3::ZERO
|
2024-02-01 08:04:07 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2024-01-30 06:38:43 +00:00
|
|
|
|
2024-03-02 12:58:00 +00:00
|
|
|
#[derive(Clone,Debug)]
|
2024-02-01 08:04:07 +00:00
|
|
|
pub enum HitboxMesh{
|
2024-01-31 03:30:11 +00:00
|
|
|
Box,//source
|
|
|
|
Cylinder,//roblox
|
|
|
|
//Sphere,//roblox old physics
|
|
|
|
//Point,
|
|
|
|
//Line,
|
|
|
|
//DualCone,
|
|
|
|
}
|
|
|
|
|
2024-03-02 12:58:00 +00:00
|
|
|
#[derive(Clone,Debug)]
|
2024-02-01 08:04:07 +00:00
|
|
|
pub struct Hitbox{
|
|
|
|
pub halfsize:Planar64Vec3,
|
|
|
|
pub mesh:HitboxMesh,
|
2024-01-30 06:38:43 +00:00
|
|
|
}
|
|
|
|
impl Hitbox{
|
2024-03-02 12:58:00 +00:00
|
|
|
pub fn roblox()->Self{
|
2024-01-30 06:38:43 +00:00
|
|
|
Self{
|
2024-08-27 20:33:50 +00:00
|
|
|
halfsize:int3(2,5,2)>>1,
|
2024-01-31 03:30:11 +00:00
|
|
|
mesh:HitboxMesh::Cylinder,
|
2024-01-30 06:38:43 +00:00
|
|
|
}
|
|
|
|
}
|
2024-03-02 12:58:00 +00:00
|
|
|
pub fn source()->Self{
|
2024-01-30 06:38:43 +00:00
|
|
|
Self{
|
2024-08-27 20:33:50 +00:00
|
|
|
halfsize:((int3(33,73,33)>>1)*VALVE_SCALE).fix_1(),
|
2024-01-31 03:30:11 +00:00
|
|
|
mesh:HitboxMesh::Box,
|
2024-01-30 06:38:43 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2024-03-02 12:58:00 +00:00
|
|
|
|
|
|
|
impl StyleModifiers{
|
2024-08-27 20:33:50 +00:00
|
|
|
pub const RIGHT_DIR:Planar64Vec3=crate::integer::vec3::X;
|
|
|
|
pub const UP_DIR:Planar64Vec3=crate::integer::vec3::Y;
|
|
|
|
pub const FORWARD_DIR:Planar64Vec3=crate::integer::vec3::NEG_Z;
|
2024-03-02 12:58:00 +00:00
|
|
|
|
|
|
|
pub fn neo()->Self{
|
|
|
|
Self{
|
|
|
|
controls_mask:Controls::all(),
|
|
|
|
controls_mask_state:Controls::all(),
|
|
|
|
strafe:Some(StrafeSettings{
|
|
|
|
enable:ControlsActivation::full_2d(),
|
|
|
|
air_accel_limit:None,
|
2024-08-27 20:33:50 +00:00
|
|
|
mv:int(3),
|
2024-03-02 12:58:00 +00:00
|
|
|
tick_rate:Ratio64::new(64,Time::ONE_SECOND.nanos() as u64).unwrap(),
|
|
|
|
}),
|
|
|
|
jump:Some(JumpSettings{
|
2024-08-27 20:33:50 +00:00
|
|
|
impulse:JumpImpulse::Energy(int(512)),
|
2024-08-07 21:44:24 +00:00
|
|
|
calculation:JumpCalculation::JumpThenBoost,
|
|
|
|
limit_minimum:false,
|
2024-03-02 12:58:00 +00:00
|
|
|
}),
|
2024-08-27 20:33:50 +00:00
|
|
|
gravity:int3(0,-80,0),
|
|
|
|
mass:int(1),
|
2024-03-02 12:58:00 +00:00
|
|
|
rocket:None,
|
|
|
|
walk:Some(WalkSettings{
|
|
|
|
accelerate:AccelerateSettings{
|
2024-08-27 20:33:50 +00:00
|
|
|
topspeed:int(16),
|
|
|
|
accel:int(80),
|
2024-03-02 12:58:00 +00:00
|
|
|
},
|
2024-08-27 20:33:50 +00:00
|
|
|
static_friction:int(2),
|
|
|
|
kinetic_friction:int(3),//unrealistic: kinetic friction is typically lower than static
|
|
|
|
surf_dot:int(3)/4,
|
2024-03-02 12:58:00 +00:00
|
|
|
}),
|
|
|
|
ladder:Some(LadderSettings{
|
|
|
|
accelerate:AccelerateSettings{
|
2024-08-27 20:33:50 +00:00
|
|
|
topspeed:int(16),
|
|
|
|
accel:int(160),
|
2024-03-02 12:58:00 +00:00
|
|
|
},
|
2024-08-27 20:33:50 +00:00
|
|
|
dot:(int(1)/2).sqrt(),
|
2024-03-02 12:58:00 +00:00
|
|
|
}),
|
|
|
|
swim:Some(PropulsionSettings{
|
2024-08-27 20:33:50 +00:00
|
|
|
magnitude:int(12),
|
2024-03-02 12:58:00 +00:00
|
|
|
}),
|
|
|
|
hitbox:Hitbox::roblox(),
|
2024-08-27 20:33:50 +00:00
|
|
|
camera_offset:int3(0,2,0),//4.5-2.5=2
|
2024-03-02 12:58:00 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn roblox_bhop()->Self{
|
|
|
|
Self{
|
|
|
|
controls_mask:Controls::all(),
|
|
|
|
controls_mask_state:Controls::all(),
|
|
|
|
strafe:Some(StrafeSettings{
|
|
|
|
enable:ControlsActivation::full_2d(),
|
|
|
|
air_accel_limit:None,
|
2024-08-27 20:33:50 +00:00
|
|
|
mv:int(27)/10,
|
2024-03-02 12:58:00 +00:00
|
|
|
tick_rate:Ratio64::new(100,Time::ONE_SECOND.nanos() as u64).unwrap(),
|
|
|
|
}),
|
|
|
|
jump:Some(JumpSettings{
|
2024-08-07 21:44:24 +00:00
|
|
|
impulse:JumpImpulse::Time(Time::from_micros(715_588)),
|
|
|
|
calculation:JumpCalculation::Max,
|
|
|
|
limit_minimum:true,
|
2024-03-02 12:58:00 +00:00
|
|
|
}),
|
2024-08-27 20:33:50 +00:00
|
|
|
gravity:int3(0,-100,0),
|
|
|
|
mass:int(1),
|
2024-03-02 12:58:00 +00:00
|
|
|
rocket:None,
|
|
|
|
walk:Some(WalkSettings{
|
|
|
|
accelerate:AccelerateSettings{
|
2024-08-27 20:33:50 +00:00
|
|
|
topspeed:int(18),
|
|
|
|
accel:int(90),
|
2024-03-02 12:58:00 +00:00
|
|
|
},
|
2024-08-27 20:33:50 +00:00
|
|
|
static_friction:int(2),
|
|
|
|
kinetic_friction:int(3),//unrealistic: kinetic friction is typically lower than static
|
|
|
|
surf_dot:int(3)/4,// normal.y=0.75
|
2024-03-02 12:58:00 +00:00
|
|
|
}),
|
|
|
|
ladder:Some(LadderSettings{
|
|
|
|
accelerate:AccelerateSettings{
|
2024-08-27 20:33:50 +00:00
|
|
|
topspeed:int(18),
|
|
|
|
accel:int(180),
|
2024-03-02 12:58:00 +00:00
|
|
|
},
|
2024-08-27 20:33:50 +00:00
|
|
|
dot:(int(1)/2).sqrt(),
|
2024-03-02 12:58:00 +00:00
|
|
|
}),
|
|
|
|
swim:Some(PropulsionSettings{
|
2024-08-27 20:33:50 +00:00
|
|
|
magnitude:int(12),
|
2024-03-02 12:58:00 +00:00
|
|
|
}),
|
|
|
|
hitbox:Hitbox::roblox(),
|
2024-08-27 20:33:50 +00:00
|
|
|
camera_offset:int3(0,2,0),//4.5-2.5=2
|
2024-03-02 12:58:00 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
pub fn roblox_surf()->Self{
|
|
|
|
Self{
|
2024-08-27 20:33:50 +00:00
|
|
|
gravity:int3(0,-50,0),
|
2024-03-02 12:58:00 +00:00
|
|
|
..Self::roblox_bhop()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
pub fn roblox_rocket()->Self{
|
|
|
|
Self{
|
|
|
|
strafe:None,
|
|
|
|
rocket:Some(PropulsionSettings{
|
2024-08-27 20:33:50 +00:00
|
|
|
magnitude:int(200),
|
2024-03-02 12:58:00 +00:00
|
|
|
}),
|
|
|
|
..Self::roblox_bhop()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn source_bhop()->Self{
|
|
|
|
Self{
|
|
|
|
controls_mask:Controls::all()-Controls::MoveUp-Controls::MoveDown,
|
|
|
|
controls_mask_state:Controls::all(),
|
|
|
|
strafe:Some(StrafeSettings{
|
|
|
|
enable:ControlsActivation::full_2d(),
|
|
|
|
air_accel_limit:Some(Planar64::raw(150<<28)*100),
|
2024-08-27 20:33:50 +00:00
|
|
|
mv:(Planar64::raw(30)*VALVE_SCALE).fix_1(),
|
2024-03-02 12:58:00 +00:00
|
|
|
tick_rate:Ratio64::new(100,Time::ONE_SECOND.nanos() as u64).unwrap(),
|
|
|
|
}),
|
|
|
|
jump:Some(JumpSettings{
|
2024-08-27 20:33:50 +00:00
|
|
|
impulse:JumpImpulse::Height((int(52)*VALVE_SCALE).fix_1()),
|
2024-08-07 21:44:24 +00:00
|
|
|
calculation:JumpCalculation::JumpThenBoost,
|
|
|
|
limit_minimum:true,
|
2024-03-02 12:58:00 +00:00
|
|
|
}),
|
2024-08-27 20:33:50 +00:00
|
|
|
gravity:(int3(0,-800,0)*VALVE_SCALE).fix_1(),
|
|
|
|
mass:int(1),
|
2024-03-02 12:58:00 +00:00
|
|
|
rocket:None,
|
|
|
|
walk:Some(WalkSettings{
|
|
|
|
accelerate:AccelerateSettings{
|
2024-08-27 20:33:50 +00:00
|
|
|
topspeed:int(18),//?
|
|
|
|
accel:int(90),//?
|
2024-03-02 12:58:00 +00:00
|
|
|
},
|
2024-08-27 20:33:50 +00:00
|
|
|
static_friction:int(2),//?
|
|
|
|
kinetic_friction:int(3),//?
|
|
|
|
surf_dot:int(3)/4,// normal.y=0.75
|
2024-03-02 12:58:00 +00:00
|
|
|
}),
|
|
|
|
ladder:Some(LadderSettings{
|
|
|
|
accelerate:AccelerateSettings{
|
2024-08-27 20:33:50 +00:00
|
|
|
topspeed:int(18),//?
|
|
|
|
accel:int(180),//?
|
2024-03-02 12:58:00 +00:00
|
|
|
},
|
2024-08-27 20:33:50 +00:00
|
|
|
dot:(int(1)/2).sqrt(),//?
|
2024-03-02 12:58:00 +00:00
|
|
|
}),
|
|
|
|
swim:Some(PropulsionSettings{
|
2024-08-27 20:33:50 +00:00
|
|
|
magnitude:int(12),//?
|
2024-03-02 12:58:00 +00:00
|
|
|
}),
|
|
|
|
hitbox:Hitbox::source(),
|
2024-08-27 20:33:50 +00:00
|
|
|
camera_offset:((int3(0,64,0)-(int3(0,73,0)>>1))*VALVE_SCALE).fix_1(),
|
2024-03-02 12:58:00 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
pub fn source_surf()->Self{
|
|
|
|
Self{
|
|
|
|
controls_mask:Controls::all()-Controls::MoveUp-Controls::MoveDown,
|
|
|
|
controls_mask_state:Controls::all(),
|
|
|
|
strafe:Some(StrafeSettings{
|
|
|
|
enable:ControlsActivation::full_2d(),
|
2024-08-27 20:33:50 +00:00
|
|
|
air_accel_limit:Some((int(150)*66*VALVE_SCALE).fix_1()),
|
|
|
|
mv:(int(30)*VALVE_SCALE).fix_1(),
|
2024-03-02 12:58:00 +00:00
|
|
|
tick_rate:Ratio64::new(66,Time::ONE_SECOND.nanos() as u64).unwrap(),
|
|
|
|
}),
|
|
|
|
jump:Some(JumpSettings{
|
2024-08-27 20:33:50 +00:00
|
|
|
impulse:JumpImpulse::Height((int(52)*VALVE_SCALE).fix_1()),
|
2024-08-07 21:44:24 +00:00
|
|
|
calculation:JumpCalculation::JumpThenBoost,
|
|
|
|
limit_minimum:true,
|
2024-03-02 12:58:00 +00:00
|
|
|
}),
|
2024-08-27 20:33:50 +00:00
|
|
|
gravity:(int3(0,-800,0)*VALVE_SCALE).fix_1(),
|
|
|
|
mass:int(1),
|
2024-03-02 12:58:00 +00:00
|
|
|
rocket:None,
|
|
|
|
walk:Some(WalkSettings{
|
|
|
|
accelerate:AccelerateSettings{
|
2024-08-27 20:33:50 +00:00
|
|
|
topspeed:int(18),//?
|
|
|
|
accel:int(90),//?
|
2024-03-02 12:58:00 +00:00
|
|
|
},
|
2024-08-27 20:33:50 +00:00
|
|
|
static_friction:int(2),//?
|
|
|
|
kinetic_friction:int(3),//?
|
|
|
|
surf_dot:int(3)/4,// normal.y=0.75
|
2024-03-02 12:58:00 +00:00
|
|
|
}),
|
|
|
|
ladder:Some(LadderSettings{
|
|
|
|
accelerate:AccelerateSettings{
|
2024-08-27 20:33:50 +00:00
|
|
|
topspeed:int(18),//?
|
|
|
|
accel:int(180),//?
|
2024-03-02 12:58:00 +00:00
|
|
|
},
|
2024-08-27 20:33:50 +00:00
|
|
|
dot:(int(1)/2).sqrt(),//?
|
2024-03-02 12:58:00 +00:00
|
|
|
}),
|
|
|
|
swim:Some(PropulsionSettings{
|
2024-08-27 20:33:50 +00:00
|
|
|
magnitude:int(12),//?
|
2024-03-02 12:58:00 +00:00
|
|
|
}),
|
|
|
|
hitbox:Hitbox::source(),
|
2024-08-27 20:33:50 +00:00
|
|
|
camera_offset:((int3(0,64,0)-(int3(0,73,0)>>1))*VALVE_SCALE).fix_1(),
|
2024-03-02 12:58:00 +00:00
|
|
|
}
|
|
|
|
}
|
2024-07-22 21:55:03 +00:00
|
|
|
}
|