1 //**************************************************************************
3 //** ## ## ## ## ## #### #### ### ###
4 //** ## ## ## ## ## ## ## ## ## ## #### ####
5 //** ## ## ## ## ## ## ## ## ## ## ## ## ## ##
6 //** ## ## ######## ## ## ## ## ## ## ## ### ##
7 //** ### ## ## ### ## ## ## ## ## ##
8 //** # ## ## # #### #### ## ##
10 //** Copyright (C) 1999-2006 Jānis Legzdiņš
11 //** Copyright (C) 2018-2023 Ketmar Dark
13 //** This program is free software: you can redistribute it and/or modify
14 //** it under the terms of the GNU General Public License as published by
15 //** the Free Software Foundation, version 3 of the License ONLY.
17 //** This program is distributed in the hope that it will be useful,
18 //** but WITHOUT ANY WARRANTY; without even the implied warranty of
19 //** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 //** GNU General Public License for more details.
22 //** You should have received a copy of the GNU General Public License
23 //** along with this program. If not, see <http://www.gnu.org/licenses/>.
25 //**************************************************************************
28 //==========================================================================
32 //==========================================================================
33 final void DebugCheckMidTex () {
35 //Aim(aimDir, 16.0*64.0, default, /*noAAim*/true);
36 AngleVector(Angles, out aimDir);
38 auto shootOrigin = Origin;
39 shootOrigin.z += CalculateLineAttackZOfs();
42 DebugTraceLineEx(shootOrigin, aimDir, 8192, allowEntities:false, out tr, stopat3dmidtex:true, nozofs:true);
46 //if (!tr.line) ptorg += in.plane.normal*1.0f;
47 int c = P_Random()>>1;
48 foreach (int i; 0..MAXPLAYERS) {
49 if (!Level.Game.Players[i]) continue;
50 if (!Level.Game.Players[i].bSpawned) continue;
51 PlayerEx(Level.Game.Players[i]).ParticleEffect(20, LineSpecialLevelInfo::pt_static,
52 LineSpecialLevelInfo::pt_explode2, ptorg, 0.0, vector(32.0, 32.0, 32.0),
53 0.5, 10.0, 40.0, RGB(c, c, c), 0.8, 0.0);
57 //k8:TODO: this should be strictly client-side
60 if (tr.line && tr.sec) {
61 SpawnDecal(tr.hit, 'K8BigScorchTestRot', tr.side, tr.line);
62 fdorg += tr.line.normal*2.0; // move slightly away from the wall
64 SpawnFlatDecal(fdorg, 'K8BigScorchTest', 2);
67 XLevel.AddFlatDecal(tr.hit, 'BigScorch', 32);
72 if (tr.didhit && tr.line) {
74 bool ok = XLevel.GetMidTexturePosition(tr.line, tr.side, out bot, out top);
75 printdebug("DebugCheckMidTex(%B): hitpoint=%s; top=%s; bot=%s; flags=0x%08x", ok, tr.hit, top, bot, (tr.line ? tr.line->flags : 0));
77 //tr.line.alpha = 1.0;
78 if (tr.line.frontsector && tr.line.backsector /*&&
79 tr.line.frontsector.floor.normal.z == 1 && tr.line.frontsector.ceiling.normal.z == -1 &&
80 tr.line.backsector.floor.normal.z == 1 && tr.line.backsector.ceiling.normal.z == -1*/)
82 //printdebug("linedef #%d", tr.line-&XLevel.Lines[0]);
83 float ffz1 = tr.line.frontsector.floor.GetPointZClamped(*tr.line.v1);
84 float ffz2 = tr.line.frontsector.floor.GetPointZClamped(*tr.line.v2);
85 //if (ffz1 != ffz2) Error("OOPS(front floor)");
86 float fcz1 = tr.line.frontsector.ceiling.GetPointZClamped(*tr.line.v1);
87 float fcz2 = tr.line.frontsector.ceiling.GetPointZClamped(*tr.line.v2);
88 //if (fcz1 != fcz2) Error("OOPS(front ceiling)");
89 float bfz1 = tr.line.backsector.floor.GetPointZClamped(*tr.line.v1);
90 float bfz2 = tr.line.backsector.floor.GetPointZClamped(*tr.line.v2);
91 //if (bfz1 != bfz2) Error("OOPS(back floor)");
92 float bcz1 = tr.line.backsector.ceiling.GetPointZClamped(*tr.line.v1);
93 float bcz2 = tr.line.backsector.ceiling.GetPointZClamped(*tr.line.v2);
94 //if (bcz1 != bcz2) Error("OOPS(back ceiling)");
95 printdebug("linedef %d: (f/b secs=%d/%d); ffz=(%f:%f); fcz=(%f:%f); bfz=(%f:%f); bcz=(%f:%f); alpha=%f; special=%s<%s>; arg=(%s,%s,%s,%s,%s)",
96 cast([unsafe])(tr.line-&XLevel.Lines[0]),
97 cast([unsafe])(tr.line.frontsector-&XLevel.Sectors[0]),
98 cast([unsafe])(tr.line.backsector-&XLevel.Sectors[0]),
99 ffz1, ffz2, fcz1, fcz2, bfz1, bfz2, bcz1, bcz2,
101 tr.line.special, LineSpecial2Str(tr.line.special),
102 tr.line.arg1, tr.line.arg2, tr.line.arg3, tr.line.arg4, tr.line.arg5);
103 printdebug("fsec(%d): ceiling=%f; floor=%f",
104 cast([unsafe])(tr.line.frontsector-&XLevel.Sectors[0]),
105 tr.line.frontsector.ceiling.minz, tr.line.frontsector.floor.maxz);
106 printdebug("bsec(%d): ceiling=%f; floor=%f",
107 cast([unsafe])(tr.line.backsector-&XLevel.Sectors[0]),
108 tr.line.backsector.ceiling.minz, tr.line.backsector.floor.maxz);
110 float ffz1 = tr.line.frontsector.floor.GetPointZClamped(*tr.line.v1);
111 float ffz2 = tr.line.frontsector.floor.GetPointZClamped(*tr.line.v2);
112 //if (ffz1 != ffz2) Error("OOPS(front floor)");
113 float fcz1 = tr.line.frontsector.ceiling.GetPointZClamped(*tr.line.v1);
114 float fcz2 = tr.line.frontsector.ceiling.GetPointZClamped(*tr.line.v2);
115 //if (fcz1 != fcz2) Error("OOPS(front ceiling)");
116 printdebug("linedef %d: (f sec=%d); ffz=(%f:%f); fcz=(%f:%f); special=%s<%s>; arg=(%s,%s,%s,%s,%s)",
117 cast([unsafe])(tr.line-&XLevel.Lines[0]),
118 cast([unsafe])(tr.line.frontsector-&XLevel.Sectors[0]),
119 ffz1, ffz2, fcz1, fcz2,
120 tr.line.special, LineSpecial2Str(tr.line.special),
121 tr.line.arg1, tr.line.arg2, tr.line.arg3, tr.line.arg4, tr.line.arg5);
123 foreach (auto snum; 0..2) {
124 if (tr.line.sidenum[snum] < 0) continue;
125 side_t *sd = cast([unsafe])(&XLevel.Sides[tr.line.sidenum[snum]]);
126 printdebug("side %s: toptex(%d)=%s; midtex(%d)=%s; bottex(%d)=%s", snum,
127 sd.TopTexture, GetTextureName(sd.TopTexture),
128 sd.MidTexture, GetTextureName(sd.MidTexture),
129 sd.BottomTexture, GetTextureName(sd.BottomTexture));
134 auto real_hit_point = tr.hit;
135 auto hitPoint = real_hit_point-(4.0*aimDir);
137 SpawnPuff(hitPoint, /*distance*/8192, BulletPuff, none, tr.sec, tr.line, real_hit_point);
142 LineAttack(aimDir, /*Range*/10000, /*damage*/10000,
143 BulletPuff, default, default,
149 //==========================================================================
153 // Trace line to the wall or entity.
154 // Returns `true` if wall was hit.
155 // Returns `false` if floor/ceiling was hit, or nothing was hit.
157 //==========================================================================
158 private final bool DebugTraceLineEx (TVec org, TVec dir, float distance, bool allowEntities, optional out trsplat_t tr, optional bool stopat3dmidtex, optional bool nozofs) {
159 TVec shootOrigin = org;
160 if (!nozofs) shootOrigin.z += (bIsPlayer ? PlayerEx(Player).GetAttackZOfs : 8.0);
162 TVec dst = shootOrigin+distance*dir;
164 tr.org = shootOrigin;
177 foreach PathTraverse(out in, shootOrigin, dst, PT_ADDLINES|(allowEntities ? PT_ADDTHINGS : 0)|(Level.CompatTrace ? PT_COMPAT : 0), SPF_NOBLOCKING, ML_BLOCKEVERYTHING) {
180 printdebug("skyplane!");
182 if (in.plane.normal.z > 0.0f) printdebug("floor plane!"); else printdebug("ceiling plane!");
185 //XLevel.AddFlatDecal(in.hitpoint, 'K8BigScorchTest', 32);
186 XLevel.AddFlatDecal(in.hitpoint, 'BigScorch', 32);
189 tr.hit = in.hitpoint;
196 hitPoint = in.hitpoint;
200 if (!li->pobject && (li->flags&ML_TWOSIDED)) {
201 opening_t *open = XLevel.LineOpenings(li, hitPoint, SPF_NOBLOCKING, stopat3dmidtex);
203 printdebug("SKYFLAT: %d (%s)", Level.Game.skyflatnum, GetTextureName(Level.Game.skyflatnum));
204 printdebug(":: line #%d (flags=0x%08x) ::", cast([unsafe])(li-&XLevel.Lines[0]), li->flags);
205 foreach (auto snum; 0..2) {
206 if (li.sidenum[snum] < 0) continue;
207 side_t *sd = cast([unsafe])(&XLevel.Sides[li.sidenum[snum]]);
208 printdebug("side %s: toptex(%d)=%s; midtex(%d)=%s; bottex(%d)=%s", snum,
209 sd.TopTexture, GetTextureName(sd.TopTexture),
210 sd.MidTexture, GetTextureName(sd.MidTexture),
211 sd.BottomTexture, GetTextureName(sd.BottomTexture));
213 for (opening_t *o = open; o; o = o->next) {
214 printdebug(" opening:");
215 printdebug(" open bot: %s", o->bottom);
216 printdebug(" open top: %s", o->top);
217 printdebug(" open range: %s", o->range);
218 printdebug(" open lowfloor: %s", o->lowfloor);
219 printdebug(" open floor: (%s:%s)", o->efloor.spGetNormal(), o->efloor.spGetDist());
220 printdebug(" open ceiling: (%s:%s)", o->eceiling.spGetNormal(), o->eceiling.spGetDist());
223 if (stopat3dmidtex && (li->flags&ML_3DMIDTEX)) {
226 in.bIsABlockingLine = true;
230 // it's a sky hack wall
231 printdebug("opening: skyhack!");
238 if (!in.bIsABlockingLine) continue;
246 // don't go any farther
251 if (in.Thing == self) continue;
252 hitPoint = in.hitpoint;