1#include "g_subs.qh" 2 3#include "antilag.qh" 4#include "command/common.qh" 5#include "../common/state.qh" 6#include "../lib/warpzone/common.qh" 7#include "../common/triggers/subs.qh" 8 9spawnfunc(info_null) 10{ 11 delete(this); 12 // if anything breaks, tell the mapper to fix his map! info_null is meant to remove itself immediately. 13} 14 15/* 16================== 17main 18 19unused but required by the engine 20================== 21*/ 22void main () 23{ 24 25} 26 27// Misc 28 29/* 30================== 31traceline_antilag 32 33A version of traceline that must be used by SOLID_SLIDEBOX things that want to hit SOLID_CORPSE things with a trace attack 34Additionally it moves players back into the past before the trace and restores them afterward. 35================== 36*/ 37void tracebox_antilag_force_wz (entity source, vector v1, vector mi, vector ma, vector v2, float nomonst, entity forent, float lag, float wz) 38{ 39 // check whether antilagged traces are enabled 40 if (lag < 0.001) 41 lag = 0; 42 if (!IS_REAL_CLIENT(forent)) 43 lag = 0; // only antilag for clients 44 45 // change shooter to SOLID_BBOX so the shot can hit corpses 46 int oldsolid = source.dphitcontentsmask; 47 if(source) 48 source.dphitcontentsmask = DPCONTENTS_SOLID | DPCONTENTS_BODY | DPCONTENTS_CORPSE; 49 50 if (lag) 51 { 52 // take players back into the past 53 FOREACH_CLIENT(IS_PLAYER(it) && it != forent, antilag_takeback(it, CS(it), time - lag)); 54 IL_EACH(g_monsters, it != forent, 55 { 56 antilag_takeback(it, it, time - lag); 57 }); 58 } 59 60 // do the trace 61 if(wz) 62 WarpZone_TraceBox (v1, mi, ma, v2, nomonst, forent); 63 else 64 tracebox (v1, mi, ma, v2, nomonst, forent); 65 66 // restore players to current positions 67 if (lag) 68 { 69 FOREACH_CLIENT(IS_PLAYER(it) && it != forent, antilag_restore(it, CS(it))); 70 IL_EACH(g_monsters, it != forent, 71 { 72 antilag_restore(it, it); 73 }); 74 } 75 76 // restore shooter solid type 77 if(source) 78 source.dphitcontentsmask = oldsolid; 79} 80void traceline_antilag_force (entity source, vector v1, vector v2, float nomonst, entity forent, float lag) 81{ 82 tracebox_antilag_force_wz(source, v1, '0 0 0', '0 0 0', v2, nomonst, forent, lag, false); 83} 84void traceline_antilag (entity source, vector v1, vector v2, float nomonst, entity forent, float lag) 85{ 86 if (autocvar_g_antilag != 2 || source.cvar_cl_noantilag) 87 lag = 0; 88 traceline_antilag_force(source, v1, v2, nomonst, forent, lag); 89} 90void tracebox_antilag (entity source, vector v1, vector mi, vector ma, vector v2, float nomonst, entity forent, float lag) 91{ 92 if (autocvar_g_antilag != 2 || source.cvar_cl_noantilag) 93 lag = 0; 94 tracebox_antilag_force_wz(source, v1, mi, ma, v2, nomonst, forent, lag, false); 95} 96void WarpZone_traceline_antilag_force (entity source, vector v1, vector v2, float nomonst, entity forent, float lag) 97{ 98 tracebox_antilag_force_wz(source, v1, '0 0 0', '0 0 0', v2, nomonst, forent, lag, true); 99} 100void WarpZone_traceline_antilag (entity source, vector v1, vector v2, float nomonst, entity forent, float lag) 101{ 102 if (autocvar_g_antilag != 2 || source.cvar_cl_noantilag) 103 lag = 0; 104 WarpZone_traceline_antilag_force(source, v1, v2, nomonst, forent, lag); 105} 106void WarpZone_tracebox_antilag (entity source, vector v1, vector mi, vector ma, vector v2, float nomonst, entity forent, float lag) 107{ 108 if (autocvar_g_antilag != 2 || source.cvar_cl_noantilag) 109 lag = 0; 110 tracebox_antilag_force_wz(source, v1, mi, ma, v2, nomonst, forent, lag, true); 111} 112 113float tracebox_inverted (vector v1, vector mi, vector ma, vector v2, float nomonsters, entity forent, float stopatentity, entity ignorestopatentity) // returns the number of traces done, for benchmarking 114{ 115 vector pos, dir, t; 116 float nudge; 117 entity stopentity; 118 119 //nudge = 2 * cvar("collision_impactnudge"); // why not? 120 nudge = 0.5; 121 122 dir = normalize(v2 - v1); 123 124 pos = v1 + dir * nudge; 125 126 float c; 127 c = 0; 128 129 for (;;) 130 { 131 if(pos * dir >= v2 * dir) 132 { 133 // went too far 134 trace_fraction = 1; 135 trace_endpos = v2; 136 return c; 137 } 138 139 tracebox(pos, mi, ma, v2, nomonsters, forent); 140 ++c; 141 142 if(c == 50) 143 { 144 LOG_TRACE("HOLY SHIT! When tracing from ", vtos(v1), " to ", vtos(v2)); 145 LOG_TRACE(" Nudging gets us nowhere at ", vtos(pos)); 146 LOG_TRACE(" trace_endpos is ", vtos(trace_endpos)); 147 LOG_TRACE(" trace distance is ", ftos(vlen(pos - trace_endpos))); 148 } 149 150 stopentity = trace_ent; 151 152 if(trace_startsolid) 153 { 154 // we started inside solid. 155 // then trace from endpos to pos 156 t = trace_endpos; 157 tracebox(t, mi, ma, pos, nomonsters, forent); 158 ++c; 159 if(trace_startsolid) 160 { 161 // t is still inside solid? bad 162 // force advance, then, and retry 163 pos = t + dir * nudge; 164 165 // but if we hit an entity, stop RIGHT before it 166 if(stopatentity && stopentity && stopentity != ignorestopatentity) 167 { 168 trace_ent = stopentity; 169 trace_endpos = t; 170 trace_fraction = ((trace_endpos - v1) * dir) / ((v2 - v1) * dir); 171 return c; 172 } 173 } 174 else 175 { 176 // we actually LEFT solid! 177 trace_fraction = ((trace_endpos - v1) * dir) / ((v2 - v1) * dir); 178 return c; 179 } 180 } 181 else 182 { 183 // pos is outside solid?!? but why?!? never mind, just return it. 184 trace_endpos = pos; 185 trace_fraction = ((trace_endpos - v1) * dir) / ((v2 - v1) * dir); 186 return c; 187 } 188 } 189} 190 191void traceline_inverted (vector v1, vector v2, float nomonsters, entity forent, float stopatentity, entity ignorestopatentity) 192{ 193 tracebox_inverted(v1, '0 0 0', '0 0 0', v2, nomonsters, forent, stopatentity, ignorestopatentity); 194} 195 196/* 197================== 198findbetterlocation 199 200Returns a point at least 12 units away from walls 201(useful for explosion animations, although the blast is performed where it really happened) 202Ripped from DPMod 203================== 204*/ 205vector findbetterlocation (vector org, float mindist) 206{ 207 vector loc; 208 vector vec; 209 float c, h; 210 211 vec = mindist * '1 0 0'; 212 c = 0; 213 while (c < 6) 214 { 215 traceline (org, org + vec, true, NULL); 216 vec = vec * -1; 217 if (trace_fraction < 1) 218 { 219 loc = trace_endpos; 220 traceline (loc, loc + vec, true, NULL); 221 if (trace_fraction >= 1) 222 org = loc + vec; 223 } 224 if (c & 1) 225 { 226 h = vec.y; 227 vec.y = vec.x; 228 vec.x = vec.z; 229 vec.z = h; 230 } 231 c = c + 1; 232 } 233 234 return org; 235} 236 237bool LOD_customize(entity this, entity client) 238{ 239 if(autocvar_loddebug) 240 { 241 int d = autocvar_loddebug; 242 if(d == 1) 243 this.modelindex = this.lodmodelindex0; 244 else if(d == 2 || !this.lodmodelindex2) 245 this.modelindex = this.lodmodelindex1; 246 else // if(d == 3) 247 this.modelindex = this.lodmodelindex2; 248 return true; 249 } 250 251 // TODO csqc network this so it only gets sent once 252 vector near_point = NearestPointOnBox(this, client.origin); 253 if(vdist(near_point - client.origin, <, this.loddistance1)) 254 this.modelindex = this.lodmodelindex0; 255 else if(!this.lodmodelindex2 || vdist(near_point - client.origin, <, this.loddistance2)) 256 this.modelindex = this.lodmodelindex1; 257 else 258 this.modelindex = this.lodmodelindex2; 259 260 return true; 261} 262 263void LOD_uncustomize(entity this) 264{ 265 this.modelindex = this.lodmodelindex0; 266} 267 268void LODmodel_attach(entity this) 269{ 270 entity e; 271 272 if(!this.loddistance1) 273 this.loddistance1 = 1000; 274 if(!this.loddistance2) 275 this.loddistance2 = 2000; 276 this.lodmodelindex0 = this.modelindex; 277 278 if(this.lodtarget1 != "") 279 { 280 e = find(NULL, targetname, this.lodtarget1); 281 if(e) 282 { 283 this.lodmodel1 = e.model; 284 delete(e); 285 } 286 } 287 if(this.lodtarget2 != "") 288 { 289 e = find(NULL, targetname, this.lodtarget2); 290 if(e) 291 { 292 this.lodmodel2 = e.model; 293 delete(e); 294 } 295 } 296 297 if(autocvar_loddebug < 0) 298 { 299 this.lodmodel1 = this.lodmodel2 = ""; // don't even initialize 300 } 301 302 if(this.lodmodel1 != "") 303 { 304 vector mi, ma; 305 mi = this.mins; 306 ma = this.maxs; 307 308 precache_model(this.lodmodel1); 309 _setmodel(this, this.lodmodel1); 310 this.lodmodelindex1 = this.modelindex; 311 312 if(this.lodmodel2 != "") 313 { 314 precache_model(this.lodmodel2); 315 _setmodel(this, this.lodmodel2); 316 this.lodmodelindex2 = this.modelindex; 317 } 318 319 this.modelindex = this.lodmodelindex0; 320 setsize(this, mi, ma); 321 } 322 323 if(this.lodmodelindex1) 324 if (!getSendEntity(this)) 325 SetCustomizer(this, LOD_customize, LOD_uncustomize); 326} 327 328void ApplyMinMaxScaleAngles(entity e) 329{ 330 if(e.angles.x != 0 || e.angles.z != 0 || e.avelocity.x != 0 || e.avelocity.z != 0) // "weird" rotation 331 { 332 e.maxs = '1 1 1' * vlen( 333 '1 0 0' * max(-e.mins.x, e.maxs.x) + 334 '0 1 0' * max(-e.mins.y, e.maxs.y) + 335 '0 0 1' * max(-e.mins.z, e.maxs.z) 336 ); 337 e.mins = -e.maxs; 338 } 339 else if(e.angles.y != 0 || e.avelocity.y != 0) // yaw only is a bit better 340 { 341 e.maxs_x = vlen( 342 '1 0 0' * max(-e.mins.x, e.maxs.x) + 343 '0 1 0' * max(-e.mins.y, e.maxs.y) 344 ); 345 e.maxs_y = e.maxs.x; 346 e.mins_x = -e.maxs.x; 347 e.mins_y = -e.maxs.x; 348 } 349 if(e.scale) 350 setsize(e, e.mins * e.scale, e.maxs * e.scale); 351 else 352 setsize(e, e.mins, e.maxs); 353} 354 355void SetBrushEntityModel(entity this) 356{ 357 if(this.model != "") 358 { 359 precache_model(this.model); 360 if(this.mins != '0 0 0' || this.maxs != '0 0 0') 361 { 362 vector mi = this.mins; 363 vector ma = this.maxs; 364 _setmodel(this, this.model); // no precision needed 365 setsize(this, mi, ma); 366 } 367 else 368 _setmodel(this, this.model); // no precision needed 369 InitializeEntity(this, LODmodel_attach, INITPRIO_FINDTARGET); 370 } 371 setorigin(this, this.origin); 372 ApplyMinMaxScaleAngles(this); 373} 374 375void SetBrushEntityModelNoLOD(entity this) 376{ 377 if(this.model != "") 378 { 379 precache_model(this.model); 380 if(this.mins != '0 0 0' || this.maxs != '0 0 0') 381 { 382 vector mi = this.mins; 383 vector ma = this.maxs; 384 _setmodel(this, this.model); // no precision needed 385 setsize(this, mi, ma); 386 } 387 else 388 _setmodel(this, this.model); // no precision needed 389 } 390 setorigin(this, this.origin); 391 ApplyMinMaxScaleAngles(this); 392} 393 394/* 395================ 396InitTrigger 397================ 398*/ 399 400void SetMovedir(entity this) 401{ 402 if(this.movedir != '0 0 0') 403 this.movedir = normalize(this.movedir); 404 else 405 { 406 makevectors(this.angles); 407 this.movedir = v_forward; 408 } 409 410 this.angles = '0 0 0'; 411} 412 413void InitTrigger(entity this) 414{ 415// trigger angles are used for one-way touches. An angle of 0 is assumed 416// to mean no restrictions, so use a yaw of 360 instead. 417 SetMovedir(this); 418 this.solid = SOLID_TRIGGER; 419 SetBrushEntityModel(this); 420 set_movetype(this, MOVETYPE_NONE); 421 this.modelindex = 0; 422 this.model = ""; 423} 424 425void InitSolidBSPTrigger(entity this) 426{ 427// trigger angles are used for one-way touches. An angle of 0 is assumed 428// to mean no restrictions, so use a yaw of 360 instead. 429 SetMovedir(this); 430 this.solid = SOLID_BSP; 431 SetBrushEntityModel(this); 432 set_movetype(this, MOVETYPE_NONE); // why was this PUSH? -div0 433// this.modelindex = 0; 434 this.model = ""; 435} 436 437bool InitMovingBrushTrigger(entity this) 438{ 439// trigger angles are used for one-way touches. An angle of 0 is assumed 440// to mean no restrictions, so use a yaw of 360 instead. 441 this.solid = SOLID_BSP; 442 SetBrushEntityModel(this); 443 set_movetype(this, MOVETYPE_PUSH); 444 if(this.modelindex == 0) 445 { 446 objerror(this, "InitMovingBrushTrigger: no brushes found!"); 447 return false; 448 } 449 return true; 450} 451