From 09c7b2b2802c96701a2f40016f3d3869ade68598 Mon Sep 17 00:00:00 2001 From: type-two Date: Mon, 27 Jul 2026 21:41:37 +1000 Subject: [PATCH] TURDRUNNER SLUR 500, FLOORED XD LOLTOP, DADSON 420YO repaint Builder learns 2-door coupes, two-tone accent bonnets, vinyl roof caps and boot spoilers. Datto repainted orange with vinyl roof per reference. Screenshot harness gains cam=front for front three-quarter checks. Co-Authored-By: Claude Fable 5 --- cars/datto_120y/car.glb | Bin 33436 -> 34740 bytes cars/datto_120y/stats.tres | 2 +- cars/floored_xd/car.glb | Bin 0 -> 31148 bytes cars/floored_xd/car.glb.import | 42 ++++++++++++++++++++++++++ cars/floored_xd/stats.tres | 13 ++++++++ cars/turdrunner_slur/car.glb | Bin 0 -> 34480 bytes cars/turdrunner_slur/car.glb.import | 42 ++++++++++++++++++++++++++ cars/turdrunner_slur/stats.tres | 13 ++++++++ shot_crash.png.import | 40 +++++++++++++++++++++++++ tests/screenshot.gd | 9 +++++- tools/build_cars.py | 44 +++++++++++++++++++++------- 11 files changed, 193 insertions(+), 12 deletions(-) create mode 100644 cars/floored_xd/car.glb create mode 100644 cars/floored_xd/car.glb.import create mode 100644 cars/floored_xd/stats.tres create mode 100644 cars/turdrunner_slur/car.glb create mode 100644 cars/turdrunner_slur/car.glb.import create mode 100644 cars/turdrunner_slur/stats.tres create mode 100644 shot_crash.png.import diff --git a/cars/datto_120y/car.glb b/cars/datto_120y/car.glb index fdc0e2016ca45bd189d2456a724faa24d998f8c5..1f85c546a9e217c11c555c19d8d6997e30225891 100644 GIT binary patch delta 1178 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 Z_O&<---+u^oM&H;^Yfc{|kh(rV9W7 literal 0 HcmV?d00001 diff --git a/cars/floored_xd/car.glb.import b/cars/floored_xd/car.glb.import new file mode 100644 index 0000000..62c3bf7 --- /dev/null +++ b/cars/floored_xd/car.glb.import @@ -0,0 +1,42 @@ +[remap] + +importer="scene" +importer_version=1 +type="PackedScene" +uid="uid://cxi104t18ug8x" +path="res://.godot/imported/car.glb-0a80c2c77b5fd88764c90110abc62a5c.scn" + +[deps] + +source_file="res://cars/floored_xd/car.glb" +dest_files=["res://.godot/imported/car.glb-0a80c2c77b5fd88764c90110abc62a5c.scn"] + +[params] + +nodes/root_type="" +nodes/root_name="" +nodes/root_script=null +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 diff --git a/cars/floored_xd/stats.tres b/cars/floored_xd/stats.tres new file mode 100644 index 0000000..e65cf79 --- /dev/null +++ b/cars/floored_xd/stats.tres @@ -0,0 +1,13 @@ +[gd_resource type="Resource" script_class="CarStats" load_steps=2 format=3] + +[ext_resource type="Script" path="res://src/car_stats.gd" id="1"] + +[resource] +script = ExtResource("1") +display_name = "FLOORED XD LOLTOP" +model_path = "res://cars/floored_xd/car.glb" +engine_power = 22.0 +mass = 1450.0 +grip = 5.2 +length = 4.85 +width = 1.91 diff --git a/cars/turdrunner_slur/car.glb b/cars/turdrunner_slur/car.glb new file mode 100644 index 0000000000000000000000000000000000000000..6b2158966426c2edde0633881a861a92bc5439d7 GIT binary patch literal 34480 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 e?;fr_oM~T&)9@|0Zozr>4LCpFfa?aFa{mv7R| void: Game.car_path = cars.get(opts.get("car", ""), cars.values()[0]) Game.level_path = Registry.levels().values()[0] Game.mode = opts.get("mode", "cruise") - root.add_child((load("res://src/game.tscn") as PackedScene).instantiate()) + var game: Game = (load("res://src/game.tscn") as PackedScene).instantiate() + root.add_child(game) await process_frame if opts.get("throttle", "1") == "1": Input.action_press("throttle") for i in int(opts.get("frames", "90")): await physics_frame + if opts.get("cam", "") == "front": + game.set_process(false) # stop the chase cam fighting us + game.cam.global_position = game.car.global_position + game.car.global_basis * Vector3(2.6, 1.6, -6.5) + game.cam.look_at(game.car.global_position + Vector3.UP * 0.4) + await process_frame + await process_frame root.get_texture().get_image().save_png("res://" + opts.get("out", "screenshot.png")) print("screenshot saved") quit(0) diff --git a/tools/build_cars.py b/tools/build_cars.py index 2f1d525..36c42bf 100644 --- a/tools/build_cars.py +++ b/tools/build_cars.py @@ -29,12 +29,24 @@ LIGHT_F = (0.95, 0.92, 0.75, 1) LIGHT_R = (0.7, 0.1, 0.08, 1) # L, W, heights: nose/belt/tail, lengths: bonnet/boot, roof height + rear roof end, -# axle overhangs, wheel radius, paint, chrome bumpers, hatch rear +# axle overhangs, wheel radius, paint, chrome bumpers, hatch rear. +# Optional: doors=2, bonnet_color (two-tone accent), roof_cap (vinyl roof), spoiler. CARS = { "datto_120y": dict(L=3.92, W=1.50, nose=0.62, belt=0.78, tail=0.72, bonnet=1.00, boot=0.85, roof=1.32, roof_rear=0.75, ohang_f=0.72, ohang_r=0.80, wheel=0.27, - paint=(0.78, 0.62, 0.16, 1), chrome_bumpers=True, hatch=False), + paint=(0.90, 0.45, 0.08, 1), chrome_bumpers=True, hatch=False, + roof_cap=(0.24, 0.23, 0.22, 1)), + "turdrunner_slur": dict(L=4.51, W=1.71, nose=0.64, belt=0.82, tail=0.76, + bonnet=1.35, boot=1.15, roof=1.34, roof_rear=0.85, + ohang_f=0.85, ohang_r=0.95, wheel=0.30, + paint=(0.95, 0.75, 0.05, 1), chrome_bumpers=False, hatch=False, + bonnet_color=(0.04, 0.04, 0.04, 1), spoiler=True), + "floored_xd": dict(L=4.85, W=1.91, nose=0.62, belt=0.86, tail=0.80, + bonnet=1.60, boot=1.00, roof=1.31, roof_rear=0.70, + ohang_f=0.95, ohang_r=1.00, wheel=0.31, + paint=(0.04, 0.04, 0.045, 1), chrome_bumpers=False, hatch=False, + doors=2), "gemmy_tx": dict(L=4.13, W=1.57, nose=0.60, belt=0.76, tail=0.70, bonnet=1.15, boot=0.95, roof=1.28, roof_rear=0.80, ohang_f=0.80, ohang_r=0.85, wheel=0.28, @@ -165,28 +177,40 @@ def build(car_id, s): door_z = (bottom + 0.3 + s["belt"]) / 2 door_h = s["belt"] - bottom - 0.32 span = (ws_base - 0.05) - (boot_y + 0.05) - half = span / 2 - parts.append(box("det_door_f%s" % side, (sx * hw, ws_base - 0.05 - half / 2, door_z), - (0.06, half - 0.06, door_h), paint_dk)) - parts.append(box("det_door_r%s" % side, (sx * hw, boot_y + 0.05 + half / 2, door_z), - (0.06, half - 0.06, door_h), paint_dk)) + if s.get("doors", 4) == 2: + parts.append(box("det_door_%s" % side, (sx * hw, ws_base - 0.05 - span * 0.35, door_z), + (0.06, span * 0.68, door_h), paint_dk)) + else: + half = span / 2 + parts.append(box("det_door_f%s" % side, (sx * hw, ws_base - 0.05 - half / 2, door_z), + (0.06, half - 0.06, door_h), paint_dk)) + parts.append(box("det_door_r%s" % side, (sx * hw, boot_y + 0.05 + half / 2, door_z), + (0.06, half - 0.06, door_h), paint_dk)) parts.append(box("det_mirror_%s" % side, (sx * (hw + 0.09), ws_base + 0.05, s["belt"] + 0.10), (0.14, 0.09, 0.12), dark)) parts.append(box("det_bumper_f", (0, f + 0.05, bottom + 0.16), (W + 0.06, 0.15, 0.16), bumper_mat)) parts.append(box("det_bumper_r", (0, r - 0.05, bottom + 0.16), (W + 0.06, 0.15, 0.16), bumper_mat)) - # bonnet plate follows the bonnet slope + # bonnet plate follows the bonnet slope; optional two-tone accent colour + bonnet_mat = material("bonnet", s["bonnet_color"], rough=0.35) if "bonnet_color" in s else paint_dk by1, bz1, by2, bz2 = f - 0.35, nose2, ws_base + 0.03, s["belt"] ang = math.atan2(bz2 - bz1, by2 - by1) parts.append(box("det_bonnet", ((0, (by1 + by2) / 2, (bz1 + bz2) / 2 + 0.02)), - (W * 0.7, math.hypot(by2 - by1, bz2 - bz1) - 0.1, 0.04), paint_dk, rot_x=-ang)) + (W * 0.7, math.hypot(by2 - by1, bz2 - bz1) - 0.1, 0.04), bonnet_mat, rot_x=-ang)) if not s["hatch"]: ty1, tz1, ty2, tz2 = boot_y - 0.03, s["belt"], r + 0.1, s["tail"] ang = math.atan2(tz2 - tz1, ty2 - ty1) parts.append(box("det_boot", ((0, (ty1 + ty2) / 2, (tz1 + tz2) / 2 + 0.02)), (W * 0.7, math.hypot(ty2 - ty1, tz2 - tz1) - 0.1, 0.04), paint_dk, rot_x=-ang)) - trim = [ + trim = [] + if "roof_cap" in s: # vinyl roof + cap_f, cap_r = ws_base - 0.55, boot_y + s["roof_rear"] + trim.append(box("trim_roof", (0, (cap_f + cap_r) / 2, s["roof"] + 0.012), + (W * 0.86, cap_f - cap_r + 0.1, 0.035), material("vinyl", s["roof_cap"], rough=0.9))) + if s.get("spoiler"): # bootlid ducktail + trim.append(box("trim_spoiler", (0, r + 0.22, s["tail"] + 0.05), (W * 0.8, 0.28, 0.09), paint)) + trim += [ box("trim_grille", (0, f + 0.01, s["nose"] - 0.14), (W * 0.5, 0.05, 0.12), dark), box("trim_light_fl", (-W * 0.33, f + 0.02, s["nose"] - 0.13), (0.24, 0.05, 0.13), material("lf", LIGHT_F)), box("trim_light_fr", (W * 0.33, f + 0.02, s["nose"] - 0.13), (0.24, 0.05, 0.13), material("lf2", LIGHT_F)),