// 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; }
// 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; }
// 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; }
//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; }
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); } } } }
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; }
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); } } } }
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; }
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; }
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; }