From 3b5644cf3ae15e8813e74d2370044a117a5ca119 Mon Sep 17 00:00:00 2001 From: Luke Date: Sun, 25 Jun 2023 11:30:09 -0700 Subject: [PATCH 1/6] feat: Rework weighted cube FGD for new model/skin system --- fgd/point/prop/prop_weighted_cube.fgd | 75 +++++++++++++++++---------- 1 file changed, 48 insertions(+), 27 deletions(-) diff --git a/fgd/point/prop/prop_weighted_cube.fgd b/fgd/point/prop/prop_weighted_cube.fgd index ca50da9f4..d160a2a2f 100644 --- a/fgd/point/prop/prop_weighted_cube.fgd +++ b/fgd/point/prop/prop_weighted_cube.fgd @@ -5,50 +5,40 @@ [ line_cube[-engine](string) readonly : "----------------------------------------------------------------------------------------------------------" : "" - cubetype[engine](integer) : "Cube Type" : 0 - cubetype(choices) : "Cube Type" : "0" : "What cube type is this? Use a prop_monster_box for FrankenTurrets. " + - "If set to Custom, use AddOutput to change it back OnMapSpawn so gel skins behave correctly." = + CubeBehavior[engine](integer) : "Cube Behavior" : 0 + CubeBehavior(choices) : "Cube Behavior" : 0 : "How does this cube function? Use a prop_monster_box for Frankenturrets." = [ - 0: "[0] Weighted Storage Cube" - 1: "[1] Weighted Companion Cube" - 2: "[2] Discouragement Redirection Cube" - 3: "[3] Edgeless Safety Cube" - 4: "[4] Antique Storage Cube" - 5: "[5] Schrodinger's Cube" - 6: "[6] Custom model" - ] - - skintype[engine](boolean) : "Skin Type" : 0 - skintype(choices) : "Skin Type" : "0" : "Is the cube clean or rusty? Storage and Reflection cubes are the only types with a rusty version." = - [ - 0: "Clean" - 1: "Rusted" + 0: "Standard Cube" + 1: "Reflection Cube" + 2: "Sphere (presses sphere buttons)" + 3: "Schrodinger's Cube" ] model[engine](studio) : "Model" : "" - model(choices) : "Model" : "models/props/metal_box.mdl" : "The model to show in Hammer, or a custom model for cube type 6." = + model(choices) : "Cube Model" : "models/props/cubes/standard_cube.mdl" : "What model to use. You can also type/paste in a custom model path here." = [ - "models/props/metal_box.mdl": "Weighted Storage/Companion Cube" - "models/props/reflection_cube.mdl": "Discouragement Redirection" - "models/props_gameplay/mp_ball.mdl": "Edgeless Safety" - "models/props_underground/underground_weighted_cube.mdl": "Antique" - "models/props/schrodinger_cube.mdl": "Schrodinger" + "models/props/cubes/standard_cube.mdl": "Weighted Storage Cube" + "models/props/cubes/standard_cube_rusty.mdl": "Weighted Storage Cube (rusty)" + "models/props/cubes/companion_cube.mdl": "Weighted Companion Cube" + "models/props/cubes/reflection_cube.mdl": "Discouragement Redirection Cube" + "models/props/cubes/reflection_cube_rusty.mdl": "Discouragement Redirection Cube (rusty)" + "models/props/cubes/sphere.mdl": "Edgeless Safety Cube" + "models/props/cubes/antique_cube.mdl": "Antique Cube" + "models/props/cubes/schrodinger_cube.mdl": "Schrodinger's Cube" ] - skin(integer) : "Skin" : 0 : "The old skin property, mainly to show in Hammer. " - paintpower[engine](integer) : "Starting Paint" : 4 paintpower(choices) : "Starting paint" : "4" : "The cube starts painted with the set gel." = [ 0: "Repulsion Gel" - 1: "Adhesion Gel" + 1: "Reflection Gel" 2: "Propulsion Gel" 3: "Conversion Gel" 4: "None" + 5: "Adhesion Gel" ] allowfunnel(boolean) : "Allow Portal Funneling" : 1 : "Whether or not this object should auto-funnel into a floor portal." - newskins(integer) readonly : "Use new skins" : 1 : "Use the values in the Cube Type and Skin Type fields instead of the Skin(OLD) field. You shouldn't need to touch this." uselasermodifier(boolean) : "Use Laser Modifier" : 0 : "If enabled, this cube will recolor incoming lasers to the modifier color." reflectmodifycolor(choices) : "Laser Modifier Color" : "255 0 0 255" : "Set reflected lasers to this color. Only applicable to reflection and Schrodinger cubes. You can also specify a custom RGBA color here." = @@ -73,6 +63,37 @@ "65 97 0 255" : "Dark Green" ] + line_cube_oldskins(string) readonly : "----------------------------------------------------------------------------------------------------------" + + newskins[engine](integer) : "Configuration Mode" : 2 + newskins(choices) : "Configuration Mode" : 2 : "How cube models and behaviors are selected. This determines which of the other keyvalues are used and is present for backwards compatibility." = + [ + 2: "New style (behavior/model)" + 1: "Old style (cube type/skin type)" + 0: "Oldest style (skin)" + ] + + cubetype[engine](integer) : "Cube Type (old)" : 0 + cubetype(choices) : "Cube Type (old)" : 0 : "The old cube type keyvalue, which overrides the model and behavior." = + [ + 0: "[0] Weighted Storage Cube" + 1: "[1] Weighted Companion Cube" + 2: "[2] Discouragement Redirection Cube" + 3: "[3] Edgeless Safety Cube" + 4: "[4] Antique Storage Cube" + 5: "[5] Schrodinger's Cube" + 6: "Custom model (old)" + ] + + skintype[engine](boolean) : "Skin Type (old)" : 0 + skintype(choices) : "Skin Type (old)" : 0 : "The old skin type keyvalue. Storage and Reflection cubes are the only types with a rusty version." = + [ + 0: "Clean" + 1: "Rusted" + ] + + skin(integer) : "Skin" : 0 : "The old skin keyvalue, mainly to show in Hammer." + // Inputs input EnablePortalFunnel(void) : "Enable portal funneling behavior." input DisablePortalFunnel(void) : "Disable portal funneling behavior." From 102c17f74c7e6d1cab4128ba98ad2e12e2e530b5 Mon Sep 17 00:00:00 2001 From: Luke Date: Sat, 1 Jul 2023 18:13:26 -0700 Subject: [PATCH 2/6] feat: Turret FGD changes --- fgd/point/npc/npc_portal_turret_floor.fgd | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/fgd/point/npc/npc_portal_turret_floor.fgd b/fgd/point/npc/npc_portal_turret_floor.fgd index fe2c698f1..62d4fdf2f 100644 --- a/fgd/point/npc/npc_portal_turret_floor.fgd +++ b/fgd/point/npc/npc_portal_turret_floor.fgd @@ -18,10 +18,11 @@ modelindex(choices) : "Model" : 0 : "Which model the turret uses. The skeleton turret is still functional." = [ 0: "Normal" - 1: "Custom Model" + 1: "Custom Model (old gel skins)" 2: "Box" 3: "Backwards" 4: "Skeleton" + 5: "Custom Model (new gel skins)" ] skinnumber[engine](integer) : "Skin" : 0 @@ -48,7 +49,7 @@ ] model[engine](studio) : "Custom Model" : "models/npcs/turret/turret.mdl" - model(choices) : "Custom Model" : "models/npcs/turret/turret.mdl" : "The model to show as in Hammer, or a custom model to use." = + model(choices) : "Custom Model" : "models/npcs/turret/turret.mdl" : "The model to show as in Hammer, or a custom model to use. You can type/paste in a model path here." = [ "models/npcs/turret/turret.mdl": "Normal" "models/npcs/turret/turret_boxed.mdl": "Box" From 17c152ed581c4bd9ad80851df886b9278884efdf Mon Sep 17 00:00:00 2001 From: Spencer Brown Date: Sun, 22 Feb 2026 17:42:13 +1000 Subject: [PATCH 3/6] feat: Split CubeBehavior into CubeShape also --- fgd/point/prop/prop_weighted_cube.fgd | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/fgd/point/prop/prop_weighted_cube.fgd b/fgd/point/prop/prop_weighted_cube.fgd index d160a2a2f..3799f01e1 100644 --- a/fgd/point/prop/prop_weighted_cube.fgd +++ b/fgd/point/prop/prop_weighted_cube.fgd @@ -6,16 +6,24 @@ line_cube[-engine](string) readonly : "----------------------------------------------------------------------------------------------------------" : "" CubeBehavior[engine](integer) : "Cube Behavior" : 0 - CubeBehavior(choices) : "Cube Behavior" : 0 : "How does this cube function? Use a prop_monster_box for Frankenturrets." = + CubeBehavior(choices) : "Cube Behavior" : 0 : "How does this cube function? Use a prop_monster_box for Frankenturrets. If Auto, this is chosen based on the cube model." = [ - 0: "Standard Cube" - 1: "Reflection Cube" - 2: "Sphere (presses sphere buttons)" + 0: "Auto (from model)" + 1: "Standard Cube" + 2: "Reflection Cube" 3: "Schrodinger's Cube" ] + CubeShape[engine](integer) : "Cube Shape" : 0 + CubeShape(choices) : "Cube Behavior" : 0 : "What shape is this cube? This determines how it presses buttons. If Auto, this is chosen based on the cube model." = + [ + 0: "Auto (from model)" + 1: "Cubic" + 2: "Spherical" + ] model[engine](studio) : "Model" : "" - model(choices) : "Cube Model" : "models/props/cubes/standard_cube.mdl" : "What model to use. You can also type/paste in a custom model path here." = + model(choices) : "Cube Model" : "models/props/cubes/standard_cube.mdl" : "What model to use. You can also type/paste in a custom model path here. " + + "If using a custom model, Cube Behavior and Shape must be set." = [ "models/props/cubes/standard_cube.mdl": "Weighted Storage Cube" "models/props/cubes/standard_cube_rusty.mdl": "Weighted Storage Cube (rusty)" @@ -25,6 +33,7 @@ "models/props/cubes/sphere.mdl": "Edgeless Safety Cube" "models/props/cubes/antique_cube.mdl": "Antique Cube" "models/props/cubes/schrodinger_cube.mdl": "Schrodinger's Cube" + "models/props/cubes/schrodinger_cube_rusty.mdl": "Schrodinger's Cube (rusty)" ] paintpower[engine](integer) : "Starting Paint" : 4 @@ -98,9 +107,9 @@ input EnablePortalFunnel(void) : "Enable portal funneling behavior." input DisablePortalFunnel(void) : "Disable portal funneling behavior." input EnableMotion(void) : "Allow physics simulation." - input DisableMotion(void) : "Prevent Physics simulation, freezing the cube in place." + input DisableMotion(void) : "Prevent physics simulation, freezing the cube in place." input ExitDisabledState(void) : "Exits the disabled state of a reflective cube." - input SetPaint(integer) : "Force the cube to be painted with 0 (Repulsion), 2 (Propulsion), or 4 (No) gel." + input SetPaint(integer) : "Force the cube to be painted with 0 (Repulsion), 1 (Reflection), 2 (Propulsion), 3 (Conversion) or 4 (No) gel." input SetReflectModifyColor(color255) : "Changes the laser modifier colour of the cube." input SetReflectFilterColor(color255) : "Changes the laser filter colour of the cube." From 1b92106f8dcae5a805d332897903a0f245f0efd3 Mon Sep 17 00:00:00 2001 From: Spencer Brown Date: Sun, 22 Feb 2026 18:05:07 +1000 Subject: [PATCH 4/6] feat: Add info_portal_gamerules keyvalue to show conversion gel on props --- fgd/point/info/info_portal_gamerules.fgd | 1 + 1 file changed, 1 insertion(+) diff --git a/fgd/point/info/info_portal_gamerules.fgd b/fgd/point/info/info_portal_gamerules.fgd index 7c4e144eb..8f02abcc6 100644 --- a/fgd/point/info/info_portal_gamerules.fgd +++ b/fgd/point/info/info_portal_gamerules.fgd @@ -19,5 +19,6 @@ 1: "Basic paint gun" 2: "Fully-upgraded paint gun" ] + showportalpaintprops(boolean) : "Show Conversion Gel on Props" : 0 : "Force Conversion Gel to be visible on props like cubes and turrets. This should be set for situations where this serves some gameplay purpose." maxhealth(integer) : "Maximum player health" : 100 : "Specifies the maximum health limit for players." ] From 7a4b90e7b7fbef9bff20ed43b15151bdc65fb387 Mon Sep 17 00:00:00 2001 From: Spencer Brown Date: Fri, 27 Feb 2026 16:06:48 +1000 Subject: [PATCH 5/6] feat: All paintable props have OnPainted/OnUnPainted outputs --- fgd/bases/PaintableProp.fgd | 7 +++++++ fgd/point/npc/npc_portal_turret_floor.fgd | 3 +-- fgd/point/prop/prop_monster_box.fgd | 2 +- fgd/point/prop/prop_physics_paintable.fgd | 2 +- fgd/point/prop/prop_weighted_cube.fgd | 5 ++--- 5 files changed, 12 insertions(+), 7 deletions(-) create mode 100644 fgd/bases/PaintableProp.fgd diff --git a/fgd/bases/PaintableProp.fgd b/fgd/bases/PaintableProp.fgd new file mode 100644 index 000000000..6a4139318 --- /dev/null +++ b/fgd/bases/PaintableProp.fgd @@ -0,0 +1,7 @@ +@BaseClass + appliesto(P2CE) += PaintableProp + [ + output OnPainted(integer): "Fired when the prop has been painted with a new paint type, other than cleansing gel. The parameter is the paint type number." + output OnUnPainted(void): "Fired when the prop has been cleaned after being painted." + ] diff --git a/fgd/point/npc/npc_portal_turret_floor.fgd b/fgd/point/npc/npc_portal_turret_floor.fgd index 62d4fdf2f..b6ff9f38c 100644 --- a/fgd/point/npc/npc_portal_turret_floor.fgd +++ b/fgd/point/npc/npc_portal_turret_floor.fgd @@ -1,4 +1,4 @@ -@PointClass base(BaseNPC) +@PointClass base(BaseNPC, PaintableProp) appliesto(P2CE) studioprop() frustum(_frustum_fov, _frustum_near, TurretRange, _frustum_color, -1) @@ -88,5 +88,4 @@ output OnExplode(void) : "Turret has exploded." output OnPhysGunPickup(void) : "Turret was picked up by player." output OnPhysGunDrop(void) : "Turret was dropped by player." - output OnPainted(void) : "Fires when the turret is first painted or if repainted by a different color." ] diff --git a/fgd/point/prop/prop_monster_box.fgd b/fgd/point/prop/prop_monster_box.fgd index 49e3c66de..7b6a660e5 100644 --- a/fgd/point/prop/prop_monster_box.fgd +++ b/fgd/point/prop/prop_monster_box.fgd @@ -1,4 +1,4 @@ -@PointClass base(BaseEntityPhysics) +@PointClass base(BaseEntityPhysics, PaintableProp) appliesto(P2CE) studioprop() = prop_monster_box: "Frankencubes: turrets shoved into storage cube chassis that walk erratically when oriented correctly, but behave identically to standard cubes." diff --git a/fgd/point/prop/prop_physics_paintable.fgd b/fgd/point/prop/prop_physics_paintable.fgd index 54009ec2c..0891d2ef6 100644 --- a/fgd/point/prop/prop_physics_paintable.fgd +++ b/fgd/point/prop/prop_physics_paintable.fgd @@ -1,4 +1,4 @@ -@PointClass base(prop_physics) +@PointClass base(prop_physics, PaintableProp) appliesto(P2CE) sphere(fademindist) sphere(fademaxdist) diff --git a/fgd/point/prop/prop_weighted_cube.fgd b/fgd/point/prop/prop_weighted_cube.fgd index 3799f01e1..30c7c569b 100644 --- a/fgd/point/prop/prop_weighted_cube.fgd +++ b/fgd/point/prop/prop_weighted_cube.fgd @@ -1,4 +1,4 @@ -@PointClass base(BasePropPhysics) +@PointClass base(BasePropPhysics, PaintableProp) appliesto(P2CE) studioprop() = prop_weighted_cube: "Aperture Science Weighted Cube. Presses floor buttons, and can be moved around." @@ -43,8 +43,8 @@ 1: "Reflection Gel" 2: "Propulsion Gel" 3: "Conversion Gel" - 4: "None" 5: "Adhesion Gel" + 4: "None" ] allowfunnel(boolean) : "Allow Portal Funneling" : 1 : "Whether or not this object should auto-funnel into a floor portal." @@ -121,7 +121,6 @@ output OnBluePickUp(void) : "ATLAS picked up the cube." output OnPlayerPickup(void) : "Any player picked up the cube." output OnPhysGunDrop(void) : "Any player dropped the cube." - output OnPainted(integer) : "Cube got painted, only if the state changed. Has the paint type as parameter." output OnPowered(void) : "Cube got powered by a laser." output OnUnpowered(void) : "Cube is no longer powered by a laser." output OnActivated(void) : "Fired when a cube is placed on a button." From 5ca3c262af3592811b952c13c6c9551278ae0552 Mon Sep 17 00:00:00 2001 From: Spencer Brown Date: Fri, 27 Feb 2026 16:07:15 +1000 Subject: [PATCH 6/6] feat: Add painted/unpainted skins to prop_physics_paintable --- fgd/point/prop/prop_physics_paintable.fgd | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/fgd/point/prop/prop_physics_paintable.fgd b/fgd/point/prop/prop_physics_paintable.fgd index 0891d2ef6..42db1ce4c 100644 --- a/fgd/point/prop/prop_physics_paintable.fgd +++ b/fgd/point/prop/prop_physics_paintable.fgd @@ -3,16 +3,21 @@ sphere(fademindist) sphere(fademaxdist) studioprop() -= prop_physics_paintable: "A version of prop_physics that can be painted by Gel. Does not appear to show up on the model." += prop_physics_paintable: "A version of prop_physics that can be painted by Gel." [ paintpower[engine](integer) : "Paint Power" : 4 paintpower(choices) : "Paint Power" : 4 : "The starting gel type for the prop." = [ 0: "Repulsion Gel" - 1: "Adhesion Gel" + 1: "Reflection Gel" 2: "Propulsion Gel" 3: "Conversion Gel" + 5: "Adhesion Gel" 4: "None" ] + cleanskin(integer) : "Unpainted Skin" : -1 : "The skin to switch to whenever this is cleaned. Painted skin must also be set." + paintskin(integer) : "Painted Skin" : -1 : "The skin to switch to whenever this is painted. Unpainted skin must also be set." + input SetPaintedSkin(integer) : "Set the skin to use whenever this is painted. If currently painted the prop will swap skins." + input SetUnpaintedSkin(integer) : "Set the skin to use whenever this is not painted. If currently unpainted the prop will swap skins." ]