/// <summary> /// Peforms a physics tick /// </summary> /// <param name="worldPlayer">The player</param> private void Tick(WorldPlayer worldPlayer) { int cx = ((int)(worldPlayer.X + 8) >> 4); int cy = ((int)(worldPlayer.Y + 8) >> 4); worldPlayer.m_current = (int)World[cx, cy, Layer.Foreground].ID; if (worldPlayer.Current == (BlockID)4 || IsClimbable(worldPlayer.Current)) { worldPlayer.m_delayed = worldPlayer.m_queue[1]; worldPlayer.m_queue[0] = worldPlayer.m_current; } else { worldPlayer.m_delayed = worldPlayer.m_queue[0]; worldPlayer.m_queue[0] = worldPlayer.m_queue[1]; } worldPlayer.m_queue[1] = worldPlayer.m_current; if (worldPlayer.IsDead) { worldPlayer.Horizontal = 0; worldPlayer.Vertical = 0; } bool isGodMode = worldPlayer.IsGod(); if (isGodMode) { worldPlayer.m_morx = 0; worldPlayer.m_mory = 0; worldPlayer.m_mox = 0; worldPlayer.m_moy = 0; } else { switch (worldPlayer.Current) { case BlockID.GravityLeft: case BlockID.InvisibleGravityLeft: worldPlayer.m_morx = -Gravity; worldPlayer.m_mory = 0; break; case BlockID.GravityUp: case BlockID.InvisibleGravityUp: worldPlayer.m_morx = 0; worldPlayer.m_mory = -Gravity; break; case BlockID.GravityRight: case BlockID.InvisibleGravityRight: worldPlayer.m_morx = Gravity; worldPlayer.m_mory = 0; break; case BlockID.BoostLeft: case BlockID.BoostRight: case BlockID.BoostUp: case BlockID.BoostDown: case BlockID.LadderNinja: case BlockID.LadderCastle: case BlockID.LadderJungleHorizontal: case BlockID.LadderJungleVertical: case BlockID.InvisibleGravityDot: case BlockID.GravityDot: worldPlayer.m_morx = 0; worldPlayer.m_mory = 0; break; case BlockID.Water: worldPlayer.m_morx = Gravity; worldPlayer.m_mory = (int)WaterBuoyancy; break; case BlockID.Mud: worldPlayer.m_morx = Gravity; worldPlayer.m_mory = (int)MudBuoyancy; break; case BlockID.HazardFire: case BlockID.HazardSpike: if (!worldPlayer.IsDead && !worldPlayer.HasProtection) { worldPlayer.KillPlayerInternal(); } break; default: worldPlayer.m_morx = 0; worldPlayer.m_mory = Gravity; break; } switch ((BlockID)worldPlayer.m_delayed) { case BlockID.GravityLeft: case BlockID.InvisibleGravityLeft: worldPlayer.m_mox = -Gravity; worldPlayer.m_moy = 0; break; case BlockID.GravityUp: case BlockID.InvisibleGravityUp: worldPlayer.m_mox = 0; worldPlayer.m_moy = -Gravity; break; case BlockID.GravityRight: case BlockID.InvisibleGravityRight: worldPlayer.m_mox = Gravity; worldPlayer.m_moy = 0; break; case BlockID.BoostLeft: case BlockID.BoostRight: case BlockID.BoostUp: case BlockID.BoostDown: case BlockID.LadderNinja: case BlockID.LadderCastle: case BlockID.LadderJungleHorizontal: case BlockID.LadderJungleVertical: case BlockID.InvisibleGravityDot: case BlockID.GravityDot: worldPlayer.m_mox = 0; worldPlayer.m_moy = 0; break; case BlockID.Water: worldPlayer.m_mox = Gravity; worldPlayer.m_moy = (int)WaterBuoyancy; break; case BlockID.Mud: worldPlayer.m_mox = Gravity; worldPlayer.m_moy = (int)MudBuoyancy; break; default: worldPlayer.m_mox = 0; worldPlayer.m_moy = Gravity; break; } } if (worldPlayer.m_moy == WaterBuoyancy || worldPlayer.m_moy == MudBuoyancy) { worldPlayer.m_mx = worldPlayer.Horizontal; worldPlayer.m_my = worldPlayer.Vertical; } else if (worldPlayer.m_moy != 0) { worldPlayer.m_mx = worldPlayer.Horizontal; worldPlayer.m_my = 0; } else if (worldPlayer.m_mox != 0) { worldPlayer.m_mx = 0; worldPlayer.m_my = worldPlayer.Vertical; } else { worldPlayer.m_mx = worldPlayer.Horizontal; worldPlayer.m_my = worldPlayer.Vertical; } worldPlayer.m_mx *= worldPlayer.SpeedMultiplier; worldPlayer.m_my *= worldPlayer.SpeedMultiplier; worldPlayer.m_mox *= World.Gravity; worldPlayer.m_moy *= World.Gravity; worldPlayer.ModifierX = worldPlayer.m_mox + worldPlayer.m_mx; worldPlayer.ModifierY = worldPlayer.m_moy + worldPlayer.m_my; if (!ApproachingZero(worldPlayer.m_speedX) || worldPlayer.m_modifierX != 0) { worldPlayer.m_speedX += worldPlayer.m_modifierX; worldPlayer.m_speedX *= BaseDrag; if ((worldPlayer.m_mx == 0 && worldPlayer.m_moy != 0) || (worldPlayer.m_speedX < 0 && worldPlayer.m_mx > 0) || (worldPlayer.m_speedX > 0 && worldPlayer.m_mx < 0) || (IsClimbable(worldPlayer.Current) && !isGodMode)) { worldPlayer.m_speedX *= NoModifierDrag; } else if (worldPlayer.Current == BlockID.Water && !isGodMode) { worldPlayer.m_speedX *= WaterDrag; } else if (worldPlayer.Current == BlockID.Mud && !isGodMode) { worldPlayer.m_speedX *= MudDrag; } if (worldPlayer.m_speedX > 16) { worldPlayer.m_speedX = 16; } else if (worldPlayer.m_speedX < -16) { worldPlayer.m_speedX = -16; } else if (worldPlayer.m_speedX < 0.0001 && worldPlayer.m_speedX > -0.0001) { worldPlayer.m_speedX = 0; } } if (!ApproachingZero(worldPlayer.m_speedY) || worldPlayer.m_modifierY != 0) { worldPlayer.m_speedY += worldPlayer.m_modifierY; worldPlayer.m_speedY *= BaseDrag; if ((worldPlayer.m_my == 0 && worldPlayer.m_mox != 0) || (worldPlayer.m_speedY < 0 && worldPlayer.m_my > 0) || (worldPlayer.m_speedY > 0 && worldPlayer.m_my < 0) || (IsClimbable(worldPlayer.Current) && !isGodMode)) { worldPlayer.m_speedY *= NoModifierDrag; } else if (worldPlayer.Current == BlockID.Water && !isGodMode) { worldPlayer.m_speedY *= WaterDrag; } else if (worldPlayer.Current == BlockID.Mud && !isGodMode) { worldPlayer.m_speedY *= MudDrag; } if (worldPlayer.m_speedY > 16) { worldPlayer.m_speedY = 16; } else if (worldPlayer.m_speedY < -16) { worldPlayer.m_speedY = -16; } else if (worldPlayer.m_speedY < 0.0001 && worldPlayer.m_speedY > -0.0001) { worldPlayer.m_speedY = 0; } } if (!isGodMode) { switch (worldPlayer.Current) { case BlockID.BoostLeft: worldPlayer.m_speedX = -Boost; break; case BlockID.BoostRight: worldPlayer.m_speedX = Boost; break; case BlockID.BoostUp: worldPlayer.m_speedY = -Boost; break; case BlockID.BoostDown: worldPlayer.m_speedY = Boost; break; } } double remainderX = worldPlayer.X % 1; double currentSX = worldPlayer.m_speedX; double remainderY = worldPlayer.Y % 1; double currentSY = worldPlayer.m_speedY; worldPlayer.m_donex = false; worldPlayer.m_doney = false; while ((currentSX != 0 && !worldPlayer.m_donex) || (currentSY != 0 && !worldPlayer.m_doney)) { ProcessPortals(worldPlayer, ref remainderX, ref currentSX, ref remainderY, ref currentSY); StepX(worldPlayer, ref remainderX, ref currentSX, ref remainderY, ref currentSY); StepY(worldPlayer, ref remainderX, ref currentSX, ref remainderY, ref currentSY); } if (!worldPlayer.IsDead) { if (worldPlayer.SpaceDown) { if (worldPlayer.HasLevitation) { worldPlayer.m_isThrusting = true; worldPlayer.m_currentThrust = MaxThrust; } } else if (worldPlayer.HasLevitation) { worldPlayer.m_isThrusting = false; } switch (worldPlayer.Current) { case BlockID.CoinGold: lock (worldPlayer.CollectedGoldCoins) { bool alreadyCollected = false; for (int i = 0; i < worldPlayer.CollectedGoldCoins.Count; i++) { if (worldPlayer.CollectedGoldCoins[i].X == cx && worldPlayer.CollectedGoldCoins[i].Y == cy) { alreadyCollected = true; break; } } if (!alreadyCollected) { worldPlayer.CollectedGoldCoins.Add(World[cx, cy, Layer.Foreground]); } } break; case BlockID.CoinBlue: lock (worldPlayer.CollectedBlueCoins) { bool alreadyCollected = false; for (int i = 0; i < worldPlayer.CollectedBlueCoins.Count; i++) { if (worldPlayer.CollectedBlueCoins[i].X == cx && worldPlayer.CollectedBlueCoins[i].Y == cy) { alreadyCollected = true; break; } } if (!alreadyCollected) { worldPlayer.CollectedBlueCoins.Add(World[cx, cy, Layer.Foreground]); } } break; } if (worldPlayer.m_pastx != cx || worldPlayer.m_pasty != cy) { switch (worldPlayer.Current) { case BlockID.SwitchPurple: if (World[cx, cy, Layer.Foreground] is PurpleBlock) { PurpleBlock block = (PurpleBlock)World[cx, cy, Layer.Foreground]; worldPlayer.m_switches[block.SwitchID] = !worldPlayer.m_switches[block.SwitchID]; } break; case BlockID.ToolCheckpoint: if (!isGodMode) { worldPlayer.LastCheckpoint = World[cx, cy, Layer.Foreground]; } break; } worldPlayer.m_pastx = cx; worldPlayer.m_pasty = cy; } if (worldPlayer.HasLevitation) { UpdateThrust(worldPlayer); } } var imx = ((int)worldPlayer.m_speedX << 8); var imy = ((int)worldPlayer.m_speedY << 8); if (worldPlayer.Current != BlockID.Water && worldPlayer.Current != BlockID.Mud) { if (imx == 0) { if (worldPlayer.m_modifierX < 0.1 && worldPlayer.m_modifierX > -0.1) { double tx = worldPlayer.X % 16; if (tx < 2) { if (tx < 0.2) { worldPlayer.X = Math.Floor(worldPlayer.X); } else { worldPlayer.X -= tx / 15; } } else { if (tx > 14) { if (tx > 15.8) { worldPlayer.X = Math.Ceiling(worldPlayer.X); } else { worldPlayer.X += (tx - 14) / 15; } } } } } if (imy == 0) { if (worldPlayer.m_modifierY < 0.1 && worldPlayer.m_modifierY > -0.1) { double ty = worldPlayer.Y % 16; if (ty < 2) { if (ty < 0.2) { worldPlayer.Y = Math.Floor(worldPlayer.Y); } else { worldPlayer.Y -= ty / 15; } } else { if (ty > 14) { if (ty > 15.8) { worldPlayer.Y = Math.Ceiling(worldPlayer.Y); } else { worldPlayer.Y += (ty - 14) / 15; } } } } } } }