From d17e2314aae22177fe10a703fda27df9dd053bbd Mon Sep 17 00:00:00 2001 From: Monster Robot Party Date: Fri, 31 Jul 2026 17:13:23 +1000 Subject: [PATCH] =?UTF-8?q?LANE6:=20LEVEL=2001=20is=20an=20office=20?= =?UTF-8?q?=E2=80=94=20Dunder=20Mifflin=20floor=20plan,=20and=20a=20spawn?= =?UTF-8?q?=20guard?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The game had no room. Props sat on a grey disc in a black void, which quietly broke the premise: a game about wrecking your workplace needs a workplace. Office.gd — LEVEL 01 - Open-plan office laid out after The Office (US) floor plan: bullpen of facing desk pairs behind cubicle partitions, reception, glass-walled manager's office, conference room, break room with vending machines, copier alcove, warehouse roller door. - Drop ceiling on a T-bar grid with fluorescent troffers that ARE the light sources (the old scene lit an interior with one outdoor directional lamp, which is exactly why it read as "props on a plane"), window wall with blinds, magnolia and carpet. - Office owns the shell + static fittings; Main._populate() owns everything smashable and asks Office where things go. Walls/desks/counters are boxes because they ARE boxes; chairs, vending machines, microwave and plant come from a new Blender generator (tools/gen_office_props.py) because a box reads as wrong for those. The level no longer falls over on its own - Records were stacked 3 cm apart vertically while being 30 cm TALL, so Jolt resolved 27 cm of interpenetration explosively on frame one and shoved the furniture over before the player touched anything. They now stand side by side. - Per-material mass (MASSES): everything was 1 kg, so a thrown record could tip a filing cabinet. - Spawn guard: placing ~40 props by formula guarantees an occasional overlap, and depenetration is violent (a chair left the building at 500 m/s). Dynamic bodies are speed-limited for 0.75 s, and each offender is named once with the position it was PLACED at, so the cause stays visible instead of being papered over. It then found the real bug: bullpen rows 3.6 m apart left the two rows' chairs meeting back-to-back with 3 cm to spare. Rows are now 4.8 m apart. - dev/DemoDriver.gd act 0 touches nothing for 5 s and prints total body speed. Now reads 0.00 m/s with zero spawn warnings. Two real melee bugs found while testing the level - The hit test was a SPHERE parked at `reach`, so anything CLOSER than the weapon's reach fell in front of it and was missed — you could stand against the printer with a sledgehammer and swing straight through it. Now a capsule swept from the camera. - Swings started at eye height (1.6 m), so a carton on the floor was ~1.5 m away even standing over it and short-reach weapons could never touch anything on the ground. Swings now originate at hand height. Co-Authored-By: Claude Opus 5 --- README.md | 9 +- game/README.md | 33 +- game/assets/store/microwave.glb | Bin 0 -> 12112 bytes game/assets/store/microwave.glb.import | 45 ++ game/assets/store/office-chair.glb | Bin 0 -> 78444 bytes game/assets/store/office-chair.glb.import | 45 ++ game/assets/store/office-plant.glb | Bin 0 -> 98140 bytes game/assets/store/office-plant.glb.import | 45 ++ game/assets/store/store-aircon.glb | Bin 0 -> 1620 bytes game/assets/store/store-aircon.glb.import | 45 ++ game/assets/store/store-bin-long.glb | Bin 0 -> 18396 bytes game/assets/store/store-bin-long.glb.import | 45 ++ game/assets/store/store-column-white.glb | Bin 0 -> 1664 bytes .../store/store-column-white.glb.import | 45 ++ game/assets/store/store-crate-blue.glb | Bin 0 -> 57332 bytes game/assets/store/store-crate-blue.glb.import | 45 ++ game/assets/store/store-door.glb | Bin 0 -> 8852 bytes game/assets/store/store-door.glb.import | 45 ++ game/assets/store/store-rack-long.glb | Bin 0 -> 22620 bytes game/assets/store/store-rack-long.glb.import | 45 ++ game/assets/store/store-rack-wide.glb | Bin 0 -> 22636 bytes game/assets/store/store-rack-wide.glb.import | 45 ++ game/assets/store/store-station.glb | Bin 0 -> 11440 bytes game/assets/store/store-station.glb.import | 45 ++ game/assets/store/store-trolley.glb | Bin 0 -> 17056 bytes game/assets/store/store-trolley.glb.import | 45 ++ game/assets/store/store-tub-black.glb | Bin 0 -> 61552 bytes game/assets/store/store-tub-black.glb.import | 45 ++ game/assets/store/store-tub-white.glb | Bin 0 -> 59156 bytes game/assets/store/store-tub-white.glb.import | 45 ++ game/assets/store/store-window.glb | Bin 0 -> 8864 bytes game/assets/store/store-window.glb.import | 45 ++ game/assets/store/vending-machine.glb | Bin 0 -> 84260 bytes game/assets/store/vending-machine.glb.import | 45 ++ game/dev/DemoDriver.gd | 119 +++-- game/scripts/Hud.gd | 2 +- game/scripts/Main.gd | 224 +++++---- game/scripts/Office.gd | 454 ++++++++++++++++++ game/scripts/Office.gd.uid | 1 + game/scripts/Player.gd | 29 +- game/scripts/Record.gd | 1 + tools/gen_office_props.py | 321 +++++++++++++ 42 files changed, 1788 insertions(+), 125 deletions(-) create mode 100644 game/assets/store/microwave.glb create mode 100644 game/assets/store/microwave.glb.import create mode 100644 game/assets/store/office-chair.glb create mode 100644 game/assets/store/office-chair.glb.import create mode 100644 game/assets/store/office-plant.glb create mode 100644 game/assets/store/office-plant.glb.import create mode 100644 game/assets/store/store-aircon.glb create mode 100644 game/assets/store/store-aircon.glb.import create mode 100644 game/assets/store/store-bin-long.glb create mode 100644 game/assets/store/store-bin-long.glb.import create mode 100644 game/assets/store/store-column-white.glb create mode 100644 game/assets/store/store-column-white.glb.import create mode 100644 game/assets/store/store-crate-blue.glb create mode 100644 game/assets/store/store-crate-blue.glb.import create mode 100644 game/assets/store/store-door.glb create mode 100644 game/assets/store/store-door.glb.import create mode 100644 game/assets/store/store-rack-long.glb create mode 100644 game/assets/store/store-rack-long.glb.import create mode 100644 game/assets/store/store-rack-wide.glb create mode 100644 game/assets/store/store-rack-wide.glb.import create mode 100644 game/assets/store/store-station.glb create mode 100644 game/assets/store/store-station.glb.import create mode 100644 game/assets/store/store-trolley.glb create mode 100644 game/assets/store/store-trolley.glb.import create mode 100644 game/assets/store/store-tub-black.glb create mode 100644 game/assets/store/store-tub-black.glb.import create mode 100644 game/assets/store/store-tub-white.glb create mode 100644 game/assets/store/store-tub-white.glb.import create mode 100644 game/assets/store/store-window.glb create mode 100644 game/assets/store/store-window.glb.import create mode 100644 game/assets/store/vending-machine.glb create mode 100644 game/assets/store/vending-machine.glb.import create mode 100644 game/scripts/Office.gd create mode 100644 game/scripts/Office.gd.uid create mode 100644 tools/gen_office_props.py diff --git a/README.md b/README.md index 5a771d4..812c41a 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,9 @@ *Clock out. Smash everything.* A comedic, non-violent, first-person workplace-destruction game from Monster Robot -Party. Level 01 is our actual record store. Nobody gets hurt but the furniture. +Party. Level 01 is an open-plan office laid out after the Dunder Mifflin floor plan — +bullpen, conference room, break room, and a photocopier that fights back. Nobody gets +hurt but the furniture. ## Monorepo layout — one lane per directory @@ -11,11 +13,14 @@ Party. Level 01 is our actual record store. Nobody gets hurt but the furniture. |---|---|---| | `game/` | **Lane 1 — the game** | Godot 4.7 (Jolt physics, Mac-native). The shippable build. | | `web/` | **Lane 3 — web toy** | Three.js dig-and-destroy demo (planned; thriftgod-adjacent). | +| `tools/` | asset build | Blender generators for the viewmodel + office props. Re-runnable. | | `LANES/` | coordination | Execution specs for parallel Claude/Opus work sessions. | | `3D-STORE/` | *not in git* | 700MB Blender/Unreal source-asset vault (see `.gitignore`). | | `destroyulater.txt` | lore | The founding chat where the idea happened. | -Asset generation lives in its own repo: `~/Documents/meshgod` (text→GLB factory). +Asset generation lives in its own repo: `~/Documents/meshgod` (text→GLB factory). The +first-person arms are cut from `~/Documents/character_kit_modular` (the GODVERSE modular +character kit) by `tools/gen_fps_arms.py`. ## Rules for parallel work sessions diff --git a/game/README.md b/game/README.md index 96b2fb4..d461c6d 100644 --- a/game/README.md +++ b/game/README.md @@ -103,7 +103,34 @@ too coarse to tell a 5 cm error from a 50 cm one. Zero script errors required. After adding any `class_name` script, run `Godot --path game --editor --quit` first — headless Godot won't rescan a stale class cache. -## What's still missing +## The level -The store has no **room**: props sit on a grey plane in a black void, and several topple -on spawn before you touch them. That's the biggest remaining gap — see the top-level README. +`scripts/Office.gd` builds LEVEL 01: an open-plan office after the Dunder Mifflin floor +plan — bullpen of facing desk pairs behind cubicle partitions, reception, a glass-walled +manager's office, conference room, break room with vending machines, a copier alcove for +the printer boss, and a warehouse roller door. Drop ceiling, fluorescent troffers (which +are the actual light sources), magnolia walls, grey carpet, a window wall with blinds. + +Office owns the **shell and static fittings**; `Main._populate()` owns everything +**smashable**, and asks Office where things go (`desk_spots()`, `chair_spots()`, +`copier_spot()`). Walls, desks and counters are boxes built in code because they are +boxes; chairs, vending machines, the microwave and the plant come from +`tools/gen_office_props.py`, because a box reads as obviously wrong for those. + +### The spawn guard + +Placing ~40 props by formula means something will eventually spawn a few centimetres +inside something else, and Jolt's depenetration is not gentle — a chair overlapping a +desk left the building at 500 m/s on frame one, knocking over the furniture on its way. + +`Main._physics_process()` speed-limits dynamic bodies for the first 0.75 s: enough for a +real overlap to push apart calmly, far too little to launch anything. Every offender is +named once in a warning with **the position it was placed at**, so the underlying overlap +stays visible and fixable rather than silently papered over. + +Verify a level is genuinely at rest with: +```bash +/Applications/Godot.app/Contents/MacOS/Godot --headless --path game --quit-after 300 dev/demo.tscn +``` +The demo's first act touches nothing and prints total body speed each second. It must +read `0.00 m/s`, and no `[spawn]` warnings should appear. diff --git a/game/assets/store/microwave.glb b/game/assets/store/microwave.glb new file mode 100644 index 0000000000000000000000000000000000000000..7b647cafbd1c0405a363ad056bcf1c0b081332db GIT binary patch literal 12112 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 literal 0 HcmV?d00001 diff --git a/game/assets/store/microwave.glb.import b/game/assets/store/microwave.glb.import new file mode 100644 index 0000000..d2ae9ed --- /dev/null +++ b/game/assets/store/microwave.glb.import @@ -0,0 +1,45 @@ +[remap] + +importer="scene" +importer_version=1 +type="PackedScene" +uid="uid://c5eckque6cbus" +path="res://.godot/imported/microwave.glb-b7b5167c74b8b5c7123b987171251d4d.scn" + +[deps] + +source_file="res://assets/store/microwave.glb" +dest_files=["res://.godot/imported/microwave.glb-b7b5167c74b8b5c7123b987171251d4d.scn"] + +[params] + +nodes/root_type="" +nodes/root_name="" +nodes/root_script=null +mesh_library/use_node_names_as_mesh_names=false +array_mesh/deduplicate_surfaces=true +nodes/apply_root_scale=true +nodes/root_scale=1.0 +nodes/import_as_skeleton_bones=false +nodes/use_name_suffixes=true +nodes/use_node_type_suffixes=true +meshes/ensure_tangents=true +meshes/generate_lods=true +meshes/create_shadow_meshes=true +meshes/light_baking=1 +meshes/lightmap_texel_size=0.2 +meshes/force_disable_compression=false +skins/use_named_skins=true +animation/import=true +animation/fps=30 +animation/trimming=false +animation/remove_immutable_tracks=true +animation/import_rest_as_RESET=false +import_script/path="" +materials/extract=0 +materials/extract_format=0 +materials/extract_path="" +_subresources={} +gltf/naming_version=2 +gltf/embedded_image_handling=1 +gltf/texture_map_mode=1 diff --git a/game/assets/store/office-chair.glb b/game/assets/store/office-chair.glb new file mode 100644 index 0000000000000000000000000000000000000000..455be34a71e4afcee5cc41cc354b21a59a5eac4e GIT binary patch literal 78444 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

fh(HZpPMPlp31Kf9cLUn?d$dO? zoQ)~cBsor9ewoFoWYlG+l)FLTd#z|ZxC&{E1R_)7JaIi)D#~Tq{>-NpbvaDSDHx7j zDo>>l6e-ou%1YB+#(~?_bX~M%#QdSp{p%Fya?bqjn2XN|`POXLIyJ0Ibg9v7omT6l zVqow5u;+UMW6tYE&{Vd`^>8bWSki#*xZkJj%%|Taix&+?QAk7Hxfx-nZNn_8#EZru zo~c<7Y(GT5HM>+O<8U0kRMty|s%w^Xl*;m&wfJksth4uy{dKL*n<1v)~qNC>r2Di$JKhZB`?W5f4)nyL){xr>ogp2ykVx} zs6;rL{l2{Rcn;iU1Mvc|A4PLs%fDkK+5bkDu&jJyyCmw!rMAQsOUg(~$muQ?9J~vP zqWr`Md{k?IW$oSJQx@Z3oo!ja4>HUuTe1NB$?@E?(^%WXRz~58YhG(#k^FF+Vcklsrao&Yj@Dg6bCeHX*0Z(8Lc5vQ-NAMn= L!xqk4@CN<@)%kU~ literal 0 HcmV?d00001 diff --git a/game/assets/store/store-aircon.glb.import b/game/assets/store/store-aircon.glb.import new file mode 100644 index 0000000..3aeec89 --- /dev/null +++ b/game/assets/store/store-aircon.glb.import @@ -0,0 +1,45 @@ +[remap] + +importer="scene" +importer_version=1 +type="PackedScene" +uid="uid://dd5jcl680fp1r" +path="res://.godot/imported/store-aircon.glb-3936a0f9c59319b1096328c7a6d1194c.scn" + +[deps] + +source_file="res://assets/store/store-aircon.glb" +dest_files=["res://.godot/imported/store-aircon.glb-3936a0f9c59319b1096328c7a6d1194c.scn"] + +[params] + +nodes/root_type="" +nodes/root_name="" +nodes/root_script=null +mesh_library/use_node_names_as_mesh_names=false +array_mesh/deduplicate_surfaces=true +nodes/apply_root_scale=true +nodes/root_scale=1.0 +nodes/import_as_skeleton_bones=false +nodes/use_name_suffixes=true +nodes/use_node_type_suffixes=true +meshes/ensure_tangents=true +meshes/generate_lods=true +meshes/create_shadow_meshes=true +meshes/light_baking=1 +meshes/lightmap_texel_size=0.2 +meshes/force_disable_compression=false +skins/use_named_skins=true +animation/import=true +animation/fps=30 +animation/trimming=false +animation/remove_immutable_tracks=true +animation/import_rest_as_RESET=false +import_script/path="" +materials/extract=0 +materials/extract_format=0 +materials/extract_path="" +_subresources={} +gltf/naming_version=2 +gltf/embedded_image_handling=1 +gltf/texture_map_mode=1 diff --git a/game/assets/store/store-bin-long.glb b/game/assets/store/store-bin-long.glb new file mode 100644 index 0000000000000000000000000000000000000000..504492d1ef306b782f41f07f47e9f160a940ec6b GIT binary patch literal 18396 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 U4A1@0_RD1@uk+L%Ci)Hh8?y|_+W-In literal 0 HcmV?d00001 diff --git a/game/assets/store/store-bin-long.glb.import b/game/assets/store/store-bin-long.glb.import new file mode 100644 index 0000000..8a01c2f --- /dev/null +++ b/game/assets/store/store-bin-long.glb.import @@ -0,0 +1,45 @@ +[remap] + +importer="scene" +importer_version=1 +type="PackedScene" +uid="uid://cm4eatc040s7p" +path="res://.godot/imported/store-bin-long.glb-682bed3d6855531dd328bb07f257ed0f.scn" + +[deps] + +source_file="res://assets/store/store-bin-long.glb" +dest_files=["res://.godot/imported/store-bin-long.glb-682bed3d6855531dd328bb07f257ed0f.scn"] + +[params] + +nodes/root_type="" +nodes/root_name="" +nodes/root_script=null +mesh_library/use_node_names_as_mesh_names=false +array_mesh/deduplicate_surfaces=true +nodes/apply_root_scale=true +nodes/root_scale=1.0 +nodes/import_as_skeleton_bones=false +nodes/use_name_suffixes=true +nodes/use_node_type_suffixes=true +meshes/ensure_tangents=true +meshes/generate_lods=true +meshes/create_shadow_meshes=true +meshes/light_baking=1 +meshes/lightmap_texel_size=0.2 +meshes/force_disable_compression=false +skins/use_named_skins=true +animation/import=true +animation/fps=30 +animation/trimming=false +animation/remove_immutable_tracks=true +animation/import_rest_as_RESET=false +import_script/path="" +materials/extract=0 +materials/extract_format=0 +materials/extract_path="" +_subresources={} +gltf/naming_version=2 +gltf/embedded_image_handling=1 +gltf/texture_map_mode=1 diff --git a/game/assets/store/store-column-white.glb b/game/assets/store/store-column-white.glb new file mode 100644 index 0000000000000000000000000000000000000000..41c44a3d092fed8cd950f26676313e71d84e6731 GIT binary patch literal 1664 zcma)7&2G~`5FXl6ehU;R9EtY8$r%5}ZVrXEYDFN4p-Ic3swyYhq!x)C*_%QYMd}5K zr)pn>N8lltUE7J1CIL&?ot^#WoB3vUm3F7LzXSl6s{p^30X|lp%7D00L>VazNSpdJ zbXgFR0{L_n27VCb+8C1C=}^B(!(8#LlRGzMMb=azk#ibGUf?5GlNBcyp$Y!$hhl9nx9gM+%N4?*U6;|&b2~9> zGw9blwCXi!lN4Ckr^pp2D!c4-B3L55dRV5+?R31xLC|lX`7}Zno-=mtyA2^43lG!% zkx$Mm;?s27P;JxN9ExhNT%ltmFq`u<>bP}TQFxbnq1W}8cb=eK#zL>&XM8yzpPg#4 zR&**tdBr&>ZpescLzNG=jd5N30o~?FVnatlF_IOEopqv~)|-WOGw|ijmhfGjAIbp0pmr4As)m zsp|YFJUsN{H?uet3Ei_|n5c#v?d|G#RR$zmwaN=zT=k-GY|+hdeI!~({YiLrce}KG zAgOypWo0ON2X|R!h7Ryd%sF+x)@k#%5j{Yx#GqAp75F3uR>! zn-R>9A3gYj_dFU e9>QZ-#u5Kk;0`>4H5}LA7QBG_u!7?XJb}Mp4zGd$ literal 0 HcmV?d00001 diff --git a/game/assets/store/store-column-white.glb.import b/game/assets/store/store-column-white.glb.import new file mode 100644 index 0000000..859188b --- /dev/null +++ b/game/assets/store/store-column-white.glb.import @@ -0,0 +1,45 @@ +[remap] + +importer="scene" +importer_version=1 +type="PackedScene" +uid="uid://dbsjlmo7ue3yw" +path="res://.godot/imported/store-column-white.glb-d047a30c24b2dbcdfcb8fbfa2b09b210.scn" + +[deps] + +source_file="res://assets/store/store-column-white.glb" +dest_files=["res://.godot/imported/store-column-white.glb-d047a30c24b2dbcdfcb8fbfa2b09b210.scn"] + +[params] + +nodes/root_type="" +nodes/root_name="" +nodes/root_script=null +mesh_library/use_node_names_as_mesh_names=false +array_mesh/deduplicate_surfaces=true +nodes/apply_root_scale=true +nodes/root_scale=1.0 +nodes/import_as_skeleton_bones=false +nodes/use_name_suffixes=true +nodes/use_node_type_suffixes=true +meshes/ensure_tangents=true +meshes/generate_lods=true +meshes/create_shadow_meshes=true +meshes/light_baking=1 +meshes/lightmap_texel_size=0.2 +meshes/force_disable_compression=false +skins/use_named_skins=true +animation/import=true +animation/fps=30 +animation/trimming=false +animation/remove_immutable_tracks=true +animation/import_rest_as_RESET=false +import_script/path="" +materials/extract=0 +materials/extract_format=0 +materials/extract_path="" +_subresources={} +gltf/naming_version=2 +gltf/embedded_image_handling=1 +gltf/texture_map_mode=1 diff --git a/game/assets/store/store-crate-blue.glb b/game/assets/store/store-crate-blue.glb new file mode 100644 index 0000000000000000000000000000000000000000..b47998607d2115712223838286642b9ffb27ca7f GIT binary patch literal 57332 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 J=l9M({~tP_sB8cL literal 0 HcmV?d00001 diff --git a/game/assets/store/store-crate-blue.glb.import b/game/assets/store/store-crate-blue.glb.import new file mode 100644 index 0000000..66795bc --- /dev/null +++ b/game/assets/store/store-crate-blue.glb.import @@ -0,0 +1,45 @@ +[remap] + +importer="scene" +importer_version=1 +type="PackedScene" +uid="uid://c5x1hboh2enh" +path="res://.godot/imported/store-crate-blue.glb-2ea0f65193f35865ca594dac5849a6d2.scn" + +[deps] + +source_file="res://assets/store/store-crate-blue.glb" +dest_files=["res://.godot/imported/store-crate-blue.glb-2ea0f65193f35865ca594dac5849a6d2.scn"] + +[params] + +nodes/root_type="" +nodes/root_name="" +nodes/root_script=null +mesh_library/use_node_names_as_mesh_names=false +array_mesh/deduplicate_surfaces=true +nodes/apply_root_scale=true +nodes/root_scale=1.0 +nodes/import_as_skeleton_bones=false +nodes/use_name_suffixes=true +nodes/use_node_type_suffixes=true +meshes/ensure_tangents=true +meshes/generate_lods=true +meshes/create_shadow_meshes=true +meshes/light_baking=1 +meshes/lightmap_texel_size=0.2 +meshes/force_disable_compression=false +skins/use_named_skins=true +animation/import=true +animation/fps=30 +animation/trimming=false +animation/remove_immutable_tracks=true +animation/import_rest_as_RESET=false +import_script/path="" +materials/extract=0 +materials/extract_format=0 +materials/extract_path="" +_subresources={} +gltf/naming_version=2 +gltf/embedded_image_handling=1 +gltf/texture_map_mode=1 diff --git a/game/assets/store/store-door.glb b/game/assets/store/store-door.glb new file mode 100644 index 0000000000000000000000000000000000000000..0625327715bcc412bf06f52e09b4602befb8bc16 GIT binary patch literal 8852 zcmeHJYj|8m8GcV&pwJdtN};6};z3k&yX-A{NsMh;S`AGTOiHzuS~kf^x{~aM-A$o} zXcbXV5tVu=h>D0e@QSF2H5Kqms-hw)ctuoHyn%Q@EZ@wTFPSr$b1aX4e0-Yc$vf|U z^M3Dq^Udre1B08^&j7H;1s2Z&&g$;$7{W~PO4V(0H|(fZ%9UEf z0Hrjn8T871UbUg^jLwFgjqyZ0m2_k7POn-kRmvnz#S`vW%&qm3f!mZ&tmZat9d*ma zA&R-(axUhUD}A1rNNgM1HuY)L9r9{BWUA7i+1c5(vY%?GyFxfrtb5f`anSedtBmvv zdflZyug`6&S4TW@@|W3ItZ&y+WA1QIb)#1=4i1)jyDB3CJIY>-JVxD~V$EAy8LU*- z7klN7wijOzwm>DmyUQnyGrX4_9jScp{OZ?haQ=L#29Yr_vVd^=heSq%J;= zx@UKGw{2?c?2sMn=3StTCC&#@yb@2pvFEDxVj27m0I==Q9QIlg*^kxl}TpjHTi! z87VZT(#dQppP{ZL3cf0zPvi=Toa|YNuFBSxWY8FFODqwis3oH=D{(ikTbriqMQ5f} zoD{|Vhl-=}sXx>6(~~>Sq)DLiyVth1w|2>EI8}k(L)pKcU3IVBD-YD^8mBXj)I1UC z?C+OfF1jG~Vs$`#&(ayXWmDTZgk<0DQ1kQIOmOXNAt^SaEuR(_(cg>OhgN(pm&?+9 zId289rmX{4@7*%Kf1_+ z&h@a5Sl8rS1N*RszbTvU?0|S+`m@< z#hat}{)q|sM)~*C&gowti2k#WjSC-++xWqQtLQ%X^+a*5M`*%0*TX(yU6XSS?86$4 zYkN`OU%AI=TZ!^y;ni z>(S$)hX*F+%KvSmcsjjsQWM6755Fy8T;#IG#>GA7dZIYjAT(i|YhWLKTl6^Bz&@7sa^-p$X$$gXZ&;&s}`?xhGMaYY>_+ z&h=W2u&F0bu}OP&ggNjLGzIsj*BYm70V8TUVN9abOKMEUR>YtoG_>ksc;je))M9QVMcG3Kmi!5SWIJ}Sof z);_a_ebgAJndc0xRl{1F59b?Wz=!8lKGz=57;}*tLmTknwRluotA>4S8lGF_XIlHr z8e;@z;0VkioP*go5=UbZ;UXN56L1n15H7&6n2X~ulW-<2a1<6|9^pJVI1$HS7U3++ z$H`cZQwdK+16JT^SV_1N&qfSq;B>;%@eDj2&%{!~rC5wp@En{*cp8=<4j0P^m*H7R zp%Kl5&B!B*0@e|(!y254=cARd70<(Su?lIzG!n>REm{a$ki>d4Aw!tKYMh0Q=qBvO z+33Ivv5jyWUV?M69a{*uU^6!1Mc6>N0WUx&w&EPZbI^vDq6_VW?RYVI;Ng72^RWZ{ zC}D(f1Xa{=Aub@i0A&oKf?mR2oQDC_Fhn?nB6i|s=p*dIFkX%^TtavWcH z0#aT(rPJlZoCWc!BvD;;mvpluE({6*WxYs0ItR!!aaB|K7xmvI;2UHBTl zg0JHq!h7%?d=K~HZo<3qO-$fhxP$Nx?8jH}T^t}hfG^?u_y+DIyc6HXkMLtWK==TD zhM(Z)c$n~E{1(5*AMp_3L--YbiC^PB!u#+8{1m^#gM<&_hxh}2f%^&X$8Yc#{1uNA zK90ZRG5iBZIFHfq3}=>el;aRO&cE?59K<7pkKj-E8)iCB5I%uF<4EV9c$Dx_z&Xa5 z=PV>#=*)MHbrv|w370!3JIkC?oF#-yoD-cBoRge6gmawP&T-CCXA$8d=V)hzbG$Q` JaIUl1c@ogdq!9oB literal 0 HcmV?d00001 diff --git a/game/assets/store/store-door.glb.import b/game/assets/store/store-door.glb.import new file mode 100644 index 0000000..4bc1725 --- /dev/null +++ b/game/assets/store/store-door.glb.import @@ -0,0 +1,45 @@ +[remap] + +importer="scene" +importer_version=1 +type="PackedScene" +uid="uid://dyxqblpqhssdl" +path="res://.godot/imported/store-door.glb-f2292c391563c5fd442da8178e40fa28.scn" + +[deps] + +source_file="res://assets/store/store-door.glb" +dest_files=["res://.godot/imported/store-door.glb-f2292c391563c5fd442da8178e40fa28.scn"] + +[params] + +nodes/root_type="" +nodes/root_name="" +nodes/root_script=null +mesh_library/use_node_names_as_mesh_names=false +array_mesh/deduplicate_surfaces=true +nodes/apply_root_scale=true +nodes/root_scale=1.0 +nodes/import_as_skeleton_bones=false +nodes/use_name_suffixes=true +nodes/use_node_type_suffixes=true +meshes/ensure_tangents=true +meshes/generate_lods=true +meshes/create_shadow_meshes=true +meshes/light_baking=1 +meshes/lightmap_texel_size=0.2 +meshes/force_disable_compression=false +skins/use_named_skins=true +animation/import=true +animation/fps=30 +animation/trimming=false +animation/remove_immutable_tracks=true +animation/import_rest_as_RESET=false +import_script/path="" +materials/extract=0 +materials/extract_format=0 +materials/extract_path="" +_subresources={} +gltf/naming_version=2 +gltf/embedded_image_handling=1 +gltf/texture_map_mode=1 diff --git a/game/assets/store/store-rack-long.glb b/game/assets/store/store-rack-long.glb new file mode 100644 index 0000000000000000000000000000000000000000..3e004dc0906ff39efafa1c3facd3423676803f67 GIT binary patch literal 22620 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 N`@)#&p_^OK`2~_X$9Dh# literal 0 HcmV?d00001 diff --git a/game/assets/store/store-rack-long.glb.import b/game/assets/store/store-rack-long.glb.import new file mode 100644 index 0000000..b672da6 --- /dev/null +++ b/game/assets/store/store-rack-long.glb.import @@ -0,0 +1,45 @@ +[remap] + +importer="scene" +importer_version=1 +type="PackedScene" +uid="uid://bgb58tfndol1h" +path="res://.godot/imported/store-rack-long.glb-2e288b622925827ec69249208c9454ca.scn" + +[deps] + +source_file="res://assets/store/store-rack-long.glb" +dest_files=["res://.godot/imported/store-rack-long.glb-2e288b622925827ec69249208c9454ca.scn"] + +[params] + +nodes/root_type="" +nodes/root_name="" +nodes/root_script=null +mesh_library/use_node_names_as_mesh_names=false +array_mesh/deduplicate_surfaces=true +nodes/apply_root_scale=true +nodes/root_scale=1.0 +nodes/import_as_skeleton_bones=false +nodes/use_name_suffixes=true +nodes/use_node_type_suffixes=true +meshes/ensure_tangents=true +meshes/generate_lods=true +meshes/create_shadow_meshes=true +meshes/light_baking=1 +meshes/lightmap_texel_size=0.2 +meshes/force_disable_compression=false +skins/use_named_skins=true +animation/import=true +animation/fps=30 +animation/trimming=false +animation/remove_immutable_tracks=true +animation/import_rest_as_RESET=false +import_script/path="" +materials/extract=0 +materials/extract_format=0 +materials/extract_path="" +_subresources={} +gltf/naming_version=2 +gltf/embedded_image_handling=1 +gltf/texture_map_mode=1 diff --git a/game/assets/store/store-rack-wide.glb b/game/assets/store/store-rack-wide.glb new file mode 100644 index 0000000000000000000000000000000000000000..457f4b362c5b067f191a0b1d1dfd3ff3bccbe41a GIT binary patch literal 22636 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 literal 0 HcmV?d00001 diff --git a/game/assets/store/store-rack-wide.glb.import b/game/assets/store/store-rack-wide.glb.import new file mode 100644 index 0000000..c88f44d --- /dev/null +++ b/game/assets/store/store-rack-wide.glb.import @@ -0,0 +1,45 @@ +[remap] + +importer="scene" +importer_version=1 +type="PackedScene" +uid="uid://cqx85qlh7ylle" +path="res://.godot/imported/store-rack-wide.glb-f670adfad19f539e72546b79d1e245bf.scn" + +[deps] + +source_file="res://assets/store/store-rack-wide.glb" +dest_files=["res://.godot/imported/store-rack-wide.glb-f670adfad19f539e72546b79d1e245bf.scn"] + +[params] + +nodes/root_type="" +nodes/root_name="" +nodes/root_script=null +mesh_library/use_node_names_as_mesh_names=false +array_mesh/deduplicate_surfaces=true +nodes/apply_root_scale=true +nodes/root_scale=1.0 +nodes/import_as_skeleton_bones=false +nodes/use_name_suffixes=true +nodes/use_node_type_suffixes=true +meshes/ensure_tangents=true +meshes/generate_lods=true +meshes/create_shadow_meshes=true +meshes/light_baking=1 +meshes/lightmap_texel_size=0.2 +meshes/force_disable_compression=false +skins/use_named_skins=true +animation/import=true +animation/fps=30 +animation/trimming=false +animation/remove_immutable_tracks=true +animation/import_rest_as_RESET=false +import_script/path="" +materials/extract=0 +materials/extract_format=0 +materials/extract_path="" +_subresources={} +gltf/naming_version=2 +gltf/embedded_image_handling=1 +gltf/texture_map_mode=1 diff --git a/game/assets/store/store-station.glb b/game/assets/store/store-station.glb new file mode 100644 index 0000000000000000000000000000000000000000..bb75a30fcdda65610a4e92adb12b6540436f76fe GIT binary patch literal 11440 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 z R*0I)7>qKid;cV+v>nV{my-ffB literal 0 HcmV?d00001 diff --git a/game/assets/store/store-window.glb.import b/game/assets/store/store-window.glb.import new file mode 100644 index 0000000..44f7a9a --- /dev/null +++ b/game/assets/store/store-window.glb.import @@ -0,0 +1,45 @@ +[remap] + +importer="scene" +importer_version=1 +type="PackedScene" +uid="uid://cl1mbjurpjjsd" +path="res://.godot/imported/store-window.glb-117aee5b13f1f48f855cc59a5478ab6e.scn" + +[deps] + +source_file="res://assets/store/store-window.glb" +dest_files=["res://.godot/imported/store-window.glb-117aee5b13f1f48f855cc59a5478ab6e.scn"] + +[params] + +nodes/root_type="" +nodes/root_name="" +nodes/root_script=null +mesh_library/use_node_names_as_mesh_names=false +array_mesh/deduplicate_surfaces=true +nodes/apply_root_scale=true +nodes/root_scale=1.0 +nodes/import_as_skeleton_bones=false +nodes/use_name_suffixes=true +nodes/use_node_type_suffixes=true +meshes/ensure_tangents=true +meshes/generate_lods=true +meshes/create_shadow_meshes=true +meshes/light_baking=1 +meshes/lightmap_texel_size=0.2 +meshes/force_disable_compression=false +skins/use_named_skins=true +animation/import=true +animation/fps=30 +animation/trimming=false +animation/remove_immutable_tracks=true +animation/import_rest_as_RESET=false +import_script/path="" +materials/extract=0 +materials/extract_format=0 +materials/extract_path="" +_subresources={} +gltf/naming_version=2 +gltf/embedded_image_handling=1 +gltf/texture_map_mode=1 diff --git a/game/assets/store/vending-machine.glb b/game/assets/store/vending-machine.glb new file mode 100644 index 0000000000000000000000000000000000000000..010edef3776fdf80e646b9fe4d9505692f6c633d GIT binary patch literal 84260 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 CLP9wJ literal 0 HcmV?d00001 diff --git a/game/assets/store/vending-machine.glb.import b/game/assets/store/vending-machine.glb.import new file mode 100644 index 0000000..4ba6624 --- /dev/null +++ b/game/assets/store/vending-machine.glb.import @@ -0,0 +1,45 @@ +[remap] + +importer="scene" +importer_version=1 +type="PackedScene" +uid="uid://b76xahj1v6a5s" +path="res://.godot/imported/vending-machine.glb-2ebbeb04f9452ff8d815cfa46a64cf12.scn" + +[deps] + +source_file="res://assets/store/vending-machine.glb" +dest_files=["res://.godot/imported/vending-machine.glb-2ebbeb04f9452ff8d815cfa46a64cf12.scn"] + +[params] + +nodes/root_type="" +nodes/root_name="" +nodes/root_script=null +mesh_library/use_node_names_as_mesh_names=false +array_mesh/deduplicate_surfaces=true +nodes/apply_root_scale=true +nodes/root_scale=1.0 +nodes/import_as_skeleton_bones=false +nodes/use_name_suffixes=true +nodes/use_node_type_suffixes=true +meshes/ensure_tangents=true +meshes/generate_lods=true +meshes/create_shadow_meshes=true +meshes/light_baking=1 +meshes/lightmap_texel_size=0.2 +meshes/force_disable_compression=false +skins/use_named_skins=true +animation/import=true +animation/fps=30 +animation/trimming=false +animation/remove_immutable_tracks=true +animation/import_rest_as_RESET=false +import_script/path="" +materials/extract=0 +materials/extract_format=0 +materials/extract_path="" +_subresources={} +gltf/naming_version=2 +gltf/embedded_image_handling=1 +gltf/texture_map_mode=1 diff --git a/game/dev/DemoDriver.gd b/game/dev/DemoDriver.gd index 1c73258..ec50b4c 100644 --- a/game/dev/DemoDriver.gd +++ b/game/dev/DemoDriver.gd @@ -19,6 +19,7 @@ var _player: Player var _t := 0.0 var _step := 0 var _step_t := 0.0 +var _frames := 0 # Each step: {dur, move_to (Vector3 or null), look_at (Vector3 or null), act (String)} # act: "" | "punch" | "kick" | "rain" | "reset" @@ -47,54 +48,108 @@ func _find_player(n: Node) -> Player: return null func _build_script() -> void: - # world layout (from Main._build_rack / _build_office, origin 0,0): - # racks (-0.95,-0.7) (0.95,-0.7) - # crates y=0.5 and y=1.2 rows, x -0.8..0.8 - # desk+printer (2.7,-0.3) cabinet (-2.7,-0.3) cooler (3.3,1.6) - # CRT (-2.7,1.3) box (1.9,2.4) turntable (-1.7,-1.3) + # Office floor plan (see Office.gd): spawn at reception (-8.6, 6.6) looking into the + # bullpen; desk clusters at (-4.6,-1.4) (-4.6,2.2) (-0.4,-1.4) (-0.4,2.2); copier + # alcove at (3.0,-0.3); break room x>5.4 z>-1.2; conference and manager along z<-4.4; + # warehouse corner around (7,-6). _script = [] - # ---- ACT 1: the loadout. Stand still and hold each weapon so the viewmodel, - # ---- the grip and one swing per archetype can all be inspected frame by frame. + # ---- ACT 0: SETTLE CHECK. Stand at the entrance and touch nothing. If anything + # ---- moves in these five seconds, the level is falling over by itself again. + _script += [ + {"dur": 2.5, "move_to": Vector3(-8.6, 0, 6.4), "look_at": Vector3(-4.0, 1.1, 0.0), "act": ""}, + {"dur": 2.5, "move_to": null, "look_at": null, "act": ""}, + ] + + # ---- ACT 1: a walk through the floor plan, so the rooms read. + _script += [ + {"dur": 2.2, "move_to": Vector3(-8.4, 0, 2.0), "look_at": Vector3(-4.6, 1.1, 1.0), "act": ""}, + {"dur": 2.2, "move_to": Vector3(-2.6, 0, 3.4), "look_at": Vector3(-0.4, 1.0, 0.5), "act": ""}, + {"dur": 2.2, "move_to": Vector3(-3.0, 0, -3.0), "look_at": Vector3(-3.4, 1.4, -6.4), "act": ""}, + {"dur": 2.2, "move_to": Vector3(1.6, 0, -2.0), "look_at": Vector3(8.0, 1.3, -6.5), "act": ""}, + {"dur": 2.2, "move_to": Vector3(3.4, 0, 3.0), "look_at": Vector3(8.0, 1.2, 4.0), "act": ""}, + ] + + # ---- ACT 2: the loadout, held still so each grip can be inspected. for slot in range(6): - _script.append({"dur": 0.5, "move_to": Vector3(0, 0, 3.2), - "look_at": Vector3(0, 1.0, 0), "act": "weapon:%d" % slot}) - _script.append({"dur": 1.0, "move_to": null, "look_at": null, "act": ""}) - _script.append({"dur": 1.1, "move_to": null, "look_at": null, "act": "swing"}) + _script.append({"dur": 0.5, "move_to": Vector3(-2.2, 0, 4.6), + "look_at": Vector3(-2.0, 1.2, 0.0), "act": "weapon:%d" % slot}) + _script.append({"dur": 0.8, "move_to": null, "look_at": null, "act": ""}) + _script.append({"dur": 1.0, "move_to": null, "look_at": null, "act": "swing"}) - # ---- ACT 2: the matrix. Box cutter shreds the carton, then clanks off the - # ---- filing cabinet; the sledge then removes the cabinet in one go. + # ---- ACT 3: the matrix. Cutter shreds a carton, clanks off a filing cabinet, + # ---- then the sledge takes the cabinet out. _script += [ - {"dur": 0.6, "move_to": null, "look_at": null, "act": "weapon:1"}, - {"dur": 1.2, "move_to": Vector3(1.9, 0, 3.4), "look_at": Vector3(1.9, 0.3, 2.4), "act": ""}, - {"dur": 0.45, "move_to": null, "look_at": null, "act": "swing"}, - {"dur": 0.45, "move_to": null, "look_at": null, "act": "swing"}, + {"dur": 0.5, "move_to": null, "look_at": null, "act": "weapon:1"}, + {"dur": 2.0, "move_to": Vector3(-1.6, 0, 5.3), "look_at": Vector3(-2.3, 0.25, 5.2), "act": ""}, + {"dur": 0.5, "move_to": null, "look_at": null, "act": "swing"}, {"dur": 0.9, "move_to": null, "look_at": null, "act": "swing"}, - # cutter vs steel — expect the clank + the HUD nudge, and no damage - {"dur": 1.3, "move_to": Vector3(-2.7, 0, 1.1), "look_at": Vector3(-2.7, 0.6, -0.3), "act": ""}, + {"dur": 2.0, "move_to": Vector3(3.1, 0, -0.9), "look_at": Vector3(4.5, 0.6, -0.9), "act": ""}, {"dur": 0.4, "move_to": null, "look_at": null, "act": "swing"}, - {"dur": 0.9, "move_to": null, "look_at": null, "act": "swing"}, - {"dur": 0.5, "move_to": null, "look_at": null, "act": "weapon:4"}, {"dur": 1.0, "move_to": null, "look_at": null, "act": "swing"}, - {"dur": 1.2, "move_to": null, "look_at": null, "act": "swing"}, + {"dur": 0.5, "move_to": null, "look_at": null, "act": "weapon:4"}, + {"dur": 1.1, "move_to": null, "look_at": null, "act": "swing"}, + {"dur": 1.3, "move_to": null, "look_at": null, "act": "swing"}, ] - # ---- ACT 3: the boss + the HUD styles + # ---- ACT 4: the printer boss, then a lap of the HUD styles. _script += [ - {"dur": 1.4, "move_to": Vector3(2.7, 0, 1.3), "look_at": Vector3(2.7, 0.95, -0.3), "act": ""}, - {"dur": 1.0, "move_to": null, "look_at": null, "act": "swing"}, - {"dur": 1.0, "move_to": null, "look_at": null, "act": "swing"}, - {"dur": 1.0, "move_to": null, "look_at": null, "act": "swing"}, - {"dur": 1.4, "move_to": null, "look_at": null, "act": "swing"}, - {"dur": 1.6, "move_to": Vector3(0.6, 0, 5.2), "look_at": Vector3(0, 0.6, 0), "act": "hud"}, - {"dur": 1.6, "move_to": null, "look_at": null, "act": "hud"}, - {"dur": 1.6, "move_to": null, "look_at": null, "act": "hud"}, - {"dur": 1.6, "move_to": null, "look_at": null, "act": "hud"}, + {"dur": 2.0, "move_to": Vector3(1.5, 0, -0.3), "look_at": Vector3(3.0, 0.95, -0.3), "act": ""}, + {"dur": 1.1, "move_to": null, "look_at": null, "act": "swing"}, + {"dur": 1.1, "move_to": null, "look_at": null, "act": "swing"}, + {"dur": 1.1, "move_to": null, "look_at": null, "act": "swing"}, + {"dur": 1.5, "move_to": null, "look_at": null, "act": "swing"}, + {"dur": 2.0, "move_to": Vector3(-1.0, 0, 5.6), "look_at": Vector3(-1.0, 1.2, -1.0), "act": "hud"}, + {"dur": 1.8, "move_to": null, "look_at": null, "act": "hud"}, + {"dur": 1.8, "move_to": null, "look_at": null, "act": "hud"}, + {"dur": 1.8, "move_to": null, "look_at": null, "act": "hud"}, ] +## Total speed across every physics body in the level. During the settle act nobody has +## touched anything, so this MUST fall to ~0 — that is the objective version of "is the +## level quietly falling over on its own before the player does anything". +func _motion(verbose := false) -> float: + var total := 0.0 + var seen := {} + var worst: Array = [] + for g in ["smashable", "debris"]: # every body is in one of these two + for n in get_tree().get_nodes_in_group(g): + if seen.has(n) or not (n is RigidBody3D): + continue + seen[n] = true + var b := n as RigidBody3D + if b.freeze: + continue + var v := b.linear_velocity.length() + total += v + worst.append([v, b]) + if verbose: + worst.sort_custom(func(a, c): return a[0] > c[0]) + for i in mini(6, worst.size()): + var b: RigidBody3D = worst[i][1] + var what := "RigidBody3D" + if b is Record: + what = "Record(sleeve %s)" % (b as Record).sleeve_genre + elif b is Smashable: + what = "Smashable(%s)" % (b as Smashable).kind + var groups := "" + for g in b.get_groups(): + groups += str(g) + " " + print(" %7.1f m/s %-18s %-22s parent=%s groups=[%s] at %s" % [ + worst[i][0], b.name, what, b.get_parent().name, groups.strip_edges(), + b.global_position.snappedf(0.01)]) + return total + func _process(dt: float) -> void: if _player == null or _step >= _script.size(): return + if _frames < 3: + _frames += 1 + if _frames == 2: + print("[settle] FIRST FRAME — where things start:") + _motion(true) + if _t < 6.0 and int(_t) != int(_t + dt): + print("[settle] t=%ds total body speed = %.2f m/s" % [int(_t + dt), _motion(true)]) _t += dt var s: Dictionary = _script[_step] var dur: float = s["dur"] diff --git a/game/scripts/Hud.gd b/game/scripts/Hud.gd index 0c4d4b0..a78aa71 100644 --- a/game/scripts/Hud.gd +++ b/game/scripts/Hud.gd @@ -292,7 +292,7 @@ func _tick_workorder() -> void: _w_head.text = "MONSTER ROBOT PARTY · WORK ORDER #%04d" % int(_g("order_no", 4471)) var tally: Dictionary = _g("tally", {}) var lines := PackedStringArray() - lines.append("SITE: LEVEL 01 — THE RECORD STORE") + lines.append("SITE: LEVEL 01 — BRANCH OFFICE, 2ND FLOOR") lines.append("TOOL: %s" % str(_g("weapon", "—"))) lines.append("") lines.append("ITEM QTY") diff --git a/game/scripts/Main.gd b/game/scripts/Main.gd index 3aaf6c1..845e3dd 100644 --- a/game/scripts/Main.gd +++ b/game/scripts/Main.gd @@ -1,16 +1,17 @@ extends Node3D -## Destroyulator — cascade prototype. +## Destroyulator — LEVEL 01, the office. ## -## Builds a little record rack out of primitives and lets you smash it. The point -## isn't the art (that's a one-line swap for your real .glb racks later) — it's to -## prove two things on your actual M3, today: -## 1. THE DAY-0 GATE: press S to rain 500 rigid bodies and watch the FPS hold. -## 2. THE CASCADE: smash a frozen shelf -> the crates on it fall -> jackets spill -## -> records tumble out -> records crack when they hit the floor (brittle). +## Main is the glue: it builds the level shell (Office), spawns everything SMASHABLE into +## it, owns score/tally, and routes each Smashable's three outcomes (break / dent / +## futile) to Juice and the HUD. ## -## Controls: WASD move · Space jump · L-click punch · R-click kick · Esc release mouse -## · B = rain 500 (stress gate) · R = reset +## Two things it still proves, from the prototype days: +## THE DAY-0 GATE: press B to rain 500 rigid bodies and watch the FPS hold. +## THE CASCADE: smash a frozen desk -> the monitor on it falls; smash a crate -> +## the records spill -> a record cracks a beat later when it lands. +## +## Controls: see KEYS_LINE below, or the Dev HUD (H cycles HUD styles). @onready var _cam: Camera3D var _world: Node3D # everything smashable/debris lives here so reset is one line @@ -29,6 +30,7 @@ var _juice: Juice var _player: Player # kept so GameMode can reach player.grab var _records: Array[Record] = [] # the live records, handed to GameMode each round var _game_mode: GameMode +var _office: Office # the level shell: walls, fittings, lighting func _ready() -> void: randomize() @@ -36,7 +38,8 @@ func _ready() -> void: _juice = Juice.new() add_child(_juice) _juice.setup(_cam) # _setup_world() set _cam to the player's camera - _build_rack(Vector3.ZERO) + _populate() + _spawn_guard = SPAWN_GUARD_TIME # rules layer: starts in FreePlay; keys 1/2 switch, F reports in FindMisfiled _game_mode = GameMode.new() @@ -48,47 +51,27 @@ func _ready() -> void: # ---------------------------------------------------------------- world / camera func _setup_world() -> void: + # The level shell: floor, walls, ceiling, windows, fittings and ALL the lighting. + # It owns the environment too, because interior lighting and the ambient/tonemap + # settings are one decision, not two. + _office = Office.new() + add_child(_office) + _office.build() + var we := WorldEnvironment.new() var env := Environment.new() - env.background_mode = Environment.BG_COLOR - env.background_color = Color(0.07, 0.06, 0.09) - env.ambient_light_source = Environment.AMBIENT_SOURCE_COLOR - env.ambient_light_color = Color(0.5, 0.5, 0.62) - env.ambient_light_energy = 0.6 + _office.configure_environment(env) we.environment = env add_child(we) - var sun := DirectionalLight3D.new() - sun.rotation_degrees = Vector3(-52, -38, 0) - sun.light_energy = 1.3 - sun.shadow_enabled = true - add_child(sun) - - # First-person player replaces the old fixed camera. add_child() runs its _ready() - # synchronously, so player.camera/grab exist on the next line; we reuse them. + # First-person player. add_child() runs its _ready() synchronously, so player.camera + # and player.grab exist on the next line; we reuse them. _player = Player.new() add_child(_player) - _player.global_position = Vector3(0, 0, 4) # stand back, facing -Z toward the rack + _player.global_position = _office.spawn_point() + _player.rotation.y = _office.spawn_yaw() _cam = _player.camera - # floor - var floor_body := StaticBody3D.new() - var fmesh := MeshInstance3D.new() - var plane := BoxMesh.new() - plane.size = Vector3(24, 0.2, 24) - fmesh.mesh = plane - var fmat := StandardMaterial3D.new() - fmat.albedo_color = Color(0.13, 0.12, 0.15) - fmesh.material_override = fmat - floor_body.add_child(fmesh) - var fcol := CollisionShape3D.new() - var fshape := BoxShape3D.new() - fshape.size = plane.size - fcol.shape = fshape - floor_body.add_child(fcol) - floor_body.position = Vector3(0, -0.1, 0) - add_child(floor_body) - _world = Node3D.new() _world.name = "World" add_child(_world) @@ -109,6 +92,14 @@ const CABINET_GLB := "res://assets/store/filing-cabinet.glb" const COOLER_GLB := "res://assets/store/water-cooler.glb" const BOX_GLB := "res://assets/store/cardboard-box.glb" const TURNTABLE_GLB := "res://assets/store/turntable.glb" +const CHAIR_GLB := "res://assets/store/office-chair.glb" + +## Mass by material, so a thrown record can't tip a filing cabinet but a sledgehammer +## still can. Everything defaulted to 1 kg before, which is why the level fell over. +const MASSES := { + "paper": 0.3, "cardboard": 1.2, "plastic": 6.0, "vinyl": 0.6, + "wood": 18.0, "glass": 12.0, "steel": 40.0, +} # Generated sleeve art (Nano Banana): each file is a 3x3 sheet of nine original # fictional album covers. A record picks one tile at random via uv1 scale/offset — @@ -120,56 +111,82 @@ const SLEEVE_ATLASES: Array[String] = [ var _sleeve_textures: Array[Texture2D] = [] var _records_skinned := 0 -func _build_rack(origin: Vector3) -> void: +## Fill the office with the SMASHABLE half of the level. The Office class owns the shell +## and the static fittings; everything spawned here is a rigid body you can wreck. +func _populate() -> void: _records.clear() # stale refs from the freed world; repopulated by _place_record - # two racks form a smashable back wall of the booth - _glb_piece(RACK_GLB, "wood", Vector2(origin.x - 0.95, origin.z - 0.7), true) - _glb_piece(RACK_GLB, "wood", Vector2(origin.x + 0.95, origin.z - 0.7), true) - # crates of records on the floor in front, in two rows - var spots := [ - Vector2(-0.8, 0.5), Vector2(0.0, 0.5), Vector2(0.8, 0.5), - Vector2(-0.4, 1.2), Vector2(0.4, 1.2), - ] - for spot in spots: - var xz: Vector2 = spot + Vector2(origin.x, origin.z) - var crate := _glb_piece(CRATE_GLB, "wood", xz, false) - var crate_top: float = crate["top"] - # a few records stacked on the crate; smashing the crate spills them, and each - # one is now a grabbable Record (sleeve + hidden disc), not a one-hit prop - for i in range(3): - var jitter := Vector2(randf_range(-0.06, 0.06), randf_range(-0.06, 0.06)) - var rec := _place_record(xz + jitter, crate_top + float(i) * 0.03) - (crate["piece"] as Smashable).supports.append(rec) - print("[art] records skinned with sleeve art: ", _records_skinned) - _build_office(origin) + # --- the bullpen: a desk at every cluster spot, each with a monitor on it --- + var spots := _office.desk_spots() + for i in spots.size(): + var t: Transform3D = spots[i] + var xz := Vector2(t.origin.x, t.origin.z) + var desk := _glb_piece(DESK_GLB, "wood", xz, true, 0.0, t.basis.get_euler().y) + var top: float = desk["top"] + var crt := _glb_piece(CRT_GLB, "glass", xz + Vector2(0.0, 0.10), false, top) + (desk["piece"] as Smashable).supports.append(crt["piece"]) + # Chair goes behind the desk, offset by the desk's OWN measured depth. Office.gd + # used to guess a constant here and kept putting chairs inside desks (or, once + # pushed out far enough to clear them, inside each other across the aisle). + var depth: float = (desk["aabb"] as AABB).size.z + var back := signf(t.origin.z - _office.CLUSTERS[i / 2].y) + if is_zero_approx(back): + back = 1.0 + _glb_piece(CHAIR_GLB, "plastic", xz + Vector2(0.0, back * (depth * 0.5 + 0.42)), + false, 0.0, t.basis.get_euler().y) -## Lane 2's workplace props scattered as furniture, with the office PRINTER as the level -## boss on its desk (soaks several hits, dies in a bigger burst). Each of these ships a -## .fractured.glb, so _glb_piece auto-wires real chunk destruction (see there). -func _build_office(origin: Vector3) -> void: - var o := Vector2(origin.x, origin.z) - # the boss: a printer on a desk. Desk is a frozen support; smashing it drops the printer. - var desk := _glb_piece(DESK_GLB, "wood", o + Vector2(2.7, -0.3), true) - var printer := _glb_piece(PRINTER_GLB, "steel", o + Vector2(2.7, -0.3), false, desk["top"]) + # --- the copier alcove: the PRINTER is the level boss, on its own desk --- + var cs := _office.copier_spot() + var cxz := Vector2(cs.origin.x, cs.origin.z) + var cdesk := _glb_piece(DESK_GLB, "wood", cxz, true, 0.0, cs.basis.get_euler().y) + var printer := _glb_piece(PRINTER_GLB, "steel", cxz, false, cdesk["top"]) var boss := printer["piece"] as Smashable boss.is_boss = true boss.toughness_scale = 5.0 # steel x5 — a real fight for anything but the sledge boss.mass = 8.0 # heavy, so hits rock it but don't shove it off the desk - (desk["piece"] as Smashable).supports.append(printer["piece"]) + (cdesk["piece"] as Smashable).supports.append(printer["piece"]) - # furniture around the booth — floor props you can wreck into real chunks - _glb_piece(CABINET_GLB, "steel", o + Vector2(-2.7, -0.3), false) - _glb_piece(COOLER_GLB, "steel", o + Vector2(3.3, 1.6), false) - _glb_piece(CRT_GLB, "glass", o + Vector2(-2.7, 1.3), false) - _glb_piece(BOX_GLB, "cardboard", o + Vector2(1.9, 2.4), false) - _glb_piece(TURNTABLE_GLB, "wood", o + Vector2(-1.7, -1.3), false) + # --- filing cabinets down the wall by the copier, water coolers, cartons --- + for z in [-1.6, -0.9, -0.2]: + _glb_piece(CABINET_GLB, "steel", Vector2(4.5, z), false) + _glb_piece(COOLER_GLB, "steel", Vector2(-6.2, 3.4), false) + _glb_piece(COOLER_GLB, "steel", Vector2(5.9, -0.6), false) + # Cartons go on OPEN floor only. Tucking them under desks or against the conference + # table spawned them inside those colliders, and Jolt resolved the overlap by firing + # them across the room on frame one. + for c in [Vector2(-2.3, 5.2), Vector2(1.6, 5.4), Vector2(2.1, 4.7), + Vector2(6.4, -3.3), Vector2(7.3, -3.8), Vector2(-9.7, 1.2)]: + _glb_piece(BOX_GLB, "cardboard", c, false) + + # --- the warehouse corner: shelving, crates, and somebody's record collection. + # --- This is where the grab/slide/throw ritual still lives. + _glb_piece(RACK_GLB, "wood", Vector2(9.4, -6.6), true) + _glb_piece(RACK_GLB, "wood", Vector2(9.4, -4.3), true) + _glb_piece(TURNTABLE_GLB, "wood", Vector2(6.9, -5.9), false) + for spot in [Vector2(6.2, -6.6), Vector2(7.0, -6.9), Vector2(7.8, -6.6)]: + var crate := _glb_piece(CRATE_GLB, "wood", spot, false) + var crate_top: float = crate["top"] + # Records stand side by side ON the crate lid, offset along Z by more than a + # sleeve is thick. They used to be stacked 3 cm apart vertically while being + # 30 cm TALL, so Jolt resolved 27 cm of interpenetration explosively on frame + # one and shoved the surrounding furniture over before you touched anything. + for i in range(3): + var rec := _place_record(spot + Vector2(randf_range(-0.02, 0.02), + (float(i) - 1.0) * 0.045), crate_top) + (crate["piece"] as Smashable).supports.append(rec) + # --- chairs: the best thing in an office to send across the room --- + for t in _office.chair_spots(): + _glb_piece(CHAIR_GLB, "plastic", Vector2(t.origin.x, t.origin.z), false, 0.0, + t.basis.get_euler().y) + + print("[art] records skinned with sleeve art: ", _records_skinned) ## Spawn one grabbable Record (sleeve + nested disc) resting on `sit_on`. Mirrors ## _glb_piece's "drop the AABB bottom onto sit_on" trick, but the Record builds its own ## visuals/colliders/disc in _ready, so we just skin the sleeve and place it. func _place_record(xz: Vector2, sit_on: float) -> Record: var rec := Record.new() + rec.name = "record" rec.setup() var g: String = GameMode.GENRES[randi() % GameMode.GENRES.size()] rec.sleeve_genre = g @@ -189,10 +206,13 @@ func _place_record(xz: Vector2, sit_on: float) -> Record: ## Instance a GLB as the VISUAL of a Smashable, give it a box collider auto-sized to ## the mesh AABB, and drop it so its bottom rests at height `sit_on`. Returns ## { piece: Smashable, top: float } so a caller can stack the next thing on top. -func _glb_piece(path: String, kind: String, xz: Vector2, frozen: bool, sit_on := 0.0) -> Dictionary: +func _glb_piece(path: String, kind: String, xz: Vector2, frozen: bool, sit_on := 0.0, + yaw := 0.0) -> Dictionary: var s := Smashable.new() s.kind = kind s.start_frozen = frozen + s.mass = float(MASSES.get(kind, 5.0)) + s.name = path.get_file().get_basename() # so physics diagnostics name the culprit # real destruction: if Lane 2 shipped a .fractured.glb next to this GLB, use it var frac := path.get_basename() + ".fractured.glb" if ResourceLoader.exists(frac): @@ -203,6 +223,8 @@ func _glb_piece(path: String, kind: String, xz: Vector2, frozen: bool, sit_on := if kind == "vinyl": _skin_record(vis) # random sleeve art on the jacket faces _world.add_child(s) # in-tree so transforms/AABBs resolve + # AABB is measured BEFORE yaw so the collider stays axis-aligned in body space; the + # body is then rotated as a whole, which keeps box/mesh in agreement. var ab := _body_local_aabb(s, vis) if ab.size == Vector3.ZERO: ab = AABB(Vector3(-0.2, 0.0, -0.2), Vector3(0.4, 0.4, 0.4)) # fallback @@ -212,9 +234,11 @@ func _glb_piece(path: String, kind: String, xz: Vector2, frozen: bool, sit_on := col.shape = box col.position = ab.get_center() s.add_child(col) + s.rotation.y = yaw s.global_position = Vector3(xz.x, sit_on - ab.position.y, xz.y) # AABB bottom lands on sit_on + s.set_meta("spawn_pos", s.global_position) # for the spawn-guard warning _wire(s) - return {"piece": s, "top": sit_on + ab.size.y} + return {"piece": s, "top": sit_on + ab.size.y, "aabb": ab} ## Give a record's sleeve faces a random cover from the generated 3x3 sheets. ## The record.glb sleeve cube carries M_Sleeve_Front / M_Sleeve_Back materials @@ -316,6 +340,44 @@ func _piece(kind: String, size: Vector3, pos: Vector3, frozen: bool, cylinder := _wire(s) return s +# ---------------------------------------------------------------- spawn guard +## A prop that spawns even slightly inside another collider gets depenetrated by Jolt, +## and depenetration is not gentle: a chair overlapping a table left the building at +## 450 m/s on frame one. Placing 30-odd props by formula means this WILL happen again +## the next time a room is re-laid-out, so it's handled systemically rather than by +## nudging coordinates until the symptom goes away. +## +## For the first fraction of a second, dynamic bodies are speed-limited — enough for a +## real overlap to push apart calmly, far too little to launch anything. Each offender +## is named once in a warning, so the underlying overlap stays visible and fixable +## instead of being silently papered over. +const SPAWN_GUARD_TIME := 0.75 +const SPAWN_MAX_SPEED := 2.5 +const SPAWN_MAX_SPIN := 10.0 +var _spawn_guard := 0.0 +var _guard_warned := {} + +func _physics_process(dt: float) -> void: + if _spawn_guard <= 0.0: + return + _spawn_guard -= dt + for n in get_tree().get_nodes_in_group("smashable"): + var b := n as RigidBody3D + if b == null or b.freeze: + continue + var v := b.linear_velocity.length() + if v > SPAWN_MAX_SPEED: + if not _guard_warned.has(b): + _guard_warned[b] = true + # report where it was PLACED, not where it is now — at 500 m/s a body is + # already 8 m away by the time this runs, which points at nothing useful + var at = b.get_meta("spawn_pos", b.global_position) + push_warning("[spawn] %s placed overlapping something at %s (%.0f m/s) — clamped" % [ + b.name, (at as Vector3).snappedf(0.01), v]) + b.linear_velocity = b.linear_velocity.normalized() * SPAWN_MAX_SPEED + if b.angular_velocity.length() > SPAWN_MAX_SPIN: + b.angular_velocity = b.angular_velocity.normalized() * SPAWN_MAX_SPIN + func _on_smashed(kind: String, at: Vector3, shards: int) -> void: _smash_count += 1 _tally[kind] = int(_tally.get(kind, 0)) + 1 @@ -392,7 +454,7 @@ func _reset() -> void: _score = 0 _tally.clear() await get_tree().process_frame - _build_rack(Vector3.ZERO) + _populate() # re-arm whatever mode we're in against the fresh set of records if _game_mode != null: if _game_mode.mode == GameMode.Mode.FIND_MISFILED: diff --git a/game/scripts/Office.gd b/game/scripts/Office.gd new file mode 100644 index 0000000..5921101 --- /dev/null +++ b/game/scripts/Office.gd @@ -0,0 +1,454 @@ +extends Node3D +class_name Office + +## LEVEL 01 — the open-plan office. +## +## The prototype ran on a grey disc in a black void, which quietly broke the premise: a +## game about wrecking your workplace needs a workplace. This is that workplace, laid out +## after the Dunder Mifflin floor plan — the shape everyone already knows. +## +## z- (back) +## +--------------------------------------------------+ +## | MANAGER | CONFERENCE | | WAREHOUSE | +## | (glass) | | | door | +## |----------+---------------+ +-----------| +## | | | +## | B U L L P E N | BREAK | x+ +## | (4 facing desk pairs) | ROOM | +## | [copier] | | +## |----------+ +-----------| +## | RECEPTION| entrance | +## +--------------------------------------------------+ +## z+ (front / street) +## +## Walls, desks, partitions and counters are boxes built in code — they ARE boxes, so +## modelling them would be wasted effort. Anything with a silhouette a box can't fake +## (chairs, vending machines, the plant) comes from tools/gen_office_props.py. +## +## This script owns the SHELL and the FITTINGS: everything static and non-smashable, plus +## the lighting. Smashable furniture stays Main's business, so the two can be tuned +## independently — Main asks this class where things go via the `spot_*` helpers. +## +## Godot 4.7 GDScript 2.0. + +# ---------------------------------------------------------------- floor plan +const X_MIN := -11.0 +const X_MAX := 11.0 +const Z_BACK := -8.0 +const Z_FRONT := 8.0 +const H := 2.75 # drop ceiling +const WALL_T := 0.16 + +# interior room boundaries +const MGR_X := -6.6 # manager's office: X_MIN..MGR_X, Z_BACK..MGR_Z +const MGR_Z := -4.4 +const CONF_X0 := -6.6 # conference room +const CONF_X1 := -0.4 +const CONF_Z := -4.4 +const BREAK_X := 5.4 # break room: BREAK_X..X_MAX, BREAK_Z..Z_FRONT +const BREAK_Z := -1.2 +const RECEP_Z := 4.6 # reception partition + +const DOOR_W := 1.1 + +const P := "res://assets/store/" + +var _spots_desk: Array[Transform3D] = [] # where Main should put smashable desks +var _spots_chair: Array[Transform3D] = [] +var _spot_copier := Transform3D.IDENTITY + +# ---------------------------------------------------------------- materials +var _m_carpet: StandardMaterial3D +var _m_wall: StandardMaterial3D +var _m_ceil: StandardMaterial3D +var _m_trim: StandardMaterial3D +var _m_glass: StandardMaterial3D +var _m_part: StandardMaterial3D +var _m_wood: StandardMaterial3D + +func build() -> void: + _materials() + _shell() + _interior_walls() + _ceiling_grid() + _lights_rig() + _bullpen() + _reception() + _conference() + _manager() + _break_room() + _dressing() + +func _materials() -> void: + _m_carpet = StandardMaterial3D.new() + _m_carpet.albedo_color = Color(0.30, 0.30, 0.32) # the grey office carpet + _m_carpet.roughness = 1.0 + + _m_wall = StandardMaterial3D.new() + _m_wall.albedo_color = Color(0.80, 0.78, 0.72) # magnolia, of course + _m_wall.roughness = 0.96 + + _m_ceil = StandardMaterial3D.new() + _m_ceil.albedo_color = Color(0.88, 0.88, 0.86) + _m_ceil.roughness = 0.98 + + _m_trim = StandardMaterial3D.new() + _m_trim.albedo_color = Color(0.13, 0.12, 0.13) + _m_trim.roughness = 0.7 + + _m_part = StandardMaterial3D.new() + _m_part.albedo_color = Color(0.44, 0.44, 0.40) # cubicle partition fabric + _m_part.roughness = 1.0 + + _m_wood = StandardMaterial3D.new() + _m_wood.albedo_color = Color(0.42, 0.29, 0.17) + _m_wood.roughness = 0.55 + + _m_glass = StandardMaterial3D.new() + _m_glass.transparency = BaseMaterial3D.TRANSPARENCY_ALPHA + _m_glass.albedo_color = Color(0.66, 0.74, 0.78, 0.15) + _m_glass.roughness = 0.05 + _m_glass.cull_mode = BaseMaterial3D.CULL_DISABLED + +# ---------------------------------------------------------------- primitives +func _slab(size: Vector3, centre: Vector3, mat: Material, collide := true, + shadow := true) -> StaticBody3D: + var body := StaticBody3D.new() + var mi := MeshInstance3D.new() + var bm := BoxMesh.new() + bm.size = size + mi.mesh = bm + mi.material_override = mat + if not shadow: + mi.cast_shadow = GeometryInstance3D.SHADOW_CASTING_SETTING_OFF + body.add_child(mi) + if collide: + var col := CollisionShape3D.new() + var sh := BoxShape3D.new() + sh.size = size + col.shape = sh + body.add_child(col) + add_child(body) + body.position = centre + return body + +## A wall running along X (or Z) with a doorway punched in it. +func _wall_x(z: float, x0: float, x1: float, mat: Material, door_at := INF) -> void: + if door_at == INF: + _slab(Vector3(x1 - x0, H, WALL_T), Vector3((x0 + x1) * 0.5, H * 0.5, z), mat) + return + var d0 := door_at - DOOR_W * 0.5 + var d1 := door_at + DOOR_W * 0.5 + if d0 > x0: + _slab(Vector3(d0 - x0, H, WALL_T), Vector3((x0 + d0) * 0.5, H * 0.5, z), mat) + if x1 > d1: + _slab(Vector3(x1 - d1, H, WALL_T), Vector3((d1 + x1) * 0.5, H * 0.5, z), mat) + _slab(Vector3(DOOR_W, H - 2.05, WALL_T), Vector3(door_at, (H + 2.05) * 0.5, z), mat) + +func _wall_z(x: float, z0: float, z1: float, mat: Material, door_at := INF) -> void: + if door_at == INF: + _slab(Vector3(WALL_T, H, z1 - z0), Vector3(x, H * 0.5, (z0 + z1) * 0.5), mat) + return + var d0 := door_at - DOOR_W * 0.5 + var d1 := door_at + DOOR_W * 0.5 + if d0 > z0: + _slab(Vector3(WALL_T, H, d0 - z0), Vector3(x, H * 0.5, (z0 + d0) * 0.5), mat) + if z1 > d1: + _slab(Vector3(WALL_T, H, z1 - d1), Vector3(x, H * 0.5, (d1 + z1) * 0.5), mat) + _slab(Vector3(WALL_T, H - 2.05, DOOR_W), Vector3(x, (H + 2.05) * 0.5, door_at), mat) + +## Static set dressing from a GLB, with a box collider sized to its own mesh so you can't +## walk through the vending machine. +func _glb(path: String, pos: Vector3, yaw := 0.0) -> Node3D: + if not ResourceLoader.exists(path): + return null + var packed := load(path) as PackedScene + if packed == null: + return null + var body := StaticBody3D.new() + add_child(body) + body.position = pos + body.rotation.y = yaw + var n: Node3D = packed.instantiate() + body.add_child(n) + var ab := _mesh_aabb(n) + if ab.size != Vector3.ZERO: + var col := CollisionShape3D.new() + var sh := BoxShape3D.new() + sh.size = ab.size + col.shape = sh + col.position = ab.get_center() + body.add_child(col) + return body + +func _mesh_aabb(root: Node3D) -> AABB: + var acc := AABB() + var started := false + for m in _meshes(root): + var mi := m as MeshInstance3D + var a := mi.get_aabb() + a = mi.transform * a + if not started: + acc = a + started = true + else: + acc = acc.merge(a) + return acc + +func _meshes(n: Node, acc: Array = []) -> Array: + if n is MeshInstance3D: + acc.append(n) + for c in n.get_children(): + _meshes(c, acc) + return acc + +## Chairs are NOT placed here. They're the most satisfying thing in an office to send +## across the room, so they're spawned by Main as smashable rigid bodies; Office only +## says where they start. +func _chair(pos: Vector3, yaw: float) -> void: + _spots_chair.append(Transform3D(Basis(Vector3.UP, yaw), pos)) + +# ---------------------------------------------------------------- shell +func _shell() -> void: + var w := X_MAX - X_MIN + var d := Z_FRONT - Z_BACK + var cx := (X_MIN + X_MAX) * 0.5 + var cz := (Z_BACK + Z_FRONT) * 0.5 + _slab(Vector3(w + 1.0, 0.30, d + 1.0), Vector3(cx, -0.15, cz), _m_carpet) + # outer walls; the +X wall is the window wall, so it's built in _windows() + _wall_x(Z_BACK - WALL_T * 0.5, X_MIN, X_MAX, _m_wall) + _wall_x(Z_FRONT + WALL_T * 0.5, X_MIN, X_MAX, _m_wall, -8.6) # entrance + _wall_z(X_MIN - WALL_T * 0.5, Z_BACK, Z_FRONT, _m_wall) + _windows() + +## The window wall. Dunder Mifflin's bullpen has that whole run of blinded windows down +## one side, and it's what stops an interior reading as a sealed box. +func _windows() -> void: + var x := X_MAX + WALL_T * 0.5 + var y0 := 0.85 + var y1 := 2.35 + _slab(Vector3(WALL_T, y0, Z_FRONT - Z_BACK), Vector3(x, y0 * 0.5, + (Z_BACK + Z_FRONT) * 0.5), _m_wall) + _slab(Vector3(WALL_T, H - y1, Z_FRONT - Z_BACK), Vector3(x, (H + y1) * 0.5, + (Z_BACK + Z_FRONT) * 0.5), _m_wall) + # mullions every 2.4 m, glazing between + var z := Z_BACK + while z < Z_FRONT - 0.1: + var z1: float = minf(z + 2.4, Z_FRONT) + _slab(Vector3(0.05, y1 - y0, z1 - z - 0.12), Vector3(X_MAX - 0.02, + (y0 + y1) * 0.5, (z + z1) * 0.5), _m_glass, false, false) + _slab(Vector3(WALL_T, y1 - y0, 0.12), Vector3(x, (y0 + y1) * 0.5, z1), _m_trim) + # venetian blind, half-raised + _slab(Vector3(0.06, 0.55, z1 - z - 0.14), Vector3(X_MAX - 0.10, y1 - 0.28, + (z + z1) * 0.5), _m_ceil, false, false) + z = z1 + +func _ceiling_grid() -> void: + var w := X_MAX - X_MIN + var d := Z_FRONT - Z_BACK + var cx := (X_MIN + X_MAX) * 0.5 + var cz := (Z_BACK + Z_FRONT) * 0.5 + _slab(Vector3(w, 0.16, d), Vector3(cx, H + 0.08, cz), _m_ceil, true, false) + # suspended-tile T-bar, purely visual — it's the texture of an office ceiling + var gx := X_MIN + while gx <= X_MAX + 0.01: + _slab(Vector3(0.05, 0.03, d), Vector3(gx, H - 0.02, cz), _m_trim, false, false) + gx += 1.22 + var gz := Z_BACK + while gz <= Z_FRONT + 0.01: + _slab(Vector3(w, 0.03, 0.05), Vector3(cx, H - 0.02, gz), _m_trim, false, false) + gz += 1.22 + +# ---------------------------------------------------------------- interior walls +func _interior_walls() -> void: + # manager's office — half solid, half glass so you can be watched through it + _wall_x(MGR_Z, X_MIN, MGR_X, _m_wall, -9.2) + _slab(Vector3(WALL_T, 1.0, MGR_Z - Z_BACK), Vector3(MGR_X, 0.5, + (Z_BACK + MGR_Z) * 0.5), _m_wall) + _slab(Vector3(0.06, H - 1.05, MGR_Z - Z_BACK), Vector3(MGR_X, (H + 1.0) * 0.5, + (Z_BACK + MGR_Z) * 0.5), _m_glass, true, false) + + # conference room + _wall_x(CONF_Z, CONF_X0, CONF_X1, _m_wall, -3.4) + _wall_z(CONF_X1, Z_BACK, CONF_Z, _m_wall) + + # break room + _wall_z(BREAK_X, BREAK_Z, Z_FRONT, _m_wall, 2.2) + _wall_x(BREAK_Z, BREAK_X, X_MAX, _m_wall) + + # warehouse roller door on the back wall + _slab(Vector3(2.6, 2.4, 0.12), Vector3(7.8, 1.2, Z_BACK + 0.06), _m_trim) + for i in range(9): + _slab(Vector3(2.5, 0.06, 0.05), Vector3(7.8, 0.18 + i * 0.26, + Z_BACK + 0.14), _m_ceil, false, false) + +# ---------------------------------------------------------------- lighting +## Recessed fluorescent troffers in the ceiling grid. These ARE the light: the old scene +## lit everything with one outdoor directional lamp, which is exactly why it read as +## "props on a plane" rather than "inside somewhere". +func _lights_rig() -> void: + var panel := StandardMaterial3D.new() + panel.albedo_color = Color(0.97, 0.97, 0.93) + panel.emission_enabled = true + panel.emission = Color(1.0, 0.98, 0.92) + panel.emission_energy_multiplier = 1.5 + + var xs := [-8.5, -4.6, -0.7, 3.2, 7.1] + var zs := [-6.2, -2.6, 1.0, 4.6] + for xc in xs: + for zc in zs: + var mi := MeshInstance3D.new() + var bm := BoxMesh.new() + bm.size = Vector3(1.14, 0.05, 0.58) + mi.mesh = bm + mi.material_override = panel + mi.cast_shadow = GeometryInstance3D.SHADOW_CASTING_SETTING_OFF + add_child(mi) + mi.position = Vector3(xc, H - 0.06, zc) + + var l := OmniLight3D.new() + l.light_color = Color(1.0, 0.98, 0.93) + l.light_energy = 1.9 + l.omni_range = 6.5 + l.omni_attenuation = 1.2 + l.shadow_enabled = false # 20 shadow-casting omnis is not worth the cost + add_child(l) + l.position = Vector3(xc, H - 0.20, zc) + + # two shadow-casters so props still sit in contact shadows + for zc in [-2.0, 3.0]: + var key := OmniLight3D.new() + key.light_color = Color(1.0, 0.97, 0.92) + key.light_energy = 1.5 + key.omni_range = 13.0 + key.shadow_enabled = true + add_child(key) + key.position = Vector3(-1.0, H - 0.30, zc) + + # daylight through the window wall + var sun := DirectionalLight3D.new() + sun.light_color = Color(0.82, 0.88, 1.0) + sun.light_energy = 0.7 + sun.rotation_degrees = Vector3(-30, -104, 0) + sun.shadow_enabled = true + add_child(sun) + +func configure_environment(env: Environment) -> void: + env.background_mode = Environment.BG_COLOR + env.background_color = Color(0.55, 0.62, 0.72) # daylight past the glass + env.ambient_light_source = Environment.AMBIENT_SOURCE_COLOR + env.ambient_light_color = Color(0.50, 0.50, 0.50) + env.ambient_light_energy = 0.5 + env.ssao_enabled = true + env.ssao_radius = 0.8 + env.ssao_intensity = 1.5 + env.tonemap_mode = Environment.TONE_MAPPER_FILMIC + env.tonemap_exposure = 1.0 + +# ---------------------------------------------------------------- bullpen +## Four pairs of desks facing each other across a low partition — the Jim-and-Dwight +## arrangement, which is the single most recognisable thing about the floor plan. +## Rows are 4.8 m apart, not 3.6. At 3.6 the two rows' chairs met back-to-back in the +## middle of the aisle with 3 cm to spare, which Jolt resolved by firing them out of the +## building — and it left no room to walk between the rows either. +const CLUSTERS := [ + Vector2(-4.6, -2.0), Vector2(-4.6, 2.8), + Vector2(-0.4, -2.0), Vector2(-0.4, 2.8), +] + +func _bullpen() -> void: + for c in CLUSTERS: + _partition(Vector3(c.x, 0.0, c.y), 1.9) + for s in [-1.0, 1.0]: + var t := Transform3D(Basis(Vector3.UP, 0.0 if s > 0.0 else PI), + Vector3(c.x, 0.0, c.y + s * 0.78)) + _spots_desk.append(t) + # NOTE: the bullpen chairs are NOT listed here. Their offset depends on how + # deep office-desk.glb actually is, which only Main knows once it has measured + # the mesh — guessing a constant here put chairs inside desks. + # the copier alcove, between the bullpen and the break room + _slab(Vector3(WALL_T, H, 2.6), Vector3(3.6, H * 0.5, -0.3), _m_wall) + _spot_copier = Transform3D(Basis(Vector3.UP, deg_to_rad(-90.0)), + Vector3(3.0, 0.0, -0.3)) + +## A cubicle divider: fabric panel on a dark base rail. +func _partition(at: Vector3, length: float) -> void: + _slab(Vector3(length, 1.18, 0.07), at + Vector3(0, 0.62, 0), _m_part) + _slab(Vector3(length + 0.06, 0.09, 0.11), at + Vector3(0, 1.24, 0), _m_trim) + for s in [-1.0, 1.0]: + _slab(Vector3(0.09, 1.24, 0.30), at + Vector3(s * length * 0.5, 0.62, 0), _m_trim) + +func desk_spots() -> Array[Transform3D]: + return _spots_desk + +func chair_spots() -> Array[Transform3D]: + return _spots_chair + +func copier_spot() -> Transform3D: + return _spot_copier + +# ---------------------------------------------------------------- rooms +func _reception() -> void: + # the counter you meet on the way in, with the waiting-area chairs + _slab(Vector3(0.70, 1.10, 3.0), Vector3(-9.9, 0.55, RECEP_Z + 1.0), _m_wood) + _slab(Vector3(0.92, 0.08, 3.2), Vector3(-9.9, 1.14, RECEP_Z + 1.0), _m_trim) + _slab(Vector3(1.8, 1.10, 0.70), Vector3(-9.6, 0.55, RECEP_Z - 0.15), _m_wood) + _wall_z(-6.9, RECEP_Z, Z_FRONT, _m_wall, 6.8) + for i in range(3): + _chair(Vector3(-7.6, 0.0, 5.5 + i * 0.85), deg_to_rad(-90)) + _glb(P + "office-plant.glb", Vector3(-6.4, 0.0, 6.6)) + +func _conference() -> void: + var cx := (CONF_X0 + CONF_X1) * 0.5 + var cz := (Z_BACK + CONF_Z) * 0.5 + # the long table everyone dreads + _slab(Vector3(3.9, 0.09, 1.35), Vector3(cx, 0.74, cz), _m_wood) + for s in [-1.0, 1.0]: + _slab(Vector3(0.16, 0.72, 0.90), Vector3(cx + s * 1.6, 0.36, cz), _m_trim) + for i in range(4): + var x := cx - 1.35 + i * 0.9 + _chair(Vector3(x, 0.0, cz - 1.15), 0.0) + _chair(Vector3(x, 0.0, cz + 1.15), PI) + # whiteboard + _slab(Vector3(2.4, 1.15, 0.05), Vector3(cx, 1.6, Z_BACK + 0.10), _m_ceil) + _slab(Vector3(2.5, 1.25, 0.03), Vector3(cx, 1.6, Z_BACK + 0.07), _m_trim) + +func _manager() -> void: + var cx := (X_MIN + MGR_X) * 0.5 + var cz := (Z_BACK + MGR_Z) * 0.5 + _chair(Vector3(cx, 0.0, cz - 0.9), 0.0) + _chair(Vector3(cx - 0.8, 0.0, cz + 1.1), PI) + _glb(P + "office-plant.glb", Vector3(X_MIN + 0.7, 0.0, MGR_Z - 0.8)) + +func _break_room() -> void: + var cz := (BREAK_Z + Z_FRONT) * 0.5 + # kitchen counter along the window wall + _slab(Vector3(0.62, 0.88, 3.4), Vector3(X_MAX - 0.42, 0.44, cz + 0.6), _m_wood) + _slab(Vector3(0.70, 0.06, 3.5), Vector3(X_MAX - 0.42, 0.90, cz + 0.6), _m_trim) + _glb(P + "microwave.glb", Vector3(X_MAX - 0.45, 0.93, cz + 1.7), deg_to_rad(-90)) + _glb(P + "vending-machine.glb", Vector3(BREAK_X + 0.9, 0.0, Z_FRONT - 0.6), PI) + _glb(P + "vending-machine.glb", Vector3(BREAK_X + 1.9, 0.0, Z_FRONT - 0.6), PI) + # two round tables with chairs + for i in range(2): + var tx := 7.4 + var tz := BREAK_Z + 1.6 + i * 2.6 + _slab(Vector3(1.05, 0.07, 1.05), Vector3(tx, 0.73, tz), _m_ceil) + _slab(Vector3(0.12, 0.70, 0.12), Vector3(tx, 0.36, tz), _m_trim) + _slab(Vector3(0.62, 0.05, 0.62), Vector3(tx, 0.03, tz), _m_trim) + for a in range(3): + var ang := deg_to_rad(a * 120.0 + 40.0) + _chair(Vector3(tx + sin(ang) * 0.95, 0.0, tz + cos(ang) * 0.95), ang + PI) + +func _dressing() -> void: + _glb(P + "office-plant.glb", Vector3(2.9, 0.0, 6.4)) + _glb(P + "office-plant.glb", Vector3(-0.9, 0.0, -3.6)) + # wall clock, because every office has one you stare at + _slab(Vector3(0.42, 0.42, 0.05), Vector3(-3.4, 2.15, Z_FRONT - 0.02), _m_ceil) + _slab(Vector3(0.48, 0.48, 0.03), Vector3(-3.4, 2.15, Z_FRONT - 0.01), _m_trim) + +## Where the player should start: just inside the entrance, looking into the bullpen. +func spawn_point() -> Vector3: + return Vector3(-8.6, 0.0, 7.2) + +func spawn_yaw() -> float: + return deg_to_rad(196.0) diff --git a/game/scripts/Office.gd.uid b/game/scripts/Office.gd.uid new file mode 100644 index 0000000..5794565 --- /dev/null +++ b/game/scripts/Office.gd.uid @@ -0,0 +1 @@ +uid://btc0q0j2wj0bs diff --git a/game/scripts/Player.gd b/game/scripts/Player.gd index a4377dc..5fb6a26 100644 --- a/game/scripts/Player.gd +++ b/game/scripts/Player.gd @@ -23,6 +23,8 @@ class_name Player @export var mouse_sensitivity: float = 0.0025 # radians per pixel of mouse motion @export var pitch_limit_deg: float = 89.0 @export var eye_height: float = 1.6 +## How far below the eye a swing actually starts (see _strike). +const SWING_DROP := 0.32 var camera: Camera3D # Main reads this for the crosshair raycast var grab: GrabController # the record grab/extract/throw hands @@ -246,21 +248,36 @@ func _process(dt: float) -> void: _look_delta = _look_delta.lerp(Vector2.ZERO, clampf(dt * 14.0, 0.0, 1.0)) # ---------------------------------------------------------------- the hit -## Forgiving SPHERE query from the camera centre (the crosshair), so melee doesn't need +## Forgiving CAPSULE sweep from the camera along the crosshair, so melee doesn't need ## pixel aim. intersect_shape is NOT distance-sorted, so pick the nearest collider. +## +## This used to be a sphere parked AT `reach`, which meant anything CLOSER than the +## weapon's reach fell in front of the test and was missed completely — you could stand +## against the printer with a sledgehammer and swing through it. A capsule spanning +## camera -> camera + dir*reach covers the whole swing instead of just its far end. +## ## Runs from _physics_process, where direct_space_state is valid. func _strike(w: Weapon) -> Node: var space := get_world_3d().direct_space_state if space == null: return null - var origin := camera.global_position + # Swing from roughly where the hands are, not from the eyeballs. With eyes at 1.6 m, + # a carton sitting on the floor is ~1.5 m away even when you're standing right over + # it, so a short-reach weapon could never touch anything on the ground. Dropping the + # origin to hand height fixes that without inflating every weapon's reach. + var origin := camera.global_position - Vector3(0.0, SWING_DROP, 0.0) var dir := -camera.global_transform.basis.z - var sphere := SphereShape3D.new() - sphere.radius = w.radius + var cap := CapsuleShape3D.new() + cap.radius = w.radius + cap.height = maxf(w.reach, w.radius * 2.0 + 0.01) # total height, caps included + # CapsuleShape3D runs along its local Y, so build a basis whose Y is the view dir + var ref := Vector3.UP if absf(dir.dot(Vector3.UP)) < 0.95 else Vector3.RIGHT + var bx := ref.cross(dir).normalized() + var bz := bx.cross(dir).normalized() var params := PhysicsShapeQueryParameters3D.new() - params.shape = sphere - params.transform = Transform3D(Basis.IDENTITY, origin + dir * w.reach) + params.shape = cap + params.transform = Transform3D(Basis(bx, dir, bz), origin + dir * (w.reach * 0.5)) params.collide_with_bodies = true params.collide_with_areas = false params.exclude = [get_rid()] diff --git a/game/scripts/Record.gd b/game/scripts/Record.gd index e729097..43f9763 100644 --- a/game/scripts/Record.gd +++ b/game/scripts/Record.gd @@ -109,6 +109,7 @@ func _split_glb() -> void: # --- disc: its own frozen vinyl Smashable that lives in the world and follows us --- _disc = Smashable.new() + _disc.name = "disc" _disc.kind = "vinyl" _disc.start_frozen = false # we drive freeze ourselves (kinematic follow) _disc.add_to_group("disc") diff --git a/tools/gen_office_props.py b/tools/gen_office_props.py new file mode 100644 index 0000000..1c42742 --- /dev/null +++ b/tools/gen_office_props.py @@ -0,0 +1,321 @@ +"""Generate the office props Godot primitives can't fake, as GLBs, in Blender. + +The office level builds its walls, desks, partitions and counters from boxes in code — +those ARE boxes, so modelling them is wasted effort. These four aren't: an office chair, +a vending machine, a microwave and a potted plant all have silhouettes that a box reads +as obviously wrong, and all four are things you instantly recognise in a workplace. + + /Applications/Blender.app/Contents/MacOS/Blender --background \ + --python tools/gen_office_props.py -- [--render] + +Convention (same as the rest of the repo): glTF Y-up, 1 unit = 1 m, ORIGIN AT +FLOOR-CENTRE, so Office.gd can drop a prop at a floor position with no offset maths. +In Blender that means authoring Z-up with the base sitting on z = 0. +""" + +import bpy +import math +import os +import sys +from mathutils import Vector, Matrix + +OUT_DIR = os.path.join( + os.path.dirname(os.path.dirname(os.path.abspath(__file__))), + "game", "assets", "store") +PREVIEW_DIR = os.path.join(os.path.dirname(os.path.abspath(__file__)), "previews") +RENDER = "--render" in sys.argv + + +def reset(): + bpy.ops.wm.read_factory_settings(use_empty=True) + + +def mat(name, color, rough=0.6, metal=0.0, alpha=1.0): + m = bpy.data.materials.new(name) + m.use_nodes = True + b = m.node_tree.nodes["Principled BSDF"] + b.inputs["Base Color"].default_value = (color[0], color[1], color[2], alpha) + b.inputs["Roughness"].default_value = rough + b.inputs["Metallic"].default_value = metal + if alpha < 1.0: + b.inputs["Alpha"].default_value = alpha + m.blend_method = 'BLEND' + return m + + +def assign(o, m): + o.data.materials.clear() + o.data.materials.append(m) + return o + + +def box(size, loc=(0, 0, 0), rot=(0, 0, 0)): + bpy.ops.mesh.primitive_cube_add(size=1.0, location=loc, rotation=rot) + o = bpy.context.active_object + o.scale = (size[0], size[1], size[2]) + bpy.ops.object.transform_apply(scale=True) + return o + + +def cyl(r, depth, loc=(0, 0, 0), rot=(0, 0, 0), verts=16, r2=None): + if r2 is None: + bpy.ops.mesh.primitive_cylinder_add(radius=r, depth=depth, vertices=verts, + location=loc, rotation=rot) + else: + bpy.ops.mesh.primitive_cone_add(radius1=r, radius2=r2, depth=depth, + vertices=verts, location=loc, rotation=rot) + return bpy.context.active_object + + +def ball(r, loc=(0, 0, 0), segs=12, rings=8): + bpy.ops.mesh.primitive_uv_sphere_add(radius=r, segments=segs, ring_count=rings, + location=loc) + return bpy.context.active_object + + +def bevel(o, width=0.008, segments=2): + m = o.modifiers.new("bevel", "BEVEL") + m.width = width + m.segments = segments + m.limit_method = 'ANGLE' + m.angle_limit = math.radians(40) + bpy.context.view_layer.objects.active = o + try: + bpy.ops.object.modifier_apply(modifier=m.name) + except Exception: + o.modifiers.remove(m) + return o + + +def shade_smooth(o, angle=35.0): + bpy.context.view_layer.objects.active = o + o.select_set(True) + try: + bpy.ops.object.shade_auto_smooth(angle=math.radians(angle)) + except Exception: + bpy.ops.object.shade_smooth() + o.select_set(False) + + +# ---------------------------------------------------------------- props + +def p_chair(M): + """Task chair: 5-star base, gas lift, seat, backrest, arms. ~1.05 m tall.""" + parts = [] + # star base + castors + for i in range(5): + a = math.radians(i * 72.0) + d = Vector((math.cos(a), math.sin(a), 0.0)) + arm = box((0.055, 0.30, 0.035), loc=tuple(d * 0.16 + Vector((0, 0, 0.055))), + rot=(0, 0, a + math.radians(90))) + parts.append(assign(bevel(arm, 0.010), M["plastic_dark"])) + w = cyl(0.030, 0.022, loc=tuple(d * 0.30 + Vector((0, 0, 0.030))), + rot=(math.radians(90), 0, a), verts=12) + parts.append(assign(w, M["rubber"])) + hub = cyl(0.055, 0.06, loc=(0, 0, 0.075), verts=16) + parts.append(assign(hub, M["plastic_dark"])) + # gas cylinder + col = cyl(0.030, 0.24, loc=(0, 0, 0.22), verts=14) + parts.append(assign(col, M["steel"])) + shroud = cyl(0.042, 0.16, loc=(0, 0, 0.18), r2=0.034, verts=14) + parts.append(assign(shroud, M["plastic_dark"])) + # seat pan + seat = box((0.46, 0.44, 0.075), loc=(0, 0, 0.375)) + parts.append(assign(bevel(seat, 0.028, 3), M["fabric"])) + # backrest, reclined + back = box((0.44, 0.070, 0.50), loc=(0, -0.20, 0.70), + rot=(math.radians(-11), 0, 0)) + parts.append(assign(bevel(back, 0.026, 3), M["fabric"])) + spine = box((0.07, 0.09, 0.20), loc=(0, -0.185, 0.47)) + parts.append(assign(bevel(spine, 0.012), M["plastic_dark"])) + # armrests + for s in (-1, 1): + post = box((0.04, 0.05, 0.16), loc=(s * 0.245, -0.03, 0.475)) + parts.append(assign(bevel(post, 0.010), M["plastic_dark"])) + pad = box((0.06, 0.26, 0.035), loc=(s * 0.245, 0.01, 0.565)) + parts.append(assign(bevel(pad, 0.014, 3), M["plastic_dark"])) + return parts + + +def p_vending(M): + """Drinks machine, 1.83 m. Glass front so it reads as a vending machine, not a box.""" + parts = [] + shell = box((0.90, 0.78, 1.83), loc=(0, 0, 0.915)) + parts.append(assign(bevel(shell, 0.014, 2), M["vend_red"])) + glass = box((0.62, 0.03, 1.28), loc=(-0.10, -0.395, 1.02)) + parts.append(assign(glass, M["glass"])) + frame = box((0.68, 0.05, 1.36), loc=(-0.10, -0.375, 1.02)) + parts.append(assign(bevel(frame, 0.008), M["plastic_dark"])) + # stacked cans behind the glass + for row in range(5): + for c in range(4): + can = cyl(0.033, 0.115, loc=(-0.31 + c * 0.14, -0.30, 0.52 + row * 0.24), + verts=10) + parts.append(assign(can, M["can"] if (row + c) % 2 else M["can2"])) + # selection panel + delivery flap + panel = box((0.17, 0.04, 1.10), loc=(0.31, -0.39, 1.12)) + parts.append(assign(bevel(panel, 0.008), M["plastic_dark"])) + for i in range(5): + btn = box((0.055, 0.02, 0.045), loc=(0.31, -0.41, 1.52 - i * 0.13)) + parts.append(assign(btn, M["can2"])) + flap = box((0.60, 0.05, 0.26), loc=(-0.10, -0.38, 0.28)) + parts.append(assign(bevel(flap, 0.010), M["plastic_dark"])) + top = box((0.92, 0.80, 0.10), loc=(0, 0, 1.86)) + parts.append(assign(bevel(top, 0.012), M["plastic_dark"])) + return parts + + +def p_microwave(M): + parts = [] + shell = box((0.50, 0.38, 0.29), loc=(0, 0, 0.145)) + parts.append(assign(bevel(shell, 0.010, 2), M["appliance"])) + door = box((0.34, 0.03, 0.22), loc=(-0.07, -0.20, 0.15)) + parts.append(assign(door, M["glass_dark"])) + handle = box((0.030, 0.035, 0.20), loc=(0.115, -0.215, 0.15)) + parts.append(assign(bevel(handle, 0.008), M["plastic_dark"])) + pad = box((0.10, 0.02, 0.22), loc=(0.19, -0.20, 0.15)) + parts.append(assign(pad, M["plastic_dark"])) + return parts + + +def p_plant(M): + """The obligatory sad office ficus.""" + parts = [] + pot = cyl(0.17, 0.34, loc=(0, 0, 0.17), r2=0.22, verts=18) + parts.append(assign(pot, M["terracotta"])) + rim = cyl(0.235, 0.05, loc=(0, 0, 0.335), verts=18) + parts.append(assign(rim, M["terracotta"])) + soil = cyl(0.20, 0.03, loc=(0, 0, 0.345), verts=18) + parts.append(assign(soil, M["soil"])) + trunk = cyl(0.028, 0.44, loc=(0, 0, 0.56), r2=0.020, verts=8) + parts.append(assign(trunk, M["stem"])) + # Leaves radiate from points ON the trunk and droop outward. Building each one as a + # span between two explicit points keeps it attached — driving it with euler tilts + # left the blades floating in mid-air, disconnected from their stalks. + for i in range(12): + a = math.radians(i * 73.0) + h = 0.60 + (i % 4) * 0.12 + droop = -0.10 - (i % 3) * 0.06 + out = Vector((math.cos(a), math.sin(a), 0.0)) + root = Vector((0.0, 0.0, h)) + out * 0.018 + stalk_end = root + out * 0.11 + Vector((0, 0, droop * 0.4)) + tip = stalk_end + out * 0.21 + Vector((0, 0, droop)) + parts.append(assign(_span(0.009, 0.009, root, stalk_end), M["stem"])) + parts.append(assign(_span(0.075, 0.012, stalk_end, tip, flat=True), M["leaf"])) + return parts + + +def _span(half_w, half_t, p0, p1, flat=False): + """A box (or flattened blade) running from p0 to p1, oriented along the span.""" + p0, p1 = Vector(p0), Vector(p1) + d = p1 - p0 + n = d.length + if n < 1e-6: + return None + o = box((half_w * 2.0, n, half_t * 2.0) if flat else (half_w * 2.0, n, half_w * 2.0)) + quat = Vector((0, 1, 0)).rotation_difference(d.normalized()) + o.matrix_world = Matrix.Translation(p0 + d * 0.5) @ quat.to_matrix().to_4x4() + bpy.ops.object.transform_apply(location=True, rotation=True) + return bevel(o, 0.006, 2) + + +PROPS = { + "office-chair": p_chair, + "vending-machine": p_vending, + "microwave": p_microwave, + "office-plant": p_plant, +} + + +def materials(): + return { + "plastic_dark": mat("plastic_dark", (0.09, 0.09, 0.10), rough=0.55), + "rubber": mat("rubber", (0.05, 0.05, 0.06), rough=0.92), + "steel": mat("steel", (0.66, 0.67, 0.70), rough=0.32, metal=1.0), + "fabric": mat("fabric", (0.16, 0.18, 0.24), rough=0.96), + "vend_red": mat("vend_red", (0.55, 0.07, 0.09), rough=0.42), + "glass": mat("glass", (0.72, 0.80, 0.85), rough=0.06, alpha=0.30), + "glass_dark": mat("glass_dark", (0.10, 0.12, 0.13), rough=0.16), + "can": mat("can", (0.72, 0.14, 0.14), rough=0.35, metal=0.7), + "can2": mat("can2", (0.14, 0.34, 0.66), rough=0.35, metal=0.7), + "appliance": mat("appliance", (0.80, 0.80, 0.82), rough=0.36, metal=0.3), + "terracotta": mat("terracotta", (0.52, 0.29, 0.20), rough=0.85), + "soil": mat("soil", (0.14, 0.11, 0.09), rough=1.0), + "stem": mat("stem", (0.22, 0.30, 0.16), rough=0.8), + "leaf": mat("leaf", (0.20, 0.42, 0.19), rough=0.72), + } + + +def export(objs, name): + objs = [o for o in objs if o is not None] + bpy.ops.object.select_all(action='DESELECT') + for o in objs: + o.select_set(True) + bpy.context.view_layer.objects.active = objs[0] + path = os.path.join(OUT_DIR, name + ".glb") + bpy.ops.export_scene.gltf(filepath=path, export_format='GLB', + use_selection=True, export_apply=True, export_yup=True) + print("[office] %-18s -> %s" % (name, os.path.basename(path))) + bpy.ops.object.select_all(action='DESELECT') + + +def render_preview(name): + scene = bpy.context.scene + engines = scene.render.bl_rna.properties['engine'].enum_items.keys() + for want in ('BLENDER_EEVEE_NEXT', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH'): + if want in engines: + scene.render.engine = want + break + scene.render.resolution_x = 560 + scene.render.resolution_y = 560 + if scene.world is None: + scene.world = bpy.data.worlds.new("preview") + scene.world.use_nodes = True + bg = scene.world.node_tree.nodes.get("Background") + if bg: + bg.inputs[0].default_value = (0.07, 0.07, 0.08, 1.0) + lo = Vector((1e9,) * 3) + hi = Vector((-1e9,) * 3) + for o in scene.objects: + if o.type != 'MESH': + continue + for c in o.bound_box: + w = o.matrix_world @ Vector(c) + lo = Vector((min(lo.x, w.x), min(lo.y, w.y), min(lo.z, w.z))) + hi = Vector((max(hi.x, w.x), max(hi.y, w.y), max(hi.z, w.z))) + centre = (lo + hi) * 0.5 + radius = max((hi - lo).length * 0.5, 0.05) + dist = radius * 2.9 + d = Vector((0.66, -0.72, 0.30)).normalized() + bpy.ops.object.camera_add(location=tuple(centre + d * dist)) + cam = bpy.context.active_object + cam.data.lens = 58 + cam.rotation_mode = 'QUATERNION' + cam.rotation_quaternion = (-d).to_track_quat('-Z', 'Y') + scene.camera = cam + for off, e, s in ((Vector((1.0, -1.0, 1.1)), 58.0, 1.2), + (Vector((-1.1, -0.5, 0.3)), 17.0, 1.8)): + bpy.ops.object.light_add(type='AREA', location=tuple(centre + off * dist)) + L = bpy.context.active_object + L.data.energy = e * (dist ** 2) + L.data.size = s * radius + scene.render.filepath = os.path.join(PREVIEW_DIR, name + ".png") + bpy.ops.render.render(write_still=True) + + +def main(): + os.makedirs(OUT_DIR, exist_ok=True) + os.makedirs(PREVIEW_DIR, exist_ok=True) + for name, builder in PROPS.items(): + reset() + M = materials() + parts = builder(M) + for p in parts: + shade_smooth(p, 34.0) + export(parts, name) + if RENDER: + render_preview(name) + print("[office] done -> %s" % OUT_DIR) + + +main()