예제 #1
0
    public 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 == q_shared.MOVETYPE_FLYMISSILE)
        {
            trace = Move(ref ent.v.origin, ref ent.v.mins, ref ent.v.maxs, ref end, q_shared.MOVE_MISSILE, ent);
        }
        else if (ent.v.solid == q_shared.SOLID_TRIGGER || ent.v.solid == q_shared.SOLID_NOT)
        {
            // only clip against bmodels
            trace = Move(ref ent.v.origin, ref ent.v.mins, ref ent.v.maxs, ref end, q_shared.MOVE_NOMONSTERS, ent);
        }
        else
        {
            trace = Move(ref ent.v.origin, ref ent.v.mins, ref ent.v.maxs, ref end, q_shared.MOVE_NORMAL, ent);
        }

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

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

        return(trace);
    }
예제 #2
0
    public static void SV_ClientThink()
    {
        if (sv_player.v.movetype == q_shared.MOVETYPE_NONE)
        {
            return;
        }

        onground = ((int)sv_player.v.flags & q_shared.FL_ONGROUND) != 0;

        DropPunchAngle();

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

        //
        // angles
        // show 1/3 the pitch angle and all the roll angle
        cmd = host_client.cmd;

        v3f v_angle;

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

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

        if (((int)sv_player.v.flags & q_shared.FL_WATERJUMP) != 0)
        {
            SV_WaterJump();
            return;
        }
        //
        // walk
        //
        if ((sv_player.v.waterlevel >= 2) && (sv_player.v.movetype != q_shared.MOVETYPE_NOCLIP))
        {
            SV_WaterMove();
            return;
        }

        SV_AirMove();
    }
예제 #3
0
    static void PF_aim()
    {
        edict_t ent   = G_EDICT(q_shared.OFS_PARM0);
        float   speed = G_FLOAT(q_shared.OFS_PARM1);

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

        start.Z += 20;

        // try sending a trace straight
        Vector3 dir;

        Mathlib.Copy(ref pr_global_struct.v_forward, out dir);
        Vector3 end = start + dir * 2048;
        trace_t tr  = SV_Move(ref start, ref q_shared.ZeroVector, ref q_shared.ZeroVector, ref end, 0, ent);

        if (tr.ent != null && tr.ent.v.takedamage == q_shared.DAMAGE_AIM &&
            (teamplay.value == 0 || ent.v.team <= 0 || ent.v.team != tr.ent.v.team))
        {
            G_VECTOR(ref pr_global_struct.v_forward);
            return;
        }

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

        for (int i = 1; i < sv.num_edicts; i++)
        {
            edict_t check = sv.edicts[i];
            if (check.v.takedamage != q_shared.DAMAGE_AIM)
            {
                continue;
            }
            if (check == ent)
            {
                continue;
            }
            if (teamplay.value != 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, ToVector(ref pr_global_struct.v_forward));
            if (dist < bestdist)
            {
                continue;       // to far to turn
            }
            tr = SV_Move(ref start, ref q_shared.ZeroVector, ref q_shared.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 pr_global_struct.v_forward);
            Mathlib.VectorScale(ref pr_global_struct.v_forward, dist, out end2);
            end2.z = dir2.z;
            Mathlib.Normalize(ref end2);
            G_VECTOR(ref end2);
        }
        else
        {
            G_VECTOR(ref bestdir);
        }
    }
예제 #4
0
    public static void SV_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 > q_shared.MAX_DATAGRAM - 16)
        {
            return;
        }

        // find precache number for sound
        int sound_num;

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

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

        int ent = NUM_FOR_EDICT(entity);

        channel = (ent << 3) | channel;

        int field_mask = 0;

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

        // directed messages go only to the entity the are targeted on
        sv.datagram.MSG_WriteByte(q_shared.svc_sound);
        sv.datagram.MSG_WriteByte(field_mask);
        if ((field_mask & q_shared.SND_VOLUME) != 0)
        {
            sv.datagram.MSG_WriteByte(volume);
        }
        if ((field_mask & q_shared.SND_ATTENUATION) != 0)
        {
            sv.datagram.MSG_WriteByte((int)(attenuation * 64));
        }
        sv.datagram.MSG_WriteShort(channel);
        sv.datagram.MSG_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.MSG_WriteCoord(v.x);
        sv.datagram.MSG_WriteCoord(v.y);
        sv.datagram.MSG_WriteCoord(v.z);
    }
예제 #5
0
    public static void SV_LinkEdict(edict_t ent, bool touch_triggers)
    {
        if (ent.area.Prev != null)
        {
            SV_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 & q_shared.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)
        {
            SV_FindTouchedLeafs(ent, sv.worldmodel.nodes[0]);
        }

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

        // find the first node that the ent's box crosses
        areanode_t node = sv_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 == q_shared.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)
        {
            SV_TouchLinks(ent, sv_areanodes[0]);
        }
    }
예제 #6
0
    public static void SV_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[q_shared.MAX_EDICTS];
        v3f[]     moved_from  = new v3f[q_shared.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;
        SV_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 == q_shared.MOVETYPE_PUSH ||
                check.v.movetype == q_shared.MOVETYPE_NONE ||
                check.v.movetype == q_shared.MOVETYPE_NOCLIP)
            {
                continue;
            }

            // if the entity is standing on the pusher, it will definately be moved
            if (!(((int)check.v.flags & q_shared.FL_ONGROUND) != 0 && PROG_TO_EDICT(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 (SV_TestEntityPosition(check) == null)
                {
                    continue;
                }
            }

            // remove the onground flag for non-players
            if (check.v.movetype != q_shared.MOVETYPE_WALK)
            {
                check.v.flags = (int)check.v.flags & ~q_shared.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 = q_shared.SOLID_NOT;
            PushEntity(check, ref move);
            pusher.v.solid = q_shared.SOLID_BSP;

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

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

                pusher.v.origin = pushorig;
                SV_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)
                {
                    pr_global_struct.self  = EDICT_TO_PROG(pusher);
                    pr_global_struct.other = EDICT_TO_PROG(check);
                    PR_ExecuteProgram(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];
                    SV_LinkEdict(moved_edict[i], false);
                }
                return;
            }
        }
    }
예제 #7
0
    public static bool SV_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 & (q_shared.FL_SWIM | q_shared.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 = PROG_TO_EDICT(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 & q_shared.FL_SWIM) != 0 &&
                        SV_PointContents(ref trace.endpos) == q_shared.CONTENTS_EMPTY)
                    {
                        return(false);   // swim monster left water
                    }
                    Mathlib.Copy(ref trace.endpos, out ent.v.origin);
                    if (relink)
                    {
                        SV_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 += q_shared.STEPSIZE;
        v3f end = neworg;

        end.z -= q_shared.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 -= q_shared.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 & q_shared.FL_PARTIALGROUND) != 0)
            {
                Mathlib.VectorAdd(ref ent.v.origin, ref move, out ent.v.origin);
                if (relink)
                {
                    SV_LinkEdict(ent, true);
                }
                ent.v.flags = (int)ent.v.flags & ~q_shared.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 (!SV_CheckBottom(ent))
        {
            if (((int)ent.v.flags & q_shared.FL_PARTIALGROUND) != 0)
            {
                // entity had floor mostly pulled out from underneath it
                // and is trying to correct
                if (relink)
                {
                    SV_LinkEdict(ent, true);
                }
                return(true);
            }
            ent.v.origin = oldorg;
            return(false);
        }

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

        // the move is ok
        if (relink)
        {
            SV_LinkEdict(ent, true);
        }
        return(true);
    }
예제 #8
0
    public static bool SV_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 (SV_PointContents(ref start) != q_shared.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 * q_shared.STEPSIZE;
        trace_t trace = SV_Move(ref start, ref q_shared.ZeroVector, ref q_shared.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 = SV_Move(ref start, ref q_shared.ZeroVector, ref q_shared.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 > q_shared.STEPSIZE)
                {
                    return(false);
                }
            }
        }

        return(true);
    }