Beispiel #1
0
void SV_ExecuteClientMessage (client_t *cl)
{
	int		c;
	char	*s;
	usercmd_t	oldest, oldcmd, newcmd;
	client_frame_t	*frame;
	vec3_t o;
	qboolean	move_issued = false; //only allow one move command
	int		checksumIndex;
	byte	checksum, calculatedChecksum;
	int		seq_hash;

	// calc ping time
	frame = &cl->frames[cl->netchan.incoming_acknowledged & UPDATE_MASK];
	frame->ping_time = realtime - frame->senttime;

	// make sure the reply sequence number matches the incoming
	// sequence number 
	if (cl->netchan.incoming_sequence >= cl->netchan.outgoing_sequence)
		cl->netchan.outgoing_sequence = cl->netchan.incoming_sequence;
	else
		cl->send_message = false;	// don't reply, sequences have slipped		

	// save time for ping calculations
	cl->frames[cl->netchan.outgoing_sequence & UPDATE_MASK].senttime = realtime;
	cl->frames[cl->netchan.outgoing_sequence & UPDATE_MASK].ping_time = -1;

	host_client = cl;
	sv_player = host_client->edict;

//	seq_hash = (cl->netchan.incoming_sequence & 0xffff) ; // ^ QW_CHECK_HASH;
	seq_hash = cl->netchan.incoming_sequence;
	
	// mark time so clients will know how much to predict
	// other players
 	cl->localtime = sv.time;
	cl->delta_sequence = -1;	// no delta unless requested
	while (1)
	{
		if (msg_badread)
		{
			Con_Printf ("SV_ReadClientMessage: badread\n");
			SV_DropClient (cl);
			return;
		}	

		c = MSG_ReadByte ();
		if (c == -1)
			break;
				
		switch (c)
		{
		default:
			Con_Printf ("SV_ReadClientMessage: unknown command char\n");
			SV_DropClient (cl);
			return;
						
		case clc_nop:
			break;

		case clc_delta:
			cl->delta_sequence = MSG_ReadByte ();
			break;

		case clc_move:
			if (move_issued)
				return;		// someone is trying to cheat...

			move_issued = true;

			checksumIndex = MSG_GetReadCount();
			checksum = (byte)MSG_ReadByte ();

			// read loss percentage
			cl->lossage = MSG_ReadByte();

			MSG_ReadDeltaUsercmd (&nullcmd, &oldest);
			MSG_ReadDeltaUsercmd (&oldest, &oldcmd);
			MSG_ReadDeltaUsercmd (&oldcmd, &newcmd);

			if ( cl->state != cs_spawned )
				break;

			// if the checksum fails, ignore the rest of the packet
			calculatedChecksum = COM_BlockSequenceCRCByte(
				net_message.data + checksumIndex + 1,
				MSG_GetReadCount() - checksumIndex - 1,
				seq_hash);

			if (calculatedChecksum != checksum)
			{
				Con_DPrintf ("Failed command checksum for %s(%d) (%d != %d)\n", 
					cl->name, cl->netchan.incoming_sequence, checksum, calculatedChecksum);
				return;
			}

			if (!sv.paused) {
				SV_PreRunCmd();

				if (net_drop < 20)
				{
					while (net_drop > 2)
					{
						SV_RunCmd (&cl->lastcmd);
						net_drop--;
					}
					if (net_drop > 1)
						SV_RunCmd (&oldest);
					if (net_drop > 0)
						SV_RunCmd (&oldcmd);
				}
				SV_RunCmd (&newcmd);

				SV_PostRunCmd();
			}

			cl->lastcmd = newcmd;
			cl->lastcmd.buttons = 0; // avoid multiple fires on lag
			break;


		case clc_stringcmd:	
			s = MSG_ReadString ();
			SV_ExecuteUserCommand (s);
			break;

		case clc_tmove:
			o[0] = MSG_ReadCoord();
			o[1] = MSG_ReadCoord();
			o[2] = MSG_ReadCoord();
			// only allowed by spectators
			if (host_client->spectator) {
				VectorCopy(o, sv_player->v.origin);
				SV_LinkEdict(sv_player, false);
			}
			break;

		case clc_upload:
			SV_NextUpload();
			break;

		}
	}
}
Beispiel #2
0
void PF_LinkEdict(edict_t *ent)
{
    areanode_t *node;
    server_entity_t *sent;
    int entnum;
#if USE_FPS
    int i;
#endif

    if (ent->area.prev)
        PF_UnlinkEdict(ent);     // unlink from old position

    if (ent == ge->edicts)
        return;        // don't add the world

    if (!ent->inuse) {
        Com_DPrintf("%s: entity %d is not in use\n", __func__, NUM_FOR_EDICT(ent));
        return;
    }

    if (!sv.cm.cache) {
        return;
    }

    entnum = NUM_FOR_EDICT(ent);
    sent = &sv.entities[entnum];

    // encode the size into the entity_state for client prediction
    switch (ent->solid) {
    case SOLID_BBOX:
        if ((ent->svflags & SVF_DEADMONSTER) || VectorCompare(ent->mins, ent->maxs)) {
            ent->s.solid = 0;
            sent->solid32 = 0;
        } else {
            ent->s.solid = MSG_PackSolid16(ent->mins, ent->maxs);
            sent->solid32 = MSG_PackSolid32(ent->mins, ent->maxs);
        }
        break;
    case SOLID_BSP:
        ent->s.solid = PACKED_BSP;      // a SOLID_BBOX will never create this value
        sent->solid32 = PACKED_BSP;     // FIXME: use 255?
        break;
    default:
        ent->s.solid = 0;
        sent->solid32 = 0;
        break;
    }

    SV_LinkEdict(&sv.cm, ent);

    // if first time, make sure old_origin is valid
    if (!ent->linkcount) {
        VectorCopy(ent->s.origin, ent->s.old_origin);
#if USE_FPS
        VectorCopy(ent->s.origin, sent->create_origin);
        sent->create_framenum = sv.framenum;
#endif
    }
    ent->linkcount++;

#if USE_FPS
    // save origin for later recovery
    i = sv.framenum & ENT_HISTORY_MASK;
    VectorCopy(ent->s.origin, sent->history[i].origin);
    sent->history[i].framenum = sv.framenum;
#endif

    if (ent->solid == SOLID_NOT)
        return;

// find the first node that the ent's box crosses
    node = sv_areanodes;
    while (1) {
        if (node->axis == -1)
            break;
        if (ent->absmin[node->axis] > node->dist)
            node = node->children[0];
        else if (ent->absmax[node->axis] < node->dist)
            node = node->children[1];
        else
            break;        // crosses the node
    }

    // link it in
    if (ent->solid == SOLID_TRIGGER)
        List_Append(&node->trigger_edicts, &ent->area);
    else
        List_Append(&node->solid_edicts, &ent->area);
}
Beispiel #3
0
/*
=============
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
=============
*/
qboolean SV_movestep (edict_t *ent, vec3_t move, qboolean relink)
{
	float		dz;
	vec3_t		oldorg, neworg, end;
	trace_t		trace;
	int			i;
	edict_t		*enemy;

// try the move	
	VectorCopy (ent->v.origin, oldorg);
	VectorAdd (ent->v.origin, move, neworg);

// flying monsters don't step up
	if ( (int)ent->v.flags & (FL_SWIM | FL_FLY) )
	{
	// try one move with vertical motion, then one without
		for (i=0 ; i<2 ; i++)
		{
			VectorAdd (ent->v.origin, move, neworg);
			enemy = PROG_TO_EDICT(ent->v.enemy);
			if (i == 0 && enemy != sv.edicts)
			{
				dz = ent->v.origin[2] - PROG_TO_EDICT(ent->v.enemy)->v.origin[2];
				if (dz > 40)
					neworg[2] -= 8;
				if (dz < 30)
					neworg[2] += 8;
			}
			trace = SV_Move (ent->v.origin, ent->v.mins, ent->v.maxs, neworg, false, ent);
	
			if (trace.fraction == 1)
			{
				if ( ((int)ent->v.flags & FL_SWIM) && SV_PointContents(trace.endpos) == CONTENTS_EMPTY )
					return false;	// swim monster left water
	
				VectorCopy (trace.endpos, ent->v.origin);
				if (relink)
					SV_LinkEdict (ent, true);
				return true;
			}
			
			if (enemy == sv.edicts)
				break;
		}
		
		return false;
	}

// push down from a step height above the wished position
	neworg[2] += STEPSIZE;
	VectorCopy (neworg, end);
	end[2] -= STEPSIZE*2;

	trace = SV_Move (neworg, ent->v.mins, ent->v.maxs, end, false, ent);

	if (trace.allsolid)
		return false;

	if (trace.startsolid)
	{
		neworg[2] -= STEPSIZE;
		trace = SV_Move (neworg, ent->v.mins, ent->v.maxs, end, false, 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 & FL_PARTIALGROUND )
		{
			VectorAdd (ent->v.origin, move, ent->v.origin);
			if (relink)
				SV_LinkEdict (ent, true);
			ent->v.flags = (int)ent->v.flags & ~FL_ONGROUND;
//	Con_Printf ("fall down\n"); 
			return true;
		}
	
		return false;		// walked off an edge
	}

// check point traces down for dangling corners
	VectorCopy (trace.endpos, ent->v.origin);
	
	if (!SV_CheckBottom (ent))
	{
		if ( (int)ent->v.flags & FL_PARTIALGROUND )
		{	// entity had floor mostly pulled out from underneath it
			// and is trying to correct
			if (relink)
				SV_LinkEdict (ent, true);
			return true;
		}
		VectorCopy (oldorg, ent->v.origin);
		return false;
	}

	if ( (int)ent->v.flags & FL_PARTIALGROUND )
	{
//		Con_Printf ("back on ground\n"); 
		ent->v.flags = (int)ent->v.flags & ~FL_PARTIALGROUND;
	}
	ent->v.groundentity = EDICT_TO_PROG(trace.ent);

// the move is ok
	if (relink)
		SV_LinkEdict (ent, true);
	return true;
}
Beispiel #4
0
void SV_Physics_Step (edict_t *ent)
{
    bool	wasonground;
    bool	inwater;
    bool	hitsound = false;
    float		*vel;
    float		speed, newspeed, control;
    float		friction;
    edict_t		*groundentity;

    groundentity = PROG_TO_EDICT(ent->v.groundentity);
    if ((int)groundentity->v.flags & FL_CONVEYOR)
        VectorScale(groundentity->v.movedir, groundentity->v.speed, ent->v.basevelocity);
    else
        VectorCopy(vec_origin, ent->v.basevelocity);
//@@
    pr_global_struct->time = sv.time;
    pr_global_struct->self = EDICT_TO_PROG(ent);
    PF_WaterMove();

    SV_CheckVelocity (ent);

    wasonground = (int)ent->v.flags & FL_ONGROUND;
//	ent->v.flags = (int)ent->v.flags & ~FL_ONGROUND;

    // add gravity except:
    //   flying monsters
    //   swimming monsters who are in the water
    inwater = SV_CheckWater(ent);
    if (! wasonground)
        if (!((int)ent->v.flags & FL_FLY))
            if (!(((int)ent->v.flags & FL_SWIM) && (ent->v.waterlevel > 0)))
            {
                if (ent->v.velocity[2] < sv_gravity.value*-0.1)
                    hitsound = true;
                if (!inwater)
                    SV_AddGravity (ent);
            }

    if (!VectorCompare(ent->v.velocity, vec_origin) || !VectorCompare(ent->v.basevelocity, vec_origin))
    {
        ent->v.flags = (int)ent->v.flags & ~FL_ONGROUND;
        // apply friction
        // let dead monsters who aren't completely onground slide
        if (wasonground)
            if (!(ent->v.health <= 0.0 && !SV_CheckBottom(ent)))
            {
                vel = ent->v.velocity;
                speed = sqrt(vel[0]*vel[0] +vel[1]*vel[1]);
                if (speed)
                {
                    friction = sv_friction.value;

                    control = speed < sv_stopspeed.value ? sv_stopspeed.value : speed;
                    newspeed = speed - host_frametime*control*friction;

                    if (newspeed < 0)
                        newspeed = 0;
                    newspeed /= speed;

                    vel[0] = vel[0] * newspeed;
                    vel[1] = vel[1] * newspeed;
                }
            }

        VectorAdd (ent->v.velocity, ent->v.basevelocity, ent->v.velocity);
        SV_FlyMove (ent, host_frametime, NULL);
        VectorSubtract (ent->v.velocity, ent->v.basevelocity, ent->v.velocity);

        // determine if it's on solid ground at all
        {
            vec3_t	mins, maxs, point;
            int		x, y;

            VectorAdd (ent->v.origin, ent->v.mins, mins);
            VectorAdd (ent->v.origin, ent->v.maxs, maxs);

            point[2] = mins[2] - 1;
            for	(x=0 ; x<=1 ; x++)
                for	(y=0 ; y<=1 ; y++)
                {
                    point[0] = x ? maxs[0] : mins[0];
                    point[1] = y ? maxs[1] : mins[1];
                    if (SV_PointContents (point) == CONTENTS_SOLID)
                    {
                        ent->v.flags = (int)ent->v.flags | FL_ONGROUND;
                        break;
                    }
                }

        }

        SV_LinkEdict (ent, true);

        if ((int)ent->v.flags & FL_ONGROUND)
            if (!wasonground)
                if (hitsound)
                    SV_StartSound (ent, 0, "demon/dland2.wav", 255, 1);
    }

// regular thinking
    SV_RunThink (ent);
    SV_CheckWaterTransition (ent);
}
/* DESCRIPTION: SV_movestep/movetest
// LOCATION: sv_move.c
// PATH: PF_walkmove_I
//
// (from QW): 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
*/
qboolean SV_movestep(edict_t *ent, vec3_t move, qboolean relink) {

   int i, var_6C_hullnum;
   float dz;
   trace_t trace;
   vec3_t oldorg, neworg, end;
   edict_t * enemy;


   if(ent->v.flags & FL_MONSTERCLIP) { //Don't know what one has to do with the other.
      var_6C_hullnum = 1;
   }
   else {
      var_6C_hullnum = 0;
   }

   oldorg[0] = ent->v.origin[0];
   oldorg[1] = ent->v.origin[1];
   oldorg[2] = ent->v.origin[2];

   neworg[0] = ent->v.origin[0] + move[0];
   neworg[1] = ent->v.origin[1] + move[1];
   neworg[2] = ent->v.origin[2] + move[2];


   //well, try it.  Flying and swimming monsters are easiest.
   if(ent->v.flags & (FL_SWIM | FL_FLY)) {

      // try one move with vertical motion, then one without
      for(i = 0; i < 2; i++) {

         neworg[0] = ent->v.origin[0] + move[0];
         neworg[1] = ent->v.origin[1] + move[1];
         neworg[2] = ent->v.origin[2] + move[2];

         enemy = ent->v.enemy;
         if(i == 0 && enemy != NULL) {

            dz = ent->v.origin[2] - enemy->v.origin[2];

            if(dz > 40) { neworg[2] -= 8; }
            else if(dz < 30) { neworg[2] += 8; }
         }

         trace = SV_Move(ent->v.origin, ent->v.mins, ent->v.maxs, neworg, 0, ent, var_6C_hullnum);

         if(trace.fraction == 1) { //yaay

            global_g_groupmask = ent->v.groupinfo;

            if((ent->v.flags & FL_SWIM) && SV_PointContents(trace.endpos) == Q1CONTENTS_EMPTY) {
               return(0); //That move takes us out of the water.  Apparently though, it's okay to travel into solids, lava, sky, etc :)
            }

            ent->v.origin[0] = trace.endpos[0];
            ent->v.origin[1] = trace.endpos[1];
            ent->v.origin[2] = trace.endpos[2];

            if(relink != 0) {
               SV_LinkEdict(ent, 1);
            }
            return(1);
         }
         else {

            if(enemy == NULL) { break; }
         }
      }

      return(0);
   }
   else {

      dz = cvar_sv_stepsize.value;
      neworg[2] += dz;
      end[0] = neworg[0];
      end[1] = neworg[1];
      end[2] = neworg[2];
      end[2] -= dz*2;

      trace = SV_Move(neworg, ent->v.mins, ent->v.maxs, end, 0, ent, var_6C_hullnum);
      if(trace.allsolid != 0) { return(0); }

      if(trace.startsolid != 0) {

         neworg[2] -= dz;

         trace = SV_Move(neworg, ent->v.mins, ent->v.maxs, end, 0, ent, var_6C_hullnum);

         if(trace.allsolid != 0 || trace.startsolid != 0) { return(0); }
      }

      if(trace.fraction == 1) {
         if(ent->v.flags & FL_PARTIALGROUND) { //Whoa, where'd the ground go?

            ent->v.origin[0] += move[0];
            ent->v.origin[1] += move[1];
            ent->v.origin[2] += move[2];

            if(relink != 0) {
               SV_LinkEdict(ent, 1);
            }
            ent->v.flags &= ~FL_ONGROUND;
            return(1);
         }

         return(0); //Fell off like a green koopa.
      }
      else {

         ent->v.origin[0] = trace.endpos[0];
         ent->v.origin[1] = trace.endpos[1];
         ent->v.origin[2] = trace.endpos[2];

         if(SV_CheckBottom(ent) == 0) {
            if(ent->v.flags & FL_PARTIALGROUND) {

               if(relink != 0) {
                  SV_LinkEdict(ent, 1);
               }
               return(1);
            }

            ent->v.origin[0] = oldorg[0];
            ent->v.origin[1] = oldorg[1];
            ent->v.origin[2] = oldorg[2];

            return(0);
         }
         else {

            if(ent->v.flags & FL_PARTIALGROUND) {
               ent->v.flags &= ~FL_PARTIALGROUND;
            }

            ent->v.groundentity = trace.pHit;

            if(relink != 0) {
               SV_LinkEdict(ent, 1);
            }
            return(1);
         }
      }
   }
}
Beispiel #6
0
//============================================================================
static void SV_Physics_Entity( edict_t *ent )
{
	// user dll can override movement type (Xash3D extension)
	if( svgame.physFuncs.SV_PhysicsEntity && svgame.physFuncs.SV_PhysicsEntity( ent ))
		return; // overrided

	SV_UpdateBaseVelocity( ent );

	if(!( ent->v.flags & FL_BASEVELOCITY ) && !VectorIsNull( ent->v.basevelocity ))
	{
		// Apply momentum (add in half of the previous frame of velocity first)
		VectorMA( ent->v.velocity, 1.0f + (host.frametime * 0.5f), ent->v.basevelocity, ent->v.velocity );
		VectorClear( ent->v.basevelocity );
	}

	ent->v.flags &= ~FL_BASEVELOCITY;

	if( svgame.globals->force_retouch != 0.0f )
	{
		// force retouch even for stationary
		SV_LinkEdict( ent, true );
	}

	switch( ent->v.movetype )
	{
	case MOVETYPE_NONE:
		SV_Physics_None( ent );
		break;
	case MOVETYPE_NOCLIP:
		SV_Physics_Noclip( ent );
		break;
	case MOVETYPE_FOLLOW:
		SV_Physics_Follow( ent );
		break;
	case MOVETYPE_COMPOUND:
		SV_Physics_Compound( ent );
		break;
	case MOVETYPE_STEP:
	case MOVETYPE_PUSHSTEP:
		SV_Physics_Step( ent );
		break;
	case MOVETYPE_FLY:
	case MOVETYPE_TOSS:
	case MOVETYPE_BOUNCE:
	case MOVETYPE_FLYMISSILE:
	case MOVETYPE_BOUNCEMISSILE:
		SV_Physics_Toss( ent );
		break;
	case MOVETYPE_PUSH:
		SV_Physics_Pusher( ent );
		break;
	case MOVETYPE_WALK:
		Host_MapDesignError( "SV_Physics: bad movetype %i for %s, reset to MOVETYPE_NONE\n", ent->v.movetype, STRING( ent->v.classname ) );
		ent->v.movetype = MOVETYPE_NONE;
		break;
	}

	// g-cont. don't alow free entities during loading because
	// this produce a corrupted baselines
	if( sv.state == ss_active && ( ent->v.flags & FL_KILLME ) )
		SV_FreeEdict( ent );
}
Beispiel #7
0
/*
============
SV_PushRotate

============
*/
static edict_t *SV_PushRotate( edict_t *pusher, float movetime )
{
	int		i, e, block, oldsolid;
	matrix4x4		start_l, end_l;
	vec3_t		lmove, amove;
	sv_pushed_t	*p, *pushed_p;
	vec3_t		org, org2, temp;
	edict_t		*check;

	if( svgame.globals->changelevel || VectorIsNull( pusher->v.avelocity ))
	{
		pusher->v.ltime += movetime;
		return NULL;
	}

	for( i = 0; i < 3; i++ )
		amove[i] = pusher->v.avelocity[i] * movetime;

	// create pusher initial position
	Matrix4x4_CreateFromEntity( start_l, pusher->v.angles, pusher->v.origin, 1.0f );

	pushed_p = svgame.pushed;

	// save the pusher's original position
	pushed_p->ent = pusher;
	VectorCopy( pusher->v.origin, pushed_p->origin );
	VectorCopy( pusher->v.angles, pushed_p->angles );
	pushed_p++;
	
	// move the pusher to it's final position
	SV_AngularMove( pusher, movetime, pusher->v.friction );
	SV_LinkEdict( pusher, false );
	pusher->v.ltime += movetime;
	oldsolid = pusher->v.solid;

	// non-solid pushers can't push anything
	if( pusher->v.solid == SOLID_NOT )
		return NULL;

	// create pusher final position
	Matrix4x4_CreateFromEntity( end_l, pusher->v.angles, pusher->v.origin, 1.0f );

	// see if any solid entities are inside the final position
	for( e = 1; e < svgame.numEntities; e++ )
	{
		check = EDICT_NUM( e );
		if( !SV_IsValidEdict( check ))
			continue;

		// filter movetypes to collide with
		if( !SV_CanPushed( check ))
			continue;

		pusher->v.solid = SOLID_NOT;
		block = SV_TestEntityPosition( check, pusher );
		pusher->v.solid = oldsolid;
		if( block ) continue;

		// if the entity is standing on the pusher, it will definately be moved
		if( !(( check->v.flags & FL_ONGROUND ) && check->v.groundentity == pusher ))
		{
			if( check->v.absmin[0] >= pusher->v.absmax[0]
			|| check->v.absmin[1] >= pusher->v.absmax[1]
			|| check->v.absmin[2] >= pusher->v.absmax[2]
			|| check->v.absmax[0] <= pusher->v.absmin[0]
			|| check->v.absmax[1] <= pusher->v.absmin[1]
			|| check->v.absmax[2] <= pusher->v.absmin[2] )
				continue;

			// see if the ent's bbox is inside the pusher's final position
			if( !SV_TestEntityPosition( check, NULL ))
				continue;
		}

		// save original position of contacted entity
		pushed_p->ent = check;
		VectorCopy( check->v.origin, pushed_p->origin );
		VectorCopy( check->v.angles, pushed_p->angles );
		pushed_p->fixangle = check->v.fixangle;
		pushed_p++;

		// calculate destination position
		if( check->v.movetype == MOVETYPE_PUSHSTEP || check->v.movetype == MOVETYPE_STEP )
			VectorAverage( check->v.absmin, check->v.absmax, org );
		else VectorCopy( check->v.origin, org );

		Matrix4x4_VectorITransform( start_l, org, temp );
		Matrix4x4_VectorTransform( end_l, temp, org2 );
		VectorSubtract( org2, org, lmove );

		// i can't clear FL_ONGROUND in all cases because many bad things may be happen
		if( check->v.movetype != MOVETYPE_WALK )
		{
			if( lmove[2] != 0.0f ) check->v.flags &= ~FL_ONGROUND;
			if( lmove[2] < 0.0f && !pusher->v.dmg )
				lmove[2] = 0.0f; // let's the free falling
                    }

		// try moving the contacted entity 
		pusher->v.solid = SOLID_NOT;
		SV_PushEntity( check, lmove, amove, &block );
		pusher->v.solid = oldsolid;

		// pushed entity blocked by wall
		if( block && check->v.movetype != MOVETYPE_WALK )
			check->v.flags &= ~FL_ONGROUND;

		// if it is still inside the pusher, block
		if( SV_TestEntityPosition( check, NULL ) && block )
		{	
			if( !SV_CanBlock( check ))
				continue;

			pusher->v.ltime -= movetime;

			// move back any entities we already moved
			// go backwards, so if the same entity was pushed
			// twice, it goes back to the original position
			for( p = pushed_p - 1; p >= svgame.pushed; p-- )
			{
				VectorCopy( p->origin, p->ent->v.origin );
				VectorCopy( p->angles, p->ent->v.angles );
				SV_LinkEdict( p->ent, (p->ent == check) ? true : false );
				p->ent->v.fixangle = p->fixangle;
			}
			return check;
		}
	}

	return NULL;
}
Beispiel #8
0
void SV_LoadGame_f (void) {
	extern cvar_t sv_progtype;
	char name[MAX_OSPATH], mapname[MAX_QPATH], str[32 * 1024], *start;
	FILE *f;
	float time, tfloat, spawn_parms[NUM_SPAWN_PARMS];
	edict_t *ent;
	int entnum, version, r;
	unsigned int i;

	if (Cmd_Argc() != 2) {
		Con_Printf ("Usage: %s <savename> : load a game\n", Cmd_Argv(0));
		return;
	}

	snprintf (name, sizeof (name), "%s/save/%s", fs_gamedir, Cmd_Argv(1));
	COM_DefaultExtension (name, ".sav");

	Con_Printf ("Loading game from %s...\n", name);
	if (!(f = fopen (name, "rb"))) {
		Con_Printf ("ERROR: couldn't open.\n");
		return;
	}

	if (fscanf (f, "%i\n", &version) != 1) {
		fclose (f);
		Con_Printf ("Error reading savegame data\n");
		return;
	}

	if (version != SAVEGAME_VERSION) {
		fclose (f);
		Con_Printf ("Savegame is version %i, not %i\n", version, SAVEGAME_VERSION);
		return;
	}

	if (fscanf (f, "%s\n", str) != 1) {
		fclose (f);
		Con_Printf ("Error reading savegame data\n");
		return;
	}
	for (i = 0; i < NUM_SPAWN_PARMS; i++) {
		if (fscanf (f, "%f\n", &spawn_parms[i]) != 1) {
			fclose (f);
			Con_Printf ("Error reading savegame data\n");
			return;
		}
	}

	// this silliness is so we can load 1.06 save files, which have float skill values
	if (fscanf (f, "%f\n", &tfloat) != 1) {
		fclose (f);
		Con_Printf ("Error reading savegame data\n");
		return;
	}
	current_skill = (int)(tfloat + 0.1);
	Cvar_Set (&skill, va("%i", current_skill));

	Cvar_SetValue (&deathmatch, 0);
	Cvar_SetValue (&coop, 0);
	Cvar_SetValue (&teamplay, 0);
	Cvar_SetValue (&maxclients, 1);

	Cvar_Set (&sv_progsname, "spprogs"); // force progsname
#ifdef USE_PR2
	Cvar_Set (&sv_progtype, "0"); // force .dat
#endif

	if (fscanf (f, "%s\n", mapname) != 1) {
		fclose (f);
		Con_Printf ("Error reading savegame data\n");
		return;
	}
	if (fscanf (f, "%f\n", &time) != 1) {
		fclose (f);
		Con_Printf ("Error reading savegame data\n");
		return;
	}

#ifndef SERVERONLY
	Host_EndGame();
	CL_BeginLocalConnection ();
#endif

	SV_SpawnServer (mapname, false);

	if (sv.state != ss_active) {
		Con_Printf ("Couldn't load map\n");
		fclose (f);
		return;
	}

	// load the light styles
	for (i = 0; i < MAX_LIGHTSTYLES; i++) {
		if (fscanf (f, "%s\n", str) != 1) {
			Con_Printf("Couldn't read lightstyles\n");
			fclose (f);
			return;
		}
		sv.lightstyles[i] = (char *) Hunk_Alloc (strlen(str) + 1);
		strlcpy (sv.lightstyles[i], str, strlen(str) + 1);
	}

	// pause until all clients connect
	if (!(sv.paused & 1))
		SV_TogglePause (NULL, 1);

	sv.loadgame = true;

	// load the edicts out of the savegame file
	entnum = -1;		// -1 is the globals
	while (!feof(f)) {
		for (i = 0; i < sizeof(str) - 1; i++) {
			r = fgetc (f);
			if (r == EOF || !r)
				break;
			str[i] = r;
			if (r == '}') {
				i++;
				break;
			}
		}
		if (i == sizeof(str)-1)
			Host_Error ("Loadgame buffer overflow");
		str[i] = 0;
		start = str;
		start = COM_Parse(str);
		if (!com_token[0])
			break;		// end of file

		if (strcmp(com_token,"{"))
			Host_Error ("First token isn't a brace");

		if (entnum == -1) {	
			// parse the global vars
			ED_ParseGlobals (start);
		} else {	
			// parse an edict
			ent = EDICT_NUM(entnum);
			ED_ClearEdict (ent); // FIXME: we also clear world edict here, is it OK?
			ED_ParseEdict (start, ent);
	
			// link it into the bsp tree
			if (!ent->e->free)
				SV_LinkEdict (ent, false);
		}
		entnum++;
	}

	sv.num_edicts = entnum;
	sv.time = time;

	fclose (f);

	for (i = 0; i < NUM_SPAWN_PARMS; i++)
		svs.clients->spawn_parms[i] = spawn_parms[i];
}
/*
===========
SV_RunCmd
===========
*/
static void SV_RunCmd (usercmd_t *ucmd)
{
	edict_t		*ent;
	int			i, n;
	int			oldmsec;

	cmd = *ucmd;

	// chop up very long commands
	if (cmd.msec > 50)
	{
		oldmsec = ucmd->msec;
		cmd.msec = oldmsec/2;
		SV_RunCmd (&cmd);
		cmd.msec = oldmsec/2;
		cmd.impulse = 0;
		SV_RunCmd (&cmd);
		return;
	}

	if (!sv_player->v.fixangle)
		VectorCopy (ucmd->angles, sv_player->v.v_angle);

	sv_player->v.button0 = ucmd->buttons & 1;
	sv_player->v.button2 = (ucmd->buttons & 2)>>1;

	if (ucmd->buttons & 4 || sv_player->v.playerclass == CLASS_DWARF) // crouched?
		sv_player->v.flags2 = ((int)sv_player->v.flags2) | FL2_CROUCHED;
	else
		sv_player->v.flags2 = ((int)sv_player->v.flags2) & (~FL2_CROUCHED);

	if (ucmd->impulse)
		sv_player->v.impulse = ucmd->impulse;

//
// angles
// show 1/3 the pitch angle and all the roll angle
	if (sv_player->v.health > 0)
	{
		if (!sv_player->v.fixangle)
		{
			sv_player->v.angles[PITCH] = -sv_player->v.v_angle[PITCH]/3;
			sv_player->v.angles[YAW] = sv_player->v.v_angle[YAW];
		}
		sv_player->v.angles[ROLL] = 
				V_CalcRoll (sv_player->v.angles, sv_player->v.velocity)*4;
	}

	host_frametime = ucmd->msec * 0.001;
	if (host_frametime > HX_FRAME_TIME)
		host_frametime = HX_FRAME_TIME;

	if (!host_client->spectator)
	{
		pr_global_struct->frametime = host_frametime;

		pr_global_struct->time = sv.time;
		pr_global_struct->self = EDICT_TO_PROG(sv_player);
		PR_ExecuteProgram (pr_global_struct->PlayerPreThink);

		SV_RunThink (sv_player);
	}

	for (i = 0; i < 3; i++)
		pmove.origin[i] = sv_player->v.origin[i] + (sv_player->v.mins[i] - player_mins[i]);

	VectorCopy (sv_player->v.velocity, pmove.velocity);
	VectorCopy (sv_player->v.v_angle, pmove.angles);

	pmove.spectator = host_client->spectator;
//	pmove.waterjumptime = sv_player->v.teleport_time;
	pmove.numphysent = 1;
	pmove.physents[0].model = sv.worldmodel;
	pmove.cmd = *ucmd;
	pmove.dead = sv_player->v.health <= 0;
	pmove.oldbuttons = host_client->oldbuttons;
	pmove.hasted = sv_player->v.hasted;
	pmove.movetype = sv_player->v.movetype;
	pmove.crouched = (sv_player->v.hull == HULL_CROUCH);
	pmove.teleport_time = realtime + (sv_player->v.teleport_time - sv.time);

//	movevars.entgravity = host_client->entgravity;
	movevars.entgravity = sv_player->v.gravity;
	movevars.maxspeed = host_client->maxspeed;

	for (i = 0; i < 3; i++)
	{
		pmove_mins[i] = pmove.origin[i] - 256;
		pmove_maxs[i] = pmove.origin[i] + 256;
	}
#if 1
	AddLinksToPmove ( sv_areanodes );
#else
	AddAllEntsToPmove ();
#endif

#if 0
	{
		int	before, after;

		before = PM_TestPlayerPosition (pmove.origin);
		PlayerMove ();
		after = PM_TestPlayerPosition (pmove.origin);

		if (sv_player->v.health > 0 && before && !after )
			Con_Printf ("player %s got stuck in playermove!!!!\n", host_client->name);
	}
#else
	PlayerMove ();
#endif

	host_client->oldbuttons = pmove.oldbuttons;
//	sv_player->v.teleport_time = pmove.waterjumptime;
	sv_player->v.waterlevel = waterlevel;
	sv_player->v.watertype = watertype;
	if (onground != -1)
	{
		sv_player->v.flags = (int)sv_player->v.flags | FL_ONGROUND;
		sv_player->v.groundentity = EDICT_TO_PROG(EDICT_NUM(pmove.physents[onground].info));
	}
	else
		sv_player->v.flags = (int)sv_player->v.flags & ~FL_ONGROUND;

	for (i = 0; i < 3; i++)
		sv_player->v.origin[i] = pmove.origin[i] - (sv_player->v.mins[i] - player_mins[i]);

#if 0
	// truncate velocity the same way the net protocol will
	for (i = 0; i < 3; i++)
		sv_player->v.velocity[i] = (int)pmove.velocity[i];
#else
	VectorCopy (pmove.velocity, sv_player->v.velocity);
#endif

	VectorCopy (pmove.angles, sv_player->v.v_angle);

	if (!host_client->spectator)
	{
		// link into place and touch triggers
		SV_LinkEdict (sv_player, true);

		// touch other objects
		for (i = 0; i < pmove.numtouch; i++)
		{
			n = pmove.physents[pmove.touchindex[i]].info;
			ent = EDICT_NUM(n);

		// Why not just do an SV_Impact here?
		//	SV_Impact(sv_player,ent);

			if (sv_player->v.touch)
			{
				pr_global_struct->self = EDICT_TO_PROG(sv_player);
				pr_global_struct->other = EDICT_TO_PROG(ent);
				PR_ExecuteProgram (sv_player->v.touch);
			}
			if (!ent->v.touch || (playertouch[n/8]&(1<<(n%8))))
				continue;
			pr_global_struct->self = EDICT_TO_PROG(ent);
			pr_global_struct->other = EDICT_TO_PROG(sv_player);
			PR_ExecuteProgram (ent->v.touch);
			playertouch[n/8] |= 1 << (n%8);
		}
	}
}
Beispiel #10
0
/*
============
SV_PushRotate
============
*/
void SV_PushRotate (edict_t *pusher, float movetime)
{
	int			i, e, t, num_moved, slaves_moved;
	edict_t		*check, *block, *ground, *master, *slave;
	edict_t		*moved_edict[MAX_EDICTS];
	vec3_t		moved_from[MAX_EDICTS];
	vec3_t		move, a, amove, mins, maxs, move2, move3, testmove;
	vec3_t		entorig, pushorig, pushorigangles;
	vec3_t		org, org2, check_center;
	vec3_t		forward, right, up;
	qboolean	moveit;

	for (i=0 ; i<3 ; i++)
	{
		amove[i] = pusher->v.avelocity[i] * movetime;
		move[i] = pusher->v.velocity[i] * movetime;
		mins[i] = pusher->v.absmin[i] + move[i];
		maxs[i] = pusher->v.absmax[i] + move[i];
	}

	VectorSubtract (vec3_origin, amove, a);
	AngleVectors (a, forward, right, up);

	VectorCopy (pusher->v.origin, pushorig);
	VectorCopy (pusher->v.angles, pushorigangles);
	
// move the pusher to it's final position

	VectorAdd (pusher->v.origin, move, pusher->v.origin);
	VectorAdd (pusher->v.angles, amove, pusher->v.angles);

	pusher->v.ltime += movetime;
	SV_LinkEdict (pusher, false);

	master = pusher;
	slaves_moved = 0;

// see if any solid entities are inside the final position
	num_moved = 0;
	check = NEXT_EDICT(sv.edicts);
	for (e=1 ; e<sv.num_edicts ; e++, check = NEXT_EDICT(check))
	{
		if (check->free)
			continue;
		if (check->v.movetype == MOVETYPE_PUSH || check->v.movetype == MOVETYPE_NONE || 
		    check->v.movetype == MOVETYPE_FOLLOW || check->v.movetype == MOVETYPE_NOCLIP)
			continue;

		// if the entity is standing on the pusher, it will definitely be moved
		moveit = false;
		ground = PROG_TO_EDICT(check->v.groundentity);
		if ((int)check->v.flags & FL_ONGROUND)
		{
			if (ground == pusher)
			{
				moveit = true;
			}
			else
			{
				for (i=0; i<slaves_moved; i++)
				{
					if (ground == moved_edict[MAX_EDICTS - i - 1])
					{
						moveit = true;
						break;
					}
				}
			}
		}

		if (!moveit)
		{
			if ( check->v.absmin[0] >= maxs[0] || check->v.absmin[1] >= maxs[1] ||
				 check->v.absmin[2] >= maxs[2] || check->v.absmax[0] <= mins[0] ||
			     check->v.absmax[1] <= mins[1] || check->v.absmax[2] <= mins[2] )
			{
				for (i=0; i<slaves_moved; i++)
				{
					slave = moved_edict[MAX_EDICTS - i - 1];
					if ( check->v.absmin[0] >= slave->v.absmax[0]
					|| check->v.absmin[1] >= slave->v.absmax[1]
					|| check->v.absmin[2] >= slave->v.absmax[2]
					|| check->v.absmax[0] <= slave->v.absmin[0]
					|| check->v.absmax[1] <= slave->v.absmin[1]
					|| check->v.absmax[2] <= slave->v.absmin[2] )
						continue;
				}
				if (i == slaves_moved)
					continue;
			}

		// see if the ent's bbox is inside the pusher's final position
			if (!SV_TestEntityPosition (check))
				continue;
		}

		// remove the onground flag for non-players
		if (check->v.movetype != MOVETYPE_WALK)
			check->v.flags = (int)check->v.flags & ~FL_ONGROUND;
		
		VectorCopy (check->v.origin, entorig);
		VectorCopy (check->v.origin, moved_from[num_moved]);
		moved_edict[num_moved] = check;
		num_moved++;

//put check in first move spot
		VectorAdd (check->v.origin, move, check->v.origin);
//Use center of model, like in QUAKE!!!!  Our origins are on the bottom!!!
		for (i=0 ; i<3 ; i++)
			check_center[i] = (check->v.absmin[i] + check->v.absmax[i])/2;
// calculate destination position
		VectorSubtract (check_center, pusher->v.origin, org);
//put check back
		VectorSubtract (check->v.origin, move, check->v.origin);
		org2[0] = DotProduct (org, forward);
		org2[1] = -DotProduct (org, right);
		org2[2] = DotProduct (org, up);
		VectorSubtract (org2, org, move2);

		//Add all moves together
		VectorAdd(move,move2,move3);

		// try moving the contacted entity 
		for( t = 0; t < 13; t++)
		{
			switch(t)
			{
				case 0:
				//try x, y and z
					VectorCopy(move3,testmove);
					break;
				case 1:
				//Try xy only
					VectorSubtract(check->v.origin,testmove,check->v.origin);
					testmove[0]=move3[0];
					testmove[1]=move3[1];
					testmove[2]=0;
					break;
				case 2:
				//Try z only
					VectorSubtract(check->v.origin,testmove,check->v.origin);
					testmove[0]=0;
					testmove[1]=0;
					testmove[2]=move3[2];
					break;
				case 3:
				//Try none
					VectorSubtract(check->v.origin,testmove,check->v.origin);
					testmove[0]=0;
					testmove[1]=0;
					testmove[2]=0;
					break;
				case 4:
				//Try xy in opposite dir
					testmove[0]=move3[0]*-1;
					testmove[1]=move3[1]*-1;
					testmove[2]=move3[2];
					break;
				case 5:
				//Try z in opposite dir
					VectorSubtract(check->v.origin,testmove,check->v.origin);
					testmove[0]=move3[0];
					testmove[1]=move3[1];
					testmove[2]=move3[2]*-1;
					break;
				case 6:
				//Try xyz in opposite dir
					VectorSubtract(check->v.origin,testmove,check->v.origin);
					testmove[0]=move3[0]*-1;
					testmove[1]=move3[1]*-1;
					testmove[2]=move3[2]*-1;
					break;
				case 7:
				//Try move3 times 2
					VectorSubtract(check->v.origin,testmove,check->v.origin);
					VectorScale(move3,2,testmove);
					break;
				case 8:
				//Try normalized org
					VectorSubtract(check->v.origin,testmove,check->v.origin);
					VectorScale(org,movetime,org);//movetime*20?
					VectorCopy(org,testmove);
					break;
				case 9:
				//Try normalized org z * 3 only
					VectorSubtract(check->v.origin,testmove,check->v.origin);
					testmove[0]=0;
					testmove[1]=0;
					testmove[2]=org[2]*3;//was: +org[2]*(fastfabs(org[1])+fastfabs(org[2]));
					break;
				case 10:
				//Try normalized org xy * 2 only
					VectorSubtract(check->v.origin,testmove,check->v.origin);
					testmove[0]=org[0]*2;//was: +org[0]*fastfabs(org[2]);
					testmove[1]=org[1]*2;//was: +org[1]*fastfabs(org[2]);
					testmove[2]=0;
					break;
				case 11:
				//Try xy in opposite org dir
					VectorSubtract(check->v.origin,testmove,check->v.origin);
					testmove[0]=org[0]*-2;
					testmove[1]=org[1]*-2;
					testmove[2]=org[2];
					break;
				case 12:
				//Try z in opposite dir
					VectorSubtract(check->v.origin,testmove,check->v.origin);
					testmove[0]=org[0];
					testmove[1]=org[1];
					testmove[2]=org[2]*-3;
					break;
			}

			if(t!=3)
			{
				//THIS IS VERY BAD BAD HACK...
				pusher->v.solid = SOLID_NOT;
				SV_PushEntity (check, move3);
				//@@TODO: do we ever want to do anybody's angles?  maybe just yaw???
				//		if (!((int)check->v.flags & (FL_CLIENT | FL_MONSTER)))
				//			VectorAdd (check->v.angles, amove, check->v.angles);
				check->v.angles[YAW] += amove[YAW];
				pusher->v.solid = SOLID_BSP;
			}
			// if it is still inside the pusher, block
			block = SV_TestEntityPosition (check);
			if(!block)
				break;
		}

		if (block)
		{	// fail the move
			//			Con_DPrintf("Check blocked\n");
			if (check->v.mins[0] == check->v.maxs[0])
				continue;
			if (check->v.solid == SOLID_NOT || check->v.solid == SOLID_TRIGGER)
			{	// corpse
				check->v.mins[0] = check->v.mins[1] = 0;
				VectorCopy (check->v.mins, check->v.maxs);
				continue;
			}
			
			VectorCopy (entorig, check->v.origin);
			SV_LinkEdict (check, true);
			
			VectorCopy (pushorig, pusher->v.origin);
			VectorCopy (pushorigangles, pusher->v.angles);
			SV_LinkEdict (pusher, false);
			pusher->v.ltime -= movetime;
			
			for (i=0; i<slaves_moved; i++)
			{
				slave = moved_edict[MAX_EDICTS - i - 1];
				VectorCopy (moved_from[MAX_EDICTS - i - 1], slave->v.angles);
				SV_LinkEdict (slave, false);
				slave->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)
			{
				*pr_global_ptrs.self = EDICT_TO_PROG(pusher);
				*pr_global_ptrs.other = EDICT_TO_PROG(check);
				PR_ExecuteProgram (pusher->v.blocked);
			}
			
			// move back any entities we already moved
			for (i=0 ; i<num_moved ; i++)
			{
				VectorCopy (moved_from[i], moved_edict[i]->v.origin);
				//@@TODO:: see above
				//				if (!((int)moved_edict[i]->v.flags & (FL_CLIENT | FL_MONSTER)))
				//					VectorSubtract (moved_edict[i]->v.angles, amove, moved_edict[i]->v.angles);
				moved_edict[i]->v.angles[YAW] -= amove[YAW];
				
				SV_LinkEdict (moved_edict[i], false);
			}
			return;
		}
	}
}
Beispiel #11
0
static void
Host_Loadgame_f (void)
{
	dstring_t  *name = 0;
	QFile      *f;
	char       *mapname = 0;
	script_t   *script = 0;
	plitem_t   *game = 0;
	plitem_t   *list;
	plitem_t   *item;
	char       *script_data = 0;
	int         i;
	int         entnum;
	int         count;
	int         version;
	float       spawn_parms[NUM_SPAWN_PARMS];

	if (cmd_source != src_command)
		goto end;

	if (Cmd_Argc () != 2) {
		Sys_Printf ("load <savename> : load a game\n");
		goto end;
	}

	cls.demonum = -1;					// stop demo loop in case this fails

	name = dstring_newstr ();
	dsprintf (name, "%s/%s", qfs_gamedir->dir.def, Cmd_Argv (1));
	QFS_DefaultExtension (name, ".sav");

	cl.loading = true;
	CL_UpdateScreen (cl.time);

	Sys_Printf ("Loading game from %s...\n", name->str);
	f = QFS_Open (name->str, "rz");
	if (!f) {
		Sys_Printf ("ERROR: couldn't open.\n");
		goto end;
	}
	script_data = malloc (Qfilesize (f) + 1);
	i = Qread (f, script_data, Qfilesize (f));
	script_data[i] = 0;
	Qclose (f);

	script = Script_New ();
	script->single = "";		// disable {}()': lexing
	Script_Start (script, name->str, script_data);

	Script_GetToken (script, 1);
	if (strequal (script->token->str, PACKAGE_NAME)) {
		if (!Script_TokenAvailable (script, 1)) {
			Sys_Printf ("Unexpected EOF reading %s\n", name->str);
			goto end;
		}
		game = PL_GetPropertyList (script->p);
	} else {
		sscanf (script->token->str, "%i", &version);
		if (version != SAVEGAME_VERSION) {
			Sys_Printf ("Savegame is version %i, not %i\n", version,
						SAVEGAME_VERSION);
			goto end;
		}
		game = convert_to_game_dict (script);
	}

	item = PL_ObjectForKey (game, "spawn_parms");
	for (i = 0; i < NUM_SPAWN_PARMS; i++) {
		if (i >= PL_A_NumObjects (item))
			break;
		spawn_parms[i] = atof (PL_String (PL_ObjectAtIndex (item, i)));
	}
	current_skill = atoi (PL_String (PL_ObjectForKey (game, "current_skill")));
	Cvar_SetValue (skill, current_skill);
	mapname = strdup (PL_String (PL_ObjectForKey (game, "name")));

	CL_Disconnect_f ();

	SV_SpawnServer (mapname);
	if (!sv.active) {
		Sys_Printf ("Couldn't load map %s\n", mapname);
		goto end;
	}
	sv.paused = true;					// pause until all clients connect
	sv.loadgame = true;

	list = PL_ObjectForKey (game, "lightstyles");
	for (i = 0; i < MAX_LIGHTSTYLES; i++) {
		const char *style;
		char       *str;
		if (i >= PL_A_NumObjects (list))
			break;
		item = PL_ObjectAtIndex (list, i);
		style = PL_String (item);
		sv.lightstyles[i] = str = Hunk_Alloc (strlen (style) + 1);
		strcpy (str, style);
	}

	ED_InitGlobals (&sv_pr_state, PL_ObjectForKey (game, "globals"));

	list = PL_ObjectForKey (game, "entities");
	entnum = 0;
	count = PL_A_NumObjects (list);
	if (count > sv.max_edicts)
		Host_Error ("too many entities in saved game. adjust max_edicts\n");
	for (entnum = 0; entnum < count; entnum++) {
		plitem_t   *entity = PL_ObjectAtIndex (list, entnum);
		edict_t    *ent = EDICT_NUM (&sv_pr_state, entnum);

		memset (&ent->v, 0, sv_pr_state.progs->entityfields * 4);
		ent->free = false;
		ED_InitEntity (&sv_pr_state, entity, ent);

		// link it into the bsp tree
		if (!ent->free)
			SV_LinkEdict (ent, false);
	}

	sv.num_edicts = entnum;
	sv.time = atof (PL_String (PL_ObjectForKey (game, "time")));

	for (i = 0; i < NUM_SPAWN_PARMS; i++)
		svs.clients->spawn_parms[i] = spawn_parms[i];

	if (cls.state != ca_dedicated) {
		CL_EstablishConnection ("local");
		Host_Reconnect_f ();
	}
end:
	if (game)
		PL_Free (game);
	if (mapname)
		free (mapname);
	if (script)
		Script_Delete (script);
	if (script_data)
		free (script_data);
	if (name)
		dstring_delete (name);
}
Beispiel #12
0
/*
============
SV_PushEntity

Does not change the entity's velocity at all
============
*/
trace_t SV_PushEntity (edict_t *ent, vec3_t push)
{
	trace_t	trace;
	vec3_t	end;
	int movetype;
		
	VectorAdd (ent->v.origin, push, end);

	if (ent->v.movetype == MOVETYPE_FLYMISSILE)
		movetype = MOVE_MISSILE;

#ifdef HEXEN2_SUPPORT
	else if (hexen2 && (ent->v.movetype == MOVETYPE_BOUNCEMISSILE))
		movetype = MOVE_MISSILE;
#endif
	else if (ent->v.solid == SOLID_TRIGGER || ent->v.solid == SOLID_NOT)
		movetype = MOVE_NOMONSTERS;		// only clip against bmodels

#ifdef HEXEN2_SUPPORT
	else if (hexen2 && (ent->v.movetype == MOVETYPE_SWIM))
		movetype = MOVE_WATER;
#endif
	else
		movetype = MOVE_NORMAL;
	
	trace = SV_Move (ent->v.origin, ent->v.mins, ent->v.maxs, end, movetype, ent);	
	
#ifdef HEXEN2_SUPPORT
	if (hexen2)
	{
		if (ent->v.solid != SOLID_PHASE)
		{
			if ((ent->v.movetype == MOVETYPE_BOUNCE) && !(trace.allsolid == 0 && trace.startsolid == 0))
			{
				trace.fraction = 0;
				return trace;
			}
		}
		else	// Entity is PHASED so bounce off walls and other entities, go through monsters and players
		{
			if (trace.ent)
			{	// Go through MONSTERS and PLAYERS, can't use FL_CLIENT cause rotating brushes do
				if (((int) trace.ent->v.flags & FL_MONSTER) || (trace.ent->v.movetype == MOVETYPE_WALK))
				{
					vec3_t  impact;
					edict_t *impact_e;
					
					VectorCopy (trace.endpos, impact);
					impact_e = trace.ent;

					trace = SV_Move (ent->v.origin, ent->v.mins, ent->v.maxs, end, MOVE_PHASE, ent);

					VectorCopy (impact, ent->v.origin);
					SV_Impact (ent, impact_e);
				}
			}
		}
	}
#endif

	VectorCopy (trace.endpos, ent->v.origin);
	
#ifdef _DEBUG
	if (!VectorCompare(trace.endpos, end))
		movetype *= 1;
#endif
	
	SV_LinkEdict (ent, true);

	if (trace.ent)
		SV_Impact (ent, trace.ent);		

	return trace;
}					
Beispiel #13
0
/*
================
SV_Physics

================
*/
void SV_Physics (void)
{
	int			i;
	edict_t		*ent;

// let the progs know that a new frame has started
#ifdef HEXEN2_SUPPORT
	edict_t		*ent2;
	vec3_t		oldOrigin, oldAngle;
	int			originMoved, c;
#endif

	PR_GLOBAL(self) = EDICT_TO_PROG(sv.edicts);
	PR_GLOBAL(other) = EDICT_TO_PROG(sv.edicts);
	PR_GLOBAL(time) = sv.time;
	PR_ExecuteProgram (PR_GLOBAL(StartFrame));

//SV_CheckAllEnts ();

// treat each object in turn
	ent = sv.edicts;
	for (i=0 ; i<sv.num_edicts ; i++, ent = NEXT_EDICT(ent))
	{
		if (ent->free)
			continue;

	#ifndef RQM_SV_ONLY
		if (!isDedicated && ((i+1) % 100 == 0))
			S_ExtraUpdateTime (); // BJP: Improve sound when many entities
	#endif

	#ifdef HEXEN2_SUPPORT
		if (hexen2)
		{
			ent2 = PROG_TO_EDICT (ent->v.movechain);
			if (ent2 != sv.edicts)
			{
				VectorCopy (ent->v.origin, oldOrigin);
				VectorCopy (ent->v.angles, oldAngle);
			}
		}
	#endif

		if (pr_global_ptrs.force_retouch && *pr_global_ptrs.force_retouch)
			SV_LinkEdict (ent, true);	// force retouch even for stationary

		if (i > 0 && i <= svs.maxclients)
			SV_Physics_Client (ent, i);
		else if (ent->v.movetype == MOVETYPE_PUSH)
			SV_Physics_Pusher (ent);
		else if (ent->v.movetype == MOVETYPE_NONE)
			SV_Physics_None (ent);
		else if (ent->v.movetype == MOVETYPE_NOCLIP)
			SV_Physics_Noclip (ent);
		else if (ent->v.movetype == MOVETYPE_STEP)
			SV_Physics_Step (ent);
	#ifdef HEXEN2_SUPPORT
		else if	((hexen2) && (ent->v.movetype == MOVETYPE_PUSHPULL))
			SV_Physics_Step (ent);
	#endif
		else if (ent->v.movetype == MOVETYPE_TOSS 
		|| ent->v.movetype == MOVETYPE_BOUNCE
	#ifdef HEXEN2_SUPPORT
		|| ((hexen2) && ((ent->v.movetype == MOVETYPE_BOUNCEMISSILE) || (ent->v.movetype == MOVETYPE_SWIM)))
	#endif
		|| ent->v.movetype == MOVETYPE_FLY
		|| ent->v.movetype == MOVETYPE_FLYMISSILE)
			SV_Physics_Toss (ent);
		else
			Sys_Error ("SV_Physics: bad movetype %i", (int)ent->v.movetype);			

	#ifdef HEXEN2_SUPPORT
		if ((hexen2) && (ent2 != sv.edicts))
		{
			originMoved = !VectorCompare(ent->v.origin, oldOrigin);
			if (originMoved || !VectorCompare(ent->v.angles, oldAngle))
			{
				VectorSubtract(ent->v.origin, oldOrigin, oldOrigin);
				VectorSubtract(ent->v.angles, oldAngle, oldAngle);

				for (c=0; c<10; c++)
				{   // chain a max of 10 objects
					if (ent2->free) break;

					VectorAdd(oldOrigin, ent2->v.origin, ent2->v.origin);
					if ((int) ent2->v.flags & FL_MOVECHAIN_ANGLE)
					{
						VectorAdd(oldAngle, ent2->v.angles, ent2->v.angles);
					}

					if (originMoved && ent2->v.chainmoved)
					{	// callback function
						*pr_global_ptrs.self = EDICT_TO_PROG(ent2);
						*pr_global_ptrs.other = EDICT_TO_PROG(ent);
						PR_ExecuteProgram(ent2->v.chainmoved);
					}

					ent2 = PROG_TO_EDICT( ent2->v.movechain );
					if (ent2 == sv.edicts) break;

				}
			}
		}
	#endif
	}
	
	if (pr_global_ptrs.force_retouch && *pr_global_ptrs.force_retouch)
		PR_GLOBAL(force_retouch)--;

	sv.time += host_frametime;
}
Beispiel #14
0
/*
================
SV_Physics_Client

Player character actions
================
*/
void SV_Physics_Client (edict_t	*ent, int num)
{
	client_t	*cl;
	vec3_t		v;
	qboolean	was_angle_set;
	
	cl = &svs.clients[num-1];
	if (!cl->active)
		return;		// unconnected slot

// call standard client pre-think
	PR_GLOBAL(time) = sv.time;
	PR_GLOBAL(self) = EDICT_TO_PROG(ent);
	PR_ExecuteProgram (PR_GLOBAL(PlayerPreThink));
	
	// for cutscene hack (see below)
	if (isDedicated || (num != 1))
		was_angle_set = false;		// do it on local client only
	else
		was_angle_set = (ent->v.fixangle != 0);
	
// do a move
	SV_CheckVelocity (ent);

// decide which move function to call
	switch ((int)ent->v.movetype)
	{
	case MOVETYPE_NONE:
		if (!SV_RunThink(ent))
			return;
		break;

	case MOVETYPE_WALK:
		if (!SV_RunThink(ent))
			return;
		if (!SV_CheckWater(ent) && !((int)ent->v.flags & FL_WATERJUMP))
			SV_AddGravity (ent);
		SV_CheckStuck (ent);
		SV_WalkMove (ent);

		break;
		
	case MOVETYPE_TOSS:
	case MOVETYPE_BOUNCE:
		SV_Physics_Toss (ent);
		break;

	case MOVETYPE_FLY:
#ifdef HEXEN2_SUPPORT
	case MOVETYPE_SWIM:
#endif
		if (!SV_RunThink(ent))
			return;
		SV_FlyMove (ent, host_frametime, NULL);
		break;
		
	case MOVETYPE_NOCLIP:
		if (!SV_RunThink(ent))
			return;
		VectorMA (ent->v.origin, host_frametime, ent->v.velocity, ent->v.origin);
		break;
		
	default:
		Sys_Error ("SV_Physics_client: bad movetype %i", (int)ent->v.movetype);
	}


	// JDH: hack for cutscenes made by Darin McNeil's Cutscene Construction Kit:
	//  (note that the extra precision is noticeable only if the viewangles 
	//  are sent from server to client as 2-byte values; hence the addition 
	//  of the new svc_setpreciseangle message code)

	if (was_angle_set && (ent->v.view_ofs[2] == 0) && host_cutscenehack.value 
		&& !strcmp (pr_strings + ent->v.classname, "camera"))
	{
		// - when camera changes back to player, classname remains "camera" for
		//   1 frame, but movedir is no longer valid.  So as an  additional check, 
		//   I verify that view_ofs[2] is still 0
		// - early version(s?) of Cutscene Construction Kit don't move the camera, 
		//   so movedir is not used.  I determine the version by checking *when* 
		//   the viewangle is set: early version does it in the .think function; 
		//   later ones in PlayerPreThink.	was_angle_set will be true only if
		//   it was changed in PlayerPreThink
		
		//if (!sv_oldprotocol.value)
		{
			v[0] = ent->v.movedir[0] - ent->v.origin[0];
			v[1] = ent->v.movedir[1] - ent->v.origin[1];
			v[2] = ent->v.origin[2] - ent->v.movedir[2];
			//vectoangles (v, ent->v.angles);
			vectoangles (v, cl->cutscene_viewangles);
		}
		
		if (!cl->in_cutscene)
		{
			int i;
			edict_t *ed;
			
			// by this time, the player's viewangles have already been changed.
			// But the dummy entity spawned in place of the player has the values
			
			for (i = 1 ; i < sv.num_edicts ; i++)
			{
			// get the current server version
				ed = EDICT_NUM(i);
				if (ed->free)
					continue;

				if (!strcmp(pr_strings + ed->v.classname, "dummy"))
				{
					VectorCopy (ed->v.angles, cl->prev_viewangles);
					break;
				}
			}

			cl->in_cutscene = true;
		}
		//sv.found_cutscene = true;
	}
	else 
	{
		if (cl->in_cutscene)
		{
		// I'm not sure why, but last viewangle while in_cutscene isn't final angle
			ent->v.fixangle = 1;
			VectorCopy (cl->prev_viewangles, ent->v.angles);
			cl->in_cutscene = false;
		}
	}
	
	SV_LinkEdict (ent, true);
	
	PR_GLOBAL(time) = sv.time;
	PR_GLOBAL(self) = EDICT_TO_PROG(ent);

// JDH: another hack, this time for progs that lack CycleWeaponReverse
	if ((ent->v.impulse == 12.0) && ((sv_imp12hack.value >= 2) || (sv_imp12hack.value && !pr_handles_imp12)) && 
		!ent->v.deadflag && (ent->v.view_ofs[0] || ent->v.view_ofs[1] || ent->v.view_ofs[2]))
	{
		eval_t  *val = GETEDICTFIELD(ent, eval_attack_finished);
		if (val && (sv.time >= val->_float))
		{
			SV_CycleWeaponReverse (ent);
		}
	}

// call standard player post-think
	PR_ExecuteProgram (PR_GLOBAL(PlayerPostThink));
}
Beispiel #15
0
/*
=============
SV_Physics_Compound

a glue two entities together
=============
*/
void SV_Physics_Compound( edict_t *ent )
{
	edict_t	*parent;
	
	// regular thinking
	if( !SV_RunThink( ent )) return;

	parent = ent->v.aiment;

	if( !SV_IsValidEdict( parent ))
	{
		MsgDev( D_ERROR, "%s have MOVETYPE_COMPOUND with no corresponding ent!", SV_ClassName( ent ));
		ent->v.movetype = MOVETYPE_NONE;
		return;
	}

	if( ent->v.solid != SOLID_TRIGGER )
		ent->v.solid = SOLID_NOT;

	switch( parent->v.movetype )
	{
	case MOVETYPE_PUSH:
	case MOVETYPE_PUSHSTEP:
		break;
	default: return;
	}

	// not initialized ?
	if( ent->v.ltime == 0.0f )
	{
		VectorCopy( parent->v.origin, ent->v.oldorigin );
		VectorCopy( parent->v.angles, ent->v.avelocity );
		ent->v.ltime = host.frametime;
		return;
	}

	if( !VectorCompare( parent->v.origin, ent->v.oldorigin ) || !VectorCompare( parent->v.angles, ent->v.avelocity ))
	{
		matrix4x4	start_l, end_l, temp_l, child;

		// create parent old position
		Matrix4x4_CreateFromEntity( temp_l, ent->v.avelocity, ent->v.oldorigin, 1.0f );
		Matrix4x4_Invert_Simple( start_l, temp_l );

		// create parent actual position
		Matrix4x4_CreateFromEntity( end_l, parent->v.angles, parent->v.origin, 1.0f );

		// stupid quake bug!!!
		if( !( host.features & ENGINE_COMPENSATE_QUAKE_BUG ))
			ent->v.angles[PITCH] = -ent->v.angles[PITCH];

		// create child actual position
		Matrix4x4_CreateFromEntity( child, ent->v.angles, ent->v.origin, 1.0f );

		// transform child from start to end
		Matrix4x4_ConcatTransforms( temp_l, start_l, child );
		Matrix4x4_ConcatTransforms( child, end_l, temp_l );

		// create child final position
		Matrix4x4_ConvertToEntity( child, ent->v.angles, ent->v.origin );

		// stupid quake bug!!!
		if( !( host.features & ENGINE_COMPENSATE_QUAKE_BUG ))
			ent->v.angles[PITCH] = -ent->v.angles[PITCH];
	}

	// notsolid ents never touch triggers
	SV_LinkEdict( ent, (ent->v.solid == SOLID_NOT) ? false : true );

	// shuffle states
	VectorCopy( parent->v.origin, ent->v.oldorigin );
	VectorCopy( parent->v.angles, ent->v.avelocity );
}
/*
===================
SV_ExecuteClientMessage

The current net_message is parsed for the given client
===================
*/
void SV_ExecuteClientMessage (client_t *cl)
{
	int		c;
	const char	*s;
	usercmd_t	oldest, oldcmd, newcmd;
	client_frame_t	*frame;
	vec3_t	o;

	// calc ping time
	frame = &cl->frames[cl->netchan.incoming_acknowledged & UPDATE_MASK];
	frame->ping_time = realtime - frame->senttime;

	// make sure the reply sequence number matches the incoming
	// sequence number
	if (cl->netchan.incoming_sequence >= cl->netchan.outgoing_sequence)
		cl->netchan.outgoing_sequence = cl->netchan.incoming_sequence;
	else
		cl->send_message = false;	// don't reply, sequences have slipped

	// save time for ping calculations
	cl->frames[cl->netchan.outgoing_sequence & UPDATE_MASK].senttime = realtime;
	cl->frames[cl->netchan.outgoing_sequence & UPDATE_MASK].ping_time = -1;

	host_client = cl;
	sv_player = host_client->edict;

	// mark time so clients will know how much to predict
	// other players
	cl->localtime = sv.time;
	cl->delta_sequence = -1;	// no delta unless requested
	while (1)
	{
		if (msg_badread)
		{
			Con_Printf ("%s: badread\n", __thisfunc__);
			SV_DropClient (cl);
			return;
		}

		c = MSG_ReadByte ();
		if (c == -1)
			break;

		switch (c)
		{
		default:
			Con_Printf ("%s: unknown command char\n", __thisfunc__);
			SV_DropClient (cl);
			return;

		case clc_nop:
			break;

		case clc_delta:
			cl->delta_sequence = MSG_ReadByte ();
			break;

		case clc_move:
			MSG_ReadUsercmd (&oldest, false);
			MSG_ReadUsercmd (&oldcmd, false);
			MSG_ReadUsercmd (&newcmd, true);

			if ( cl->state != cs_spawned )
				break;

			SV_PreRunCmd();

			if (net_drop < 20)
			{
				while (net_drop > 2)
				{
					SV_RunCmd (&cl->lastcmd);
					net_drop--;
				}
				if (net_drop > 1)
					SV_RunCmd (&oldest);
				if (net_drop > 0)
					SV_RunCmd (&oldcmd);
			}
			SV_RunCmd (&newcmd);

			SV_PostRunCmd();

			cl->lastcmd = newcmd;
			cl->lastcmd.buttons = 0; // avoid multiple fires on lag
			break;

		case clc_stringcmd:
			s = MSG_ReadString ();
			SV_ExecuteUserCommand (s);
			break;

		case clc_tmove:
			o[0] = MSG_ReadCoord();
			o[1] = MSG_ReadCoord();
			o[2] = MSG_ReadCoord();
			// only allowed by spectators
			if (host_client->spectator)
			{
				VectorCopy(o, sv_player->v.origin);
				SV_LinkEdict(sv_player, false);
			}
			break;

		case clc_inv_select:
			cl->edict->v.inventory = MSG_ReadByte();
			break;

		case clc_get_effect:
			c = MSG_ReadByte();
			if (sv.Effects[c].type)
			{
				Con_Printf("Getting effect %d\n",(int)c);
				SV_SendEffect(&host_client->netchan.message, c);
			}
			break;
		}
	}
}
Beispiel #17
0
/*
=============
SV_Physics_Step

Monsters freefall when they don't have a ground entity, otherwise
all movement is done with discrete steps.

This is also used for objects that have become still on the ground, but
will fall if the floor is pulled out from under them.
=============
*/
void SV_Physics_Step( edict_t *ent )
{
	qboolean	inwater;
	qboolean	wasonground;
	qboolean	wasonmover;
	vec3_t	mins, maxs;
	vec3_t	point;
	trace_t	trace;
	int	x, y;

	SV_WaterMove( ent );
	SV_CheckVelocity( ent );

	wasonground = (ent->v.flags & FL_ONGROUND);
	wasonmover = SV_CheckMover( ent );
	inwater = SV_CheckWater( ent );

	if( ent->v.flags & FL_FLOAT && ent->v.waterlevel > 0 )
	{
		float buoyancy = SV_Submerged( ent ) * ent->v.skin * host.frametime;

		SV_AddGravity( ent );
		ent->v.velocity[2] += buoyancy;
	}

	if( !wasonground && !( ent->v.flags & FL_FLY ) && (!( ent->v.flags & FL_SWIM ) || ent->v.waterlevel <= 0 ))
	{
		if( !inwater )
			SV_AddGravity( ent );
	}

	if( !VectorIsNull( ent->v.velocity ) || !VectorIsNull( ent->v.basevelocity ))
	{
		ent->v.flags &= ~FL_ONGROUND;

		if(( wasonground || wasonmover ) && ( ent->v.health > 0 || SV_CheckBottom( ent, MOVE_NORMAL )))
		{
			float	*vel = ent->v.velocity;
			float	control, speed, newspeed;
			float	friction;

			speed = sqrt(( vel[0] * vel[0] ) + ( vel[1] * vel[1] ));	// DotProduct2D

			if( speed )
			{
				friction = sv_friction->value * ent->v.friction;	// factor
				ent->v.friction = 1.0f; // g-cont. ???
				if( wasonmover ) friction *= 0.5f; // add a little friction

				control = (speed < sv_stopspeed->value) ? sv_stopspeed->value : speed;
				newspeed = speed - (host.frametime * control * friction);
				if( newspeed < 0 ) newspeed = 0;
				newspeed /= speed;

				vel[0] = vel[0] * newspeed;
				vel[1] = vel[1] * newspeed;
			}
		}

		VectorAdd( ent->v.velocity, ent->v.basevelocity, ent->v.velocity );
		SV_CheckVelocity( ent );

		SV_FlyMove( ent, host.frametime, NULL );
		if( ent->free ) return;

		SV_CheckVelocity( ent );
		VectorSubtract( ent->v.velocity, ent->v.basevelocity, ent->v.velocity );

		SV_CheckVelocity( ent );

		VectorAdd( ent->v.origin, ent->v.mins, mins );
		VectorAdd( ent->v.origin, ent->v.maxs, maxs );

		point[2] = mins[2] - 1.0f;

		for( x = 0; x <= 1; x++ )
		{
			if( ent->v.flags & FL_ONGROUND )
				break;

			for( y = 0; y <= 1; y++ )
			{
				point[0] = x ? maxs[0] : mins[0];
				point[1] = y ? maxs[1] : mins[1];

				trace = SV_Move( point, vec3_origin, vec3_origin, point, MOVE_NORMAL, ent );

				if( trace.startsolid )
				{
					ent->v.flags |= FL_ONGROUND;
					ent->v.groundentity = trace.ent;
					ent->v.friction = 1.0f;
					break;
				}
			}
		}

		SV_LinkEdict( ent, true );
	}
	else
	{
		if( svgame.globals->force_retouch != 0 )
		{
			trace = SV_Move( ent->v.origin, ent->v.mins, ent->v.maxs, ent->v.origin, MOVE_NORMAL, ent );

			// hentacle impact code
			if(( trace.fraction < 1.0f || trace.startsolid ) && SV_IsValidEdict( trace.ent ))
			{
				SV_Impact( ent, trace.ent, &trace );
				if( ent->free ) return;
			}
		}
	}

	if( !SV_RunThink( ent )) return;
	SV_CheckWaterTransition( ent );

}
Beispiel #18
0
/*
===========
SV_RunCmd
===========
*/
void SV_RunCmd( sv_client_t *cl, usercmd_t *ucmd, int random_seed )
{
    usercmd_t lastcmd;
    edict_t	*clent, *touch;
    double	frametime;
    int	i, oldmsec;
    pmtrace_t	*pmtrace;
    trace_t	trace;
    vec3_t	oldvel;

    clent = cl->edict;

    if( cl->next_movetime > host.realtime )
    {
        cl->last_movetime += ( ucmd->msec * 0.001f );
        return;
    }

    cl->next_movetime = 0.0;

    // chop up very long commands
    if( ucmd->msec > 50 )
    {
        lastcmd = *ucmd;
        oldmsec = ucmd->msec;
        lastcmd.msec = oldmsec / 2;

        SV_RunCmd( cl, &lastcmd, random_seed );

        lastcmd.msec = oldmsec / 2 + (oldmsec & 1);	// give them back thier msec.
        lastcmd.impulse = 0;
        SV_RunCmd( cl, &lastcmd, random_seed );
        return;
    }

    if( !cl->fakeclient )
    {
        SV_SetupMoveInterpolant( cl );
    }

    lastcmd = *ucmd;
    svgame.dllFuncs.pfnCmdStart( cl->edict, ucmd, random_seed );

    frametime = ucmd->msec * 0.001;
    cl->timebase += frametime;
    cl->last_movetime += frametime;

    PM_CheckMovingGround( clent, frametime );

    VectorCopy( clent->v.v_angle, svgame.pmove->oldangles ); // save oldangles
    if( !clent->v.fixangle ) VectorCopy( ucmd->viewangles, clent->v.v_angle );

    VectorClear( clent->v.clbasevelocity );

    // copy player buttons
    clent->v.button = ucmd->buttons;
    if( ucmd->impulse ) clent->v.impulse = ucmd->impulse;

    if( ucmd->impulse == 204 )
    {
        // force client.dll update
        SV_RefreshUserinfo();
    }

    svgame.globals->time = cl->timebase;
    svgame.dllFuncs.pfnPlayerPreThink( clent );
    SV_PlayerRunThink( clent, frametime, cl->timebase );

    // If conveyor, or think, set basevelocity, then send to client asap too.
    if( !VectorIsNull( clent->v.basevelocity ))
        VectorCopy( clent->v.basevelocity, clent->v.clbasevelocity );

    // setup playermove state
    SV_SetupPMove( svgame.pmove, cl, ucmd, cl->physinfo );

    // motor!
    svgame.dllFuncs.pfnPM_Move( svgame.pmove, true );

    // copy results back to client
    SV_FinishPMove( svgame.pmove, cl );

    // link into place and touch triggers
    SV_LinkEdict( clent, true );
    VectorCopy( clent->v.velocity, oldvel ); // save velocity

    // touch other objects
    for( i = 0; i < svgame.pmove->numtouch; i++ )
    {
        // never touch the objects when "playersonly" is active
        if( i == MAX_PHYSENTS || ( sv.hostflags & SVF_PLAYERSONLY ))
            break;

        pmtrace = &svgame.pmove->touchindex[i];
        touch = EDICT_NUM( svgame.pmove->physents[pmtrace->ent].info );
        if( touch == clent ) continue;

        VectorCopy( pmtrace->deltavelocity, clent->v.velocity );
        SV_ConvertPMTrace( &trace, pmtrace, touch );
        SV_Impact( touch, clent, &trace );
    }

    // restore velocity
    VectorCopy( oldvel, clent->v.velocity );

    svgame.pmove->numtouch = 0;
    svgame.globals->time = cl->timebase;
    svgame.globals->frametime = frametime;

    // run post-think
    svgame.dllFuncs.pfnPlayerPostThink( clent );
    svgame.dllFuncs.pfnCmdEnd( clent );

    if( !cl->fakeclient )
    {
        SV_RestoreMoveInterpolant( cl );
    }
}
Beispiel #19
0
/*
============
SV_PushMove

============
*/
static edict_t *SV_PushMove( edict_t *pusher, float movetime )
{
	int		i, e, block;
	int		num_moved, oldsolid;
	vec3_t		mins, maxs, lmove;
	sv_pushed_t	*p, *pushed_p;
	edict_t		*check;	

	if( svgame.globals->changelevel || VectorIsNull( pusher->v.velocity ))
	{
		pusher->v.ltime += movetime;
		return NULL;
	}

	for( i = 0; i < 3; i++ )
	{
		lmove[i] = pusher->v.velocity[i] * movetime;
		mins[i] = pusher->v.absmin[i] + lmove[i];
		maxs[i] = pusher->v.absmax[i] + lmove[i];
	}

	pushed_p = svgame.pushed;

	// save the pusher's original position
	pushed_p->ent = pusher;
	VectorCopy( pusher->v.origin, pushed_p->origin );
	VectorCopy( pusher->v.angles, pushed_p->angles );
	pushed_p++;
	
	// move the pusher to it's final position
	SV_LinearMove( pusher, movetime, 0.0f );
	SV_LinkEdict( pusher, false );
	pusher->v.ltime += movetime;
	oldsolid = pusher->v.solid;

	// non-solid pushers can't push anything
	if( pusher->v.solid == SOLID_NOT )
		return NULL;

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

	for( e = 1; e < svgame.numEntities; e++ )
	{
		check = EDICT_NUM( e );
		if( !SV_IsValidEdict( check )) continue;

		// filter movetypes to collide with
		if( !SV_CanPushed( check ))
			continue;

		pusher->v.solid = SOLID_NOT;
		block = SV_TestEntityPosition( check, pusher );
		pusher->v.solid = oldsolid;
		if( block ) continue;

		// if the entity is standing on the pusher, it will definately be moved
		if( !(( check->v.flags & FL_ONGROUND ) && check->v.groundentity == pusher ))
		{
			if( check->v.absmin[0] >= maxs[0]
			 || check->v.absmin[1] >= maxs[1]
			 || check->v.absmin[2] >= maxs[2]
			 || check->v.absmax[0] <= mins[0]
			 || check->v.absmax[1] <= mins[1]
			 || check->v.absmax[2] <= mins[2] )
				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 != MOVETYPE_WALK )
			check->v.flags &= ~FL_ONGROUND;

		// save original position of contacted entity
		pushed_p->ent = check;
		VectorCopy( check->v.origin, pushed_p->origin );
		VectorCopy( check->v.angles, pushed_p->angles );
		pushed_p++;

		// try moving the contacted entity 
		pusher->v.solid = SOLID_NOT;
		SV_PushEntity( check, lmove, vec3_origin, &block );
		pusher->v.solid = oldsolid;

		// if it is still inside the pusher, block
		if( SV_TestEntityPosition( check, NULL ) && block )
		{	
			if( !SV_CanBlock( check ))
				continue;

			pusher->v.ltime -= movetime;

			// move back any entities we already moved
			// go backwards, so if the same entity was pushed
			// twice, it goes back to the original position
			for( p = pushed_p - 1; p >= svgame.pushed; p-- )
			{
				VectorCopy( p->origin, p->ent->v.origin );
				VectorCopy( p->angles, p->ent->v.angles );
				SV_LinkEdict( p->ent, (p->ent == check) ? true : false );
			}
			return check;
		}	
	}

	return NULL;
}
Beispiel #20
0
void SV_SetupMoveInterpolant( sv_client_t *cl )
{
    int		i, j, clientnum;
    float		finalpush, lerp_msec;
    float		latency, temp, lerpFrac;
    client_frame_t	*frame, *frame2;
    entity_state_t	*state, *lerpstate;
    vec3_t		curpos, newpos;
    sv_client_t	*check;
    sv_interp_t	*lerp;

    Q_memset( svgame.interp, 0, sizeof( svgame.interp ));
    has_update = false;

    // don't allow unlag in singleplayer
    if( sv_maxclients->integer <= 1 || cl->state != cs_spawned )
        return;

    // unlag disabled by game request
    if( !svgame.dllFuncs.pfnAllowLagCompensation() || !sv_unlag->integer )
        return;

    // unlag disabled for current client
    if( !cl->lag_compensation )
        return;

    has_update = true;

    for( i = 0, check = svs.clients; i < sv_maxclients->integer; i++, check++ )
    {
        if( check->state != cs_spawned || check == cl )
            continue;

        lerp = &svgame.interp[i];

        VectorCopy( check->edict->v.origin, lerp->oldpos );
        VectorCopy( check->edict->v.absmin, lerp->mins );
        VectorCopy( check->edict->v.absmax, lerp->maxs );
        lerp->active = true;
    }

    if( cl->latency > 1.5f )
        latency = 1.5f;
    else latency = cl->latency;

    temp = sv_maxunlag->value;

    if( temp > 0 && latency > temp )
        latency = temp;

    lerp_msec = cl->lastcmd.lerp_msec * 0.001f;
    if( lerp_msec > 0.1f ) lerp_msec = 0.1f;

    if( lerp_msec < cl->cl_updaterate )
        lerp_msec = cl->cl_updaterate;

    finalpush = sv_unlagpush->value + (( host.realtime - latency ) - lerp_msec );

    if( finalpush > host.realtime )
        finalpush = host.realtime;

    frame = NULL;

    for( frame2 = NULL, i = 0; i < SV_UPDATE_BACKUP; i++, frame2 = frame )
    {
        frame = &cl->frames[(cl->netchan.outgoing_sequence - 1) & SV_UPDATE_MASK];

        for( j = 0; j < frame->num_entities; j++ )
        {
            state = &svs.packet_entities[(frame->first_entity+j)%svs.num_client_entities];

            if( state->number <= 0 || state->number >= sv_maxclients->integer )
                continue;

            lerp = &svgame.interp[state->number-1];
            if( lerp->nointerp ) continue;

            if( state->health <= 0 || ( state->effects & EF_NOINTERP ))
                lerp->nointerp = true;

            if( !lerp->firstframe )
                lerp->firstframe = true;
            else if( SV_UnlagCheckTeleport( state->origin, lerp->finalpos ))
                lerp->nointerp = true;

            VectorCopy( state->origin, lerp->finalpos );
        }

        if( finalpush > frame->senttime )
            break;
    }

    if( i == SV_UPDATE_BACKUP || finalpush - frame->senttime > 1.0 )
    {
        Q_memset( svgame.interp, 0, sizeof( svgame.interp ));
        has_update = false;
        return;
    }

    if( !frame2 )
    {
        frame2 = frame;
        lerpFrac = 0;
    }
    else
    {
        if( frame2->senttime - frame->senttime == 0.0 )
        {
            lerpFrac = 0;
        }
        else
        {
            lerpFrac = (finalpush - frame->senttime) / (frame2->senttime - frame->senttime);
            lerpFrac = bound( 0.0f, lerpFrac, 1.0f );
        }
    }

    for( i = 0; i < frame->num_entities; i++ )
    {
        state = &svs.packet_entities[(frame->first_entity+i)%svs.num_client_entities];

        if( state->number <= 0 || state->number >= sv_maxclients->integer )
            continue;

        clientnum = state->number - 1;
        check = &svs.clients[clientnum];

        if( check->state != cs_spawned || check == cl )
            continue;

        lerp = &svgame.interp[clientnum];

        if( !lerp->active || lerp->nointerp )
            continue;

        lerpstate = SV_FindEntInPack( state->number, frame2 );

        if( !lerpstate )
        {
            VectorCopy( state->origin, curpos );
        }
        else
        {
            VectorSubtract( lerpstate->origin, state->origin, newpos );
            VectorMA( state->origin, lerpFrac, newpos, curpos );
        }

        VectorCopy( curpos, lerp->curpos );
        VectorCopy( curpos, lerp->newpos );

        if( !VectorCompare( curpos, check->edict->v.origin ))
        {
            VectorCopy( curpos, check->edict->v.origin );
            SV_LinkEdict( check->edict, false );
            lerp->moving = true;
        }
    }
}
Beispiel #21
0
/*
================
SV_Physics_Client

Player character actions
================
*/
void SV_Physics_Client (edict_t	*ent, int num)
{
    if ( ! svs.clients[num-1].active )
        return;		// unconnected slot

//
// call standard client pre-think
//
    pr_global_struct->time = sv.time;
    pr_global_struct->self = EDICT_TO_PROG(ent);
    PR_ExecuteProgram (pr_global_struct->PlayerPreThink);

//
// do a move
//
    SV_CheckVelocity (ent);

//
// decide which move function to call
//
    switch ((int)ent->v.movetype)
    {
    case MOVETYPE_NONE:
        if (!SV_RunThink (ent))
            return;
        break;

    case MOVETYPE_WALK:
        if (!SV_RunThink (ent))
            return;
        if (!SV_CheckWater (ent) && ! ((int)ent->v.flags & FL_WATERJUMP) )
            SV_AddGravity (ent);
        SV_CheckStuck (ent);
#ifdef QUAKE2
        VectorAdd (ent->v.velocity, ent->v.basevelocity, ent->v.velocity);
#endif
        SV_WalkMove (ent);

#ifdef QUAKE2
        VectorSubtract (ent->v.velocity, ent->v.basevelocity, ent->v.velocity);
#endif
        break;

    case MOVETYPE_TOSS:
    case MOVETYPE_BOUNCE:
        SV_Physics_Toss (ent);
        break;

    case MOVETYPE_FLY:
        if (!SV_RunThink (ent))
            return;
        SV_FlyMove (ent, host_frametime, NULL);
        break;

    case MOVETYPE_NOCLIP:
        if (!SV_RunThink (ent))
            return;
        VectorMA (ent->v.origin, host_frametime, ent->v.velocity, ent->v.origin);
        break;

    default:
        Sys_Error ("SV_Physics_client: bad movetype %i", (int)ent->v.movetype);
    }

//
// call standard player post-think
//
    SV_LinkEdict (ent, true);

    pr_global_struct->time = sv.time;
    pr_global_struct->self = EDICT_TO_PROG(ent);
    PR_ExecuteProgram (pr_global_struct->PlayerPostThink);
}
Beispiel #22
0
void SV_LoadGame_f (void) {
	char name[MAX_OSPATH], mapname[MAX_QPATH], str[32 * 1024], *start;
	FILE *f;
	float time, tfloat, spawn_parms[NUM_SPAWN_PARMS];
	edict_t *ent;
	int entnum, version, i, r;

	if (Cmd_Argc() != 2) {
		Com_Printf ("Usage: %s <savename> : load a game\n", Cmd_Argv(0));
		return;
	}

	Q_snprintfz(name, sizeof(name), "%s/save/%s", com_gamedir, Cmd_Argv(1));
	COM_DefaultExtension (name, ".sav");

	Com_Printf ("Loading game from %s...\n", name);
	if (!(f = fopen (name, "r"))) {
		Com_Printf ("ERROR: couldn't open.\n");
		return;
	}

	fscanf (f, "%i\n", &version);
	if (version != SAVEGAME_VERSION) {
		fclose (f);
		Com_Printf ("Savegame is version %i, not %i\n", version, SAVEGAME_VERSION);
		return;
	}

	fscanf (f, "%s\n", str);
	for (i = 0; i < NUM_SPAWN_PARMS; i++)
		fscanf (f, "%f\n", &spawn_parms[i]);

	// this silliness is so we can load 1.06 save files, which have float skill values
	fscanf (f, "%f\n", &tfloat);
	current_skill = (int)(tfloat + 0.1);
	Cvar_Set (&skill, va("%i", current_skill));

	Cvar_SetValue (&deathmatch, 0);
	Cvar_SetValue (&coop, 0);
	Cvar_SetValue (&teamplay, 0);
	Cvar_SetValue (&maxclients, 1);

	fscanf (f, "%s\n", mapname);
	fscanf (f, "%f\n", &time);

	Host_EndGame();

	CL_BeginLocalConnection ();

	SV_SpawnServer (mapname, false);

	if (sv.state != ss_active) {
		Com_Printf ("Couldn't load map\n");
		return;
	}
	sv.paused = true;		// pause until all clients connect
	sv.loadgame = true;

	Sys_Error("The local server is currently broken. Sorry.");

	// load the light styles
	for (i = 0; i < MAX_LIGHTSTYLES; i++) {
		fscanf (f, "%s\n", str);
#if 0
		/* You need to fix that call */
		sv.lightstyles[i] = Junk_Alloc(strlen(str) + 1);
#endif
		strcpy (sv.lightstyles[i], str);
	}

	// load the edicts out of the savegame file
	entnum = -1;		// -1 is the globals
	while (!feof(f)) {
		for (i = 0; i < sizeof(str) - 1; i++) {
			r = fgetc (f);
			if (r == EOF || !r)
				break;
			str[i] = r;
			if (r == '}') {
				i++;
				break;
			}
		}
		if (i == sizeof(str)-1)
			Host_Error ("Loadgame buffer overflow");
		str[i] = 0;
		start = str;
		start = COM_Parse(str);
		if (!com_token[0])
			break;		// end of file

		if (strcmp(com_token,"{"))
			Host_Error ("First token isn't a brace");

		if (entnum == -1) {	
			// parse the global vars
			ED_ParseGlobals (start);
		} else {	
			// parse an edict
			ent = EDICT_NUM(entnum);
			memset (&ent->v, 0, progs->entityfields * 4);
			ent->free = false;
			ED_ParseEdict (start, ent);
	
			// link it into the bsp tree
			if (!ent->free)
				SV_LinkEdict (ent, false);
		}
		entnum++;
	}

	sv.num_edicts = entnum;
	sv.time = time;

	fclose (f);

	for (i = 0; i < NUM_SPAWN_PARMS; i++)
		svs.clients[0]->spawn_parms[i] = spawn_parms[i];
}
Beispiel #23
0
/*
============
SV_PushRotate

============
*/
void SV_PushRotate (edict_t *pusher, float movetime)
{
    int			i, e;
    edict_t		*check, *block;
    vec3_t		move, a, amove;
    vec3_t		entorig, pushorig;
    int			num_moved;
    edict_t		*moved_edict[MAX_EDICTS];
    vec3_t		moved_from[MAX_EDICTS];
    vec3_t		org, org2;
    vec3_t		forward, right, up;

    if (!pusher->v.avelocity[0] && !pusher->v.avelocity[1] && !pusher->v.avelocity[2])
    {
        pusher->v.ltime += movetime;
        return;
    }

    for (i=0 ; i<3 ; i++)
        amove[i] = pusher->v.avelocity[i] * movetime;

    VectorSubtract (vec3_origin, amove, a);
    AngleVectors (a, forward, right, up);

    VectorCopy (pusher->v.angles, pushorig);

// move the pusher to it's final position

    VectorAdd (pusher->v.angles, amove, pusher->v.angles);
    pusher->v.ltime += movetime;
    SV_LinkEdict (pusher, false);


// see if any solid entities are inside the final position
    num_moved = 0;
    check = NEXT_EDICT(sv.edicts);
    for (e=1 ; e<sv.num_edicts ; e++, check = NEXT_EDICT(check))
    {
        if (check->free)
            continue;
        if (check->v.movetype == MOVETYPE_PUSH
                || check->v.movetype == MOVETYPE_NONE
                || check->v.movetype == MOVETYPE_FOLLOW
                || check->v.movetype == MOVETYPE_NOCLIP)
            continue;

        // if the entity is standing on the pusher, it will definately be moved
        if ( ! ( ((int)check->v.flags & FL_ONGROUND)
                 && PROG_TO_EDICT(check->v.groundentity) == pusher) )
        {
            if ( check->v.absmin[0] >= pusher->v.absmax[0]
                    || check->v.absmin[1] >= pusher->v.absmax[1]
                    || check->v.absmin[2] >= pusher->v.absmax[2]
                    || check->v.absmax[0] <= pusher->v.absmin[0]
                    || check->v.absmax[1] <= pusher->v.absmin[1]
                    || check->v.absmax[2] <= pusher->v.absmin[2] )
                continue;

            // see if the ent's bbox is inside the pusher's final position
            if (!SV_TestEntityPosition (check))
                continue;
        }

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

        VectorCopy (check->v.origin, entorig);
        VectorCopy (check->v.origin, moved_from[num_moved]);
        moved_edict[num_moved] = check;
        num_moved++;

        // calculate destination position
        VectorSubtract (check->v.origin, pusher->v.origin, org);
        org2[0] = DotProduct (org, forward);
        org2[1] = -DotProduct (org, right);
        org2[2] = DotProduct (org, up);
        VectorSubtract (org2, org, move);

        // try moving the contacted entity
        pusher->v.solid = SOLID_NOT;
        SV_PushEntity (check, move);
        pusher->v.solid = SOLID_BSP;

        // if it is still inside the pusher, block
        block = SV_TestEntityPosition (check);
        if (block)
        {   // fail the move
            if (check->v.mins[0] == check->v.maxs[0])
                continue;
            if (check->v.solid == SOLID_NOT || check->v.solid == SOLID_TRIGGER)
            {   // corpse
                check->v.mins[0] = check->v.mins[1] = 0;
                VectorCopy (check->v.mins, check->v.maxs);
                continue;
            }

            VectorCopy (entorig, check->v.origin);
            SV_LinkEdict (check, true);

            VectorCopy (pushorig, pusher->v.angles);
            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)
            {
                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 (i=0 ; i<num_moved ; i++)
            {
                VectorCopy (moved_from[i], moved_edict[i]->v.origin);
                VectorSubtract (moved_edict[i]->v.angles, amove, moved_edict[i]->v.angles);
                SV_LinkEdict (moved_edict[i], false);
            }
            return;
        }
        else
        {
            VectorAdd (check->v.angles, amove, check->v.angles);
        }
    }


}
Beispiel #24
0
/*
===============
SV_LoadGame_f
===============
*/
void SV_LoadGame_f (void)
{
	char	name[MAX_OSPATH];
	FILE	*f;
	char	mapname[MAX_QPATH];
	float	time, tfloat;
	char	str[32768], *start;
	int		i, r;
	edict_t	*ent;
	int		entnum;
	int		version;
	float	spawn_parms[NUM_SPAWN_PARMS];
	qbool	save_disabled_for_loading;

	if (Cmd_Argc() != 2) {
		Com_Printf ("load <savename> : load a game\n");
		return;
	}

	sprintf (name, "%s/save/%s", com_gamedir, Cmd_Argv(1));
	COM_DefaultExtension (name, ".sav");
	
// we can't call SCR_BeginLoadingPlaque, because too much stack space has
// been used.  The menu calls it before stuffing loadgame command
//	SCR_BeginLoadingPlaque ();

	Com_Printf ("Loading game from %s...\n", name);
	f = fopen (name, "r");
	if (!f)
	{
		Com_Printf ("ERROR: couldn't open.\n");
		return;
	}

	fscanf (f, "%i\n", &version);
	if (version != SAVEGAME_VERSION)
	{
		fclose (f);
		Com_Printf ("Savegame is version %i, not %i\n", version, SAVEGAME_VERSION);
		return;
	}
	fscanf (f, "%s\n", str);
	for (i=0 ; i<NUM_SPAWN_PARMS ; i++)
		fscanf (f, "%f\n", &spawn_parms[i]);
// this silliness is so we can load 1.06 save files, which have float skill values
	fscanf (f, "%f\n", &tfloat);
	current_skill = (int)(tfloat + 0.1);
	Cvar_Set (&skill, va("%i", current_skill));

	Cvar_SetValue (&deathmatch, 0);
	Cvar_SetValue (&coop, 0);
	Cvar_SetValue (&teamplay, 0);
	Cvar_SetValue (&maxclients, 1);

	fscanf (f, "%s\n",mapname);
	fscanf (f, "%f\n",&time);

	save_disabled_for_loading = scr_disabled_for_loading;

	Host_EndGame ();

	// Host_EndGame disables the loading plaque, restore it
	scr_disabled_for_loading = save_disabled_for_loading;

	CL_BeginLocalConnection ();

	SV_SpawnServer (mapname, false);
	if (sv.state != ss_active)
	{
		Com_Printf ("Couldn't load map\n");
		return;
	}
	Cvar_ForceSet (&sv_paused, "1");	// pause until all clients connect
	sv.loadgame = true;

// load the light styles

	for (i=0 ; i<MAX_LIGHTSTYLES ; i++)
	{
		fscanf (f, "%s\n", str);
		sv.lightstyles[i] = Hunk_Alloc (strlen(str)+1);
		strcpy (sv.lightstyles[i], str);
	}

// load the edicts out of the savegame file
	entnum = -1;		// -1 is the globals
	while (!feof(f))
	{
		for (i=0 ; i<sizeof(str)-1 ; i++)
		{
			r = fgetc (f);
			if (r == EOF || !r)
				break;
			str[i] = r;
			if (r == '}')
			{
				i++;
				break;
			}
		}
		if (i == sizeof(str)-1)
			Host_Error ("Loadgame buffer overflow");
		str[i] = 0;
		start = str;
		start = COM_Parse(str);
		if (!com_token[0])
			break;		// end of file
		if (strcmp(com_token,"{"))
			Host_Error ("First token isn't a brace");
			
		if (entnum == -1)
		{	// parse the global vars
			ED_ParseGlobals (start);
		}
		else
		{	// parse an edict
			ent = EDICT_NUM(entnum);
			memset (&ent->v, 0, progs->entityfields * 4);
			ent->inuse = true;
			ED_ParseEdict (start, ent);
	
			// link it into the bsp tree
			if (ent->inuse)
				SV_LinkEdict (ent, false);
		}

		entnum++;
	}
	
	sv.num_edicts = entnum;
	sv.time = time;

	fclose (f);

	// FIXME: this assumes the player is using client slot #0
	for (i = 0; i < NUM_SPAWN_PARMS; i++)
		svs.clients->spawn_parms[i] = spawn_parms[i];
}
qboolean SV_movetest(edict_t *ent, vec3_t move, qboolean relink) {

   float temp;
   vec3_t oldorg, neworg, end;
   trace_t trace;


   oldorg[0] = ent->v.origin[0];
   oldorg[1] = ent->v.origin[1];
   oldorg[2] = ent->v.origin[2];

   neworg[0] = ent->v.origin[0] + move[0];
   neworg[1] = ent->v.origin[1] + move[1];
   neworg[2] = ent->v.origin[2] + move[2];

   temp = cvar_sv_stepsize.value;

   neworg[2] += temp;
   end[0] = neworg[0];
   end[1] = neworg[1];
   end[2] = neworg[2];
   end[2] -= temp*2;

   trace = SV_MoveNoEnts(neworg, ent->v.mins, ent->v.maxs, end, 0, ent);

   if(trace.allsolid != 0) { return(0); }
   if(trace.startsolid != 0) {

      neworg[2] -= temp;

      trace = SV_MoveNoEnts(neworg, ent->v.mins, ent->v.maxs, end, 0, ent);

      if(trace.allsolid != 0 || trace.startsolid != 0) { return(0); }
   }

   if(trace.fraction == 1) {
      if(ent->v.flags & FL_PARTIALGROUND) {
         ent->v.origin[0] += move[0];
         ent->v.origin[1] += move[1];
         ent->v.origin[2] += move[2];

         if(relink != 0) {
            SV_LinkEdict(ent, 1);
         }
         ent->v.flags &= ~FL_ONGROUND;
         return(1);
      }

      return(0);
   }
   else {

      ent->v.origin[0] = trace.endpos[0];
      ent->v.origin[1] = trace.endpos[1];
      ent->v.origin[2] = trace.endpos[2];

      if(SV_CheckBottom(ent) == 0) {
         if(ent->v.flags & FL_PARTIALGROUND) {

            if(relink != 0) {
               SV_LinkEdict(ent, 1);
            }
            return(1);
         }

         ent->v.origin[0] = oldorg[0];
         ent->v.origin[1] = oldorg[1];
         ent->v.origin[2] = oldorg[2];

         return(0);
      }
      else {

         if(ent->v.flags & FL_PARTIALGROUND) {
            ent->v.flags &= ~FL_PARTIALGROUND;
         }

         ent->v.groundentity = trace.pHit;

         if(relink != 0) {
            SV_LinkEdict(ent, 1);
         }
         return(1);
      }
   }
}
Beispiel #26
0
/*
================
SV_Physics

================
*/
void SV_Physics (void)
{
	int		i;
	edict_t	*ent;

// 2000-04-30 NVS HANDSHAKE SRV<->CL/QC<->CL by Maddes  start
	eval_t	*val;

	// let the QuakeC code know the NVS versions of the server and clients
	if (pr_field_nvs_svc)
	{
		// set world/server
// 2001-11-15 Better GetEdictFieldValue performance by LordHavoc/Maddes  start
//		val = GetEdictFieldValue(sv.edicts, "nvs_svc");
		val = GETEDICTFIELDVALUE(sv.edicts, pr_field_nvs_svc);
// 2001-11-15 Better GetEdictFieldValue performance by LordHavoc/Maddes  end
		if (val)
		{
			val->_float = nvs_current_ssvc->value;
		}

		// set clients
		ent = NEXT_EDICT(sv.edicts);	// set to first not-world entity (=1st client)
		for (i=1 ; i<=svs.maxclients && i<sv.num_edicts ; i++, ent = NEXT_EDICT(ent))
		{
			if (ent->free)
				continue;

			if (!svs.clients[i-1].active)
				continue;		// unconnected slot

// 2001-11-15 Better GetEdictFieldValue performance by LordHavoc/Maddes  start
//			val = GetEdictFieldValue(ent, "nvs_svc");
			val = GETEDICTFIELDVALUE(ent, pr_field_nvs_svc);
// 2001-11-15 Better GetEdictFieldValue performance by LordHavoc/Maddes  end
			if (val)
			{
				val->_float = svs.clients[i-1].nvs_csvc;
			}
		}
	}
// 2000-04-30 NVS HANDSHAKE SRV<->CL/QC<->CL by Maddes  end

// let the progs know that a new frame has started
	pr_global_struct->self = EDICT_TO_PROG(sv.edicts);
	pr_global_struct->other = EDICT_TO_PROG(sv.edicts);
	pr_global_struct->time = sv.time;
	PR_ExecuteProgram (pr_global_struct->StartFrame);

//SV_CheckAllEnts ();

//
// treat each object in turn
//
	ent = sv.edicts;
	for (i=0 ; i<sv.num_edicts ; i++, ent = NEXT_EDICT(ent))
	{
		if (ent->free)
			continue;

		if (pr_global_struct->force_retouch)
		{
			SV_LinkEdict (ent, true);	// force retouch even for stationary
		}

		if (i > 0 && i <= svs.maxclients)
			SV_Physics_Client (ent, i);
		else if (ent->v.movetype == MOVETYPE_PUSH)
			SV_Physics_Pusher (ent);
		else if (ent->v.movetype == MOVETYPE_NONE)
			SV_Physics_None (ent);
		else if (ent->v.movetype == MOVETYPE_FOLLOW)
			SV_Physics_Follow (ent);
		else if (ent->v.movetype == MOVETYPE_NOCLIP)
			SV_Physics_Noclip (ent);
		else if (ent->v.movetype == MOVETYPE_STEP)
			SV_Physics_Step (ent);
		else if (ent->v.movetype == MOVETYPE_TOSS
		|| ent->v.movetype == MOVETYPE_BOUNCE
		|| ent->v.movetype == MOVETYPE_BOUNCEMISSILE
		|| ent->v.movetype == MOVETYPE_FLY
		|| ent->v.movetype == MOVETYPE_FLYMISSILE)
			SV_Physics_Toss (ent);
		else
			Sys_Error ("SV_Physics: bad movetype %i", (int)ent->v.movetype);
	}

// 2000-01-02 EndFrame function by Maddes/FrikaC  start
	if (pr_func_endframe)
	{
		// let the progs know that a new frame has ended
		pr_global_struct->self = EDICT_TO_PROG(sv.edicts);
		pr_global_struct->other = EDICT_TO_PROG(sv.edicts);
		pr_global_struct->time = sv.time;
		PR_ExecuteProgram (pr_func_endframe);
	}
// 2000-01-02 EndFrame function by Maddes/FrikaC  end

	if (pr_global_struct->force_retouch)
		pr_global_struct->force_retouch--;

	sv.time += host_frametime;
}
Beispiel #27
0
int LoadGamestate(char *level, char *startspot)
{
	char	name[MAX_OSPATH];
	FILE	*f;
	char	mapname[MAX_QPATH];
	float	time, sk;
	char	str[32768], *start;
	int		i, r;
	edict_t	*ent;
	int		entnum;
	int		version;
//	float	spawn_parms[NUM_SPAWN_PARMS];

	sprintf (name, "%s/%s.gip", com_gamedir, level);
	
	Con_Printf ("Loading game from %s...\n", name);
	f = fopen (name, "r");
	if (!f)
	{
		Con_Printf ("ERROR: couldn't open.\n");
		return -1;
	}

	fscanf (f, "%i\n", &version);
	if (version != SAVEGAME_VERSION)
	{
		fclose (f);
		Con_Printf ("Savegame is version %i, not %i\n", version, SAVEGAME_VERSION);
		return -1;
	}
	fscanf (f, "%s\n", str);
//	for (i=0 ; i<NUM_SPAWN_PARMS ; i++)
//		fscanf (f, "%f\n", &spawn_parms[i]);
	fscanf (f, "%f\n", &sk);
	Cvar_SetValue ("skill", sk);

	fscanf (f, "%s\n",mapname);
	fscanf (f, "%f\n",&time);

	SV_SpawnServer (mapname, startspot);

	if (!sv.active)
	{
		Con_Printf ("Couldn't load map\n");
		return -1;
	}

// load the light styles
	for (i=0 ; i<MAX_LIGHTSTYLES ; i++)
	{
		fscanf (f, "%s\n", str);
		sv.lightstyles[i] = Hunk_Alloc (strlen(str)+1);
		strcpy (sv.lightstyles[i], str);
	}

// load the edicts out of the savegame file
	while (!feof(f))
	{
		fscanf (f, "%i\n",&entnum);
		for (i=0 ; i<sizeof(str)-1 ; i++)
		{
			r = fgetc (f);
			if (r == EOF || !r)
				break;
			str[i] = r;
			if (r == '}')
			{
				i++;
				break;
			}
		}
		if (i == sizeof(str)-1)
			Sys_Error ("Loadgame buffer overflow");
		str[i] = 0;
		start = str;
		start = COM_Parse(str);
		if (!com_token[0])
			break;		// end of file
		if (strcmp(com_token,"{"))
			Sys_Error ("First token isn't a brace");
			
		// parse an edict

		ent = EDICT_NUM(entnum);
		memset (&ent->v, 0, progs->entityfields * 4);
		ent->free = false;
		ED_ParseEdict (start, ent);
	
		// link it into the bsp tree
		if (!ent->free)
			SV_LinkEdict (ent, false);
	}
	
//	sv.num_edicts = entnum;
	sv.time = time;
	fclose (f);

//	for (i=0 ; i<NUM_SPAWN_PARMS ; i++)
//		svs.clients->spawn_parms[i] = spawn_parms[i];

	return 0;
}
Beispiel #28
0
/*
============
SV_PushMove

============
*/
void SV_PushMove (edict_t *pusher, float movetime)
{
	int			i, e;
	edict_t		*check, *block;
	vec3_t		mins, maxs, move;
	vec3_t		entorig, pushorig;
	int			num_moved;
// 2001-09-20 Configurable entity limits by Maddes  start
/*
	edict_t		*moved_edict[MAX_EDICTS];
	vec3_t		moved_from[MAX_EDICTS];
*/
// 2001-09-20 Configurable entity limits by Maddes  end
	float		solid_backup;		// 1999-10-07 MOVETYPE_PUSH fix by LordHavoc/Maddes

	if (!pusher->v.velocity[0] && !pusher->v.velocity[1] && !pusher->v.velocity[2])
	{
		pusher->v.ltime += movetime;
		return;
	}

// 2001-09-20 Configurable entity limits by Maddes  start
// FIXME: is this really necessary
	memset (moved_edict, 0, sv.max_edicts*sizeof(edict_t *));
	memset (moved_from, 0, sv.max_edicts*sizeof(vec3_t));
// 2001-09-20 Configurable entity limits by Maddes  end

	for (i=0 ; i<3 ; i++)
	{
		move[i] = pusher->v.velocity[i] * movetime;
		mins[i] = pusher->v.absmin[i] + move[i];
		maxs[i] = pusher->v.absmax[i] + move[i];
	}

	VectorCopy (pusher->v.origin, pushorig);

// move the pusher to it's final position

	VectorAdd (pusher->v.origin, move, pusher->v.origin);
	pusher->v.ltime += movetime;
	SV_LinkEdict (pusher, false);


// see if any solid entities are inside the final position
	num_moved = 0;
	check = NEXT_EDICT(sv.edicts);
	for (e=1 ; e<sv.num_edicts ; e++, check = NEXT_EDICT(check))
	{
		if (check->free)
			continue;
		if (check->v.movetype == MOVETYPE_PUSH
		|| check->v.movetype == MOVETYPE_NONE
		|| check->v.movetype == MOVETYPE_FOLLOW
		|| check->v.movetype == MOVETYPE_NOCLIP)
			continue;

	// if the entity is standing on the pusher, it will definately be moved
		if ( ! ( ((int)check->v.flags & FL_ONGROUND)
		&& PROG_TO_EDICT(check->v.groundentity) == pusher) )
		{
			if ( check->v.absmin[0] >= maxs[0]
			|| check->v.absmin[1] >= maxs[1]
			|| check->v.absmin[2] >= maxs[2]
			|| check->v.absmax[0] <= mins[0]
			|| check->v.absmax[1] <= mins[1]
			|| check->v.absmax[2] <= mins[2] )
				continue;

		// see if the ent's bbox is inside the pusher's final position
			if (!SV_TestEntityPosition (check))
				continue;
		}

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

		VectorCopy (check->v.origin, entorig);
		VectorCopy (check->v.origin, moved_from[num_moved]);
		moved_edict[num_moved] = check;
		num_moved++;

// 1999-10-07 MOVETYPE_PUSH fix by LordHavoc/Maddes  start
		solid_backup = pusher->v.solid;
		if ( solid_backup == SOLID_BSP		// everything that blocks: bsp models==map brushes==doors,plats,etc.
		|| solid_backup == SOLID_BBOX		// normally boxes
		|| solid_backup == SOLID_SLIDEBOX )	// normally monsters
		{
// 1999-10-07 MOVETYPE_PUSH fix by LordHavoc/Maddes  end
			// try moving the contacted entity
			pusher->v.solid = SOLID_NOT;
			SV_PushEntity (check, move);
// 1999-10-07 MOVETYPE_PUSH fix by LordHavoc/Maddes  start
//			pusher->v.solid = SOLID_BSP;
			pusher->v.solid = solid_backup;
// 1999-10-07 MOVETYPE_PUSH fix by LordHavoc/Maddes  end

			// if it is still inside the pusher, block
// 1999-10-07 MOVETYPE_PUSH fix by LordHavoc/Maddes  start
			block = SV_TestEntityPosition (check);
		}
		else
			block = NULL;
// 1999-10-07 MOVETYPE_PUSH fix by LordHavoc/Maddes  end

		if (block)
		{	// fail the move
			if (check->v.mins[0] == check->v.maxs[0])
				continue;
			if (check->v.solid == SOLID_NOT || check->v.solid == SOLID_TRIGGER)
			{	// corpse
				check->v.mins[0] = check->v.mins[1] = 0;
				VectorCopy (check->v.mins, check->v.maxs);
				continue;
			}

			VectorCopy (entorig, check->v.origin);
			SV_LinkEdict (check, true);

			VectorCopy (pushorig, pusher->v.origin);
			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)
			{
				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 (i=0 ; i<num_moved ; i++)
			{
				VectorCopy (moved_from[i], moved_edict[i]->v.origin);
				SV_LinkEdict (moved_edict[i], false);
			}
			return;
		}
	}


}
Beispiel #29
0
/*
===============
Host_Loadgame_f
===============
*/
static void
Host_Loadgame_f(void)
{
    char name[MAX_OSPATH];
    char mapname[MAX_QPATH];
    FILE *f;
    float time, tfloat;
    char str[32768];
    char *lightstyle;
    const char *start;
    int i, r, length, err;
    edict_t *ent;
    int entnum;
    int version;
    float spawn_parms[NUM_SPAWN_PARMS];

    if (cmd_source != src_command)
	return;

    if (Cmd_Argc() != 2) {
	Con_Printf("load <savename> : load a game\n");
	return;
    }

    cls.demonum = -1;		// stop demo loop in case this fails

    length = snprintf(name, sizeof(name), "%s/%s", com_gamedir, Cmd_Argv(1));
    err = COM_DefaultExtension(name, ".sav", name, sizeof(name));
    if (length >= sizeof(name) || err) {
	Con_Printf("ERROR: couldn't open save game, filename too long.\n");
	return;
    }

// we can't call SCR_BeginLoadingPlaque, because too much stack space has
// been used.  The menu calls it before stuffing loadgame command
//      SCR_BeginLoadingPlaque();

    Con_Printf("Loading game from %s...\n", name);
    f = fopen(name, "r");
    if (!f) {
	Con_Printf("ERROR: couldn't open.\n");
	return;
    }

    fscanf(f, "%i\n", &version);
    if (version != SAVEGAME_VERSION) {
	fclose(f);
	Con_Printf("Savegame is version %i, not %i\n", version,
		   SAVEGAME_VERSION);
	return;
    }
    fscanf(f, "%s\n", str);
    for (i = 0; i < NUM_SPAWN_PARMS; i++)
	fscanf(f, "%f\n", &spawn_parms[i]);

    /*
     * This silliness is so we can load 1.06 save files, which have float
     * skill values
     */
    fscanf(f, "%f\n", &tfloat);
    current_skill = (int)(tfloat + 0.1);
    Cvar_SetValue("skill", (float)current_skill);

    fscanf(f, "%s\n", mapname);
    fscanf(f, "%f\n", &time);

    CL_Disconnect_f();

    SV_SpawnServer(mapname);

    if (!sv.active) {
	Con_Printf("Couldn't load map\n");
	return;
    }
    sv.paused = true;		// pause until all clients connect
    sv.loadgame = true;

// load the light styles

    for (i = 0; i < MAX_LIGHTSTYLES; i++) {
	fscanf(f, "%s\n", str);
	lightstyle = Hunk_Alloc(strlen(str) + 1);
	strcpy(lightstyle, str);
	sv.lightstyles[i] = lightstyle;
    }

// load the edicts out of the savegame file
    entnum = -1;		// -1 is the globals
    while (!feof(f)) {
	for (i = 0; i < sizeof(str) - 1; i++) {
	    r = fgetc(f);
	    if (r == EOF || !r)
		break;
	    str[i] = r;
	    if (r == '}') {
		i++;
		break;
	    }
	}
	if (i == sizeof(str) - 1)
	    Sys_Error("Loadgame buffer overflow");
	str[i] = 0;
	start = COM_Parse(str);
	if (!com_token[0])
	    break;		// end of file
	if (strcmp(com_token, "{"))
	    Sys_Error("First token isn't a brace");

	if (entnum == -1) {	// parse the global vars
	    ED_ParseGlobals(start);
	} else {		// parse an edict

	    ent = EDICT_NUM(entnum);
	    memset(&ent->v, 0, progs->entityfields * 4);
	    ent->free = false;
	    ED_ParseEdict(start, ent);

	    // link it into the bsp tree
	    if (!ent->free)
		SV_LinkEdict(ent, false);
	}

	entnum++;
    }

    sv.num_edicts = entnum;
    sv.time = time;

    fclose(f);

    for (i = 0; i < NUM_SPAWN_PARMS; i++)
	svs.clients->spawn_parms[i] = spawn_parms[i];

    if (cls.state != ca_dedicated) {
	CL_EstablishConnection("local");
	Host_Reconnect_f();
    }
}
Beispiel #30
0
qboolean SV_MoveTest( edict_t *ent, vec3_t move, qboolean relink )
{
	float	temp;
	vec3_t	oldorg, neworg, end;
	trace_t	trace;

	VectorCopy( ent->v.origin, oldorg );
	VectorAdd( ent->v.origin, move, neworg );

	temp = svgame.movevars.stepsize;

	neworg[2] += temp;
	VectorCopy( neworg, end );
	end[2] -= temp * 2.0f;

	trace = SV_MoveNoEnts( neworg, ent->v.mins, ent->v.maxs, end, MOVE_NORMAL, ent );

	if( trace.allsolid != 0 )
		return 0;

	if( trace.startsolid != 0 )
	{
		neworg[2] -= temp;
		trace = SV_MoveNoEnts( neworg, ent->v.mins, ent->v.maxs, end, MOVE_NORMAL, ent );

		if( trace.allsolid != 0 || trace.startsolid != 0 )
			return 0;
	}

	if( trace.fraction == 1.0f )
	{
		if( ent->v.flags & FL_PARTIALGROUND )
		{
			VectorAdd( ent->v.origin, move, ent->v.origin );
			if( relink ) SV_LinkEdict( ent, true );
			ent->v.flags &= ~FL_ONGROUND;
			return 1;
		}
		return 0;
	}
	else
	{
		VectorCopy( trace.endpos, ent->v.origin );

		if( SV_CheckBottom( ent, WALKMOVE_WORLDONLY ) == 0 )
		{
			if( ent->v.flags & FL_PARTIALGROUND )
			{
				if( relink ) SV_LinkEdict( ent, true );
				return 1;
			}

			VectorCopy( oldorg, ent->v.origin );
			return 0;
		}
		else
		{
			ent->v.flags &= ~FL_PARTIALGROUND;
			ent->v.groundentity = trace.ent;
			if( relink ) SV_LinkEdict( ent, true );

			return 1;
		}
	}
}