3 void(vector destangle, float tspeed, void() func) SUB_CalcAngleMove;
4 void() SUB_CalcMoveDone;
5 void() SUB_CalcAngleMoveDone;
6 //void() SUB_UseTargets;
9 void spawnfunc_info_null (void)
12 // if anything breaks, tell the mapper to fix his map! info_null is meant to remove itself immediately.
22 void SUB_Remove (void)
31 Applies some friction to self
35 void SUB_Friction (void)
37 self.nextthink = time;
38 if(self.flags & FL_ONGROUND)
39 self.velocity = self.velocity * (1 - frametime * self.friction);
46 Makes client invisible or removes non-client
49 void SUB_VanishOrRemove (entity ent)
51 if (ent.flags & FL_CLIENT)
66 void SUB_SetFade_Think (void)
68 self.think = SUB_SetFade_Think;
69 self.nextthink = self.fade_time;
70 self.alpha = 1 - (time - self.fade_time) * self.fade_rate;
71 if (self.alpha < 0.01)
72 SUB_VanishOrRemove(self);
73 self.alpha = bound(0.01, self.alpha, 1);
80 Fade 'ent' out when time >= 'when'
83 void SUB_SetFade (entity ent, float when, float fadetime)
85 //if (ent.flags & FL_CLIENT) // && ent.deadflag != DEAD_NO)
88 ent.fade_rate = 1/fadetime;
90 ent.think = SUB_SetFade_Think;
98 calculate self.velocity and self.nextthink to reach dest from
99 self.origin traveling at speed
102 void SUB_CalcMoveDone (void)
104 // After moving, set origin to exact final destination
106 setorigin (self, self.finaldest);
107 self.velocity = '0 0 0';
113 void SUB_CalcMove (vector tdest, float tspeed, void() func)
119 objerror ("No speed is defined!");
122 self.finaldest = tdest;
123 self.think = SUB_CalcMoveDone;
125 if (tdest == self.origin)
127 self.velocity = '0 0 0';
128 self.nextthink = self.ltime + 0.1;
132 delta = tdest - self.origin;
133 traveltime = vlen (delta) / tspeed;
135 if (traveltime < 0.1)
137 self.velocity = '0 0 0';
138 self.nextthink = self.ltime + 0.1;
142 self.velocity = delta * (1/traveltime); // QuakeC doesn't allow vector/float division
144 self.nextthink = self.ltime + traveltime;
147 void SUB_CalcMoveEnt (entity ent, vector tdest, float tspeed, void() func)
154 SUB_CalcMove (tdest, tspeed, func);
163 calculate self.avelocity and self.nextthink to reach destangle from
166 The calling function should make sure self.think is valid
169 void SUB_CalcAngleMoveDone (void)
171 // After rotating, set angle to exact final angle
172 self.angles = self.finalangle;
173 self.avelocity = '0 0 0';
179 // FIXME: I fixed this function only for rotation around the main axes
180 void SUB_CalcAngleMove (vector destangle, float tspeed, void() func)
186 objerror ("No speed is defined!");
188 // take the shortest distance for the angles
189 self.angles_x -= 360 * floor((self.angles_x - destangle_x) / 360 + 0.5);
190 self.angles_y -= 360 * floor((self.angles_y - destangle_y) / 360 + 0.5);
191 self.angles_z -= 360 * floor((self.angles_z - destangle_z) / 360 + 0.5);
192 delta = destangle - self.angles;
193 traveltime = vlen (delta) / tspeed;
196 self.finalangle = destangle;
197 self.think = SUB_CalcAngleMoveDone;
199 if (traveltime < 0.1)
201 self.avelocity = '0 0 0';
202 self.nextthink = self.ltime + 0.1;
206 self.avelocity = delta * (1 / traveltime);
207 self.nextthink = self.ltime + traveltime;
210 void SUB_CalcAngleMoveEnt (entity ent, vector destangle, float tspeed, void() func)
217 SUB_CalcAngleMove (destangle, tspeed, func);
226 unused but required by the engine
240 A version of traceline that must be used by SOLID_SLIDEBOX things that want to hit SOLID_CORPSE things with a trace attack
241 Additionally it moves players back into the past before the trace and restores them afterward.
244 void traceline_antilag_force (entity source, vector v1, vector v2, float nomonst, entity forent, float lag)
247 local float oldsolid;
249 // check whether antilagged traces are enabled
252 if (clienttype(forent) != CLIENTTYPE_REAL)
253 lag = 0; // only antilag for clients
255 // change shooter to SOLID_BBOX so the shot can hit corpses
256 oldsolid = source.dphitcontentsmask;
257 source.dphitcontentsmask = DPCONTENTS_SOLID | DPCONTENTS_BODY | DPCONTENTS_CORPSE;
261 // take players back into the past
262 player = player_list;
265 antilag_takeback(player, time - lag);
266 player = player.nextplayer;
271 traceline (v1, v2, nomonst, forent);
273 // restore players to current positions
276 player = player_list;
279 antilag_restore(player);
280 player = player.nextplayer;
284 // restore shooter solid type
285 source.dphitcontentsmask = oldsolid;
287 void traceline_antilag (entity source, vector v1, vector v2, float nomonst, entity forent, float lag)
289 if (cvar("g_antilag") != 2)
291 traceline_antilag_force(source, v1, v2, nomonst, forent, lag);
294 float tracebox_inverted (vector v1, vector mi, vector ma, vector v2, float nomonsters, entity forent) // returns the number of traces done, for benchmarking
299 //nudge = 2 * cvar("collision_impactnudge"); // why not?
302 dir = normalize(v2 - v1);
304 pos = v1 + dir * nudge;
311 if((pos - v1) * dir >= (v2 - v1) * dir)
319 tracebox(pos, mi, ma, v2, nomonsters, forent);
324 dprint("HOLY SHIT! When tracing from ", vtos(v1), " to ", vtos(v2), "\n");
325 dprint(" Nudging gets us nowhere at ", vtos(pos), "\n");
326 dprint(" trace_endpos is ", vtos(trace_endpos), "\n");
327 dprint(" trace distance is ", ftos(vlen(pos - trace_endpos)), "\n");
332 // we started inside solid.
333 // then trace from endpos to pos
335 tracebox(t, mi, ma, pos, nomonsters, forent);
339 // t is still inside solid? bad
340 // force advance, then, and retry
341 pos = t + dir * nudge;
345 // we actually LEFT solid!
346 trace_fraction = ((trace_endpos - v1) * dir) / ((v2 - v1) * dir);
352 // pos is outside solid?!? but why?!? never mind, just return it.
354 trace_fraction = ((trace_endpos - v1) * dir) / ((v2 - v1) * dir);
360 void traceline_inverted (vector v1, vector v2, float nomonsters, entity forent)
366 //nudge = 2 * cvar("collision_impactnudge"); // why not?
369 dir = normalize(v2 - v1);
371 pos = v1 + dir * nudge;
375 if((pos - v1) * dir >= (v2 - v1) * dir)
382 traceline(pos, v2, nomonsters, forent);
386 // we started inside solid.
387 // then trace from endpos to pos
389 traceline(t, pos, nomonsters, forent);
392 // t is inside solid? bad
393 // force advance, then
394 pos = pos + dir * nudge;
398 // we actually LEFT solid!
399 trace_fraction = ((trace_endpos - v1) * dir) / ((v2 - v1) * dir);
405 // pos is outside solid?!? but why?!? never mind, just return it.
407 trace_fraction = ((trace_endpos - v1) * dir) / ((v2 - v1) * dir);
412 tracebox_inverted(v1, '0 0 0', '0 0 0', v2, nomonsters, forent);
419 Returns a point at least 12 units away from walls
420 (useful for explosion animations, although the blast is performed where it really happened)
424 vector findbetterlocation (vector org, float mindist)
430 vec = mindist * '1 0 0';
434 traceline (org, org + vec, TRUE, world);
436 if (trace_fraction < 1)
439 traceline (loc, loc + vec, TRUE, world);
440 if (trace_fraction >= 1)
460 Returns a random number between -1.0 and 1.0
465 return 2 * (random () - 0.5);
470 Angc used for animations
475 float angc (float a1, float a2)
502 .float lodmodelindex0;
503 .float lodmodelindex1;
504 .float lodmodelindex2;
508 vector NearestPointOnBox(entity box, vector org);
509 float LOD_customize()
515 d = cvar("loddebug");
517 self.modelindex = self.lodmodelindex0;
519 self.modelindex = self.lodmodelindex1;
521 self.modelindex = self.lodmodelindex2;
525 // TODO csqc network this so it only gets sent once
526 d = vlen(NearestPointOnBox(self, other.origin) - other.origin);
527 if(d < self.loddistance1)
528 self.modelindex = self.lodmodelindex0;
529 else if(!self.lodmodelindex2 || d < self.loddistance2)
530 self.modelindex = self.lodmodelindex1;
532 self.modelindex = self.lodmodelindex2;
537 void LOD_uncustomize()
539 self.modelindex = self.lodmodelindex0;
542 void LODmodel_attach()
546 if(!self.loddistance1)
547 self.loddistance1 = 1000;
548 if(!self.loddistance2)
549 self.loddistance2 = 2000;
550 self.lodmodelindex0 = self.modelindex;
552 if(self.lodtarget1 != "")
554 e = find(world, targetname, self.lodtarget1);
557 self.lodmodel1 = e.model;
561 if(self.lodtarget2 != "")
563 e = find(world, targetname, self.lodtarget2);
566 self.lodmodel2 = e.model;
571 if(cvar("loddebug") < 0)
573 self.lodmodel1 = self.lodmodel2 = ""; // don't even initialize
576 if(self.lodmodel1 != "")
582 precache_model(self.lodmodel1);
583 setmodel(self, self.lodmodel1);
584 self.lodmodelindex1 = self.modelindex;
586 if(self.lodmodel2 != "")
588 precache_model(self.lodmodel2);
589 setmodel(self, self.lodmodel2);
590 self.lodmodelindex2 = self.modelindex;
593 self.modelindex = self.lodmodelindex0;
594 setsize(self, mi, ma);
597 if(self.lodmodelindex1)
598 SetCustomizer(self, LOD_customize, LOD_uncustomize);
601 void SetBrushEntityModel()
605 precache_model(self.model);
606 setmodel(self, self.model); // no precision needed
607 InitializeEntity(self, LODmodel_attach, INITPRIO_FINDTARGET);
609 setorigin(self, self.origin);
611 setsize(self, self.mins * self.scale, self.maxs * self.scale);
613 setsize(self, self.mins, self.maxs);
624 if (self.movedir != '0 0 0')
625 self.movedir = normalize(self.movedir);
628 if (self.angles == '0 -1 0')
629 self.movedir = '0 0 1';
630 else if (self.angles == '0 -2 0')
631 self.movedir = '0 0 -1';
634 makevectors (self.angles);
635 self.movedir = v_forward;
639 self.angles = '0 0 0';
644 // trigger angles are used for one-way touches. An angle of 0 is assumed
645 // to mean no restrictions, so use a yaw of 360 instead.
646 if (self.movedir == '0 0 0')
647 if (self.angles != '0 0 0')
649 self.solid = SOLID_TRIGGER;
650 SetBrushEntityModel();
651 self.movetype = MOVETYPE_NONE;
656 void InitSolidBSPTrigger()
658 // trigger angles are used for one-way touches. An angle of 0 is assumed
659 // to mean no restrictions, so use a yaw of 360 instead.
660 if (self.movedir == '0 0 0')
661 if (self.angles != '0 0 0')
663 self.solid = SOLID_BSP;
664 SetBrushEntityModel();
665 self.movetype = MOVETYPE_NONE; // why was this PUSH? -div0
666 // self.modelindex = 0;
670 float InitMovingBrushTrigger()
672 // trigger angles are used for one-way touches. An angle of 0 is assumed
673 // to mean no restrictions, so use a yaw of 360 instead.
674 self.solid = SOLID_BSP;
675 SetBrushEntityModel();
676 self.movetype = MOVETYPE_PUSH;
677 if(self.modelindex == 0)
679 objerror("InitMovingBrushTrigger: no brushes found!");