Нуклип: Ctrl замедляет (как в GMod), а не опускает
Some checks are pending
CI / checks (push) Waiting to run

Пользователь: в оригинале Ctrl в ноуклипе замедляет движение. Убрано
`move_up -= 1` по Ctrl; скорость: Shift ×3, Ctrl ×0.35, иначе обычная.
Плюс тесты-сканы карты: поверхности с «зеркальными» материалами (0 в зале) и
сущности рядом с залом — подтверждают, что func_reflective_glass один
(model *6, точка -2064 -2076 -286).
This commit is contained in:
Niko Marmeladkov 2026-10-24 13:23:42 +03:00
parent 300a6c6d98
commit 209412ea3d
2 changed files with 94 additions and 3 deletions

View file

@ -879,9 +879,6 @@ pub fn map(assets: Option<PathBuf>, args: MapArgs) -> anyhow::Result<()> {
if pressed.contains(&Keycode::A) {
move_right -= 1.0;
}
if pressed.contains(&Keycode::LCtrl) {
move_up -= 1.0;
}
// Сенсорный стик складывается с клавиатурой: на Android клавиш нет,
// а на десктопе `--touch` удобно проверять рядом с WASD.
let (touch_forward, touch_right) = touch.movement();
@ -892,8 +889,11 @@ pub fn map(assets: Option<PathBuf>, args: MapArgs) -> anyhow::Result<()> {
}
let touch_jump = touch.take_jump();
if player.noclip {
// Как в GMod: Shift ускоряет, Ctrl замедляет (а не опускает).
let speed = if pressed.contains(&Keycode::LShift) {
args.speed * 3.0
} else if pressed.contains(&Keycode::LCtrl) {
args.speed * 0.35
} else {
args.speed
};

View file

@ -1472,3 +1472,94 @@ fn real_map_visual_entities() {
}
assert!(!classes.is_empty(), "сущностей нет");
}
/// Где на карте поверхности с «зеркальными» материалами.
#[test]
fn real_map_mirror_materials() {
let Some(root) = assets_root() else {
eprintln!("пропуск: ассеты не найдены");
return;
};
let map = root.join("garrysmod/maps/gm_construct.bsp");
if !map.is_file() {
eprintln!("пропуск: нет {}", map.display());
return;
}
let bsp = formats::bsp::Bsp::from_path(&map).expect("разбор карты");
let geometry = bsp.geometry().expect("геометрия");
let texdata = bsp.texdata().expect("texdata");
let names = bsp.texture_names().expect("имена текстур");
let mut found = 0usize;
for (index, face) in geometry.faces.iter().enumerate() {
if face.num_edges < 3 {
continue;
}
let Some(texinfo) = geometry.texinfos.get(face.texinfo.max(0) as usize) else {
continue;
};
let name = texdata
.get(texinfo.texdata.max(0) as usize)
.map(|data| data.name_id.max(0) as usize)
.and_then(|id| names.get(id))
.cloned()
.unwrap_or_default();
let lower = name.to_ascii_lowercase();
if !(lower.contains("mirror") || lower.contains("reflect") || lower.contains("glass")) {
continue;
}
let Ok(indices) = geometry.face_vertex_indices(index) else {
continue;
};
let mut center = math::Vec3::ZERO;
let mut count = 0.0f32;
for &v in &indices {
if let Some(vertex) = geometry.vertices.get(v as usize) {
center += math::Vec3::new(vertex.pos[0], vertex.pos[1], vertex.pos[2]);
count += 1.0;
}
}
if count == 0.0 {
continue;
}
let center = center / count;
// Интересуют только вертикальные поверхности в зале (z около -300..-500).
if (-600.0..=-200.0).contains(&center.z) {
eprintln!("грань {index}: {name} в {center:?}");
found += 1;
}
if found > 20 {
break;
}
}
eprintln!("найдено зеркальных граней в зале: {found}");
}
/// Сущности рядом с залом, где пользователь ждёт зеркало.
#[test]
fn real_map_entities_near_hall() {
let Some(root) = assets_root() else {
eprintln!("пропуск: ассеты не найдены");
return;
};
let map = root.join("garrysmod/maps/gm_construct.bsp");
if !map.is_file() {
eprintln!("пропуск: нет {}", map.display());
return;
}
let vfs = mount_game(&root);
let bsp = formats::bsp::Bsp::from_path(&map).expect("разбор карты");
let world = engine::build_world(&bsp, &vfs).expect("сборка мира");
let hall = math::Vec3::new(-1717.0, -1693.0, -400.0);
for entity in world.entities.iter() {
let distance = (entity.origin - hall).length();
if distance < 700.0 {
eprintln!(
"{:.0}: {} @ {:?} model={:?}",
distance,
entity.classname,
entity.origin,
entity.key("model")
);
}
}
}