| 132 | static int cornersurface = 0; |
| 133 | |
| 134 | bool mmcollide(physent *d, float &hi, float &lo) // collide with a mapmodel |
| 135 | { |
| 136 | const float eyeheight = d->eyeheight, SQRT2HALF = SQRT2 / 2.0f; |
| 137 | const float playerheight = eyeheight + d->aboveeye; |
| 138 | if(editmode) clentstats.firstclip = 0; |
| 139 | for(int i = clentstats.firstclip; i < ents.length(); i++) |
| 140 | { |
| 141 | entity &e = ents[i]; |
| 142 | if (e.type==CLIP || (e.type == PLCLIP && (d->type == ENT_BOT || d->type == ENT_PLAYER || (d->type == ENT_BOUNCE && ((bounceent *)d)->plclipped)))) |
| 143 | { |
| 144 | bool hitarea = false; |
| 145 | switch(e.attr7 & 3) |
| 146 | { |
| 147 | default: // classic unrotated clip, possibly tilted |
| 148 | hitarea = (fabs(e.x - d->o.x) - (float(e.attr2) / ENTSCALE5 + d->radius) < 1e-5) && (fabs(e.y - d->o.y) - (float(e.attr3) / ENTSCALE5 + d->radius) < 1e-5); // fix PLCLIP-step-up bug where e.g. 2.1<=2.1 was FALSE [sic!] |
| 149 | break; |
| 150 | case 3: // clip rotated 45° |
| 151 | { |
| 152 | float rx = (e.x - d->o.x) * SQRT2HALF, ry = (e.y - d->o.y) * SQRT2HALF, rr = d->radius * SQRT2; // rotate player instead of clip (adjust player radius to compensate) |
| 153 | float a1 = fabs(rx - ry) - float(e.attr3) / ENTSCALE5 - rr, a2 = fabs(rx + ry) - float(e.attr2) / ENTSCALE5 - rr; |
| 154 | if(a1 < 0 && a2 < 0) |
| 155 | { |
| 156 | float a3 = a1 + a2 + rr; |
| 157 | if(a3 < 0) hitarea = true; |
| 158 | if(a3 < -1e-2 && (a3 < -rr || a1 * a2 < 0.42f)) cornersurface = a1 > a2 ? 1 : 2; |
| 159 | } |
| 160 | break; |
| 161 | } |
| 162 | } |
| 163 | if(hitarea) |
| 164 | { |
| 165 | float cz = float(S(e.x, e.y)->floor + float(e.attr1) / ENTSCALE10), ch = float(e.attr4) / ENTSCALE5; |
| 166 | if(e.attr6) switch(e.attr7 & 3) |
| 167 | { // incredibly ugly solution - but it only applies on the one tilted clip we stand on |
| 168 | case 1: cz += (floor(0.5f + clamp(d->o.x - e.x + d->radius * (e.attr6 > 0 ? 1 : -1), -float(e.attr2) / ENTSCALE5, float(e.attr2) / ENTSCALE5))) * float(e.attr6) / (4 * ENTSCALE10); break; // tilt x |
| 169 | case 2: cz += (floor(0.5f + clamp(d->o.y - e.y + d->radius * (e.attr6 > 0 ? 1 : -1), -float(e.attr3) / ENTSCALE5, float(e.attr3) / ENTSCALE5))) * float(e.attr6) / (4 * ENTSCALE10); break; // tilt y |
| 170 | } |
| 171 | const float dz = d->o.z - d->eyeheight; |
| 172 | if(dz < cz - 0.42) { if(cz<hi) hi = cz; } |
| 173 | else if(cz+ch>lo) lo = cz+ch; |
| 174 | if(hi-lo < playerheight) return true; |
| 175 | if(dz + (d->type != ENT_BOUNCE ? 1.26 : 0) > cz + ch || dz + playerheight < cz) cornersurface = 0; |
| 176 | } |
| 177 | } |
| 178 | else if(e.type==MAPMODEL) |
| 179 | { |
| 180 | mapmodelinfo *mmi = getmminfo(e.attr2); |
| 181 | if(!mmi || !mmi->h) continue; |
| 182 | const float r = mmi->rad + d->radius; |
| 183 | if(fabs(e.x-d->o.x)<r && fabs(e.y-d->o.y)<r) |
| 184 | { |
| 185 | const float mmz = float(S(e.x, e.y)->floor + mmi->zoff + float(e.attr3) / ENTSCALE5); |
| 186 | const float dz = d->o.z-eyeheight; |
| 187 | if(dz < mmz - 0.42) { if(mmz < hi) hi = mmz; } |
| 188 | else if(mmz + mmi->h > lo) lo = mmz + mmi->h; |
| 189 | if(hi-lo < playerheight) return true; |
| 190 | } |
| 191 | } |