diff --git a/common/bspfile.cc b/common/bspfile.cc index 4fb302b1..26fd6af4 100644 --- a/common/bspfile.cc +++ b/common/bspfile.cc @@ -466,14 +466,15 @@ public: if (contents_are_detail_fence(contents) || contents_are_detail_wall(contents)) { return create_solid_contents(); } + if (contents.flags & EWT_VISCONTENTS_MIST) { // clear mist. detail_illusionary on its own becomes CONTENTS_EMPTY, // detail_illusionary in water becomes CONTENTS_WATER, etc. - return contentflags_t::make(contents.flags & ~EWT_VISCONTENTS_MIST); + contents = contentflags_t::make(contents.flags & ~EWT_VISCONTENTS_MIST); } if (contents.flags & EWT_VISCONTENTS_ILLUSIONARY_VISBLOCKER) { // this exports as empty - return contentflags_t::make(contents.flags & ~EWT_VISCONTENTS_ILLUSIONARY_VISBLOCKER); + contents = contentflags_t::make(contents.flags & ~EWT_VISCONTENTS_ILLUSIONARY_VISBLOCKER); } return contents; @@ -484,14 +485,20 @@ public: auto bits_a = a.flags; auto bits_b = b.flags; + auto result = contentflags_t::make(bits_a | bits_b); + if (contents_are_solid(a) || contents_are_solid(b)) { return create_solid_contents(); } if (contents_are_sky(a) || contents_are_sky(b)) { return contentflags_t::make(EWT_VISCONTENTS_SKY); } + if ((a.flags & EWT_VISCONTENTS_ILLUSIONARY_VISBLOCKER) || (b.flags & EWT_VISCONTENTS_ILLUSIONARY_VISBLOCKER)) { + // strip out detail flag, otherwise it breaks the visblocker feature + result = contentflags_t::make(result.flags & ~EWT_CFLAG_DETAIL); + } - return contentflags_t::make(bits_a | bits_b); + return result; } contentflags_t portal_visible_contents(contentflags_t a, contentflags_t b) const override @@ -1297,6 +1304,11 @@ struct gamedef_q2_t : public gamedef_t bits_a &= ~EWT_CFLAG_DETAIL; bits_b &= ~EWT_CFLAG_DETAIL; } + if ((bits_a & EWT_VISCONTENTS_ILLUSIONARY_VISBLOCKER) || (bits_b & EWT_VISCONTENTS_ILLUSIONARY_VISBLOCKER)) { + // strip out detail flag, otherwise it breaks the visblocker feature + bits_a &= ~EWT_CFLAG_DETAIL; + bits_b &= ~EWT_CFLAG_DETAIL; + } return contentflags_t::make(bits_a | bits_b); } diff --git a/testmaps/q1_func_illusionary_visblocker_interactions.map b/testmaps/q1_func_illusionary_visblocker_interactions.map index ff22a6c4..1898264f 100644 --- a/testmaps/q1_func_illusionary_visblocker_interactions.map +++ b/testmaps/q1_func_illusionary_visblocker_interactions.map @@ -199,3 +199,35 @@ "classname" "ambient_flouro_buzz" "origin" "280 -48 104" } +// entity 15 +{ +"classname" "func_detail_illusionary" +"_mirrorinside" "1" +// brush 0 +{ +( 8 328 -32 ) ( 8 329 -32 ) ( 8 328 -31 ) bolt14 8 -48 0 1 1 +( -56 208 -32 ) ( -56 208 -31 ) ( -55 208 -32 ) bolt14 -8 -48 0 1 1 +( -56 328 16 ) ( -55 328 16 ) ( -56 329 16 ) bolt14 -8 -8 0 1 1 +( 184 376 128 ) ( 184 377 128 ) ( 185 376 128 ) bolt14 -8 -8 0 1 1 +( 184 288 -16 ) ( 185 288 -16 ) ( 184 288 -15 ) bolt14 -8 -48 0 1 1 +( 104 376 -16 ) ( 104 376 -15 ) ( 104 377 -16 ) bolt14 8 -48 0 1 1 +} +} +// entity 16 +{ +"classname" "func_illusionary_visblocker" +// brush 0 +{ +( 16 344 -32 ) ( 16 345 -32 ) ( 16 344 -31 ) *zwater1 56 -48 0 1 1 +( -48 216 -32 ) ( -48 216 -31 ) ( -47 216 -32 ) *zwater1 -16 -48 0 1 1 +( -48 344 16 ) ( -47 344 16 ) ( -48 345 16 ) *zwater1 -16 -56 0 1 1 +( 192 392 120 ) ( 192 393 120 ) ( 193 392 120 ) *zwater1 -16 -56 0 1 1 +( 192 280 -16 ) ( 193 280 -16 ) ( 192 280 -15 ) *zwater1 -16 -48 0 1 1 +( 96 392 -16 ) ( 96 392 -15 ) ( 96 393 -16 ) *zwater1 56 -48 0 1 1 +} +} +// entity 17 +{ +"classname" "info_null" +"origin" "48 248 56" +} diff --git a/tests/test_vis.cc b/tests/test_vis.cc index 51a8c901..91bc2ea2 100644 --- a/tests/test_vis.cc +++ b/tests/test_vis.cc @@ -143,6 +143,22 @@ TEST(vis, q1FuncIllusionaryVisblocker) } } +TEST(vis, q1FuncIllusionaryVisblockerInteractions) +{ + SCOPED_TRACE("make sure illusionary_visblocker covered by detail_illusionary doesn't break the visblocker"); + auto [bsp, bspx, lit] = QbspVisLight_Q1("q1_func_illusionary_visblocker_interactions.map", {}, runvis_t::yes); + + const auto vis = DecompressAllVis(&bsp); + + const auto player_start = qvec3d(80, -272, 40); + const auto in_visblocker_covered_by_illusionary = qvec3d(48, 248, 56); + + auto *player_start_leaf = BSP_FindLeafAtPoint(&bsp, &bsp.dmodels[0], player_start); + auto *in_visblocker_covered_by_illusionary_leaf = BSP_FindLeafAtPoint(&bsp, &bsp.dmodels[0], in_visblocker_covered_by_illusionary); + + EXPECT_FALSE(q1_leaf_sees(bsp, vis, in_visblocker_covered_by_illusionary_leaf, player_start_leaf)); +} + TEST(vis, ClipStackWinding) { pstack_t stack{};