// Chase_Update public void Update() { // if can't see player, reset Vector3 forward, up, right; MathLib.AngleVectors(ref this.Host.Client.cl.viewangles, out forward, out right, out up); // calc exact destination this._Dest = this.Host.RenderContext.RefDef.vieworg - forward * this.Host.Cvars.Back.Get <float>( ) - right * this.Host.Cvars.Right.Get <float>( ); this._Dest.Z = this.Host.RenderContext.RefDef.vieworg.Z + this.Host.Cvars.Up.Get <float>( ); // find the spot the player is looking at var dest = this.Host.RenderContext.RefDef.vieworg + forward * 4096; Vector3 stop; this.TraceLine(ref this.Host.RenderContext.RefDef.vieworg, ref dest, out stop); // calculate pitch to look at the same spot from camera stop -= this.Host.RenderContext.RefDef.vieworg; float dist; dist = Vector3.Dot(stop, forward); if (dist < 1) { dist = 1; } this.Host.RenderContext.RefDef.viewangles.X = ( float )(-Math.Atan(stop.Z / dist) / Math.PI * 180.0); //r_refdef.viewangles[PITCH] = -atan(stop[2] / dist) / M_PI * 180; // move towards destination this.Host.RenderContext.RefDef.vieworg = this._Dest; //VectorCopy(chase_dest, r_refdef.vieworg); }
/// <summary> /// R_SetupFrame /// </summary> private void SetupFrame( ) { // don't allow cheats in multiplayer if (Host.Client.cl.maxclients > 1) { Host.CVars.Set("r_fullbright", false); } AnimateLight( ); _FrameCount++; // build the transformation matrix for the given view angles Origin = _RefDef.vieworg; MathLib.AngleVectors(ref _RefDef.viewangles, out ViewPn, out ViewRight, out ViewUp); // current viewleaf Occlusion.SetupFrame(ref Origin); Host.View.SetContentsColor(Occlusion.ViewLeaf.contents); Host.View.CalcBlend( ); _CacheThrash = false; _BrushPolys = 0; _AliasPolys = 0; }
/// <summary> /// SV_AirMove /// </summary> private void AirMove() { var pangles = Utilities.ToVector(ref _Player.v.angles); MathLib.AngleVectors(ref pangles, out _Forward, out _Right, out _Up); var fmove = _Cmd.forwardmove; var smove = _Cmd.sidemove; // hack to not let you back into teleporter if (sv.time < _Player.v.teleport_time && fmove < 0) { fmove = 0; } var wishvel = _Forward * fmove + _Right * smove; if (( Int32 )_Player.v.movetype != Movetypes.MOVETYPE_WALK) { wishvel.Z = _Cmd.upmove; } else { wishvel.Z = 0; } _WishDir = wishvel; _WishSpeed = MathLib.Normalize(ref _WishDir); var maxSpeed = Host.Cvars.MaxSpeed.Get <Single>(); if (_WishSpeed > maxSpeed) { wishvel *= maxSpeed / _WishSpeed; _WishSpeed = maxSpeed; } if (_Player.v.movetype == Movetypes.MOVETYPE_NOCLIP) { // noclip MathLib.Copy(ref wishvel, out _Player.v.velocity); } else if (_OnGround) { UserFriction(); Accelerate(); } else { // not on ground, so little effect on velocity AirAccelerate(wishvel); } }
/// <summary> /// SV_AirMove /// </summary> private void AirMove() { var pangles = Utilities.ToVector(ref this._Player.v.angles); MathLib.AngleVectors(ref pangles, out this._Forward, out this._Right, out this._Up); var fmove = this._Cmd.forwardmove; var smove = this._Cmd.sidemove; // hack to not let you back into teleporter if (this.sv.time < this._Player.v.teleport_time && fmove < 0) { fmove = 0; } var wishvel = this._Forward * fmove + this._Right * smove; if (( int )this._Player.v.movetype != Movetypes.MOVETYPE_WALK) { wishvel.Z = this._Cmd.upmove; } else { wishvel.Z = 0; } this._WishDir = wishvel; this._WishSpeed = MathLib.Normalize(ref this._WishDir); var maxSpeed = this.Host.Cvars.MaxSpeed.Get <float>(); if (this._WishSpeed > maxSpeed) { wishvel *= maxSpeed / this._WishSpeed; this._WishSpeed = maxSpeed; } if (this._Player.v.movetype == Movetypes.MOVETYPE_NOCLIP) { // noclip MathLib.Copy(ref wishvel, out this._Player.v.velocity); } else if (this._OnGround) { this.UserFriction(); this.Accelerate(); } else { // not on ground, so little effect on velocity this.AirAccelerate(wishvel); } }
/// <summary> /// SV_WallFriction /// </summary> private void WallFriction( MemoryEdict ent, Trace_t trace ) { Vector3 forward, right, up, vangle = Utilities.ToVector( ref ent.v.v_angle ); MathLib.AngleVectors( ref vangle, out forward, out right, out up ); var d = Vector3.Dot( trace.plane.normal, forward ); d += 0.5f; if ( d >= 0 ) return; // cut the tangential velocity var vel = Utilities.ToVector( ref ent.v.velocity ); var i = Vector3.Dot( trace.plane.normal, vel ); var into = trace.plane.normal * i; var side = vel - into; ent.v.velocity.x = side.X * ( 1 + d ); ent.v.velocity.y = side.Y * ( 1 + d ); }
/// <summary> /// V_CalcRoll /// Used by view and sv_user /// </summary> public Single CalcRoll(ref Vector3 angles, ref Vector3 velocity) { MathLib.AngleVectors(ref angles, out _Forward, out _Right, out _Up); var side = Vector3.Dot(velocity, _Right); Single sign = side < 0 ? -1 : 1; side = Math.Abs(side); var value = Host.Cvars.ClRollAngle.Get <Single>(); if (side < Host.Cvars.ClRollSpeed.Get <Single>()) { side = side * value / Host.Cvars.ClRollSpeed.Get <Single>(); } else { side = value; } return(side * sign); }
/// <summary> /// V_CalcRoll /// Used by view and sv_user /// </summary> public float CalcRoll(ref Vector3 angles, ref Vector3 velocity) { MathLib.AngleVectors(ref angles, out this._Forward, out this._Right, out this._Up); var side = Vector3.Dot(velocity, this._Right); float sign = side < 0 ? -1 : 1; side = Math.Abs(side); var value = this.Host.Cvars.ClRollAngle.Get <float>(); if (side < this.Host.Cvars.ClRollSpeed.Get <float>()) { side = side * value / this.Host.Cvars.ClRollSpeed.Get <float>(); } else { side = value; } return(side * sign); }
/// <summary> /// R_DrawSpriteModel /// </summary> private void DrawSpriteModel(Entity e) { // don't even bother culling, because it's just a single // polygon without a surface cache var frame = GetSpriteFrame(e); var psprite = ( msprite_t )e.model.cache.data; // Uze: changed from _CurrentEntity to e Vector3 v_forward, right, up; if (psprite.type == SpriteType.Oriented) { // bullet marks on walls MathLib.AngleVectors(ref e.angles, out v_forward, out right, out up); // Uze: changed from _CurrentEntity to e } else { // normal sprite up = ViewUp; // vup; right = ViewRight; // vright; } var texture = Host.Model.SpriteTextures.Where(t => ((Renderer.OpenGL.Textures.GLTextureDesc)t.Desc).TextureNumber == frame.gl_texturenum).FirstOrDefault(); Host.Video.Device.Graphics.DrawSpriteModel(texture, frame, up, right, e.origin); }
/// <summary> /// CL_RelinkEntities /// </summary> private void RelinkEntities() { // determine partial update time var frac = this.LerpPoint(); this.NumVisEdicts = 0; // // interpolate player info // this.cl.velocity = this.cl.mvelocity[1] + frac * (this.cl.mvelocity[0] - this.cl.mvelocity[1]); if (this.cls.demoplayback) { // interpolate the angles var angleDelta = this.cl.mviewangles[0] - this.cl.mviewangles[1]; MathLib.CorrectAngles180(ref angleDelta); this.cl.viewangles = this.cl.mviewangles[1] + frac * angleDelta; } var bobjrotate = MathLib.AngleMod(100 * this.cl.time); // start on the entity after the world for (var i = 1; i < this.cl.num_entities; i++) { var ent = this._Entities[i]; if (ent.model == null) { // empty slot if (ent.forcelink) { this.Host.RenderContext.RemoveEfrags(ent); // just became empty } continue; } // if the object wasn't included in the last packet, remove it if (ent.msgtime != this.cl.mtime[0]) { ent.model = null; continue; } var oldorg = ent.origin; if (ent.forcelink) { // the entity was not updated in the last message // so move to the final spot ent.origin = ent.msg_origins[0]; ent.angles = ent.msg_angles[0]; } else { // if the delta is large, assume a teleport and don't lerp var f = frac; var delta = ent.msg_origins[0] - ent.msg_origins[1]; if (Math.Abs(delta.X) > 100 || Math.Abs(delta.Y) > 100 || Math.Abs(delta.Z) > 100) { f = 1; // assume a teleportation, not a motion } // interpolate the origin and angles ent.origin = ent.msg_origins[1] + f * delta; var angleDelta = ent.msg_angles[0] - ent.msg_angles[1]; MathLib.CorrectAngles180(ref angleDelta); ent.angles = ent.msg_angles[1] + f * angleDelta; } // rotate binary objects locally if (ent.model.Flags.HasFlag(EntityFlags.Rotate)) { ent.angles.Y = bobjrotate; } if ((ent.effects & EntityEffects.EF_BRIGHTFIELD) != 0) { this.Host.RenderContext.Particles.EntityParticles(this.Host.Client.cl.time, ent.origin); } if ((ent.effects & EntityEffects.EF_MUZZLEFLASH) != 0) { var dl = this.AllocDlight(i); dl.origin = ent.origin; dl.origin.Z += 16; Vector3 fv, rv, uv; MathLib.AngleVectors(ref ent.angles, out fv, out rv, out uv); dl.origin += fv * 18; dl.radius = 200 + (MathLib.Random() & 31); dl.minlight = 32; dl.die = ( float )this.cl.time + 0.1f; } if ((ent.effects & EntityEffects.EF_BRIGHTLIGHT) != 0) { var dl = this.AllocDlight(i); dl.origin = ent.origin; dl.origin.Z += 16; dl.radius = 400 + (MathLib.Random() & 31); dl.die = ( float )this.cl.time + 0.001f; } if ((ent.effects & EntityEffects.EF_DIMLIGHT) != 0) { var dl = this.AllocDlight(i); dl.origin = ent.origin; dl.radius = 200 + (MathLib.Random() & 31); dl.die = ( float )this.cl.time + 0.001f; } if (ent.model.Flags.HasFlag(EntityFlags.Gib)) { this.Host.RenderContext.Particles.RocketTrail(this.Host.Client.cl.time, ref oldorg, ref ent.origin, 2); } else if (ent.model.Flags.HasFlag(EntityFlags.ZomGib)) { this.Host.RenderContext.Particles.RocketTrail(this.Host.Client.cl.time, ref oldorg, ref ent.origin, 4); } else if (ent.model.Flags.HasFlag(EntityFlags.Tracer)) { this.Host.RenderContext.Particles.RocketTrail(this.Host.Client.cl.time, ref oldorg, ref ent.origin, 3); } else if (ent.model.Flags.HasFlag(EntityFlags.Tracer2)) { this.Host.RenderContext.Particles.RocketTrail(this.Host.Client.cl.time, ref oldorg, ref ent.origin, 5); } else if (ent.model.Flags.HasFlag(EntityFlags.Rocket)) { this.Host.RenderContext.Particles.RocketTrail(this.Host.Client.cl.time, ref oldorg, ref ent.origin, 0); var dl = this.AllocDlight(i); dl.origin = ent.origin; dl.radius = 200; dl.die = ( float )this.cl.time + 0.01f; } else if (ent.model.Flags.HasFlag(EntityFlags.Grenade)) { this.Host.RenderContext.Particles.RocketTrail(this.Host.Client.cl.time, ref oldorg, ref ent.origin, 1); } else if (ent.model.Flags.HasFlag(EntityFlags.Tracer3)) { this.Host.RenderContext.Particles.RocketTrail(this.Host.Client.cl.time, ref oldorg, ref ent.origin, 6); } ent.forcelink = false; if (i == this.cl.viewentity && !this.Host.ChaseView.IsActive) { continue; } if (this.NumVisEdicts < ClientDef.MAX_VISEDICTS) { this._VisEdicts[this.NumVisEdicts] = ent; this.NumVisEdicts++; } } }
// V_CalcRefdef private void CalcRefDef( ) { DriftPitch(); // ent is the player model (visible when out of body) var ent = Host.Client.ViewEntity; // view is the weapon model (only visible from inside body) var view = Host.Client.ViewEnt; // transform the view offset by the model's matrix to get the offset from // model origin for the view ent.angles.Y = Host.Client.cl.viewangles.Y; // the model should face the view dir ent.angles.X = -Host.Client.cl.viewangles.X; // the model should face the view dir var bob = CalcBob(); var rdef = Host.RenderContext.RefDef; var cl = Host.Client.cl; // refresh position rdef.vieworg = ent.origin; rdef.vieworg.Z += cl.viewheight + bob; // never let it sit exactly on a node line, because a water plane can // dissapear when viewed with the eye exactly on it. // the server protocol only specifies to 1/16 pixel, so add 1/32 in each axis rdef.vieworg += SmallOffset; rdef.viewangles = cl.viewangles; CalcViewRoll(); AddIdle(Host.Cvars.IdleScale.Get <Single>()); // offsets var angles = ent.angles; angles.X = -angles.X; // because entity pitches are actually backward Vector3 forward, right, up; MathLib.AngleVectors(ref angles, out forward, out right, out up); rdef.vieworg += forward * Host.Cvars.ScrOfsX.Get <Single>() + right * Host.Cvars.ScrOfsY.Get <Single>() + up * Host.Cvars.ScrOfsZ.Get <Single>(); BoundOffsets(); // set up gun position view.angles = cl.viewangles; CalcGunAngle(); view.origin = ent.origin; view.origin.Z += cl.viewheight; view.origin += forward * bob * 0.4f; view.origin.Z += bob; // fudge position around to keep amount of weapon visible // roughly equal with different FOV var viewSize = Host.Screen.ViewSize.Get <Single>(); // scr_viewsize if (viewSize == 110) { view.origin.Z += 1; } else if (viewSize == 100) { view.origin.Z += 2; } else if (viewSize == 90) { view.origin.Z += 1; } else if (viewSize == 80) { view.origin.Z += 0.5f; } view.model = cl.model_precache[cl.stats[QStatsDef.STAT_WEAPON]]; view.frame = cl.stats[QStatsDef.STAT_WEAPONFRAME]; view.colormap = Host.Screen.vid.colormap; // set up the refresh position rdef.viewangles += cl.punchangle; // smooth out stair step ups if (cl.onground && ent.origin.Z - _OldZ > 0) { var steptime = ( Single )(cl.time - cl.oldtime); if (steptime < 0) { steptime = 0; } _OldZ += steptime * 80; if (_OldZ > ent.origin.Z) { _OldZ = ent.origin.Z; } if (ent.origin.Z - _OldZ > 12) { _OldZ = ent.origin.Z - 12; } rdef.vieworg.Z += _OldZ - ent.origin.Z; view.origin.Z += _OldZ - ent.origin.Z; } else { _OldZ = ent.origin.Z; } if (Host.ChaseView.IsActive) { Host.ChaseView.Update(); } }
// V_ParseDamage public void ParseDamage( ) { var armor = Host.Network.Reader.ReadByte(); var blood = Host.Network.Reader.ReadByte(); var from = Host.Network.Reader.ReadCoords(); var count = blood * 0.5f + armor * 0.5f; if (count < 10) { count = 10; } var cl = Host.Client.cl; cl.faceanimtime = ( Single )cl.time + 0.2f; // put sbar face into pain frame cl.cshifts[ColorShift.CSHIFT_DAMAGE].percent += ( Int32 )(3 * count); if (cl.cshifts[ColorShift.CSHIFT_DAMAGE].percent < 0) { cl.cshifts[ColorShift.CSHIFT_DAMAGE].percent = 0; } if (cl.cshifts[ColorShift.CSHIFT_DAMAGE].percent > 150) { cl.cshifts[ColorShift.CSHIFT_DAMAGE].percent = 150; } if (armor > blood) { cl.cshifts[ColorShift.CSHIFT_DAMAGE].destcolor[0] = 200; cl.cshifts[ColorShift.CSHIFT_DAMAGE].destcolor[1] = 100; cl.cshifts[ColorShift.CSHIFT_DAMAGE].destcolor[2] = 100; } else if (armor != 0) { cl.cshifts[ColorShift.CSHIFT_DAMAGE].destcolor[0] = 220; cl.cshifts[ColorShift.CSHIFT_DAMAGE].destcolor[1] = 50; cl.cshifts[ColorShift.CSHIFT_DAMAGE].destcolor[2] = 50; } else { cl.cshifts[ColorShift.CSHIFT_DAMAGE].destcolor[0] = 255; cl.cshifts[ColorShift.CSHIFT_DAMAGE].destcolor[1] = 0; cl.cshifts[ColorShift.CSHIFT_DAMAGE].destcolor[2] = 0; } // // calculate view angle kicks // var ent = Host.Client.Entities[cl.viewentity]; from -= ent.origin; // VectorSubtract (from, ent->origin, from); MathLib.Normalize(ref from); Vector3 forward, right, up; MathLib.AngleVectors(ref ent.angles, out forward, out right, out up); var side = Vector3.Dot(from, right); _DmgRoll = count * side * Host.Cvars.KickRoll.Get <Single>(); side = Vector3.Dot(from, forward); _DmgPitch = count * side * Host.Cvars.KickPitch.Get <Single>(); _DmgTime = Host.Cvars.KickTime.Get <Single>(); }
/// <summary> /// SV_WaterMove /// </summary> private void WaterMove() { // // user intentions // var pangle = Utilities.ToVector(ref this._Player.v.v_angle); MathLib.AngleVectors(ref pangle, out this._Forward, out this._Right, out this._Up); var wishvel = this._Forward * this._Cmd.forwardmove + this._Right * this._Cmd.sidemove; if (this._Cmd.forwardmove == 0 && this._Cmd.sidemove == 0 && this._Cmd.upmove == 0) { wishvel.Z -= 60; // drift towards bottom } else { wishvel.Z += this._Cmd.upmove; } var wishspeed = wishvel.Length(); var maxSpeed = this.Host.Cvars.MaxSpeed.Get <float>(); if (wishspeed > maxSpeed) { wishvel *= maxSpeed / wishspeed; wishspeed = maxSpeed; } wishspeed *= 0.7f; // // water friction // float newspeed, speed = MathLib.Length(ref this._Player.v.velocity); if (speed != 0) { newspeed = ( float )(speed - this.Host.FrameTime * speed * this.Host.Cvars.Friction.Get <float>( )); if (newspeed < 0) { newspeed = 0; } MathLib.VectorScale(ref this._Player.v.velocity, newspeed / speed, out this._Player.v.velocity); } else { newspeed = 0; } // // water acceleration // if (wishspeed == 0) { return; } var addspeed = wishspeed - newspeed; if (addspeed <= 0) { return; } MathLib.Normalize(ref wishvel); var accelspeed = ( float )(this.Host.Cvars.Accelerate.Get <float>( ) * wishspeed * this.Host.FrameTime); if (accelspeed > addspeed) { accelspeed = addspeed; } wishvel *= accelspeed; this._Player.v.velocity.X += wishvel.X; this._Player.v.velocity.Y += wishvel.Y; this._Player.v.velocity.Z += wishvel.Z; }
/// <summary> /// SV_WaterMove /// </summary> private void WaterMove() { // // user intentions // var pangle = Utilities.ToVector(ref _Player.v.v_angle); MathLib.AngleVectors(ref pangle, out _Forward, out _Right, out _Up); var wishvel = _Forward * _Cmd.forwardmove + _Right * _Cmd.sidemove; if (_Cmd.forwardmove == 0 && _Cmd.sidemove == 0 && _Cmd.upmove == 0) { wishvel.Z -= 60; // drift towards bottom } else { wishvel.Z += _Cmd.upmove; } var wishspeed = wishvel.Length; var maxSpeed = Host.Cvars.MaxSpeed.Get <Single>(); if (wishspeed > maxSpeed) { wishvel *= maxSpeed / wishspeed; wishspeed = maxSpeed; } wishspeed *= 0.7f; // // water friction // Single newspeed, speed = MathLib.Length(ref _Player.v.velocity); if (speed != 0) { newspeed = ( Single )(speed - Host.FrameTime * speed * Host.Cvars.Friction.Get <Single>( )); if (newspeed < 0) { newspeed = 0; } MathLib.VectorScale(ref _Player.v.velocity, newspeed / speed, out _Player.v.velocity); } else { newspeed = 0; } // // water acceleration // if (wishspeed == 0) { return; } var addspeed = wishspeed - newspeed; if (addspeed <= 0) { return; } MathLib.Normalize(ref wishvel); var accelspeed = ( Single )(Host.Cvars.Accelerate.Get <Single>( ) * wishspeed * Host.FrameTime); if (accelspeed > addspeed) { accelspeed = addspeed; } wishvel *= accelspeed; _Player.v.velocity.x += wishvel.X; _Player.v.velocity.y += wishvel.Y; _Player.v.velocity.z += wishvel.Z; }
/// <summary> /// R_DrawBrushModel /// </summary> private void DrawBrushModel(Entity e) { _CurrentEntity = e; Host.DrawingContext.CurrentTexture = -1; var clmodel = ( BrushModelData )e.model; var rotated = false; Vector3 mins, maxs; if (e.angles.X != 0 || e.angles.Y != 0 || e.angles.Z != 0) { rotated = true; mins = e.origin; mins.X -= clmodel.Radius; mins.Y -= clmodel.Radius; mins.Z -= clmodel.Radius; maxs = e.origin; maxs.X += clmodel.Radius; maxs.Y += clmodel.Radius; maxs.Z += clmodel.Radius; } else { mins = e.origin + clmodel.BoundsMin; maxs = e.origin + clmodel.BoundsMax; } if (Utilities.CullBox(ref mins, ref maxs, ref _Frustum)) { return; } Array.Clear(_LightMapPolys, 0, _LightMapPolys.Length); _ModelOrg = _RefDef.vieworg - e.origin; if (rotated) { var temp = _ModelOrg; Vector3 forward, right, up; MathLib.AngleVectors(ref e.angles, out forward, out right, out up); _ModelOrg.X = Vector3.Dot(temp, forward); _ModelOrg.Y = -Vector3.Dot(temp, right); _ModelOrg.Z = Vector3.Dot(temp, up); } // calculate dynamic lighting for bmodel if it's not an // instanced model if (clmodel.FirstModelSurface != 0 && !Host.Cvars.glFlashBlend.Get <Boolean>( )) { for (var k = 0; k < ClientDef.MAX_DLIGHTS; k++) { if ((Host.Client.DLights[k].die < Host.Client.cl.time) || (Host.Client.DLights[k].radius == 0)) { continue; } MarkLights(Host.Client.DLights[k], 1 << k, clmodel.Nodes[clmodel.Hulls[0].firstclipnode]); } } Host.Video.Device.PushMatrix( ); e.angles.X = -e.angles.X; // stupid quake bug Host.Video.Device.RotateForEntity(e.origin, e.angles); e.angles.X = -e.angles.X; // stupid quake bug var surfOffset = clmodel.FirstModelSurface; var psurf = clmodel.Surfaces; //[clmodel.firstmodelsurface]; // // draw texture // for (var i = 0; i < clmodel.NumModelSurfaces; i++, surfOffset++) { // find which side of the node we are on var pplane = psurf[surfOffset].plane; var dot = Vector3.Dot(_ModelOrg, pplane.normal) - pplane.dist; // draw the polygon var planeBack = (psurf[surfOffset].flags & ( Int32 )Q1SurfaceFlags.PlaneBack) != 0; if ((planeBack && (dot < -QDef.BACKFACE_EPSILON)) || (!planeBack && (dot > QDef.BACKFACE_EPSILON))) { if (Host.Cvars.glTexSort.Get <Boolean>( )) { RenderBrushPoly(psurf[surfOffset]); } else { DrawSequentialPoly(psurf[surfOffset]); } } } BlendLightmaps( ); Host.Video.Device.PopMatrix( ); }