Ejemplo n.º 1
0
// TODO: should be more general
CHARACTER *GAMEWORLD::intersect_character(vec2 pos0, vec2 pos1, float radius, vec2& new_pos, ENTITY *notthis)
{
	// Find other players
	float closest_len = distance(pos0, pos1) * 100.0f;
	vec2 line_dir = normalize(pos1-pos0);
	CHARACTER *closest = 0;

	CHARACTER *p = (CHARACTER *)game.world.find_first(NETOBJTYPE_CHARACTER);
	for(; p; p = (CHARACTER *)p->typenext())
 	{
		if(p == notthis)
			continue;
			
		vec2 intersect_pos = closest_point_on_line(pos0, pos1, p->pos);
		float len = distance(p->pos, intersect_pos);
		if(len < CHARACTER::phys_size+radius)
		{
			if(len < closest_len)
			{
				new_pos = intersect_pos;
				closest_len = len;
				closest = p;
			}
		}
	}
	
	return closest;
}
Ejemplo n.º 2
0
// TODO: should be more general
CCharacter *CGameWorld::IntersectCharacter(vec2 Pos0, vec2 Pos1, float Radius, vec2& NewPos, CCharacter *pNotThis, int CollideWith, class CCharacter *pThisOnly)
{
	// Find other players
	float ClosestLen = distance(Pos0, Pos1) * 100.0f;
	vec2 LineDir = normalize(Pos1-Pos0);
	CCharacter *pClosest = 0;

	CCharacter *p = (CCharacter *)FindFirst(ENTTYPE_CHARACTER);
	for(; p; p = (CCharacter *)p->TypeNext())
 	{
		if(p == pNotThis)
			continue;
		if(CollideWith != -1 && !p->CanCollide(CollideWith)) continue;
		vec2 IntersectPos = closest_point_on_line(Pos0, Pos1, p->m_Pos);
		float Len = distance(p->m_Pos, IntersectPos);
		if(Len < p->m_ProximityRadius+Radius)
		{
			Len = distance(Pos0, IntersectPos);
			if(Len < ClosestLen)
			{
				NewPos = IntersectPos;
				ClosestLen = Len;
				pClosest = p;
			}
			if(pThisOnly && p == pThisOnly)
				return p;
		}
	}
	
	return pClosest;
}
Ejemplo n.º 3
0
// TODO: should be more general
CCharacter *CGameWorld::IntersectCharacter(vec2 Pos0, vec2 Pos1, float Radius, vec2& NewPos, CEntityCore *pNotThis)
{
	// Find other players
	float ClosestLen = distance(Pos0, Pos1) * 100.0f;
	CCharacter *pClosest = 0;

	CCharacter *p = (CCharacter *)FindFirst(MOD_ENTTYPE_CHARACTER);
	for(; p; p = (CCharacter *)p->TypeNext())
 	{
		if(p == pNotThis)
			continue;

		vec2 IntersectPos = closest_point_on_line(Pos0, Pos1, p->m_Pos);
		float Len = distance(p->m_Pos, IntersectPos);
		if(Len < p->m_ProximityRadius+Radius)
		{
			Len = distance(Pos0, IntersectPos);
			if(Len < ClosestLen)
			{
				NewPos = IntersectPos;
				ClosestLen = Len;
				pClosest = p;
			}
		}
	}

	return pClosest;
}
Ejemplo n.º 4
0
//H-Client
// TODO: should be more general
int CGameClient::IntersectCharacter(vec2 Pos0, vec2 Pos1, vec2& NewPos, float Speed/*hook speed*/, int ownID)
{
	// Find other players
	const float ProximityRadius2 = (28.f + 2.f) * (28.f + 2.f);
	float ClosestLen2 = distance2(Pos0, Pos1) * 10000.0f;
	int ClosestID = -1;
	
	if (!m_Tuning.m_PlayerHooking)
		return ClosestID;

	for (int i=0; i<MAX_CLIENTS; i++)
	{
        const CClientData& cData = m_aClients[i];

        if (!cData.m_Active || cData.m_Team == TEAM_SPECTATORS || i == ownID || !m_Teams.SameTeam(i, ownID))
            continue;

        vec2 Position = cData.m_Predicted.m_Pos;
        vec2 Velocity = cData.m_Predicted.m_Vel;

		vec2 IntersectPos = closest_point_on_line(Pos0, Pos1, Position);
		
		if(Speed != 0.f)
		{
			const float DistFromTarget = distance(Pos0, IntersectPos);
			// predict
			Position += Velocity * (DistFromTarget / Speed);
			// can be deleted ?
			IntersectPos = closest_point_on_line(Pos0, Pos1, Position);
		}
		
		float Len2 = distance2(Position, IntersectPos);
		if(Len2 < ProximityRadius2)
		{
			Len2 = distance2(Pos0, IntersectPos);
			if(Len2 < ClosestLen2)
			{
				NewPos = IntersectPos;
				ClosestLen2 = Len2;
				ClosestID = i;
			}
		}
	}

	return ClosestID;
}
Ejemplo n.º 5
0
void CBarrier::Tick()
{
	m_LifeSpan--;
	
	if(m_LifeSpan < 0)
	{
		GameServer()->m_World.DestroyEntity(this);
	}
	else
	{
		// Find other players
		for(CCharacter *p = (CCharacter*) GameWorld()->FindFirst(CGameWorld::ENTTYPE_CHARACTER); p; p = (CCharacter *)p->TypeNext())
		{
			if(!p->IsInfected()) continue;

			vec2 IntersectPos = closest_point_on_line(m_Pos, m_Pos2, p->m_Pos);
			float Len = distance(p->m_Pos, IntersectPos);
			if(Len < p->m_ProximityRadius+g_BarrierRadius)
			{
				//Check for portal traps
				if(p->GetClass() != PLAYERCLASS_UNDEAD && (Server()->Tick() - p->m_PortalTick) < Server()->TickSpeed()/2)
				{
					CPlayer* pPortalPlayer = GameServer()->m_apPlayers[p->m_LastPortalOwner];
					if(pPortalPlayer)
					{
						pPortalPlayer->IncreaseScore(1);
					}
				}
				
				//Check for hook traps. The case when the player is frozen is in the function Die()
				if(!p->IsFrozen())
				{
					for(CCharacter *pHook = (CCharacter*) GameWorld()->FindFirst(CGameWorld::ENTTYPE_CHARACTER); pHook; pHook = (CCharacter *)pHook->TypeNext())
					{
						if(p->GetPlayer() && pHook->GetPlayer() && pHook->m_Core.m_HookedPlayer == p->GetPlayer()->GetCID() && pHook->GetPlayer()->GetCID() != m_Owner)
						{
							pHook->GetPlayer()->IncreaseScore(1);
						}
					}
				}
				
				p->Die(m_Owner, WEAPON_HAMMER);
			}
		}
	}
}
Ejemplo n.º 6
0
std::list<class CCharacter *> CGameWorld::IntersectedCharacters(vec2 Pos0, vec2 Pos1, float Radius, class CEntity *pNotThis)
{
	std::list< CCharacter * > listOfChars;

	CCharacter *pChr = (CCharacter *)FindFirst(CGameWorld::ENTTYPE_CHARACTER);
	for(; pChr; pChr = (CCharacter *)pChr->TypeNext())
 	{
		if(pChr == pNotThis)
			continue;

		vec2 IntersectPos = closest_point_on_line(Pos0, Pos1, pChr->m_Pos);
		float Len = distance(pChr->m_Pos, IntersectPos);
		if(Len < pChr->m_ProximityRadius+Radius)
		{
			pChr->m_Intersection = IntersectPos;
			listOfChars.push_back(pChr);
		}
	}
	return listOfChars;
}
Ejemplo n.º 7
0
void CBarrier::Tick()
{
	m_LifeSpan--;
	
	if(m_LifeSpan < 0)
	{
		GameServer()->m_World.DestroyEntity(this);
	}
	
	{
		// Find other players
		for(CCharacter *p = (CCharacter*) GameWorld()->FindFirst(CGameWorld::ENTTYPE_CHARACTER); p; p = (CCharacter *)p->TypeNext())
		{
			if(!p->IsInfected()) continue;

			vec2 IntersectPos = closest_point_on_line(m_Pos, m_Pos2, p->m_Pos);
			float Len = distance(p->m_Pos, IntersectPos);
			if(Len < p->m_ProximityRadius+g_BarrierRadius)
			{
				p->Die(m_Owner, WEAPON_HAMMER);
			}
		}
	}
}
Ejemplo n.º 8
0
void CHARACTER_CORE::tick(bool use_input)
{
	float phys_size = 28.0f;
	triggered_events = 0;

	// get ground state
	bool grounded = false;
	if(col_check_point(pos.x+phys_size/2, pos.y+phys_size/2+5))
		grounded = true;
	if(col_check_point(pos.x-phys_size/2, pos.y+phys_size/2+5))
		grounded = true;
	//platte
	if(col_check_platte(pos.x+phys_size/2, pos.y+phys_size/2+5))
		grounded = true;
	if(col_check_platte(pos.x-phys_size/2, pos.y+phys_size/2+5))
		grounded = true;

	vec2 target_direction = normalize(vec2(input.target_x, input.target_y));

	vel.y += world->tuning.gravity;

	float max_speed = grounded ? world->tuning.ground_control_speed : world->tuning.air_control_speed;
	float accel = grounded ? world->tuning.ground_control_accel : world->tuning.air_control_accel;
	float friction = grounded ? world->tuning.ground_friction : world->tuning.air_friction;

	// handle input
	if(use_input)
	{
		direction = input.direction;

		// setup angle
		float a = 0;
		if(input.target_x == 0)
			a = atan((float)input.target_y);
		else
			a = atan((float)input.target_y/(float)input.target_x);

		if(input.target_x < 0)
			a = a+pi;

		angle = (int)(a*256.0f);

		// handle jump
		if(input.jump)
		{
			if(!(jumped&1))
			{
				if(grounded)
				{
					triggered_events |= COREEVENT_GROUND_JUMP;
					vel.y = -world->tuning.ground_jump_impulse;
					jumped |= 1;
				}
				else if(!(jumped&2))
				{
					triggered_events |= COREEVENT_AIR_JUMP;
					vel.y = -world->tuning.air_jump_impulse;
					jumped |= 3;
				}
			}
		}
		else
			jumped &= ~1;

		// handle hook
		if(input.hook)
		{
			if(hook_state == HOOK_IDLE)
			{
				hook_state = HOOK_FLYING;
				hook_pos = pos+target_direction*phys_size*1.5f;
				hook_dir = target_direction;
				hooked_player = -1;
				hook_tick = 0;
				triggered_events |= COREEVENT_HOOK_LAUNCH;
			}
		}
		else
		{
			hooked_player = -1;
			hook_state = HOOK_IDLE;
			hook_pos = pos;
		}
	}

	// add the speed modification according to players wanted direction
	if(direction < 0)
		vel.x = saturated_add(-max_speed, max_speed, vel.x, -accel);
	if(direction > 0)
		vel.x = saturated_add(-max_speed, max_speed, vel.x, accel);
	if(direction == 0)
		vel.x *= friction;

	// handle jumping
	// 1 bit = to keep track if a jump has been made on this input
	// 2 bit = to keep track if a air-jump has been made
	if(grounded)
		jumped &= ~2;

	// do hook
	if(hook_state == HOOK_IDLE)
	{
		hooked_player = -1;
		hook_state = HOOK_IDLE;
		hook_pos = pos;
	}
	else if(hook_state >= HOOK_RETRACT_START && hook_state < HOOK_RETRACT_END)
	{
		hook_state++;
	}
	else if(hook_state == HOOK_RETRACT_END)
	{
		hook_state = HOOK_RETRACTED;
		triggered_events |= COREEVENT_HOOK_RETRACT;
		hook_state = HOOK_RETRACTED;
	}
	else if(hook_state == HOOK_FLYING)
	{
		vec2 new_pos = hook_pos+hook_dir*world->tuning.hook_fire_speed;
		if(distance(pos, new_pos) > world->tuning.hook_length)
		{
			hook_state = HOOK_RETRACT_START;
			new_pos = pos + normalize(new_pos-pos) * world->tuning.hook_length;
		}

		// make sure that the hook doesn't go though the ground
		bool going_to_hit_ground = false;
		bool going_to_retract = false;
		int hit = col_intersect_line(hook_pos, new_pos, &new_pos, 0);
		if(hit)
		{
			if(hit&COLFLAG_NOHOOK)
				going_to_retract = true;
			else
				going_to_hit_ground = true;
		}

		// Check against other players first
		if(world && world->tuning.player_hooking)
		{
			float dist = 0.0f;
			for(int i = 0; i < MAX_CLIENTS; i++)
			{
				CHARACTER_CORE *p = world->characters[i];
				if(!p || p == this)
					continue;

				vec2 closest_point = closest_point_on_line(hook_pos, new_pos, p->pos);
				if(distance(p->pos, closest_point) < phys_size+2.0f)
				{
					if (hooked_player == -1 || distance (hook_pos, p->pos) < dist)
					{
						triggered_events |= COREEVENT_HOOK_ATTACH_PLAYER;
						hook_state = HOOK_GRABBED;
						hooked_player = i;
						dist = distance (hook_pos, p->pos);
					}
				}
			}
		}

		if(hook_state == HOOK_FLYING)
		{
			// check against ground
			if(going_to_hit_ground)
			{
				triggered_events |= COREEVENT_HOOK_ATTACH_GROUND;
				hook_state = HOOK_GRABBED;
			}
			else if(going_to_retract)
			{
				triggered_events |= COREEVENT_HOOK_HIT_NOHOOK;
				hook_state = HOOK_RETRACT_START;
			}

			hook_pos = new_pos;
		}
	}

	if(hook_state == HOOK_GRABBED)
	{
		if(hooked_player != -1)
		{
			CHARACTER_CORE *p = world->characters[hooked_player];
			if(p)
				hook_pos = p->pos;
			else
			{
				// release hook
				hooked_player = -1;
				hook_state = HOOK_RETRACTED;
				hook_pos = pos;
			}

			// keep players hooked for a max of 1.5sec
			//if(server_tick() > hook_tick+(server_tickspeed()*3)/2)
				//release_hooked();
		}

		// don't do this hook rutine when we are hook to a player
		if(hooked_player == -1 && distance(hook_pos, pos) > 46.0f)
		{
			vec2 hookvel = normalize(hook_pos-pos)*world->tuning.hook_drag_accel;
			// the hook as more power to drag you up then down.
			// this makes it easier to get on top of an platform
			if(hookvel.y > 0)
				hookvel.y *= 0.3f;

			// the hook will boost it's power if the player wants to move
			// in that direction. otherwise it will dampen everything abit
			if((hookvel.x < 0 && direction < 0) || (hookvel.x > 0 && direction > 0))
				hookvel.x *= 0.95f;
			else
				hookvel.x *= 0.75f;

			vec2 new_vel = vel+hookvel;

			// check if we are under the legal limit for the hook
			if(length(new_vel) < world->tuning.hook_drag_speed || length(new_vel) < length(vel))
				vel = new_vel; // no problem. apply

		}

		// release hook (max hook time is 1.25
		hook_tick++;
		if(hooked_player != -1 && (hook_tick > SERVER_TICK_SPEED+SERVER_TICK_SPEED/5 || !world->characters[hooked_player]))
		{
			hooked_player = -1;
			hook_state = HOOK_RETRACTED;
			hook_pos = pos;
		}
	}

	if(world && world->tuning.player_collision)
	{
		for(int i = 0; i < MAX_CLIENTS; i++)
		{
			CHARACTER_CORE *p = world->characters[i];
			if(!p)
				continue;

			//player *p = (player*)ent;
			if(p == this) // || !(p->flags&FLAG_ALIVE)
				continue; // make sure that we don't nudge our self

			// handle player <-> player collision
			float d = distance(pos, p->pos);
			vec2 dir = normalize(pos - p->pos);
			if(d < phys_size*1.25f && d > 1.0f)
			{
				float a = (phys_size*1.45f - d);

				// make sure that we don't add excess force by checking the
				// direction against the current velocity
				vec2 veldir = normalize(vel);
				float v = 1-(dot(veldir, dir)+1)/2;
				vel = vel + dir*a*(v*0.75f);
				vel = vel * 0.85f;
			}

			// handle hook influence
			if(hooked_player == i)
			{
				if(d > phys_size*1.50f) // TODO: fix tweakable variable
				{
					float accel = world->tuning.hook_drag_accel * (d/world->tuning.hook_length);
					float drag_speed = world->tuning.hook_drag_speed;

					// add force to the hooked player
					p->vel.x = saturated_add(-drag_speed, drag_speed, p->vel.x, accel*dir.x*1.5f);
					p->vel.y = saturated_add(-drag_speed, drag_speed, p->vel.y, accel*dir.y*1.5f);

					// add a little bit force to the guy who has the grip
					vel.x = saturated_add(-drag_speed, drag_speed, vel.x, -accel*dir.x*0.25f);
					vel.y = saturated_add(-drag_speed, drag_speed, vel.y, -accel*dir.y*0.25f);
				}
			}
		}
	}

	// clamp the velocity to something sane
	if(length(vel) > 6000)
		vel = normalize(vel) * 6000;
}
Ejemplo n.º 9
0
void CCharacterCore::Tick(bool UseInput)
{
	float PhysSize = 28.0f;
	m_TriggeredEvents = 0;

	// get ground state
	bool Grounded = false;
	if(m_pCollision->CheckPoint(m_Pos.x+PhysSize/2, m_Pos.y+PhysSize/2+5))
		Grounded = true;
	if(m_pCollision->CheckPoint(m_Pos.x-PhysSize/2, m_Pos.y+PhysSize/2+5))
		Grounded = true;

	vec2 TargetDirection = normalize(vec2(m_Input.m_TargetX, m_Input.m_TargetY));

	m_Vel.y += m_pWorld->m_Tuning.m_Gravity;

	float MaxSpeed = Grounded ? m_pWorld->m_Tuning.m_GroundControlSpeed : m_pWorld->m_Tuning.m_AirControlSpeed;
	float Accel = Grounded ? m_pWorld->m_Tuning.m_GroundControlAccel : m_pWorld->m_Tuning.m_AirControlAccel;
	float Friction = Grounded ? m_pWorld->m_Tuning.m_GroundFriction : m_pWorld->m_Tuning.m_AirFriction;

	// handle input
	if(UseInput)
	{
		m_Direction = m_Input.m_Direction;

		// setup angle
		float a = 0;
		if(m_Input.m_TargetX == 0)
			a = atanf((float)m_Input.m_TargetY);
		else
			a = atanf((float)m_Input.m_TargetY/(float)m_Input.m_TargetX);

		if(m_Input.m_TargetX < 0)
			a = a+pi;

		m_Angle = (int)(a*256.0f);

		// handle jump
		if(m_Input.m_Jump)
		{
			if(!(m_Jumped&1))
			{
				if(Grounded)
				{
					m_TriggeredEvents |= COREEVENT_GROUND_JUMP;
					m_Vel.y = -m_pWorld->m_Tuning.m_GroundJumpImpulse;
					m_Jumped |= 1;
				}
				else if(!(m_Jumped&2))
				{
					m_TriggeredEvents |= COREEVENT_AIR_JUMP;
					m_Vel.y = -m_pWorld->m_Tuning.m_AirJumpImpulse;
					m_Jumped |= 3;
				}
			}
		}
		else
			m_Jumped &= ~1;

		// handle hook
		if(m_Input.m_Hook)
		{
			if(m_HookState == HOOK_IDLE)
			{
				m_HookState = HOOK_FLYING;
				m_HookPos = m_Pos+TargetDirection*PhysSize*1.5f;
				m_HookDir = TargetDirection;
				m_HookedPlayer = -1;
				m_HookTick = 0;
				m_TriggeredEvents |= COREEVENT_HOOK_LAUNCH;
			}
		}
		else
		{
			m_HookedPlayer = -1;
			m_HookState = HOOK_IDLE;
			m_HookPos = m_Pos;
		}
	}

	// add the speed modification according to players wanted direction
	if(m_Direction < 0)
		m_Vel.x = SaturatedAdd(-MaxSpeed, MaxSpeed, m_Vel.x, -Accel);
	if(m_Direction > 0)
		m_Vel.x = SaturatedAdd(-MaxSpeed, MaxSpeed, m_Vel.x, Accel);
	if(m_Direction == 0)
		m_Vel.x *= Friction;

	// handle jumping
	// 1 bit = to keep track if a jump has been made on this input
	// 2 bit = to keep track if a air-jump has been made
	if(Grounded)
		m_Jumped &= ~2;

	// do hook
	if(m_HookState == HOOK_IDLE)
	{
		m_HookedPlayer = -1;
		m_HookState = HOOK_IDLE;
		m_HookPos = m_Pos;
	}
	else if(m_HookState >= HOOK_RETRACT_START && m_HookState < HOOK_RETRACT_END)
	{
		m_HookState++;
	}
	else if(m_HookState == HOOK_RETRACT_END)
	{
		m_HookState = HOOK_RETRACTED;
		m_TriggeredEvents |= COREEVENT_HOOK_RETRACT;
		m_HookState = HOOK_RETRACTED;
	}
	else if(m_HookState == HOOK_FLYING)
	{
		vec2 NewPos = m_HookPos+m_HookDir*m_pWorld->m_Tuning.m_HookFireSpeed;
		if(distance(m_Pos, NewPos) > m_pWorld->m_Tuning.m_HookLength)
		{
			m_HookState = HOOK_RETRACT_START;
			NewPos = m_Pos + normalize(NewPos-m_Pos) * m_pWorld->m_Tuning.m_HookLength;
		}

		// make sure that the hook doesn't go though the ground
		bool GoingToHitGround = false;
		bool GoingToRetract = false;
		int Hit = m_pCollision->IntersectLine(m_HookPos, NewPos, &NewPos, 0, false);
		if(Hit)
		{
			if(Hit&CCollision::COLFLAG_NOHOOK)
				GoingToRetract = true;
			else
				GoingToHitGround = true;
		}

		// Check against other players first
		if(m_pWorld && m_pWorld->m_Tuning.m_PlayerHooking && m_CanCollide)
		{
			float Distance = 0.0f;
			for(int i = 0; i < MAX_CLIENTS; i++)
			{
				CCharacterCore *pCharCore = m_pWorld->m_apCharacters[i];
				if(!pCharCore || pCharCore == this || !pCharCore->m_CanCollide)
					continue;

				vec2 ClosestPoint = closest_point_on_line(m_HookPos, NewPos, pCharCore->m_Pos);
				if(distance(pCharCore->m_Pos, ClosestPoint) < PhysSize+2.0f)
				{
					if (m_HookedPlayer == -1 || distance(m_HookPos, pCharCore->m_Pos) < Distance)
					{
						m_TriggeredEvents |= COREEVENT_HOOK_ATTACH_PLAYER;
						m_HookState = HOOK_GRABBED;
						m_HookedPlayer = i;
						Distance = distance(m_HookPos, pCharCore->m_Pos);
					}
				}
			}
		}

		if(m_HookState == HOOK_FLYING)
		{
			// check against ground
			if(GoingToHitGround)
			{
				m_TriggeredEvents |= COREEVENT_HOOK_ATTACH_GROUND;
				m_HookState = HOOK_GRABBED;
			}
			else if(GoingToRetract)
			{
				m_TriggeredEvents |= COREEVENT_HOOK_HIT_NOHOOK;
				m_HookState = HOOK_RETRACT_START;
			}

			m_HookPos = NewPos;
		}
	}

	if(m_HookState == HOOK_GRABBED)
	{
		if(m_HookedPlayer != -1)
		{
			CCharacterCore *pCharCore = m_pWorld->m_apCharacters[m_HookedPlayer];
			if(pCharCore)
				m_HookPos = pCharCore->m_Pos;
			else
			{
				// release hook
				m_HookedPlayer = -1;
				m_HookState = HOOK_RETRACTED;
				m_HookPos = m_Pos;
			}

			// keep players hooked for a max of 1.5sec
			//if(Server()->Tick() > hook_tick+(Server()->TickSpeed()*3)/2)
				//release_hooked();
		}

		// don't do this hook rutine when we are hook to a player
		if(m_HookedPlayer == -1 && distance(m_HookPos, m_Pos) > 46.0f)
		{
			vec2 HookVel = normalize(m_HookPos-m_Pos)*m_pWorld->m_Tuning.m_HookDragAccel;
			// the hook as more power to drag you up then down.
			// this makes it easier to get on top of an platform
			if(HookVel.y > 0)
				HookVel.y *= 0.3f;

			// the hook will boost it's power if the player wants to move
			// in that direction. otherwise it will dampen everything abit
			if((HookVel.x < 0 && m_Direction < 0) || (HookVel.x > 0 && m_Direction > 0))
				HookVel.x *= 0.95f;
			else
				HookVel.x *= 0.75f;

			vec2 NewVel = m_Vel+HookVel;

			// check if we are under the legal limit for the hook
			if(length(NewVel) < m_pWorld->m_Tuning.m_HookDragSpeed || length(NewVel) < length(m_Vel))
				m_Vel = NewVel; // no problem. apply

		}

		// release hook (max hook time is 1.25
		m_HookTick++;
		if(m_HookedPlayer != -1 && (m_HookTick > SERVER_TICK_SPEED+SERVER_TICK_SPEED/5 || !m_pWorld->m_apCharacters[m_HookedPlayer]))
		{
			m_HookedPlayer = -1;
			m_HookState = HOOK_RETRACTED;
			m_HookPos = m_Pos;
		}
	}

	if(m_pWorld && m_CanCollide)
	{
		for(int i = 0; i < MAX_CLIENTS; i++)
		{
			CCharacterCore *pCharCore = m_pWorld->m_apCharacters[i];
			if(!pCharCore || !pCharCore->m_CanCollide || !pCharCore->m_CanCollide)
				continue;

			//player *p = (player*)ent;
			if(pCharCore == this) // || !(p->flags&FLAG_ALIVE)
				continue; // make sure that we don't nudge our self

			// handle player <-> player collision
			float Distance = distance(m_Pos, pCharCore->m_Pos);
			vec2 Dir = normalize(m_Pos - pCharCore->m_Pos);
			if(m_pWorld->m_Tuning.m_PlayerCollision && Distance < PhysSize*1.25f && Distance > 0.0f)
			{
				float a = (PhysSize*1.45f - Distance);
				float Velocity = 0.5f;

				// make sure that we don't add excess force by checking the
				// direction against the current velocity. if not zero.
				if (length(m_Vel) > 0.0001)
					Velocity = 1-(dot(normalize(m_Vel), Dir)+1)/2;

				m_Vel += Dir*a*(Velocity*0.75f);
				m_Vel *= 0.85f;
			}

			// handle hook influence
			if(m_HookedPlayer == i && m_pWorld->m_Tuning.m_PlayerHooking)
			{
				if(Distance > PhysSize*1.50f) // TODO: fix tweakable variable
				{
					float Accel = m_pWorld->m_Tuning.m_HookDragAccel * (Distance/m_pWorld->m_Tuning.m_HookLength);
					float DragSpeed = m_pWorld->m_Tuning.m_HookDragSpeed;

					// add force to the hooked player
					pCharCore->m_Vel.x = SaturatedAdd(-DragSpeed, DragSpeed, pCharCore->m_Vel.x, Accel*Dir.x*1.5f);
					pCharCore->m_Vel.y = SaturatedAdd(-DragSpeed, DragSpeed, pCharCore->m_Vel.y, Accel*Dir.y*1.5f);

					// add a little bit force to the guy who has the grip
					m_Vel.x = SaturatedAdd(-DragSpeed, DragSpeed, m_Vel.x, -Accel*Dir.x*0.25f);
					m_Vel.y = SaturatedAdd(-DragSpeed, DragSpeed, m_Vel.y, -Accel*Dir.y*0.25f);
				}
			}
		}
	}

	// clamp the velocity to something sane
	if(length(m_Vel) > 6000)
		m_Vel = normalize(m_Vel) * 6000;
}
Ejemplo n.º 10
0
void CCharacterCore::Tick(bool UseInput)
{
	float PhysSize = 28.0f;
	vec2 PrevPos = m_Pos; // H-Client: DDNet
	m_TriggeredEvents = 0;

	// get ground state
	bool Grounded = false;
	if(m_pCollision->CheckPoint(m_Pos.x+PhysSize/2, m_Pos.y+PhysSize/2+5))
		Grounded = true;
	if(m_pCollision->CheckPoint(m_Pos.x-PhysSize/2, m_Pos.y+PhysSize/2+5))
		Grounded = true;

    // H-Client: DDNet
	bool InTileFreeze = m_pCollision->CheckPointFreeze(m_Pos);
	bool InTileSpeed = m_pCollision->CheckPointSpeedUp(m_Pos);
    //


	vec2 TargetDirection = normalize(vec2(m_Input.m_TargetX, m_Input.m_TargetY));

	m_Vel.y += m_pWorld->m_Tuning.m_Gravity;

	float MaxSpeed = Grounded ? m_pWorld->m_Tuning.m_GroundControlSpeed : m_pWorld->m_Tuning.m_AirControlSpeed;
	float Accel = Grounded ? m_pWorld->m_Tuning.m_GroundControlAccel : m_pWorld->m_Tuning.m_AirControlAccel;
	float Friction = Grounded ? m_pWorld->m_Tuning.m_GroundFriction : m_pWorld->m_Tuning.m_AirFriction;

	// handle input
	if(UseInput)
	{
		m_Direction = m_Input.m_Direction;

		// setup angle
		float a = 0;
		if(m_Input.m_TargetX == 0)
			a = atanf((float)m_Input.m_TargetY);
		else
			a = atanf((float)m_Input.m_TargetY/(float)m_Input.m_TargetX);

		if(m_Input.m_TargetX < 0)
			a = a+PI;

		m_Angle = (int)(a*256.0f);

		// handle jump
		if((g_Config.m_ddrPreventPrediction && m_Input.m_Jump && !m_Freezes && !InTileFreeze) || (!g_Config.m_ddrPreventPrediction && m_Input.m_Jump)) // H-Client: DDNet
		{
			if(!(m_Jumped&1))
			{
				if(Grounded)
				{
					m_TriggeredEvents |= COREEVENT_GROUND_JUMP;
					m_Vel.y = -m_pWorld->m_Tuning.m_GroundJumpImpulse;
					m_Jumped |= 1;
				}
				else if(!(m_Jumped&2))
				{
					m_TriggeredEvents |= COREEVENT_AIR_JUMP;
					m_Vel.y = -m_pWorld->m_Tuning.m_AirJumpImpulse;
					m_Jumped |= 3;
				}
			}
		}
		else
			m_Jumped &= ~1;

		// handle hook
		if((g_Config.m_ddrPreventPrediction && m_Input.m_Hook && !m_Freezes && !InTileFreeze) || (!g_Config.m_ddrPreventPrediction && m_Input.m_Hook)) // H-Client: DDNet
		{
			if(m_HookState == HOOK_IDLE)
			{
				m_HookState = HOOK_FLYING;
				m_HookPos = m_Pos+TargetDirection*PhysSize*1.5f;
				m_HookDir = TargetDirection;
				m_HookedPlayer = -1;
				m_HookTick = 0;
				m_TriggeredEvents |= COREEVENT_HOOK_LAUNCH;
			}
		}
		else
		{
			m_HookedPlayer = -1;
			m_HookState = HOOK_IDLE;
			m_HookPos = m_Pos;
		}
	}

	// add the speed modification according to players wanted direction
	// H-Client: DDNet
	if (g_Config.m_ddrPreventPrediction && (m_Freezes || InTileFreeze))
        m_Vel.x *= Friction;
    else
    {
        if (m_Direction < 0)
            m_Vel.x = SaturatedAdd(-MaxSpeed, MaxSpeed, m_Vel.x, -Accel);
        else if (m_Direction > 0)
            m_Vel.x = SaturatedAdd(-MaxSpeed, MaxSpeed, m_Vel.x, Accel);
        else
            m_Vel.x *= Friction;
    }

	// handle jumping
	// 1 bit = to keep track if a jump has been made on this input
	// 2 bit = to keep track if a air-jump has been made
	if(Grounded)
		m_Jumped &= ~2;

	// do hook
	if(m_HookState == HOOK_IDLE)
	{
		m_HookedPlayer = -1;
		m_HookState = HOOK_IDLE;
		m_HookPos = m_Pos;
	}
	else if(m_HookState >= HOOK_RETRACT_START && m_HookState < HOOK_RETRACT_END)
	{
		m_HookState++;
	}
	else if(m_HookState == HOOK_RETRACT_END)
	{
		m_HookState = HOOK_RETRACTED;
		m_TriggeredEvents |= COREEVENT_HOOK_RETRACT;
		m_HookState = HOOK_RETRACTED;
	}
	else if(m_HookState == HOOK_FLYING)
	{
		vec2 NewPos = m_HookPos+m_HookDir*m_pWorld->m_Tuning.m_HookFireSpeed;
		if(distance(m_Pos, NewPos) > m_pWorld->m_Tuning.m_HookLength)
		{
			m_HookState = HOOK_RETRACT_START;
			NewPos = m_Pos + normalize(NewPos-m_Pos) * m_pWorld->m_Tuning.m_HookLength;
		}

		// make sure that the hook doesn't go though the ground
		bool GoingToHitGround = false;
		bool GoingToRetract = false;
		int Hit = m_pCollision->IntersectLine(m_HookPos, NewPos, &NewPos, 0, true); // H-Client: DDNet
		if(Hit)
		{
			if(Hit&CCollision::COLFLAG_NOHOOK)
				GoingToRetract = true;
			else
				GoingToHitGround = true;
		}

		// Check against other players first
		if(m_pWorld && m_pWorld->m_Tuning.m_PlayerHooking)
		{
			float Distance = 0.0f;
			for(int i = 0; i < MAX_CLIENTS; i++)
			{
				CCharacterCore *pCharCore = m_pWorld->m_apCharacters[i];
				if(!pCharCore || pCharCore == this)
					continue;

				vec2 ClosestPoint = closest_point_on_line(m_HookPos, NewPos, pCharCore->m_Pos);
				if(distance(pCharCore->m_Pos, ClosestPoint) < PhysSize+2.0f)
				{
					if (m_HookedPlayer == -1 || distance(m_HookPos, pCharCore->m_Pos) < Distance)
					{
						m_TriggeredEvents |= COREEVENT_HOOK_ATTACH_PLAYER;
						m_HookState = HOOK_GRABBED;
						m_HookedPlayer = i;
						Distance = distance(m_HookPos, pCharCore->m_Pos);
					}
				}
			}
		}

		if(m_HookState == HOOK_FLYING)
		{
			// check against ground
			if(GoingToHitGround)
			{
				m_TriggeredEvents |= COREEVENT_HOOK_ATTACH_GROUND;
				m_HookState = HOOK_GRABBED;
			}
			else if(GoingToRetract)
			{
				m_TriggeredEvents |= COREEVENT_HOOK_HIT_NOHOOK;
				m_HookState = HOOK_RETRACT_START;
			}

			m_HookPos = NewPos;
		}
	}

	if(m_HookState == HOOK_GRABBED)
	{
		if(m_HookedPlayer != -1)
		{
			CCharacterCore *pCharCore = m_pWorld->m_apCharacters[m_HookedPlayer];
			if(pCharCore)
				m_HookPos = pCharCore->m_Pos;
			else
			{
				// release hook
				m_HookedPlayer = -1;
				m_HookState = HOOK_RETRACTED;
				m_HookPos = m_Pos;
			}

			// keep players hooked for a max of 1.5sec
			//if(Server()->Tick() > hook_tick+(Server()->TickSpeed()*3)/2)
				//release_hooked();
		}

		// don't do this hook rutine when we are hook to a player
		if(m_HookedPlayer == -1 && distance(m_HookPos, m_Pos) > 46.0f)
		{
			vec2 HookVel = normalize(m_HookPos-m_Pos)*m_pWorld->m_Tuning.m_HookDragAccel;
			// the hook as more power to drag you up then down.
			// this makes it easier to get on top of an platform
			if(HookVel.y > 0)
				HookVel.y *= 0.3f;

			// the hook will boost it's power if the player wants to move
			// in that direction. otherwise it will dampen everything abit
			if((HookVel.x < 0 && m_Direction < 0) || (HookVel.x > 0 && m_Direction > 0))
				HookVel.x *= 0.95f;
			else
				HookVel.x *= 0.75f;

			vec2 NewVel = m_Vel+HookVel;

			// check if we are under the legal limit for the hook
			if(length(NewVel) < m_pWorld->m_Tuning.m_HookDragSpeed || length(NewVel) < length(m_Vel))
				m_Vel = NewVel; // no problem. apply

		}

		// release hook (max hook time is 1.25
		m_HookTick++;
		if(m_HookedPlayer != -1 && (m_HookTick > SERVER_TICK_SPEED+SERVER_TICK_SPEED/5 || !m_pWorld->m_apCharacters[m_HookedPlayer]))
		{
			m_HookedPlayer = -1;
			m_HookState = HOOK_RETRACTED;
			m_HookPos = m_Pos;
		}
	}

	if(m_pWorld)
	{
		for(int i = 0; i < MAX_CLIENTS; i++)
		{
			CCharacterCore *pCharCore = m_pWorld->m_apCharacters[i];
			if(!pCharCore)
				continue;

			//player *p = (player*)ent;
			if(pCharCore == this) // || !(p->flags&FLAG_ALIVE)
				continue; // make sure that we don't nudge our self

			// handle player <-> player collision
			float Distance = distance(m_Pos, pCharCore->m_Pos);
			vec2 Dir = normalize(m_Pos - pCharCore->m_Pos);
			if(m_pWorld->m_Tuning.m_PlayerCollision && Distance < PhysSize*1.25f && Distance > 0.0f)
			{
				float a = (PhysSize*1.45f - Distance);
				float Velocity = 0.5f;

				// make sure that we don't add excess force by checking the
				// direction against the current velocity. if not zero.
				if (length(m_Vel) > 0.0001)
					Velocity = 1-(dot(normalize(m_Vel), Dir)+1)/2;

				m_Vel += Dir*a*(Velocity*0.75f);
				m_Vel *= 0.85f;
			}

			// handle hook influence
			if(m_HookedPlayer == i && m_pWorld->m_Tuning.m_PlayerHooking)
			{
				if(Distance > PhysSize*1.50f) // TODO: fix tweakable variable
				{
					float Accel = m_pWorld->m_Tuning.m_HookDragAccel * (Distance/m_pWorld->m_Tuning.m_HookLength);
					float DragSpeed = m_pWorld->m_Tuning.m_HookDragSpeed;

					// add force to the hooked player
					pCharCore->m_Vel.x = SaturatedAdd(-DragSpeed, DragSpeed, pCharCore->m_Vel.x, Accel*Dir.x*1.5f);
					pCharCore->m_Vel.y = SaturatedAdd(-DragSpeed, DragSpeed, pCharCore->m_Vel.y, Accel*Dir.y*1.5f);

					// add a little bit force to the guy who has the grip
					m_Vel.x = SaturatedAdd(-DragSpeed, DragSpeed, m_Vel.x, -Accel*Dir.x*0.25f);
					m_Vel.y = SaturatedAdd(-DragSpeed, DragSpeed, m_Vel.y, -Accel*Dir.y*0.25f);
				}
			}
		}

		// SpeedUps Prediction
		if(InTileSpeed)
		{
			int CurrentIndex = m_pCollision->GetPureMapIndex(m_Pos);
			vec2 Direction, MaxVel, TempVel = m_Vel;
			int Force, MaxSpeed = 0;
			float TeeAngle, SpeederAngle, DiffAngle, SpeedLeft, TeeSpeed;
			m_pCollision->GetSpeedUp(CurrentIndex, &Direction, &Force, &MaxSpeed);
			if(Force == 255 && MaxSpeed)
			{
				m_Vel = Direction * (MaxSpeed/5);
			}
			else
			{
				if(MaxSpeed > 0 && MaxSpeed < 5) MaxSpeed = 5;
				if(MaxSpeed > 0)
				{
					if(Direction.x > 0.0000001f)
						SpeederAngle = -atan(Direction.y / Direction.x);
					else if(Direction.x < 0.0000001f)
						SpeederAngle = atan(Direction.y / Direction.x) + 2.0f * asin(1.0f);
					else if(Direction.y > 0.0000001f)
						SpeederAngle = asin(1.0f);
					else
						SpeederAngle = asin(-1.0f);

					if(SpeederAngle < 0)
						SpeederAngle = 4.0f * asin(1.0f) + SpeederAngle;

					if(TempVel.x > 0.0000001f)
						TeeAngle = -atan(TempVel.y / TempVel.x);
					else if(TempVel.x < 0.0000001f)
						TeeAngle = atan(TempVel.y / TempVel.x) + 2.0f * asin(1.0f);
					else if(TempVel.y > 0.0000001f)
						TeeAngle = asin(1.0f);
					else
						TeeAngle = asin(-1.0f);

					if(TeeAngle < 0)
						TeeAngle = 4.0f * asin(1.0f) + TeeAngle;

					TeeSpeed = sqrt(pow(TempVel.x, 2) + pow(TempVel.y, 2));

					DiffAngle = SpeederAngle - TeeAngle;
					SpeedLeft = MaxSpeed / 5.0f - cos(DiffAngle) * TeeSpeed;

					if(abs(SpeedLeft) > Force && SpeedLeft > 0.0000001f)
						TempVel += Direction * Force;
					else if(abs(SpeedLeft) > Force)
						TempVel += Direction * -Force;
					else
						TempVel += Direction * SpeedLeft;
				}
				else
					TempVel += Direction * Force;

				m_Vel = TempVel;
			}
		}

		// Only in DDRace (Special Weapons) // FIXME: Use vanilla weapons causes mistakes!
		if (str_find_nocase(m_pWorld->m_aGameType, "ddrace"))
		{
			// jetpack and ninjajetpack prediction
			if(!InTileFreeze && UseInput && (m_Input.m_Fire&1) && (m_ActiveWeapon == WEAPON_GUN || m_ActiveWeapon == WEAPON_NINJA))
				m_Vel += TargetDirection * -1.0f * (m_pWorld->m_Tuning.m_JetpackStrength / 100.0f / 6.11f);
		}
		//

		// Predict Stoppers!
		int TilesIndexGame[5] = { -1, -1, -1, -1, -1 }, TilesIndexFront[5] = { -1, -1, -1, -1, -1 }, TilesIndexSwitch[5] = { -1, -1, -1, -1, -1 };
		int TilesFlagsGame[5] = { -1, -1, -1, -1, -1 }, TilesFlagsFront[5] = { -1, -1, -1, -1, -1 }, TilesFlagsSwitch[5] = { -1, -1, -1, -1, -1 };
		m_pCollision->GetRadTiles(CCollision::TILEMAP_GAME, m_Pos, TilesIndexGame, TilesFlagsGame);
		m_pCollision->GetRadTiles(CCollision::TILEMAP_FRONT, m_Pos, TilesIndexFront, TilesFlagsFront);
		m_pCollision->GetRadTiles(CCollision::TILEMAP_SWITCH, m_Pos, TilesIndexSwitch, TilesFlagsSwitch, m_Team);

		if (((TilesIndexGame[0] == TILE_STOP && TilesFlagsGame[0] == ROTATION_270) ||
		      (TilesIndexGame[1] == TILE_STOP && TilesFlagsGame[1] == ROTATION_270) ||
			  (TilesIndexGame[1] == TILE_STOPS && (TilesFlagsGame[1] == ROTATION_90 || TilesFlagsGame[1] == ROTATION_270)) ||
			  (TilesIndexGame[1] == TILE_STOPA) ||
			  (TilesIndexFront[0] == TILE_STOP && TilesFlagsFront[0] == ROTATION_270) ||
			  (TilesIndexFront[1] == TILE_STOP && TilesFlagsFront[1] == ROTATION_270) ||
			  (TilesIndexFront[1] == TILE_STOPS && (TilesFlagsFront[1] == ROTATION_90 || TilesFlagsFront[1] == ROTATION_270)) ||
			  (TilesIndexFront[1] == TILE_STOPA) ||
			  (TilesIndexSwitch[0] == TILE_STOP && TilesFlagsSwitch[0] == ROTATION_270) ||
			  (TilesIndexSwitch[1] == TILE_STOP && TilesFlagsSwitch[1] == ROTATION_270) ||
			  (TilesIndexSwitch[1] == TILE_STOPS && (TilesFlagsSwitch[1] == ROTATION_90 || TilesFlagsSwitch[1] == ROTATION_270)) ||
			  (TilesIndexSwitch[1] == TILE_STOPA)) && m_Vel.x > 0)
		{
			if((int)m_pCollision->GetPos(TilesIndexGame[1]).x < (int)m_Pos.x)
				m_Pos = PrevPos;

			m_Vel.x = 0;
		}
		if (((TilesIndexGame[0] == TILE_STOP && TilesFlagsGame[0] == ROTATION_90) ||
				(TilesIndexGame[2] == TILE_STOP && TilesFlagsGame[2] == ROTATION_90) ||
				(TilesIndexGame[2] == TILE_STOPS && (TilesFlagsGame[2] == ROTATION_90 || TilesFlagsGame[2] == ROTATION_270)) ||
				(TilesIndexGame[2] == TILE_STOPA) ||
				(TilesIndexFront[0] == TILE_STOP && TilesFlagsFront[0] == ROTATION_90) ||
				(TilesIndexFront[2] == TILE_STOP && TilesFlagsFront[2] == ROTATION_90) ||
				(TilesIndexFront[2] == TILE_STOPS && (TilesFlagsFront[2] == ROTATION_90 || TilesFlagsFront[2] == ROTATION_270)) ||
				(TilesIndexFront[2] == TILE_STOPA) ||
				(TilesIndexSwitch[0] == TILE_STOP && TilesFlagsSwitch[0] == ROTATION_90) ||
				(TilesIndexSwitch[2] == TILE_STOP && TilesFlagsSwitch[2] == ROTATION_90) ||
				(TilesIndexSwitch[2] == TILE_STOPS && (TilesFlagsSwitch[2] == ROTATION_90 || TilesFlagsSwitch[2] == ROTATION_270)) ||
				(TilesIndexSwitch[2] == TILE_STOPA)) && m_Vel.x < 0)
		{
			if((int)m_pCollision->GetPos(TilesIndexGame[2]).x < (int)m_Pos.x)
				m_Pos = PrevPos;

			m_Vel.x = 0;
		}
		if (((TilesIndexGame[0] == TILE_STOP && TilesFlagsGame[0] == ROTATION_180) ||
				(TilesIndexGame[4] == TILE_STOP && TilesFlagsGame[4] == ROTATION_180) ||
				(TilesIndexGame[4] == TILE_STOPS && (TilesFlagsGame[4] == ROTATION_0 || TilesFlagsGame[4] == ROTATION_180)) ||
				(TilesIndexGame[4] == TILE_STOPA) ||
				(TilesIndexFront[0] == TILE_STOP && TilesFlagsFront[0] == ROTATION_180) ||
				(TilesIndexFront[4] == TILE_STOP && TilesFlagsFront[4] == ROTATION_180) ||
				(TilesIndexFront[4] == TILE_STOPS && (TilesFlagsFront[4] == ROTATION_0 || TilesFlagsFront[4] == ROTATION_180)) ||
				(TilesIndexFront[4] == TILE_STOPA) ||
				(TilesIndexSwitch[0] == TILE_STOP && TilesFlagsSwitch[0] == ROTATION_180) ||
				(TilesIndexSwitch[4] == TILE_STOP && TilesFlagsSwitch[4] == ROTATION_180) ||
				(TilesIndexSwitch[4] == TILE_STOPS && (TilesFlagsSwitch[4] == ROTATION_0 || TilesFlagsSwitch[4] == ROTATION_180)) ||
				(TilesIndexSwitch[4] == TILE_STOPA)) && m_Vel.y < 0)
		{
			if((int)m_pCollision->GetPos(TilesIndexGame[4]).y < (int)m_Pos.y)
				m_Pos = PrevPos;

			m_Vel.y = 0;
		}
		if(((TilesIndexGame[0] == TILE_STOP && TilesFlagsGame[0] == ROTATION_0) ||
				(TilesIndexGame[3] == TILE_STOP && TilesFlagsGame[3] == ROTATION_0) ||
				(TilesIndexGame[3] == TILE_STOPS && (TilesFlagsGame[3] == ROTATION_0 || TilesFlagsGame[3] == ROTATION_180)) ||
				(TilesIndexGame[3] == TILE_STOPA) ||
				(TilesIndexFront[0] == TILE_STOP && TilesFlagsFront[0] == ROTATION_0) ||
				(TilesIndexFront[3] == TILE_STOP && TilesFlagsFront[3] == ROTATION_0) ||
				(TilesIndexFront[3] == TILE_STOPS && (TilesFlagsFront[3] == ROTATION_0 || TilesFlagsFront[3] == ROTATION_180)) ||
				(TilesIndexFront[3] == TILE_STOPA) ||
				(TilesIndexSwitch[0] == TILE_STOP && TilesFlagsSwitch[0] == ROTATION_0) ||
				(TilesIndexSwitch[3] == TILE_STOP && TilesFlagsSwitch[3] == ROTATION_0) ||
				(TilesIndexSwitch[3] == TILE_STOPS && (TilesFlagsSwitch[3] == ROTATION_0 || TilesFlagsSwitch[3] == ROTATION_180)) ||
				(TilesIndexSwitch[3] == TILE_STOPA)) && m_Vel.y > 0)
		{
			if((int)m_pCollision->GetPos(TilesIndexGame[3]).y < (int)m_Pos.y)
				m_Pos = PrevPos;

			m_Vel.y = 0;
			m_Jumped = 0;
		}
	}

	// clamp the velocity to something sane
	if(length(m_Vel) > 6000)
		m_Vel = normalize(m_Vel) * 6000;
}