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 traceline_inverted (vector v1, 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 traceline(pos, v2, nomonsters, forent);
319 // we started inside solid.
320 // then trace from endpos to pos
322 traceline(t, 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);
350 Returns a point at least 12 units away from walls
351 (useful for explosion animations, although the blast is performed where it really happened)
355 vector findbetterlocation (vector org, float mindist)
361 vec = mindist * '1 0 0';
365 traceline (org, org + vec, TRUE, world);
367 if (trace_fraction < 1)
370 traceline (loc, loc + vec, TRUE, world);
371 if (trace_fraction >= 1)
390 Returns a random number between -1.0 and 1.0
395 return 2 * (random () - 0.5);
400 Angc used for animations
405 float angc (float a1, float a2)
432 .float lodmodelindex0;
433 .float lodmodelindex1;
434 .float lodmodelindex2;
438 vector NearestPointOnBox(entity box, vector org);
439 float LOD_customize()
445 d = cvar("loddebug");
447 self.modelindex = self.lodmodelindex0;
449 self.modelindex = self.lodmodelindex1;
451 self.modelindex = self.lodmodelindex2;
455 // TODO csqc network this so it only gets sent once
456 d = vlen(NearestPointOnBox(self, other.origin) - other.origin);
457 if(d < self.loddistance1)
458 self.modelindex = self.lodmodelindex0;
459 else if(!self.lodmodelindex2 || d < self.loddistance2)
460 self.modelindex = self.lodmodelindex1;
462 self.modelindex = self.lodmodelindex2;
467 void LOD_uncustomize()
469 self.modelindex = self.lodmodelindex0;
472 void LODmodel_attach()
476 if(!self.loddistance1)
477 self.loddistance1 = 1000;
478 if(!self.loddistance2)
479 self.loddistance2 = 2000;
480 self.lodmodelindex0 = self.modelindex;
482 if(self.lodtarget1 != "")
484 e = find(world, targetname, self.lodtarget1);
487 self.lodmodel1 = e.model;
491 if(self.lodtarget2 != "")
493 e = find(world, targetname, self.lodtarget2);
496 self.lodmodel2 = e.model;
501 if(self.lodmodel1 != "")
507 precache_model(self.lodmodel1);
508 setmodel(self, self.lodmodel1);
509 self.lodmodelindex1 = self.modelindex;
511 if(self.lodmodel2 != "")
513 precache_model(self.lodmodel2);
514 setmodel(self, self.lodmodel2);
515 self.lodmodelindex2 = self.modelindex;
518 self.modelindex = self.lodmodelindex0;
519 setsize(self, mi, ma);
522 if(self.lodmodelindex1)
523 SetCustomizer(self, LOD_customize, LOD_uncustomize);
526 void SetBrushEntityModel()
530 precache_model(self.model);
531 setmodel(self, self.model); // no precision needed
532 InitializeEntity(self, LODmodel_attach, INITPRIO_FINDTARGET);
534 setorigin(self, self.origin);
536 setsize(self, self.mins * self.scale, self.maxs * self.scale);
538 setsize(self, self.mins, self.maxs);
549 if (self.movedir != '0 0 0')
550 self.movedir = normalize(self.movedir);
553 if (self.angles == '0 -1 0')
554 self.movedir = '0 0 1';
555 else if (self.angles == '0 -2 0')
556 self.movedir = '0 0 -1';
559 makevectors (self.angles);
560 self.movedir = v_forward;
564 self.angles = '0 0 0';
569 // trigger angles are used for one-way touches. An angle of 0 is assumed
570 // to mean no restrictions, so use a yaw of 360 instead.
571 if (self.movedir == '0 0 0')
572 if (self.angles != '0 0 0')
574 self.solid = SOLID_TRIGGER;
575 SetBrushEntityModel();
576 self.movetype = MOVETYPE_NONE;
581 void InitSolidBSPTrigger()
583 // trigger angles are used for one-way touches. An angle of 0 is assumed
584 // to mean no restrictions, so use a yaw of 360 instead.
585 if (self.movedir == '0 0 0')
586 if (self.angles != '0 0 0')
588 self.solid = SOLID_BSP;
589 SetBrushEntityModel();
590 self.movetype = MOVETYPE_PUSH;
591 // self.modelindex = 0;
595 void InitMovingBrushTrigger()
597 // trigger angles are used for one-way touches. An angle of 0 is assumed
598 // to mean no restrictions, so use a yaw of 360 instead.
599 self.solid = SOLID_BSP;
600 SetBrushEntityModel();
601 self.movetype = MOVETYPE_PUSH;