-void _Movetype_PushMove(entity this, float dt) // SV_PushMove
+#include "push.qh"
+
+void _Movetype_PushMove(entity this, float dt) // SV_PushMove
{
- if (this.move_velocity == '0 0 0' && this.move_avelocity == '0 0 0')
+ if(this.velocity == '0 0 0' && this.avelocity == '0 0 0')
{
- this.move_ltime += dt;
+ this.ltime += dt;
return;
}
- switch (this.solid)
+ switch(this.solid)
{
- // LordHavoc: valid pusher types
+ // LadyHavoc: valid pusher types
case SOLID_BSP:
case SOLID_BBOX:
case SOLID_SLIDEBOX:
- case SOLID_CORPSE: // LordHavoc: this would be weird...
+ case SOLID_CORPSE: // LadyHavoc: this would be weird...
break;
- // LordHavoc: no collisions
+ // LadyHavoc: no collisions
case SOLID_NOT:
case SOLID_TRIGGER:
- this.move_origin = this.move_origin + dt * this.move_velocity;
- this.move_angles = this.move_angles + dt * this.move_avelocity;
- this.move_angles_x -= 360.0 * floor(this.move_angles.x * (1.0 / 360.0));
- this.move_angles_y -= 360.0 * floor(this.move_angles.y * (1.0 / 360.0));
- this.move_angles_z -= 360.0 * floor(this.move_angles.z * (1.0 / 360.0));
- this.move_ltime += dt;
- _Movetype_LinkEdict(this, true);
+ {
+ this.origin = this.origin + dt * this.velocity;
+ this.angles = this.angles + dt * this.avelocity;
+ this.angles_x -= 360.0 * floor(this.angles_x * (1.0 / 360.0));
+ this.angles_y -= 360.0 * floor(this.angles_y * (1.0 / 360.0));
+ this.angles_z -= 360.0 * floor(this.angles_z * (1.0 / 360.0));
+ this.ltime += dt;
+ _Movetype_LinkEdict(this, false);
return;
+ }
default:
- LOG_TRACEF("_Movetype_PushMove: entity %e, unrecognized solid type %d\n", this, this.solid);
+ {
+ LOG_INFOF("_Movetype_Physics_Push: entity #%d, unrecognized solid type %d", etof(this), this.solid);
return;
+ }
+ }
+ if(!this.modelindex)
+ {
+ LOG_INFOF("_Movetype_Physics_Push: entity #%d has an invalid modelindex %d", etof(this), this.modelindex);
+ return;
}
- bool rotated = (this.move_angles * this.move_angles) + (this.move_avelocity * this.move_avelocity) > 0;
+ bool rotated = ((vlen2(this.angles) + vlen2(this.avelocity)) > 0);
- vector move1 = this.move_velocity * dt;
- vector moveangle = this.move_avelocity * dt;
+ vector move1 = this.velocity * dt;
+ vector moveangle = this.avelocity * dt;
- makevectors_matrix(-moveangle);
+ vector a = -moveangle;
+ vector forward, left, up;
+ MAKE_VECTORS(a, forward, left, up);
+ left *= -1; // actually make it left!
-// vector pushorig = this.move_origin;
-// vector pushang = this.move_angles;
-// float pushltime = this.move_ltime;
+ vector pushorig = this.origin;
+ vector pushang = this.angles;
+ float pushltime = this.ltime;
-// move the pusher to its final position
+ // move the pusher to its final position
- this.move_origin = this.move_origin + dt * this.move_velocity;
- this.move_angles = this.move_angles + dt * this.move_avelocity;
+ this.origin = this.origin + dt * this.velocity;
+ this.angles = this.angles + dt * this.avelocity;
+ this.ltime += dt;
+ _Movetype_LinkEdict(this, false); // pulls absmin/absmax from the engine
- this.move_ltime += dt;
- _Movetype_LinkEdict(this, true);
+ if(this.move_movetype == MOVETYPE_FAKEPUSH) // Tenebrae's MOVETYPE_PUSH variant that doesn't push...
+ {
+ this.angles_x -= 360.0 * floor(this.angles_x * (1.0 / 360.0));
+ this.angles_y -= 360.0 * floor(this.angles_y * (1.0 / 360.0));
+ this.angles_z -= 360.0 * floor(this.angles_z * (1.0 / 360.0));
+ return;
+ }
- int savesolid = this.solid;
+ IL_CLEAR(g_pushmove_moved); // make sure it's not somehow uncleared
- if (this.move_movetype != MOVETYPE_FAKEPUSH)
+ for(entity check = findradius((this.absmin + this.absmax) * 0.5, vlen(this.absmax - this.absmin) * 0.5 + 1); check; check = check.chain)
{
- for (entity check = findradius(0.5 * (this.absmin + this.absmax), 0.5 * vlen(this.absmax - this.absmin)); check; check = check.chain)
+ switch(check.move_movetype)
{
- switch (check.move_movetype)
- {
- case MOVETYPE_NONE:
- case MOVETYPE_PUSH:
- case MOVETYPE_FOLLOW:
- case MOVETYPE_NOCLIP:
- case MOVETYPE_FLY_WORLDONLY:
- continue;
- default:
- break;
- }
-
- if (check.owner == this)
+ case MOVETYPE_NONE:
+ case MOVETYPE_PUSH:
+ case MOVETYPE_FOLLOW:
+ case MOVETYPE_NOCLIP:
+ case MOVETYPE_FLY_WORLDONLY:
continue;
+ default:
+ break;
+ }
+
+ if(check.owner == this || this.owner == check)
+ continue;
- if (this.owner == check)
+ // if the entity is standing on the pusher, it will definitely be moved
+ // if the entity is not standing on the pusher, but is in the pusher's
+ // final position, move it
+ if (!IS_ONGROUND(check) || check.groundentity != this)
+ {
+ tracebox(check.origin, check.mins, check.maxs, check.origin, MOVE_NOMONSTERS, check);
+ if(!trace_startsolid)
continue;
+ }
+ vector pivot = check.mins + 0.5 * (check.maxs - check.mins);
+ vector move;
- vector pivot = check.mins + 0.5 * (check.maxs - check.mins);
- vector move;
- if (rotated)
- {
- vector org = (check.move_origin - this.move_origin) + pivot;
- vector org2;
- org2.x = org * v_forward;
- org2.y = org * v_right;
- org2.z = org * v_up;
- move = (org2 - org) + move1;
- }
- else
- {
- move = move1;
- }
+ if(rotated)
+ {
+ vector org = check.origin - this.origin;
+ org = org + pivot;
+
+ vector org2;
+ org2.x = (org * forward);
+ org2.y = (org * left);
+ org2.z = (org * up);
+ move = org2 - org;
+ move = move + move1;
+ }
+ else
+ move = move1;
+
+ check.moved_from = check.origin;
+ check.moved_fromangles = check.angles;
+ IL_PUSH(g_pushmove_moved, check);
+
+ // physics objects need better collisions than this code can do
+ if(check.move_movetype == MOVETYPE_PHYSICS)
+ {
+ check.origin = check.origin + move;
+ _Movetype_LinkEdict(check, true);
+ continue;
+ }
- // physics objects need better collisions than this code can do
- if (check.move_movetype == 32) // MOVETYPE_PHYSICS
+ // try moving the contacted entity
+ int savesolid = this.solid;
+ this.solid = SOLID_NOT;
+ if(!_Movetype_PushEntity(check, move, true))
+ {
+ // entity "check" got teleported
+ check.angles_y += trace_fraction * moveangle.y;
+ this.solid = savesolid;
+ continue; // pushed enough
+ }
+ // FIXME: turn players specially
+ check.angles_y += trace_fraction * moveangle.y;
+ this.solid = savesolid;
+
+ // this trace.fraction < 1 check causes items to fall off of pushers
+ // if they pass under or through a wall
+ // the groundentity check causes items to fall off of ledges
+ if(check.move_movetype != MOVETYPE_WALK && (trace_fraction < 1 || check.groundentity != this))
+ UNSET_ONGROUND(check);
+
+ // if it is still inside the pusher, block
+ tracebox(check.origin, check.mins, check.maxs, check.origin, MOVE_NOMONSTERS, check);
+ if(trace_startsolid)
+ {
+ if(_Movetype_NudgeOutOfSolid_PivotIsKnownGood(check, pivot))
{
- check.move_origin = check.move_origin + move;
- _Movetype_LinkEdict(check, true);
+ // hack to invoke all necessary movement triggers
+ _Movetype_PushEntity(check, '0 0 0', true);
+ // we could fix it or entity "check" was telported
continue;
}
- // try moving the contacted entity
- this.solid = SOLID_NOT;
- bool flag = false;
- flag = _Movetype_PushEntity(check, move, true);
- if (!flag)
+ // still inside pusher, so it's really blocked
+
+ // fail the move
+ if(check.mins_x == check.maxs_x)
+ continue;
+ if(check.solid == SOLID_NOT || check.solid == SOLID_TRIGGER)
{
- // entity "check" got teleported
- check.move_angles_y += trace_fraction * moveangle.y;
- this.solid = savesolid;
- continue; // pushed enough
+ // corpse
+ check.mins_x = check.mins_y = 0;
+ check.maxs = check.mins;
+ continue;
}
- // FIXME: turn players specially
- check.move_angles_y += trace_fraction * moveangle.y;
- this.solid = savesolid;
- // this trace.fraction < 1 check causes items to fall off of pushers
- // if they pass under or through a wall
- // the groundentity check causes items to fall off of ledges
- if (check.move_movetype != MOVETYPE_WALK && (trace_fraction < 1 || check.move_groundentity != this))
- check.move_flags &= ~FL_ONGROUND;
+ this.origin = pushorig;
+ this.angles = pushang;
+ this.ltime = pushltime;
+ _Movetype_LinkEdict(this, false);
+
+ // move back any entities we already moved
+ IL_EACH(g_pushmove_moved, true,
+ {
+ check.origin = check.moved_from;
+ check.angles = check.moved_fromangles;
+ _Movetype_LinkEdict(check, false);
+ });
+
+ // if the pusher has a "blocked" function, call it, otherwise just stay in place until the obstacle is gone
+ if(getblocked(this))
+ getblocked(this)(this, check);
+ break;
}
}
-
- this.move_angles_x -= 360.0 * floor(this.move_angles.x * (1.0 / 360.0));
- this.move_angles_y -= 360.0 * floor(this.move_angles.y * (1.0 / 360.0));
- this.move_angles_z -= 360.0 * floor(this.move_angles.z * (1.0 / 360.0));
+ this.angles_x -= 360.0 * floor(this.angles_x * (1.0 / 360.0));
+ this.angles_y -= 360.0 * floor(this.angles_y * (1.0 / 360.0));
+ this.angles_z -= 360.0 * floor(this.angles_z * (1.0 / 360.0));
+ IL_CLEAR(g_pushmove_moved); // clean up
}
-void _Movetype_Physics_Pusher(entity this, float dt) // SV_Physics_Pusher
+void _Movetype_Physics_Push(entity this, float dt) // SV_Physics_Pusher
{
- float oldltime = this.move_ltime;
- float thinktime = this.move_nextthink;
- float movetime;
- if (thinktime < this.move_ltime + dt)
+ float oldltime = this.ltime;
+ float movetime = dt;
+ if(this.nextthink < this.ltime + dt)
{
- movetime = thinktime - this.move_ltime;
- if (movetime < 0)
+ movetime = this.nextthink - this.ltime;
+ if(movetime < 0)
movetime = 0;
}
- else
- {
- movetime = dt;
- }
- if (movetime)
- // advances this.move_ltime if not blocked
+ if(movetime)
+ {
+ // advances this.ltime if not blocked
_Movetype_PushMove(this, movetime);
+ }
- if (thinktime > oldltime && thinktime <= this.move_ltime)
+ if(this.nextthink > oldltime && this.nextthink <= this.ltime)
{
- this.move_nextthink = 0;
- this.move_time = time;
- other = world;
- WITH(entity, self, this, this.move_think());
+ this.nextthink = 0;
+ getthink(this)(this);
}
}