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 void tracebox_inverted (vector v1, vector mi, vector ma, vector v2, float nomonsters, entity forent)
299 //nudge = 2 * cvar("collision_impactnudge"); // why not?
302 dir = normalize(v2 - v1);
304 pos = v1 + dir * nudge;
308 if((pos - v1) * dir >= (v2 - v1) * dir)
315 tracebox(pos, mi, ma, v2, nomonsters, forent);
319 // we started inside solid.
320 // then trace from endpos to pos
322 tracebox(t, mi, ma, pos, nomonsters, forent);
325 // t is inside solid? bad
326 // force advance, then
327 pos = pos + dir * nudge;
331 // we actually LEFT solid!
332 trace_fraction = ((trace_endpos - v1) * dir) / ((v2 - v1) * dir);
338 // pos is outside solid?!? but why?!? never mind, just return it.
340 trace_fraction = ((trace_endpos - v1) * dir) / ((v2 - v1) * dir);
346 void traceline_inverted (vector v1, vector v2, float nomonsters, entity forent)
352 //nudge = 2 * cvar("collision_impactnudge"); // why not?
355 dir = normalize(v2 - v1);
357 pos = v1 + dir * nudge;
361 if((pos - v1) * dir >= (v2 - v1) * dir)
368 traceline(pos, v2, nomonsters, forent);
372 // we started inside solid.
373 // then trace from endpos to pos
375 traceline(t, pos, nomonsters, forent);
378 // t is inside solid? bad
379 // force advance, then
380 pos = pos + dir * nudge;
384 // we actually LEFT solid!
385 trace_fraction = ((trace_endpos - v1) * dir) / ((v2 - v1) * dir);
391 // pos is outside solid?!? but why?!? never mind, just return it.
393 trace_fraction = ((trace_endpos - v1) * dir) / ((v2 - v1) * dir);
398 tracebox_inverted(v1, '0 0 0', '0 0 0', v2, nomonsters, forent);
405 Returns a point at least 12 units away from walls
406 (useful for explosion animations, although the blast is performed where it really happened)
410 vector findbetterlocation (vector org, float mindist)
416 vec = mindist * '1 0 0';
420 traceline (org, org + vec, TRUE, world);
422 if (trace_fraction < 1)
425 traceline (loc, loc + vec, TRUE, world);
426 if (trace_fraction >= 1)
445 Returns a random number between -1.0 and 1.0
450 return 2 * (random () - 0.5);
455 Angc used for animations
460 float angc (float a1, float a2)
487 .float lodmodelindex0;
488 .float lodmodelindex1;
489 .float lodmodelindex2;
493 vector NearestPointOnBox(entity box, vector org);
494 float LOD_customize()
500 d = cvar("loddebug");
502 self.modelindex = self.lodmodelindex0;
504 self.modelindex = self.lodmodelindex1;
506 self.modelindex = self.lodmodelindex2;
510 // TODO csqc network this so it only gets sent once
511 d = vlen(NearestPointOnBox(self, other.origin) - other.origin);
512 if(d < self.loddistance1)
513 self.modelindex = self.lodmodelindex0;
514 else if(!self.lodmodelindex2 || d < self.loddistance2)
515 self.modelindex = self.lodmodelindex1;
517 self.modelindex = self.lodmodelindex2;
522 void LOD_uncustomize()
524 self.modelindex = self.lodmodelindex0;
527 void LODmodel_attach()
531 if(!self.loddistance1)
532 self.loddistance1 = 1000;
533 if(!self.loddistance2)
534 self.loddistance2 = 2000;
535 self.lodmodelindex0 = self.modelindex;
537 if(self.lodtarget1 != "")
539 e = find(world, targetname, self.lodtarget1);
542 self.lodmodel1 = e.model;
546 if(self.lodtarget2 != "")
548 e = find(world, targetname, self.lodtarget2);
551 self.lodmodel2 = e.model;
556 if(self.lodmodel1 != "")
562 precache_model(self.lodmodel1);
563 setmodel(self, self.lodmodel1);
564 self.lodmodelindex1 = self.modelindex;
566 if(self.lodmodel2 != "")
568 precache_model(self.lodmodel2);
569 setmodel(self, self.lodmodel2);
570 self.lodmodelindex2 = self.modelindex;
573 self.modelindex = self.lodmodelindex0;
574 setsize(self, mi, ma);
577 if(self.lodmodelindex1)
578 SetCustomizer(self, LOD_customize, LOD_uncustomize);
581 void SetBrushEntityModel()
585 precache_model(self.model);
586 setmodel(self, self.model); // no precision needed
587 InitializeEntity(self, LODmodel_attach, INITPRIO_FINDTARGET);
589 setorigin(self, self.origin);
591 setsize(self, self.mins * self.scale, self.maxs * self.scale);
593 setsize(self, self.mins, self.maxs);
604 if (self.movedir != '0 0 0')
605 self.movedir = normalize(self.movedir);
608 if (self.angles == '0 -1 0')
609 self.movedir = '0 0 1';
610 else if (self.angles == '0 -2 0')
611 self.movedir = '0 0 -1';
614 makevectors (self.angles);
615 self.movedir = v_forward;
619 self.angles = '0 0 0';
624 // trigger angles are used for one-way touches. An angle of 0 is assumed
625 // to mean no restrictions, so use a yaw of 360 instead.
626 if (self.movedir == '0 0 0')
627 if (self.angles != '0 0 0')
629 self.solid = SOLID_TRIGGER;
630 SetBrushEntityModel();
631 self.movetype = MOVETYPE_NONE;
636 void InitSolidBSPTrigger()
638 // trigger angles are used for one-way touches. An angle of 0 is assumed
639 // to mean no restrictions, so use a yaw of 360 instead.
640 if (self.movedir == '0 0 0')
641 if (self.angles != '0 0 0')
643 self.solid = SOLID_BSP;
644 SetBrushEntityModel();
645 self.movetype = MOVETYPE_NONE; // why was this PUSH? -div0
646 // self.modelindex = 0;
650 float InitMovingBrushTrigger()
652 // trigger angles are used for one-way touches. An angle of 0 is assumed
653 // to mean no restrictions, so use a yaw of 360 instead.
654 self.solid = SOLID_BSP;
655 SetBrushEntityModel();
656 self.movetype = MOVETYPE_PUSH;
657 if(self.modelindex == 0)
659 objerror("InitMovingBrushTrigger: no brushes found!");