X-Git-Url: http://git.xonotic.org/?a=blobdiff_plain;f=qcsrc%2Fserver%2Fg_subs.qc;h=371f9da399ee9988cd7982b9f887239d95dbe1cc;hb=a4aa85e0876a9581bf6b0ff4b9198d82e600999c;hp=ad9d752fcbed9b96e6f8db694fc2ea88a646d486;hpb=03d8c5662a307caed1a0ac242a573f8cff4d67e9;p=xonotic%2Fxonotic-data.pk3dir.git diff --git a/qcsrc/server/g_subs.qc b/qcsrc/server/g_subs.qc index ad9d752fc..371f9da39 100644 --- a/qcsrc/server/g_subs.qc +++ b/qcsrc/server/g_subs.qc @@ -1,6 +1,4 @@ -void SUB_Null() {}; -float SUB_True() { return 1; } -float SUB_False() { return 0; } +void SUB_NullThink(void) { } void(vector destangle, float tspeed, void() func) SUB_CalcAngleMove; void() SUB_CalcMoveDone; @@ -16,6 +14,9 @@ void spawnfunc_info_null (void) void setanim(entity e, vector anim, float looping, float override, float restart) { + if (!anim) + return; // no animation was given to us! We can't use this. + if (anim_x == e.animstate_startframe) if (anim_y == e.animstate_numframes) if (anim_z == e.animstate_framerate) @@ -38,7 +39,7 @@ void setanim(entity e, vector anim, float looping, float override, float restart e.animstate_override = override; e.frame = e.animstate_startframe; e.frame1time = servertime; -}; +} void updateanim(entity e) { @@ -53,31 +54,7 @@ void updateanim(entity e) } e.frame = e.animstate_startframe + bound(0, (time - e.animstate_starttime) * e.animstate_framerate, e.animstate_numframes - 1); //print(ftos(time), " -> ", ftos(e.frame), "\n"); -}; - -float animparseerror; -vector animparseline(float animfile) -{ - local string line; - local float c; - local vector anim; - if (animfile < 0) - return '0 1 2'; - line = fgets(animfile); - c = tokenize_console(line); - if (c < 3) - { - animparseerror = TRUE; - return '0 1 2'; - } - anim_x = stof(argv(0)); - anim_y = stof(argv(1)); - anim_z = stof(argv(2)); - // don't allow completely bogus values - if (anim_x < 0 || anim_y < 1 || anim_z < 0.001) - anim = '0 1 2'; - return anim; -}; +} /* ================== @@ -118,7 +95,7 @@ void SUB_VanishOrRemove (entity ent) if (ent.flags & FL_CLIENT) { // vanish - ent.model = ""; + ent.alpha = -1; ent.effects = 0; ent.glow_size = 0; ent.pflags = 0; @@ -132,12 +109,15 @@ void SUB_VanishOrRemove (entity ent) void SUB_SetFade_Think (void) { + if(self.alpha == 0) + self.alpha = 1; self.think = SUB_SetFade_Think; - self.nextthink = self.fade_time; - self.alpha = 1 - (time - self.fade_time) * self.fade_rate; + self.nextthink = time; + self.alpha -= frametime * self.fade_rate; if (self.alpha < 0.01) SUB_VanishOrRemove(self); - self.alpha = bound(0.01, self.alpha, 1); + else + self.nextthink = time; } /* @@ -153,7 +133,6 @@ void SUB_SetFade (entity ent, float when, float fadetime) // return; //ent.alpha = 1; ent.fade_rate = 1/fadetime; - ent.fade_time = when; ent.think = SUB_SetFade_Think; ent.nextthink = when; } @@ -180,36 +159,41 @@ void SUB_CalcMoveDone (void) void SUB_CalcMove_controller_think (void) { entity oldself; - float movephase; float traveltime; float phasepos; + float nexttick; vector delta; + vector delta2; vector veloc; + vector nextpos; + delta = self.destvec; + delta2 = self.destvec2; if(time < self.animstate_endtime) { - delta = self.destvec; - traveltime = self.animstate_endtime - self.animstate_starttime; - movephase = (time - self.animstate_starttime) / traveltime; - - //bprint(ftos(movephase)); - //bprint("\n"); - - // TODO: Don't mess with the velocity, instead compute where - // we want to be next tick and compute velocity from that - - veloc = delta * (1/traveltime); // QuakeC doesn't allow vector/float division - - // scale velocity with pi/2 so integrated over time we - // still have the original velocity - veloc = veloc * 1.5708; - - // scale velocity with sin(phase) - phasepos = movephase * 3.1416; // phase * pi - phasepos = sin(phasepos); - veloc = veloc * phasepos; + nexttick = time + sys_frametime; + traveltime = self.animstate_endtime - self.animstate_starttime; + phasepos = (nexttick - self.animstate_starttime) / traveltime; // range: [0, 1] + if(self.platmovetype != 1) + { + phasepos = 3.14159265 + (phasepos * 3.14159265); // range: [pi, 2pi] + phasepos = cos(phasepos); // cos [pi, 2pi] is in [-1, 1] + phasepos = phasepos + 1; // correct range to [0, 2] + phasepos = phasepos / 2; // correct range to [0, 1] + } + nextpos = self.origin + (delta * phasepos) + (delta2 * phasepos * phasepos); + // derivative: delta + 2 * delta2 * phasepos (e.g. for angle positioning) + + if(nexttick < self.animstate_endtime) { + veloc = nextpos - self.owner.origin; + veloc = veloc * (1 / sys_frametime); // so it arrives for the next frame + } else { + veloc = self.finaldest - self.owner.origin; + veloc = veloc * (1 / sys_frametime); // so it arrives for the next frame + } self.owner.velocity = veloc; - self.nextthink = time + 0.1; + self.nextthink = nexttick; } else { + // derivative: delta + 2 * delta2 (e.g. for angle positioning) oldself = self; self.owner.think = self.think1; self = self.owner; @@ -218,9 +202,35 @@ void SUB_CalcMove_controller_think (void) } } -void SUB_CalcMove (vector tdest, float tspeed, void() func) +void SUB_CalcMove_controller_setbezier (entity controller, vector org, vector control, vector dest) +{ + // 0 * (1-t) * (1-t) + 2 * control * t * (1-t) + dest * t * t + // 2 * control * t - 2 * control * t * t + dest * t * t + // 2 * control * t + (dest - 2 * control) * t * t + + controller.origin = org; // starting point + control -= org; + dest -= org; + + controller.destvec = 2 * control; // control point + controller.destvec2 = dest - 2 * control; // quadratic part required to reach end point +} + +void SUB_CalcMove_controller_setlinear (entity controller, vector org, vector dest) +{ + // 0 * (1-t) * (1-t) + 2 * control * t * (1-t) + dest * t * t + // 2 * control * t - 2 * control * t * t + dest * t * t + // 2 * control * t + (dest - 2 * control) * t * t + + controller.origin = org; // starting point + dest -= org; + + controller.destvec = dest; // end point + controller.destvec2 = '0 0 0'; +} + +void SUB_CalcMove_Bezier (vector tcontrol, vector tdest, float tspeed, void() func) { - vector delta; float traveltime; entity controller; @@ -231,45 +241,31 @@ void SUB_CalcMove (vector tdest, float tspeed, void() func) self.finaldest = tdest; self.think = SUB_CalcMoveDone; - if (tdest == self.origin) - { - self.velocity = '0 0 0'; - self.nextthink = self.ltime + 0.1; - return; - } - - delta = tdest - self.origin; - traveltime = vlen (delta) / tspeed; + if(tspeed > 0) // positive: start speed + traveltime = 2 * vlen(tcontrol - self.origin) / tspeed; + else // negative: end speed + traveltime = 2 * vlen(tcontrol - tdest) / -tspeed; - if (traveltime < 0.1) + if (traveltime < 0.1) // useless anim { self.velocity = '0 0 0'; self.nextthink = self.ltime + 0.1; return; } - // the controller only thinks every 0.1 seconds, so very short - // animations should just use the traditional movement - if (traveltime < 0.3) - { - self.velocity = delta * (1/traveltime); // QuakeC doesn't allow vector/float division - self.nextthink = self.ltime + traveltime; - return; - } - controller = spawn(); controller.classname = "SUB_CalcMove_controller"; controller.owner = self; - controller.origin = self.origin; // starting point - controller.finaldest = tdest; // where do we want to end? - controller.destvec = delta; + controller.platmovetype = self.platmovetype; + SUB_CalcMove_controller_setbezier(controller, self.origin, tcontrol, tdest); + controller.finaldest = (tdest + '0 0 0.125'); // where do we want to end? Offset to overshoot a bit. controller.animstate_starttime = time; controller.animstate_endtime = time + traveltime; controller.think = SUB_CalcMove_controller_think; controller.think1 = self.think; // the thinking is now done by the controller - self.think = SUB_Null; + self.think = SUB_NullThink; // for PushMove self.nextthink = self.ltime + traveltime; // invoke controller @@ -278,6 +274,43 @@ void SUB_CalcMove (vector tdest, float tspeed, void() func) self = self.owner; } +void SUB_CalcMove (vector tdest, float tspeed, void() func) +{ + vector delta; + float traveltime; + + if (!tspeed) + objerror ("No speed is defined!"); + + self.think1 = func; + self.finaldest = tdest; + self.think = SUB_CalcMoveDone; + + if (tdest == self.origin) + { + self.velocity = '0 0 0'; + self.nextthink = self.ltime + 0.1; + return; + } + + delta = tdest - self.origin; + traveltime = vlen (delta) / tspeed; + + // Very short animations don't really show off the effect + // of controlled animation, so let's just use linear movement. + // Alternatively entities can choose to specify non-controlled movement. + // The only currently implemented alternative movement is linear (value 1) + if (traveltime < 0.15 || self.platmovetype == 1) + { + self.velocity = delta * (1/traveltime); // QuakeC doesn't allow vector/float division + self.nextthink = self.ltime + traveltime; + return; + } + + // now just run like a bezier curve... + SUB_CalcMove_Bezier((self.origin + tdest) * 0.5, tdest, tspeed, func); +} + void SUB_CalcMoveEnt (entity ent, vector tdest, float tspeed, void() func) { entity oldself; @@ -377,8 +410,8 @@ Additionally it moves players back into the past before the trace and restores t */ void tracebox_antilag_force_wz (entity source, vector v1, vector mi, vector ma, vector v2, float nomonst, entity forent, float lag, float wz) { - local entity player; - local float oldsolid; + entity player; + float oldsolid; // check whether antilagged traces are enabled if (lag < 0.001) @@ -387,21 +420,16 @@ void tracebox_antilag_force_wz (entity source, vector v1, vector mi, vector ma, lag = 0; // only antilag for clients // change shooter to SOLID_BBOX so the shot can hit corpses + oldsolid = source.dphitcontentsmask; if(source) - { - oldsolid = source.dphitcontentsmask; source.dphitcontentsmask = DPCONTENTS_SOLID | DPCONTENTS_BODY | DPCONTENTS_CORPSE; - } if (lag) { // take players back into the past - player = player_list; - while (player) - { - antilag_takeback(player, time - lag); - player = player.nextplayer; - } + FOR_EACH_PLAYER(player) + if(player != forent) + antilag_takeback(player, time - lag); } // do the trace @@ -413,12 +441,9 @@ void tracebox_antilag_force_wz (entity source, vector v1, vector mi, vector ma, // restore players to current positions if (lag) { - player = player_list; - while (player) - { - antilag_restore(player); - player = player.nextplayer; - } + FOR_EACH_PLAYER(player) + if(player != forent) + antilag_restore(player); } // restore shooter solid type @@ -431,13 +456,13 @@ void traceline_antilag_force (entity source, vector v1, vector v2, float nomonst } void traceline_antilag (entity source, vector v1, vector v2, float nomonst, entity forent, float lag) { - if (cvar("g_antilag") != 2 || source.cvar_cl_noantilag) + if (autocvar_g_antilag != 2 || source.cvar_cl_noantilag) lag = 0; traceline_antilag_force(source, v1, v2, nomonst, forent, lag); } void tracebox_antilag (entity source, vector v1, vector mi, vector ma, vector v2, float nomonst, entity forent, float lag) { - if (cvar("g_antilag") != 2 || source.cvar_cl_noantilag) + if (autocvar_g_antilag != 2 || source.cvar_cl_noantilag) lag = 0; tracebox_antilag_force_wz(source, v1, mi, ma, v2, nomonst, forent, lag, FALSE); } @@ -447,21 +472,22 @@ void WarpZone_traceline_antilag_force (entity source, vector v1, vector v2, floa } void WarpZone_traceline_antilag (entity source, vector v1, vector v2, float nomonst, entity forent, float lag) { - if (cvar("g_antilag") != 2 || source.cvar_cl_noantilag) + if (autocvar_g_antilag != 2 || source.cvar_cl_noantilag) lag = 0; WarpZone_traceline_antilag_force(source, v1, v2, nomonst, forent, lag); } void WarpZone_tracebox_antilag (entity source, vector v1, vector mi, vector ma, vector v2, float nomonst, entity forent, float lag) { - if (cvar("g_antilag") != 2 || source.cvar_cl_noantilag) + if (autocvar_g_antilag != 2 || source.cvar_cl_noantilag) lag = 0; tracebox_antilag_force_wz(source, v1, mi, ma, v2, nomonst, forent, lag, TRUE); } -float tracebox_inverted (vector v1, vector mi, vector ma, vector v2, float nomonsters, entity forent) // returns the number of traces done, for benchmarking +float tracebox_inverted (vector v1, vector mi, vector ma, vector v2, float nomonsters, entity forent, float stopatentity) // returns the number of traces done, for benchmarking { vector pos, dir, t; float nudge; + entity stopentity; //nudge = 2 * cvar("collision_impactnudge"); // why not? nudge = 0.5; @@ -494,6 +520,8 @@ float tracebox_inverted (vector v1, vector mi, vector ma, vector v2, float nomon dprint(" trace distance is ", ftos(vlen(pos - trace_endpos)), "\n"); } + stopentity = trace_ent; + if(trace_startsolid) { // we started inside solid. @@ -506,6 +534,15 @@ float tracebox_inverted (vector v1, vector mi, vector ma, vector v2, float nomon // t is still inside solid? bad // force advance, then, and retry pos = t + dir * nudge; + + // but if we hit an entity, stop RIGHT before it + if(stopatentity && stopentity) + { + trace_ent = stopentity; + trace_endpos = t; + trace_fraction = ((trace_endpos - v1) * dir) / ((v2 - v1) * dir); + return c; + } } else { @@ -524,59 +561,9 @@ float tracebox_inverted (vector v1, vector mi, vector ma, vector v2, float nomon } } -void traceline_inverted (vector v1, vector v2, float nomonsters, entity forent) +void traceline_inverted (vector v1, vector v2, float nomonsters, entity forent, float stopatentity) { -#if 0 - vector pos, dir, t; - float nudge; - - //nudge = 2 * cvar("collision_impactnudge"); // why not? - nudge = 0.5; - - dir = normalize(v2 - v1); - - pos = v1 + dir * nudge; - - for(;;) - { - if((pos - v1) * dir >= (v2 - v1) * dir) - { - // went too far - trace_fraction = 1; - return; - } - - traceline(pos, v2, nomonsters, forent); - - if(trace_startsolid) - { - // we started inside solid. - // then trace from endpos to pos - t = trace_endpos; - traceline(t, pos, nomonsters, forent); - if(trace_startsolid) - { - // t is inside solid? bad - // force advance, then - pos = pos + dir * nudge; - } - else - { - // we actually LEFT solid! - trace_fraction = ((trace_endpos - v1) * dir) / ((v2 - v1) * dir); - return; - } - } - else - { - // pos is outside solid?!? but why?!? never mind, just return it. - trace_endpos = pos; - trace_fraction = ((trace_endpos - v1) * dir) / ((v2 - v1) * dir); - return; - } - } -#else - tracebox_inverted(v1, '0 0 0', '0 0 0', v2, nomonsters, forent); + tracebox_inverted(v1, '0 0 0', '0 0 0', v2, nomonsters, forent, stopatentity); } /* @@ -676,9 +663,9 @@ float LOD_customize() { float d; - if(cvar("loddebug")) + if(autocvar_loddebug) { - d = cvar("loddebug"); + d = autocvar_loddebug; if(d == 1) self.modelindex = self.lodmodelindex0; else if(d == 2 || !self.lodmodelindex2) @@ -734,7 +721,7 @@ void LODmodel_attach() } } - if(cvar("loddebug") < 0) + if(autocvar_loddebug < 0) { self.lodmodel1 = self.lodmodel2 = ""; // don't even initialize } @@ -765,19 +752,51 @@ void LODmodel_attach() SetCustomizer(self, LOD_customize, LOD_uncustomize); } +void ApplyMinMaxScaleAngles(entity e) +{ + if(e.angles_x != 0 || e.angles_z != 0 || self.avelocity_x != 0 || self.avelocity_z != 0) // "weird" rotation + { + e.maxs = '1 1 1' * vlen( + '1 0 0' * max(-e.mins_x, e.maxs_x) + + '0 1 0' * max(-e.mins_y, e.maxs_y) + + '0 0 1' * max(-e.mins_z, e.maxs_z) + ); + e.mins = -e.maxs; + } + else if(e.angles_y != 0 || self.avelocity_y != 0) // yaw only is a bit better + { + e.maxs_x = vlen( + '1 0 0' * max(-e.mins_x, e.maxs_x) + + '0 1 0' * max(-e.mins_y, e.maxs_y) + ); + e.maxs_y = e.maxs_x; + e.mins_x = -e.maxs_x; + e.mins_y = -e.maxs_x; + } + if(e.scale) + setsize(e, e.mins * e.scale, e.maxs * e.scale); + else + setsize(e, e.mins, e.maxs); +} + void SetBrushEntityModel() { if(self.model != "") { precache_model(self.model); - setmodel(self, self.model); // no precision needed + if(self.mins != '0 0 0' || self.maxs != '0 0 0') + { + vector mi = self.mins; + vector ma = self.maxs; + setmodel(self, self.model); // no precision needed + setsize(self, mi, ma); + } + else + setmodel(self, self.model); // no precision needed InitializeEntity(self, LODmodel_attach, INITPRIO_FINDTARGET); } setorigin(self, self.origin); - if(self.scale) - setsize(self, self.mins * self.scale, self.maxs * self.scale); - else - setsize(self, self.mins, self.maxs); + ApplyMinMaxScaleAngles(self); } void SetBrushEntityModelNoLOD() @@ -785,13 +804,18 @@ void SetBrushEntityModelNoLOD() if(self.model != "") { precache_model(self.model); - setmodel(self, self.model); // no precision needed + if(self.mins != '0 0 0' || self.maxs != '0 0 0') + { + vector mi = self.mins; + vector ma = self.maxs; + setmodel(self, self.model); // no precision needed + setsize(self, mi, ma); + } + else + setmodel(self, self.model); // no precision needed } setorigin(self, self.origin); - if(self.scale) - setsize(self, self.mins * self.scale, self.maxs * self.scale); - else - setsize(self, self.mins, self.maxs); + ApplyMinMaxScaleAngles(self); } /* @@ -811,35 +835,31 @@ void SetMovedir() } self.angles = '0 0 0'; -}; +} void InitTrigger() { // trigger angles are used for one-way touches. An angle of 0 is assumed // to mean no restrictions, so use a yaw of 360 instead. - if (self.movedir == '0 0 0') - if (self.angles != '0 0 0') - SetMovedir (); + SetMovedir (); self.solid = SOLID_TRIGGER; SetBrushEntityModel(); self.movetype = MOVETYPE_NONE; self.modelindex = 0; self.model = ""; -}; +} void InitSolidBSPTrigger() { // trigger angles are used for one-way touches. An angle of 0 is assumed // to mean no restrictions, so use a yaw of 360 instead. - if (self.movedir == '0 0 0') - if (self.angles != '0 0 0') - SetMovedir (); + SetMovedir (); self.solid = SOLID_BSP; SetBrushEntityModel(); self.movetype = MOVETYPE_NONE; // why was this PUSH? -div0 // self.modelindex = 0; self.model = ""; -}; +} float InitMovingBrushTrigger() { @@ -854,4 +874,4 @@ float InitMovingBrushTrigger() return 0; } return 1; -}; +}