diff --git a/Cargo.lock b/Cargo.lock
index c407d0e..f194684 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -2,6 +2,12 @@
 # It is not intended for manual editing.
 version = 3
 
+[[package]]
+name = "bitflags"
+version = "2.4.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ed570934406eb16438a4e976b1b4500774099c13b8cb96eec99f620f05090ddf"
+
 [[package]]
 name = "glam"
 version = "0.25.0"
@@ -40,6 +46,7 @@ dependencies = [
 name = "strafesnet_common"
 version = "0.1.0"
 dependencies = [
+ "bitflags",
  "glam",
  "id",
 ]
diff --git a/Cargo.toml b/Cargo.toml
index d671ba1..9af2044 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -6,5 +6,6 @@ edition = "2021"
 # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
 
 [dependencies]
+bitflags = "2.4.2"
 glam = "0.25.0"
 id = { git = "https://git.itzana.me/Quaternions/id", rev = "1f710976cc786c8853dab73d6e1cee53158deeb0" }
diff --git a/src/controls_bitflag.rs b/src/controls_bitflag.rs
new file mode 100644
index 0000000..f7e7def
--- /dev/null
+++ b/src/controls_bitflag.rs
@@ -0,0 +1,30 @@
+bitflags::bitflags!{
+	#[derive(Clone,Copy,Debug,Default)]
+	pub struct Controls:u32{
+		const MoveForward=1<<0;
+		const MoveLeft=1<<1;
+		const MoveBackward=1<<2;
+		const MoveRight=1<<3;
+		const MoveUp=1<<4;
+		const MoveDown=1<<5;
+		const LookUp=1<<6;
+		const LookLeft=1<<7;
+		const LookDown=1<<8;
+		const LookRight=1<<9;
+		const Jump=1<<10;
+		const Crouch=1<<11;
+		const Sprint=1<<12;
+		const Zoom=1<<13;
+		const Use=1<<14;//Interact with object
+		const PrimaryAction=1<<15;//LBM/Shoot/Melee
+		const SecondaryAction=1<<16;//RMB/ADS/Block
+	}
+}
+impl Controls{
+	pub const fn wasd()->Self{
+		Self::MoveForward.union(Self::MoveLeft).union(Self::MoveBackward).union(Self::MoveRight)
+	}
+	pub const fn wasdqe()->Self{
+		Self::MoveForward.union(Self::MoveLeft).union(Self::MoveBackward).union(Self::MoveRight).union(Self::MoveUp).union(Self::MoveDown)
+	}
+}
\ No newline at end of file
diff --git a/src/gameplay_style.rs b/src/gameplay_style.rs
index 4a6e179..b619294 100644
--- a/src/gameplay_style.rs
+++ b/src/gameplay_style.rs
@@ -1,216 +1,45 @@
 const VALVE_SCALE:Planar64=Planar64::raw(1<<28);// 1/16
 
 use crate::integer::{Time,Ratio64,Planar64,Planar64Vec3};
+use crate::controls_bitflag::Controls;
 
 #[derive(Clone)]
 pub struct StyleModifiers{
-	pub controls_used:u32,//controls which are allowed to pass into gameplay
-	pub controls_mask:u32,//controls which are masked from control state (e.g. jump in scroll style)
+	//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
 	pub strafe:Option<StrafeSettings>,
-	pub jump_impulse:JumpImpulse,
-	pub jump_calculation:JumpCalculation,
+	//player gets a controllable rocket force
+	pub rocket:Option<PropulsionSettings>,
+	//flying
+	//jumping is allowed
+	pub jump:Option<JumpSettings>,
+	//sliding
 	pub static_friction:Planar64,
 	pub kinetic_friction:Planar64,
-	pub walk_speed:Planar64,
-	pub walk_accel:Planar64,
-	pub ladder_speed:Planar64,
-	pub ladder_accel:Planar64,
-	pub ladder_dot:Planar64,
-	pub swim_speed:Planar64,
-	pub mass:Planar64,
-	pub mv:Planar64,
+	//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
 	pub surf_slope:Option<Planar64>,
-	pub rocket_force:Option<Planar64>,
 	pub gravity:Planar64Vec3,
+	//hitbox
 	pub hitbox:Hitbox,
+	//camera location relative to the center (0,0,0) of the hitbox
 	pub camera_offset:Planar64Vec3,
+	//unused
+	pub mass:Planar64,
 }
 impl std::default::Default for StyleModifiers{
 	fn default()->Self{
 		Self::roblox_bhop()
 	}
 }
-impl StyleModifiers{
-	pub const CONTROL_MOVEFORWARD:u32=0b00000001;
-	pub const CONTROL_MOVEBACK:u32=0b00000010;
-	pub const CONTROL_MOVERIGHT:u32=0b00000100;
-	pub const CONTROL_MOVELEFT:u32=0b00001000;
-	pub const CONTROL_MOVEUP:u32=0b00010000;
-	pub const CONTROL_MOVEDOWN:u32=0b00100000;
-	pub const CONTROL_JUMP:u32=0b01000000;
-	pub const CONTROL_ZOOM:u32=0b10000000;
-
-	pub const RIGHT_DIR:Planar64Vec3=Planar64Vec3::X;
-	pub const UP_DIR:Planar64Vec3=Planar64Vec3::Y;
-	pub const FORWARD_DIR:Planar64Vec3=Planar64Vec3::NEG_Z;
-
-	fn neo()->Self{
-		Self{
-			controls_used:!0,
-			controls_mask:!0,//&!(Self::CONTROL_MOVEUP|Self::CONTROL_MOVEDOWN),
-			strafe:Some(StrafeSettings{
-				enable:EnableStrafe::Always,
-				air_accel_limit:None,
-				tick_rate:Ratio64::new(64,Time::ONE_SECOND.nanos() as u64).unwrap(),
-			}),
-			jump_impulse:JumpImpulse::FromEnergy(Planar64::int(512)),
-			jump_calculation:JumpCalculation::Energy,
-			gravity:Planar64Vec3::int(0,-80,0),
-			static_friction:Planar64::int(2),
-			kinetic_friction:Planar64::int(3),//unrealistic: kinetic friction is typically lower than static
-			mass:Planar64::int(1),
-			mv:Planar64::int(3),
-			rocket_force:None,
-			walk_speed:Planar64::int(16),
-			walk_accel:Planar64::int(80),
-			ladder_speed:Planar64::int(16),
-			ladder_accel:Planar64::int(160),
-			ladder_dot:(Planar64::int(1)/2).sqrt(),
-			swim_speed:Planar64::int(12),
-			surf_slope:Some(Planar64::raw(7)/8),
-			hitbox:Hitbox::roblox(),
-			camera_offset:Planar64Vec3::int(0,2,0),//4.5-2.5=2
-		}
-	}
-
-	pub fn roblox_bhop()->Self{
-		Self{
-			controls_used:!0,
-			controls_mask:!0,//&!(Self::CONTROL_MOVEUP|Self::CONTROL_MOVEDOWN),
-			strafe:Some(StrafeSettings{
-				enable:EnableStrafe::Always,
-				air_accel_limit:None,
-				tick_rate:Ratio64::new(100,Time::ONE_SECOND.nanos() as u64).unwrap(),
-			}),
-			jump_impulse:JumpImpulse::FromTime(Time::from_micros(715_588)),
-			jump_calculation:JumpCalculation::Capped,
-			gravity:Planar64Vec3::int(0,-100,0),
-			static_friction:Planar64::int(2),
-			kinetic_friction:Planar64::int(3),//unrealistic: kinetic friction is typically lower than static
-			mass:Planar64::int(1),
-			mv:Planar64::int(27)/10,
-			rocket_force:None,
-			walk_speed:Planar64::int(18),
-			walk_accel:Planar64::int(90),
-			ladder_speed:Planar64::int(18),
-			ladder_accel:Planar64::int(180),
-			ladder_dot:(Planar64::int(1)/2).sqrt(),
-			swim_speed:Planar64::int(12),
-			surf_slope:Some(Planar64::raw(3787805118)),// normal.y=0.75
-			hitbox:Hitbox::roblox(),
-			camera_offset:Planar64Vec3::int(0,2,0),//4.5-2.5=2
-		}
-	}
-	fn roblox_surf()->Self{
-		Self{
-			controls_used:!0,
-			controls_mask:!0,//&!(Self::CONTROL_MOVEUP|Self::CONTROL_MOVEDOWN),
-			strafe:Some(StrafeSettings{
-				enable:EnableStrafe::Always,
-				air_accel_limit:None,
-				tick_rate:Ratio64::new(100,Time::ONE_SECOND.nanos() as u64).unwrap(),
-			}),
-			jump_impulse:JumpImpulse::FromTime(Time::from_micros(715_588)),
-			jump_calculation:JumpCalculation::Capped,
-			gravity:Planar64Vec3::int(0,-50,0),
-			static_friction:Planar64::int(2),
-			kinetic_friction:Planar64::int(3),//unrealistic: kinetic friction is typically lower than static
-			mass:Planar64::int(1),
-			mv:Planar64::int(27)/10,
-			rocket_force:None,
-			walk_speed:Planar64::int(18),
-			walk_accel:Planar64::int(90),
-			ladder_speed:Planar64::int(18),
-			ladder_accel:Planar64::int(180),
-			ladder_dot:(Planar64::int(1)/2).sqrt(),
-			swim_speed:Planar64::int(12),
-			surf_slope:Some(Planar64::raw(3787805118)),// normal.y=0.75
-			hitbox:Hitbox::roblox(),
-			camera_offset:Planar64Vec3::int(0,2,0),//4.5-2.5=2
-		}
-	}
-
-	fn source_bhop()->Self{
-		Self{
-			controls_used:!0,
-			controls_mask:!0,//&!(Self::CONTROL_MOVEUP|Self::CONTROL_MOVEDOWN),
-			strafe:Some(StrafeSettings{
-				enable:EnableStrafe::Always,
-				air_accel_limit:Some(Planar64::raw(150<<28)*100),
-				tick_rate:Ratio64::new(100,Time::ONE_SECOND.nanos() as u64).unwrap(),
-			}),
-			jump_impulse:JumpImpulse::FromHeight(Planar64::int(52)*VALVE_SCALE),
-			jump_calculation:JumpCalculation::Linear,
-			gravity:Planar64Vec3::int(0,-800,0)*VALVE_SCALE,
-			static_friction:Planar64::int(2),//?
-			kinetic_friction:Planar64::int(3),//?
-			mass:Planar64::int(1),
-			mv:Planar64::raw(30)*VALVE_SCALE,
-			rocket_force:None,
-			walk_speed:Planar64::int(18),//?
-			walk_accel:Planar64::int(90),//?
-			ladder_speed:Planar64::int(18),//?
-			ladder_accel:Planar64::int(180),//?
-			ladder_dot:(Planar64::int(1)/2).sqrt(),//?
-			swim_speed:Planar64::int(12),//?
-			surf_slope:Some(Planar64::raw(3787805118)),// normal.y=0.75
-			hitbox:Hitbox::source(),
-			camera_offset:(Planar64Vec3::int(0,64,0)-Planar64Vec3::int(0,73,0)/2)*VALVE_SCALE,
-		}
-	}
-	fn source_surf()->Self{
-		Self{
-			controls_used:!0,
-			controls_mask:!0,//&!(Self::CONTROL_MOVEUP|Self::CONTROL_MOVEDOWN),
-			strafe:Some(StrafeSettings{
-				enable:EnableStrafe::Always,
-				air_accel_limit:Some(Planar64::int(150)*66*VALVE_SCALE),
-				tick_rate:Ratio64::new(66,Time::ONE_SECOND.nanos() as u64).unwrap(),
-			}),
-			jump_impulse:JumpImpulse::FromHeight(Planar64::int(52)*VALVE_SCALE),
-			jump_calculation:JumpCalculation::Linear,
-			gravity:Planar64Vec3::int(0,-800,0)*VALVE_SCALE,
-			static_friction:Planar64::int(2),//?
-			kinetic_friction:Planar64::int(3),//?
-			mass:Planar64::int(1),
-			mv:Planar64::int(30)*VALVE_SCALE,
-			rocket_force:None,
-			walk_speed:Planar64::int(18),//?
-			walk_accel:Planar64::int(90),//?
-			ladder_speed:Planar64::int(18),//?
-			ladder_accel:Planar64::int(180),//?
-			ladder_dot:(Planar64::int(1)/2).sqrt(),//?
-			swim_speed:Planar64::int(12),//?
-			surf_slope:Some(Planar64::raw(3787805118)),// normal.y=0.75
-			hitbox:Hitbox::source(),
-			camera_offset:(Planar64Vec3::int(0,64,0)-Planar64Vec3::int(0,73,0)/2)*VALVE_SCALE,
-		}
-	}
-	fn roblox_rocket()->Self{
-		Self{
-			controls_used:!0,
-			controls_mask:!0,
-			strafe:None,
-			jump_impulse:JumpImpulse::FromTime(Time::from_micros(715_588)),
-			jump_calculation:JumpCalculation::Capped,
-			gravity:Planar64Vec3::int(0,-100,0),
-			static_friction:Planar64::int(2),
-			kinetic_friction:Planar64::int(3),//unrealistic: kinetic friction is typically lower than static
-			mass:Planar64::int(1),
-			mv:Planar64::int(27)/10,
-			rocket_force:Some(Planar64::int(200)),
-			walk_speed:Planar64::int(18),
-			walk_accel:Planar64::int(90),
-			ladder_speed:Planar64::int(18),
-			ladder_accel:Planar64::int(180),
-			ladder_dot:(Planar64::int(1)/2).sqrt(),
-			swim_speed:Planar64::int(12),
-			surf_slope:Some(Planar64::raw(3787805118)),// normal.y=0.75
-			hitbox:Hitbox::roblox(),
-			camera_offset:Planar64Vec3::int(0,2,0),//4.5-2.5=2
-		}
-	}
-}
 
 #[derive(Clone)]
 pub enum JumpCalculation{
@@ -230,18 +59,113 @@ pub enum JumpImpulse{
 //Capped means it increases the dot to the cap
 //Energy means it adds energy
 //Linear means it linearly adds on
+impl JumpImpulse{
+	//fn get_jump_time(&self)->Planar64
+	//fn get_jump_height(&self)->Planar64
+	//fn get_jump_energy(&self)->Planar64
+	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{
+			&JumpImpulse::FromTime(time)=>gravity.length()*(time/2),
+			&JumpImpulse::FromHeight(height)=>(gravity.length()*height*2).sqrt(),
+			&JumpImpulse::FromDeltaV(deltav)=>deltav,
+			&JumpImpulse::FromEnergy(energy)=>(energy*2/mass).sqrt(),
+		}
+	}
+}
 
 #[derive(Clone)]
-pub enum EnableStrafe{
-	Always,
-	MaskAny(u32),//hsw, shsw
-	MaskAll(u32),
+pub struct ControlsActivation{
+	//allowed keys
+	controls_mask:Controls,
+	//allow strafing only if any of the masked controls are held, eg W|S for shsw
+	controls_intersects:Controls,
+	//allow strafing only if all of the masked controls are held, eg W for hsw, w-only
+	controls_contains:Controls,
 	//Function(Box<dyn Fn(u32)->bool>),
 }
+impl ControlsActivation{
+	pub const fn new(
+		controls_mask:Controls,
+		controls_intersects:Controls,
+		controls_contains:Controls,
+	)->Self{
+		Self{
+			controls_mask,
+			controls_intersects,
+			controls_contains,
+		}
+	}
+	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{
+		Self{
+			controls_mask:Controls::wasdqe(),
+			controls_intersects:Controls::wasdqe(),
+			controls_contains:Controls::empty(),
+		}
+	}
+	//classical styles
+	//Normal
+	pub const fn full_2d()->Self{
+		Self{
+			controls_mask:Controls::wasd(),
+			controls_intersects:Controls::wasd(),
+			controls_contains:Controls::empty(),
+		}
+	}
+	//Sideways
+	pub const fn sideways()->Self{
+		Self{
+			controls_mask:Controls::MoveForward.union(Controls::MoveBackward),
+			controls_intersects:Controls::MoveForward.union(Controls::MoveBackward),
+			controls_contains:Controls::empty(),
+		}
+	}
+	//Half-Sideways
+	pub const fn half_sideways()->Self{
+		Self{
+			controls_mask:Controls::MoveForward.union(Controls::MoveLeft).union(Controls::MoveRight),
+			controls_intersects:Controls::MoveLeft.union(Controls::MoveRight),
+			controls_contains:Controls::MoveForward,
+		}
+	}
+	//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
+}
 
 #[derive(Clone)]
 pub struct StrafeSettings{
-	enable:EnableStrafe,
+	enable:ControlsActivation,
+	mv:Planar64,
 	air_accel_limit:Option<Planar64>,
 	tick_rate:Ratio64,
 }
@@ -249,15 +173,50 @@ impl StrafeSettings{
 	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))
 	}
-	pub fn mask(&self,controls:u32)->bool{
-		match self.enable{
-			EnableStrafe::Always=>true,
-			EnableStrafe::MaskAny(mask)=>mask&controls!=0,
-			EnableStrafe::MaskAll(mask)=>mask&controls==mask,
-		}
+	pub fn allow_strafe(&self,controls:Controls)->bool{
+		self.enable.activates(controls)
 	}
 }
 
+#[derive(Clone)]
+pub struct PropulsionSettings{
+	enable:ControlsActivation,
+	magnitude:Planar64,
+}
+impl PropulsionSettings{
+	pub fn activates(&self,controls:Controls)->bool{
+		self.enable.activates(controls)
+	}
+}
+
+#[derive(Clone)]
+pub struct JumpSettings{
+	//information used to calculate jump power
+	impulse:JumpImpulse,
+	//information used to calculate jump behaviour
+	calculation:JumpCalculation,
+}
+
+#[derive(Clone)]
+pub struct AccelerateSettings{
+	accel:Planar64,
+	topspeed:Planar64,
+}
+#[derive(Clone)]
+pub struct WalkSettings{
+	enable:ControlsActivation,
+	accelerate:AccelerateSettings,
+}
+
+#[derive(Clone)]
+pub struct LadderSettings{
+	enable:ControlsActivation,
+	accelerate:AccelerateSettings,
+	//how close to pushing directly into/out of the ladder normal
+	//does your input need to be to redirect straight up/down the ladder
+	dot:Planar64,
+}
+
 #[derive(Clone)]
 pub enum HitboxMesh{
 	Box,//source
@@ -274,16 +233,213 @@ pub struct Hitbox{
 	pub mesh:HitboxMesh,
 }
 impl Hitbox{
-	fn roblox()->Self{
+	pub fn roblox()->Self{
 		Self{
 			halfsize:Planar64Vec3::int(2,5,2)/2,
 			mesh:HitboxMesh::Cylinder,
 		}
 	}
-	fn source()->Self{
+	pub fn source()->Self{
 		Self{
 			halfsize:Planar64Vec3::raw(33,73,33)/2*VALVE_SCALE,
 			mesh:HitboxMesh::Box,
 		}
 	}
 }
+
+impl StyleModifiers{
+	pub const RIGHT_DIR:Planar64Vec3=Planar64Vec3::X;
+	pub const UP_DIR:Planar64Vec3=Planar64Vec3::Y;
+	pub const FORWARD_DIR:Planar64Vec3=Planar64Vec3::NEG_Z;
+
+	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,
+				mv:Planar64::int(3),
+				tick_rate:Ratio64::new(64,Time::ONE_SECOND.nanos() as u64).unwrap(),
+			}),
+			jump:Some(JumpSettings{
+				impulse:JumpImpulse::FromEnergy(Planar64::int(512)),
+				calculation:JumpCalculation::Energy,
+			}),
+			gravity:Planar64Vec3::int(0,-80,0),
+			static_friction:Planar64::int(2),
+			kinetic_friction:Planar64::int(3),//unrealistic: kinetic friction is typically lower than static
+			mass:Planar64::int(1),
+			rocket:None,
+			walk:Some(WalkSettings{
+				enable:ControlsActivation::full_3d(),
+				accelerate:AccelerateSettings{
+					topspeed:Planar64::int(16),
+					accel:Planar64::int(80),
+				},
+			}),
+			ladder:Some(LadderSettings{
+				enable:ControlsActivation::full_3d(),
+				accelerate:AccelerateSettings{
+					topspeed:Planar64::int(16),
+					accel:Planar64::int(160),
+				},
+				dot:(Planar64::int(1)/2).sqrt(),
+			}),
+			swim:Some(PropulsionSettings{
+				enable:ControlsActivation::full_3d(),
+				magnitude:Planar64::int(12),
+			}),
+			surf_slope:Some(Planar64::raw(7)/8),
+			hitbox:Hitbox::roblox(),
+			camera_offset:Planar64Vec3::int(0,2,0),//4.5-2.5=2
+		}
+	}
+
+	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,
+				mv:Planar64::int(27)/10,
+				tick_rate:Ratio64::new(100,Time::ONE_SECOND.nanos() as u64).unwrap(),
+			}),
+			jump:Some(JumpSettings{
+				impulse:JumpImpulse::FromTime(Time::from_micros(715_588)),
+				calculation:JumpCalculation::Capped,
+			}),
+			gravity:Planar64Vec3::int(0,-100,0),
+			static_friction:Planar64::int(2),
+			kinetic_friction:Planar64::int(3),//unrealistic: kinetic friction is typically lower than static
+			mass:Planar64::int(1),
+			rocket:None,
+			walk:Some(WalkSettings{
+				enable:ControlsActivation::full_3d(),
+				accelerate:AccelerateSettings{
+					topspeed:Planar64::int(18),
+					accel:Planar64::int(90),
+				},
+			}),
+			ladder:Some(LadderSettings{
+				enable:ControlsActivation::full_3d(),
+				accelerate:AccelerateSettings{
+					topspeed:Planar64::int(18),
+					accel:Planar64::int(180),
+				},
+				dot:(Planar64::int(1)/2).sqrt(),
+			}),
+			swim:Some(PropulsionSettings{
+				enable:ControlsActivation::full_3d(),
+				magnitude:Planar64::int(12),
+			}),
+			surf_slope:Some(Planar64::raw(3787805118)),// normal.y=0.75
+			hitbox:Hitbox::roblox(),
+			camera_offset:Planar64Vec3::int(0,2,0),//4.5-2.5=2
+		}
+	}
+	pub fn roblox_surf()->Self{
+		Self{
+			gravity:Planar64Vec3::int(0,-50,0),
+			..Self::roblox_bhop()
+		}
+	}
+	pub fn roblox_rocket()->Self{
+		Self{
+			strafe:None,
+			rocket:Some(PropulsionSettings{
+				enable:ControlsActivation::full_3d(),
+				magnitude:Planar64::int(200),
+			}),
+			..Self::roblox_bhop()
+		}
+	}
+
+	pub fn source_bhop()->Self{
+		Self{
+			controls_mask:Controls::all(),
+			controls_mask_state:Controls::all(),
+			strafe:Some(StrafeSettings{
+				enable:ControlsActivation::full_2d(),
+				air_accel_limit:Some(Planar64::raw(150<<28)*100),
+				mv:Planar64::raw(30)*VALVE_SCALE,
+				tick_rate:Ratio64::new(100,Time::ONE_SECOND.nanos() as u64).unwrap(),
+			}),
+			jump:Some(JumpSettings{
+				impulse:JumpImpulse::FromHeight(Planar64::int(52)*VALVE_SCALE),
+				calculation:JumpCalculation::Linear,
+			}),
+			gravity:Planar64Vec3::int(0,-800,0)*VALVE_SCALE,
+			static_friction:Planar64::int(2),//?
+			kinetic_friction:Planar64::int(3),//?
+			mass:Planar64::int(1),
+			rocket:None,
+			walk:Some(WalkSettings{
+				enable:ControlsActivation::full_2d(),
+				accelerate:AccelerateSettings{
+					topspeed:Planar64::int(18),//?
+					accel:Planar64::int(90),//?
+				},
+			}),
+			ladder:Some(LadderSettings{
+				enable:ControlsActivation::full_2d(),
+				accelerate:AccelerateSettings{
+					topspeed:Planar64::int(18),//?
+					accel:Planar64::int(180),//?
+				},
+				dot:(Planar64::int(1)/2).sqrt(),//?
+			}),
+			swim:Some(PropulsionSettings{
+				enable:ControlsActivation::full_2d(),
+				magnitude:Planar64::int(12),//?
+			}),
+			surf_slope:Some(Planar64::raw(3787805118)),// normal.y=0.75
+			hitbox:Hitbox::source(),
+			camera_offset:(Planar64Vec3::int(0,64,0)-Planar64Vec3::int(0,73,0)/2)*VALVE_SCALE,
+		}
+	}
+	pub fn source_surf()->Self{
+		Self{
+			controls_mask:Controls::all(),
+			controls_mask_state:Controls::all(),
+			strafe:Some(StrafeSettings{
+				enable:ControlsActivation::full_2d(),
+				air_accel_limit:Some(Planar64::int(150)*66*VALVE_SCALE),
+				mv:Planar64::int(30)*VALVE_SCALE,
+				tick_rate:Ratio64::new(66,Time::ONE_SECOND.nanos() as u64).unwrap(),
+			}),
+			jump:Some(JumpSettings{
+				impulse:JumpImpulse::FromHeight(Planar64::int(52)*VALVE_SCALE),
+				calculation:JumpCalculation::Linear,
+			}),
+			gravity:Planar64Vec3::int(0,-800,0)*VALVE_SCALE,
+			static_friction:Planar64::int(2),//?
+			kinetic_friction:Planar64::int(3),//?
+			mass:Planar64::int(1),
+			rocket:None,
+			walk:Some(WalkSettings{
+				enable:ControlsActivation::full_2d(),
+				accelerate:AccelerateSettings{
+					topspeed:Planar64::int(18),//?
+					accel:Planar64::int(90),//?
+				},
+			}),
+			ladder:Some(LadderSettings{
+				enable:ControlsActivation::full_2d(),
+				accelerate:AccelerateSettings{
+					topspeed:Planar64::int(18),//?
+					accel:Planar64::int(180),//?
+				},
+				dot:(Planar64::int(1)/2).sqrt(),//?
+			}),
+			swim:Some(PropulsionSettings{
+				enable:ControlsActivation::full_2d(),
+				magnitude:Planar64::int(12),//?
+			}),
+			surf_slope:Some(Planar64::raw(3787805118)),// normal.y=0.75
+			hitbox:Hitbox::source(),
+			camera_offset:(Planar64Vec3::int(0,64,0)-Planar64Vec3::int(0,73,0)/2)*VALVE_SCALE,
+		}
+	}
+}
\ No newline at end of file
diff --git a/src/lib.rs b/src/lib.rs
index b567481..36a0933 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -6,6 +6,7 @@ pub mod zeroes;
 pub mod integer;
 pub mod updatable;
 pub mod instruction;
+pub mod gameplay_attributes;
 pub mod gameplay_modes;
 pub mod gameplay_style;
-pub mod gameplay_attributes;
\ No newline at end of file
+pub mod controls_bitflag;
\ No newline at end of file