示例#1
0
        /// <summary>
        /// PushEntity
        /// Does not change the entities velocity at all
        /// </summary>
        private static trace_t PushEntity(edict_t ent, ref v3f push)
        {
            v3f end;

            Mathlib.VectorAdd(ref ent.v.origin, ref push, out end);

            trace_t trace;

            if (ent.v.movetype == Movetypes.MOVETYPE_FLYMISSILE)
            {
                trace = Move(ref ent.v.origin, ref ent.v.mins, ref ent.v.maxs, ref end, MOVE_MISSILE, ent);
            }
            else if (ent.v.solid == Solids.SOLID_TRIGGER || ent.v.solid == Solids.SOLID_NOT)
            {
                // only clip against bmodels
                trace = Move(ref ent.v.origin, ref ent.v.mins, ref ent.v.maxs, ref end, MOVE_NOMONSTERS, ent);
            }
            else
            {
                trace = Move(ref ent.v.origin, ref ent.v.mins, ref ent.v.maxs, ref end, MOVE_NORMAL, ent);
            }

            Mathlib.Copy(ref trace.endpos, out ent.v.origin);
            LinkEdict(ent, true);

            if (trace.ent != null)
            {
                Impact(ent, trace.ent);
            }

            return(trace);
        }
示例#2
0
        /// <summary>
        /// SV_ClientThink
        /// the move fields specify an intended velocity in pix/sec
        /// the angle fields specify an exact angular motion in degrees
        /// </summary>
        static void ClientThink()
        {
            if (_Player.v.movetype == Movetypes.MOVETYPE_NONE)
            {
                return;
            }

            _OnGround = ((int)_Player.v.flags & EdictFlags.FL_ONGROUND) != 0;

            DropPunchAngle();

            //
            // if dead, behave differently
            //
            if (_Player.v.health <= 0)
            {
                return;
            }

            //
            // angles
            // show 1/3 the pitch angle and all the roll angle
            _Cmd = Host.HostClient.cmd;

            v3f v_angle;

            Mathlib.VectorAdd(ref _Player.v.v_angle, ref _Player.v.punchangle, out v_angle);
            Vector3 pang = Common.ToVector(ref _Player.v.angles);
            Vector3 pvel = Common.ToVector(ref _Player.v.velocity);

            _Player.v.angles.z = View.CalcRoll(ref pang, ref pvel) * 4;
            if (_Player.v.fixangle == 0)
            {
                _Player.v.angles.x = -v_angle.x / 3;
                _Player.v.angles.y = v_angle.y;
            }

            if (((int)_Player.v.flags & EdictFlags.FL_WATERJUMP) != 0)
            {
                WaterJump();
                return;
            }
            //
            // walk
            //
            if ((_Player.v.waterlevel >= 2) && (_Player.v.movetype != Movetypes.MOVETYPE_NOCLIP))
            {
                WaterMove();
                return;
            }

            AirMove();
        }
示例#3
0
        /// <summary>
        /// SV_PushMove
        /// </summary>
        static void PushMove(edict_t pusher, float movetime)
        {
            if (pusher.v.velocity.IsEmpty)
            {
                pusher.v.ltime += movetime;
                return;
            }

            v3f move, mins, maxs;

            Mathlib.VectorScale(ref pusher.v.velocity, movetime, out move);
            Mathlib.VectorAdd(ref pusher.v.absmin, ref move, out mins);
            Mathlib.VectorAdd(ref pusher.v.absmax, ref move, out maxs);

            v3f pushorig = pusher.v.origin;

            edict_t[] moved_edict = new edict_t[QDef.MAX_EDICTS];
            v3f[]     moved_from  = new v3f[QDef.MAX_EDICTS];

            // move the pusher to it's final position

            Mathlib.VectorAdd(ref pusher.v.origin, ref move, out pusher.v.origin);
            pusher.v.ltime += movetime;
            LinkEdict(pusher, false);


            // see if any solid entities are inside the final position
            int num_moved = 0;

            for (int e = 1; e < sv.num_edicts; e++)
            {
                edict_t check = sv.edicts[e];
                if (check.free)
                {
                    continue;
                }
                if (check.v.movetype == Movetypes.MOVETYPE_PUSH ||
                    check.v.movetype == Movetypes.MOVETYPE_NONE ||
                    check.v.movetype == Movetypes.MOVETYPE_NOCLIP)
                {
                    continue;
                }

                // if the entity is standing on the pusher, it will definately be moved
                if (!(((int)check.v.flags & EdictFlags.FL_ONGROUND) != 0 && ProgToEdict(check.v.groundentity) == pusher))
                {
                    if (check.v.absmin.x >= maxs.x || check.v.absmin.y >= maxs.y ||
                        check.v.absmin.z >= maxs.z || check.v.absmax.x <= mins.x ||
                        check.v.absmax.y <= mins.y || check.v.absmax.z <= mins.z)
                    {
                        continue;
                    }

                    // see if the ent's bbox is inside the pusher's final position
                    if (TestEntityPosition(check) == null)
                    {
                        continue;
                    }
                }

                // remove the onground flag for non-players
                if (check.v.movetype != Movetypes.MOVETYPE_WALK)
                {
                    check.v.flags = (int)check.v.flags & ~EdictFlags.FL_ONGROUND;
                }

                v3f entorig = check.v.origin;
                moved_from[num_moved]  = entorig;
                moved_edict[num_moved] = check;
                num_moved++;

                // try moving the contacted entity
                pusher.v.solid = Solids.SOLID_NOT;
                PushEntity(check, ref move);
                pusher.v.solid = Solids.SOLID_BSP;

                // if it is still inside the pusher, block
                edict_t block = TestEntityPosition(check);
                if (block != null)
                {
                    // fail the move
                    if (check.v.mins.x == check.v.maxs.x)
                    {
                        continue;
                    }
                    if (check.v.solid == Solids.SOLID_NOT || check.v.solid == Solids.SOLID_TRIGGER)
                    {
                        // corpse
                        check.v.mins.x = check.v.mins.y = 0;
                        check.v.maxs   = check.v.mins;
                        continue;
                    }

                    check.v.origin = entorig;
                    LinkEdict(check, true);

                    pusher.v.origin = pushorig;
                    LinkEdict(pusher, false);
                    pusher.v.ltime -= movetime;

                    // if the pusher has a "blocked" function, call it
                    // otherwise, just stay in place until the obstacle is gone
                    if (pusher.v.blocked != 0)
                    {
                        Progs.GlobalStruct.self  = EdictToProg(pusher);
                        Progs.GlobalStruct.other = EdictToProg(check);
                        Progs.Execute(pusher.v.blocked);
                    }

                    // move back any entities we already moved
                    for (int i = 0; i < num_moved; i++)
                    {
                        moved_edict[i].v.origin = moved_from[i];
                        LinkEdict(moved_edict[i], false);
                    }
                    return;
                }
            }
        }
示例#4
0
        /// <summary>
        /// SV_LinkEdict
        ///
        /// Needs to be called any time an entity changes origin, mins, maxs, or solid
        /// flags ent->v.modified
        /// sets ent->v.absmin and ent->v.absmax
        /// if touchtriggers, calls prog functions for the intersected triggers
        /// </summary>
        public static void LinkEdict(edict_t ent, bool touch_triggers)
        {
            if (ent.area.Prev != null)
            {
                UnlinkEdict(ent);       // unlink from old position
            }
            if (ent == sv.edicts[0])
            {
                return;         // don't add the world
            }
            if (ent.free)
            {
                return;
            }

            // set the abs box
            Mathlib.VectorAdd(ref ent.v.origin, ref ent.v.mins, out ent.v.absmin);
            Mathlib.VectorAdd(ref ent.v.origin, ref ent.v.maxs, out ent.v.absmax);

            //
            // to make items easier to pick up and allow them to be grabbed off
            // of shelves, the abs sizes are expanded
            //
            if (((int)ent.v.flags & EdictFlags.FL_ITEM) != 0)
            {
                ent.v.absmin.x -= 15;
                ent.v.absmin.y -= 15;
                ent.v.absmax.x += 15;
                ent.v.absmax.y += 15;
            }
            else
            {   // because movement is clipped an epsilon away from an actual edge,
                // we must fully check even when bounding boxes don't quite touch
                ent.v.absmin.x -= 1;
                ent.v.absmin.y -= 1;
                ent.v.absmin.z -= 1;
                ent.v.absmax.x += 1;
                ent.v.absmax.y += 1;
                ent.v.absmax.z += 1;
            }

            // link to PVS leafs
            ent.num_leafs = 0;
            if (ent.v.modelindex != 0)
            {
                FindTouchedLeafs(ent, sv.worldmodel.nodes[0]);
            }

            if (ent.v.solid == Solids.SOLID_NOT)
            {
                return;
            }

            // find the first node that the ent's box crosses
            areanode_t node = _AreaNodes[0];

            while (true)
            {
                if (node.axis == -1)
                {
                    break;
                }
                if (Mathlib.Comp(ref ent.v.absmin, node.axis) > node.dist)
                {
                    node = node.children[0];
                }
                else if (Mathlib.Comp(ref ent.v.absmax, node.axis) < node.dist)
                {
                    node = node.children[1];
                }
                else
                {
                    break;              // crosses the node
                }
            }

            // link it in

            if (ent.v.solid == Solids.SOLID_TRIGGER)
            {
                ent.area.InsertBefore(node.trigger_edicts);
            }
            else
            {
                ent.area.InsertBefore(node.solid_edicts);
            }

            // if touch_triggers, touch all entities at this node and decend for more
            if (touch_triggers)
            {
                TouchLinks(ent, _AreaNodes[0]);
            }
        }
示例#5
0
        /*
         * =============
         * PF_aim
         *
         * Pick a vector for the player to shoot along
         * vector aim(entity, missilespeed)
         * =============
         */
        static void PF_aim()
        {
            edict_t ent   = GetEdict(OFS.OFS_PARM0);
            float   speed = GetFloat(OFS.OFS_PARM1);

            Vector3 start = Common.ToVector(ref ent.v.origin);

            start.Z += 20;

            // try sending a trace straight
            Vector3 dir;

            Mathlib.Copy(ref Progs.GlobalStruct.v_forward, out dir);
            Vector3 end = start + dir * 2048;
            trace_t tr  = Server.Move(ref start, ref Common.ZeroVector, ref Common.ZeroVector, ref end, 0, ent);

            if (tr.ent != null && tr.ent.v.takedamage == Damages.DAMAGE_AIM &&
                (Host.TeamPlay == 0 || ent.v.team <= 0 || ent.v.team != tr.ent.v.team))
            {
                ReturnVector(ref Progs.GlobalStruct.v_forward);
                return;
            }

            // try all possible entities
            Vector3 bestdir  = dir;
            float   bestdist = Server.Aim;
            edict_t bestent  = null;

            for (int i = 1; i < Server.sv.num_edicts; i++)
            {
                edict_t check = Server.sv.edicts[i];
                if (check.v.takedamage != Damages.DAMAGE_AIM)
                {
                    continue;
                }
                if (check == ent)
                {
                    continue;
                }
                if (Host.TeamPlay != 0 && ent.v.team > 0 && ent.v.team == check.v.team)
                {
                    continue;   // don't aim at teammate
                }
                v3f tmp;
                Mathlib.VectorAdd(ref check.v.mins, ref check.v.maxs, out tmp);
                Mathlib.VectorMA(ref check.v.origin, 0.5f, ref tmp, out tmp);
                Mathlib.Copy(ref tmp, out end);

                dir = end - start;
                Mathlib.Normalize(ref dir);
                float dist = Vector3.Dot(dir, Common.ToVector(ref Progs.GlobalStruct.v_forward));
                if (dist < bestdist)
                {
                    continue;   // to far to turn
                }
                tr = Server.Move(ref start, ref Common.ZeroVector, ref Common.ZeroVector, ref end, 0, ent);
                if (tr.ent == check)
                {       // can shoot at this one
                    bestdist = dist;
                    bestent  = check;
                }
            }

            if (bestent != null)
            {
                v3f dir2, end2;
                Mathlib.VectorSubtract(ref bestent.v.origin, ref ent.v.origin, out dir2);
                float dist = Mathlib.DotProduct(ref dir2, ref Progs.GlobalStruct.v_forward);
                Mathlib.VectorScale(ref Progs.GlobalStruct.v_forward, dist, out end2);
                end2.z = dir2.z;
                Mathlib.Normalize(ref end2);
                ReturnVector(ref end2);
            }
            else
            {
                ReturnVector(ref bestdir);
            }
        }
示例#6
0
        /// <summary>
        /// SV_movestep
        /// Called by monster program code.
        /// The move will be adjusted for slopes and stairs, but if the move isn't
        /// possible, no move is done, false is returned, and
        /// pr_global_struct.trace_normal is set to the normal of the blocking wall
        /// </summary>
        public static bool MoveStep(edict_t ent, ref v3f move, bool relink)
        {
            trace_t trace;

            // try the move
            v3f oldorg = ent.v.origin;
            v3f neworg;

            Mathlib.VectorAdd(ref ent.v.origin, ref move, out neworg);

            // flying monsters don't step up
            if (((int)ent.v.flags & (EdictFlags.FL_SWIM | EdictFlags.FL_FLY)) != 0)
            {
                // try one move with vertical motion, then one without
                for (int i = 0; i < 2; i++)
                {
                    Mathlib.VectorAdd(ref ent.v.origin, ref move, out neworg);
                    edict_t enemy = ProgToEdict(ent.v.enemy);
                    if (i == 0 && enemy != sv.edicts[0])
                    {
                        float dz = ent.v.origin.z - enemy.v.origin.z;
                        if (dz > 40)
                        {
                            neworg.z -= 8;
                        }
                        if (dz < 30)
                        {
                            neworg.z += 8;
                        }
                    }

                    trace = Move(ref ent.v.origin, ref ent.v.mins, ref ent.v.maxs, ref neworg, 0, ent);
                    if (trace.fraction == 1)
                    {
                        if (((int)ent.v.flags & EdictFlags.FL_SWIM) != 0 &&
                            PointContents(ref trace.endpos) == Contents.CONTENTS_EMPTY)
                        {
                            return(false);       // swim monster left water
                        }
                        Mathlib.Copy(ref trace.endpos, out ent.v.origin);
                        if (relink)
                        {
                            LinkEdict(ent, true);
                        }
                        return(true);
                    }

                    if (enemy == sv.edicts[0])
                    {
                        break;
                    }
                }

                return(false);
            }

            // push down from a step height above the wished position
            neworg.z += STEPSIZE;
            v3f end = neworg;

            end.z -= STEPSIZE * 2;

            trace = Move(ref neworg, ref ent.v.mins, ref ent.v.maxs, ref end, 0, ent);

            if (trace.allsolid)
            {
                return(false);
            }

            if (trace.startsolid)
            {
                neworg.z -= STEPSIZE;
                trace     = Move(ref neworg, ref ent.v.mins, ref ent.v.maxs, ref end, 0, ent);
                if (trace.allsolid || trace.startsolid)
                {
                    return(false);
                }
            }
            if (trace.fraction == 1)
            {
                // if monster had the ground pulled out, go ahead and fall
                if (((int)ent.v.flags & EdictFlags.FL_PARTIALGROUND) != 0)
                {
                    Mathlib.VectorAdd(ref ent.v.origin, ref move, out ent.v.origin);
                    if (relink)
                    {
                        LinkEdict(ent, true);
                    }
                    ent.v.flags = (int)ent.v.flags & ~EdictFlags.FL_ONGROUND;
                    return(true);
                }

                return(false);           // walked off an edge
            }

            // check point traces down for dangling corners
            Mathlib.Copy(ref trace.endpos, out ent.v.origin);

            if (!CheckBottom(ent))
            {
                if (((int)ent.v.flags & EdictFlags.FL_PARTIALGROUND) != 0)
                {
                    // entity had floor mostly pulled out from underneath it
                    // and is trying to correct
                    if (relink)
                    {
                        LinkEdict(ent, true);
                    }
                    return(true);
                }
                ent.v.origin = oldorg;
                return(false);
            }

            if (((int)ent.v.flags & EdictFlags.FL_PARTIALGROUND) != 0)
            {
                ent.v.flags = (int)ent.v.flags & ~EdictFlags.FL_PARTIALGROUND;
            }
            ent.v.groundentity = EdictToProg(trace.ent);

            // the move is ok
            if (relink)
            {
                LinkEdict(ent, true);
            }
            return(true);
        }
示例#7
0
        /// <summary>
        /// SV_CheckBottom
        /// </summary>
        public static bool CheckBottom(edict_t ent)
        {
            v3f mins, maxs;

            Mathlib.VectorAdd(ref ent.v.origin, ref ent.v.mins, out mins);
            Mathlib.VectorAdd(ref ent.v.origin, ref ent.v.maxs, out maxs);

            // if all of the points under the corners are solid world, don't bother
            // with the tougher checks
            // the corners must be within 16 of the midpoint
            Vector3 start;

            start.Z = mins.z - 1;
            for (int x = 0; x <= 1; x++)
            {
                for (int y = 0; y <= 1; y++)
                {
                    start.X = (x != 0 ? maxs.x : mins.x);
                    start.Y = (y != 0 ? maxs.y : mins.y);
                    if (PointContents(ref start) != Contents.CONTENTS_SOLID)
                    {
                        goto RealCheck;
                    }
                }
            }

            return(true);                // we got out easy

RealCheck:

            //
            // check it for real...
            //
            start.Z = mins.z;

            // the midpoint must be within 16 of the bottom
            start.X = (mins.x + maxs.x) * 0.5f;
            start.Y = (mins.y + maxs.y) * 0.5f;
            Vector3 stop = start;

            stop.Z -= 2 * STEPSIZE;
            trace_t trace = Move(ref start, ref Common.ZeroVector, ref Common.ZeroVector, ref stop, 1, ent);

            if (trace.fraction == 1.0)
            {
                return(false);
            }

            float mid    = trace.endpos.Z;
            float bottom = mid;

            // the corners must be within 16 of the midpoint
            for (int x = 0; x <= 1; x++)
            {
                for (int y = 0; y <= 1; y++)
                {
                    start.X = stop.X = (x != 0 ? maxs.x : mins.x);
                    start.Y = stop.Y = (y != 0 ? maxs.y : mins.y);

                    trace = Move(ref start, ref Common.ZeroVector, ref Common.ZeroVector, ref stop, 1, ent);

                    if (trace.fraction != 1.0 && trace.endpos.Z > bottom)
                    {
                        bottom = trace.endpos.Z;
                    }
                    if (trace.fraction == 1.0 || mid - trace.endpos.Z > STEPSIZE)
                    {
                        return(false);
                    }
                }
            }

            return(true);
        }
示例#8
0
        /// <summary>
        /// SV_StartSound
        /// Each entity can have eight independant sound sources, like voice,
        /// weapon, feet, etc.
        ///
        /// Channel 0 is an auto-allocate channel, the others override anything
        /// allready running on that entity/channel pair.
        ///
        /// An attenuation of 0 will play full volume everywhere in the level.
        /// Larger attenuations will drop off.  (max 4 attenuation)
        /// </summary>
        public static void StartSound(edict_t entity, int channel, string sample, int volume, float attenuation)
        {
            if (volume < 0 || volume > 255)
            {
                Sys.Error("SV_StartSound: volume = {0}", volume);
            }

            if (attenuation < 0 || attenuation > 4)
            {
                Sys.Error("SV_StartSound: attenuation = {0}", attenuation);
            }

            if (channel < 0 || channel > 7)
            {
                Sys.Error("SV_StartSound: channel = {0}", channel);
            }

            if (sv.datagram.Length > QDef.MAX_DATAGRAM - 16)
            {
                return;
            }

            // find precache number for sound
            int sound_num;

            for (sound_num = 1; sound_num < QDef.MAX_SOUNDS && sv.sound_precache[sound_num] != null; sound_num++)
            {
                if (sample == sv.sound_precache[sound_num])
                {
                    break;
                }
            }

            if (sound_num == QDef.MAX_SOUNDS || String.IsNullOrEmpty(sv.sound_precache[sound_num]))
            {
                Con.Print("SV_StartSound: {0} not precacheed\n", sample);
                return;
            }

            int ent = NumForEdict(entity);

            channel = (ent << 3) | channel;

            int field_mask = 0;

            if (volume != Sound.DEFAULT_SOUND_PACKET_VOLUME)
            {
                field_mask |= Protocol.SND_VOLUME;
            }
            if (attenuation != Sound.DEFAULT_SOUND_PACKET_ATTENUATION)
            {
                field_mask |= Protocol.SND_ATTENUATION;
            }

            // directed messages go only to the entity the are targeted on
            sv.datagram.WriteByte(Protocol.svc_sound);
            sv.datagram.WriteByte(field_mask);
            if ((field_mask & Protocol.SND_VOLUME) != 0)
            {
                sv.datagram.WriteByte(volume);
            }
            if ((field_mask & Protocol.SND_ATTENUATION) != 0)
            {
                sv.datagram.WriteByte((int)(attenuation * 64));
            }
            sv.datagram.WriteShort(channel);
            sv.datagram.WriteByte(sound_num);
            v3f v;

            Mathlib.VectorAdd(ref entity.v.mins, ref entity.v.maxs, out v);
            Mathlib.VectorMA(ref entity.v.origin, 0.5f, ref v, out v);
            sv.datagram.WriteCoord(v.x);
            sv.datagram.WriteCoord(v.y);
            sv.datagram.WriteCoord(v.z);
        }