internal void FinishMatch(ClientSession session) { if (this.StartedOn != null) { double now = this.StartedOn.Elapsed.TotalSeconds; if (this.LevelData.Seconds > 0 && this.LevelData.Mode != LevelMode.KingOfTheHat && now > (this.LevelData.Seconds + 5)) //Small threashold { return; } if (this.Players.TryGetValue(session.SocketId, out MatchPlayer player) && !player.Forfiet && player.FinishTime == null) { player.FinishTime = now; this.Clients.SendPacket(new PlayerFinishedOutgoingMessage(session.SocketId, (IReadOnlyCollection <MatchPlayer>) this.Players.Values)); ulong expEarned = ExpUtils.GetExpEarnedForFinishing(now); List <object[]> expArray = new List <object[]>(); if (this.LevelData.Mode == LevelMode.Race) { expArray.Add(new object[] { "Level completed", expEarned }); } else if (this.LevelData.Mode == LevelMode.Deathmatch) { expArray.Add(new object[] { "Fighting spirit", expEarned }); } else if (this.LevelData.Mode == LevelMode.HatAttack) { expArray.Add(new object[] { "Hat owner", expEarned }); } else if (this.LevelData.Mode == LevelMode.CoinFiend) { expArray.Add(new object[] { "Coin meizer", expEarned }); } else if (this.LevelData.Mode == LevelMode.DamageDash) { expArray.Add(new object[] { "Damage dealer", expEarned }); } else if (this.LevelData.Mode == LevelMode.KingOfTheHat) { expArray.Add(new object[] { "Hat holder", expEarned }); } bool firstPlace = true; foreach (MatchPlayer other in this.Players.Values) { if (other != player) { bool defeated = false; switch (this.LevelData.Mode) { case LevelMode.Race: case LevelMode.HatAttack: case LevelMode.KingOfTheHat: defeated = other.Forfiet || other.FinishTime == null; break; case LevelMode.Deathmatch: defeated = other.Forfiet || other.FinishTime != null; break; case LevelMode.CoinFiend: defeated = other.Forfiet || player.Coins > other.Coins; break; case LevelMode.DamageDash: defeated = other.Forfiet || player.Dash > other.Dash; break; } if (defeated) { ulong playerExp = (ulong)Math.Round(ExpUtils.GetExpForDefeatingPlayer(other.UserData.Rank) * ExpUtils.GetPlaytimeMultiplayer(other.FinishTime ?? now) * ExpUtils.GetKeyPressMultiplayer(other.KeyPresses)); if (other.IPAddress == player.IPAddress) { playerExp /= 2; } expEarned += playerExp; expArray.Add(new object[] { "Defeated " + other.UserData.Username, playerExp }); } else { firstPlace = false; } } } ulong baseExp = expEarned; if (firstPlace) { MatchPrize prize = Interlocked.Exchange(ref this.Prize, null); if (prize != null) { bool partExp = false; if (prize.Category == "hat") { if (player.UserData.HasHat((Hat)prize.Id)) { partExp = true; } else { player.UserData.GiveHat((Hat)prize.Id); } } else if (prize.Category == "head") { if (player.UserData.HasHead((Part)prize.Id)) { partExp = true; } else { player.UserData.GiveHead((Part)prize.Id); } } else if (prize.Category == "body") { if (player.UserData.HasBody((Part)prize.Id)) { partExp = true; } else { player.UserData.GiveBody((Part)prize.Id); } } else if (prize.Category == "feet") { if (player.UserData.HasFeet((Part)prize.Id)) { partExp = true; } else { player.UserData.GiveFeet((Part)prize.Id); } } if (!prize.RewardsExpBonus) { partExp = false; } if (partExp) { expEarned += (ulong)Math.Round(baseExp * 0.5); expArray.Add(new object[] { "Prize bonus", "EXP X 1.5" }); } session.SendPacket(new PrizeOutgoingMessage(prize, partExp ? "exp" : "got")); } } float expHatBonus = 0; foreach (MatchPlayerHat hat in player.Hats) { if (!hat.Spawned && hat.Hat == Hat.BaseballCap) { expHatBonus += expHatBonus == 0 ? 1f : 0.1f; } } if (expHatBonus > 0) { expEarned += (ulong)Math.Round(baseExp * expHatBonus); expArray.Add(new object[] { "Exp hat", $"EXP X {expHatBonus + 1}" }); } ulong bonusExpDrained = 0; if (player.UserData.BonusExp > 0) { bonusExpDrained = Math.Min(player.UserData.BonusExp, baseExp); if (bonusExpDrained > 0) { expEarned += bonusExpDrained; expArray.Add(new object[] { "Bonus exp", $"EXP X {(bonusExpDrained / baseExp) + 1}" }); expArray.Add(new object[] { "Bonus exp left", player.UserData.BonusExp - bonusExpDrained }); player.UserData.DrainBonusExp(bonusExpDrained); } } session.SendPackets(new YouFinishedOutgoingMessage(session.UserData.Rank, session.UserData.Exp, ExpUtils.GetNextRankExpRequirement(session.UserData.Rank), expEarned, expArray)); player.UserData.AddExp(expEarned); this.CheckGameState(); } } }
internal void Start() { byte[] bytes = new byte[4]; using (RandomNumberGenerator rng = RandomNumberGenerator.Create()) //Why not? { rng.GetBytes(bytes); } Random random = new Random(BitConverter.ToInt32(bytes, 0)); HashSet <string> events = new HashSet <string>(); if (this.LevelData.Snow > random.NextDouble() * 100) { events.Add("snow"); } if (this.LevelData.Wind > random.NextDouble() * 100) { events.Add("wind"); } if (this.LevelData.Mode != LevelMode.KingOfTheHat) { if (this.LevelData.Sfchm > random.NextDouble() * 100) { events.Add("sfchm"); foreach (MatchPlayer player in this.Players.Values) { this.AddHatToPlayer(player, Hat.Cowboy, player.UserData.CurrentHatColor, false); } } else { foreach (MatchPlayer player in this.Players.Values) { if (player.UserData.CurrentHat != Hat.None) { this.AddHatToPlayer(player, player.UserData.CurrentHat, player.UserData.CurrentHatColor, false); } else if (this.LevelData.Mode == LevelMode.HatAttack) { this.AddHatToPlayer(player, Hat.CardboardBox, player.UserData.CurrentHatColor, false); } } } } else { Hat hat = (Hat)this.LevelData.KingOfTheHat[0]; Color hatColor = Color.FromArgb((int)this.LevelData.KingOfTheHat[1]); foreach (Point point in this.FinishBlocks) { this.DropHat(hat, hatColor, (point.X * 40) + 20, (point.Y * 40) + 20); } } if (this.LevelData.Alien > random.NextDouble() * 100) { events.Add("aliens"); } if (this.LevelData.HasPrize && this.LevelData.Prizes.Count > 0) { (string prizeType, uint prizeId) = this.LevelData.Prizes[random.Next(this.LevelData.Prizes.Count)]; this.Prize = new MatchPrize(prizeType, prizeId, rewardsExpBonus: false); } else if (this.Players.Count >= 2) { int diffIpsCount = this.Players.Values.Select((p) => p.IPAddress).Distinct().Count(); if (diffIpsCount >= 2) { double change = diffIpsCount * 5; if (diffIpsCount >= 4) { if (random.Next(40 / diffIpsCount) == 0) { change *= 2; } } if (change > random.NextDouble() * 100) { Part specialPartId = Part.None; if (random.Next(2) == 0) { DateTimeOffset now = DateTimeOffset.UtcNow; if (now >= new DateTimeOffset(now.Year, 10, 24, 0, 0, 0, TimeSpan.Zero) && now < new DateTimeOffset(now.Year, 11, 7, 0, 0, 0, TimeSpan.Zero)) //Halloween { specialPartId = Part.Ghost; } else if (now >= new DateTimeOffset(now.Year, 11, 17, 0, 0, 0, TimeSpan.Zero) && now < new DateTimeOffset(now.Year, 12, 1, 0, 0, 0, TimeSpan.Zero)) //Thanksgiving { specialPartId = Part.Turkey; } else if (now >= new DateTimeOffset(now.Year, 12, 1, 0, 0, 0, TimeSpan.Zero) && now < new DateTimeOffset(now.Year + 1, 1, 1, 0, 0, 0, TimeSpan.Zero)) //Christmas { specialPartId = Part.Reindeer; } } if (specialPartId != Part.None) { uint headsCount = 0; uint bodysCount = 0; uint feetsCount = 0; foreach (MatchPlayer player in this.Players.Values) { if (player.UserData.HasHead(specialPartId)) { headsCount++; } if (player.UserData.HasBody(specialPartId)) { bodysCount++; } if (player.UserData.HasFeet(specialPartId)) { feetsCount++; } } if (this.Players.Count != headsCount || this.Players.Count != bodysCount || this.Players.Count != feetsCount) { HashSet <string> possiblities = new HashSet <string>(); if (this.Players.Count != headsCount) { possiblities.Add("head"); } if (this.Players.Count != bodysCount) { possiblities.Add("body"); } if (this.Players.Count != feetsCount) { possiblities.Add("feet"); } this.Prize = new MatchPrize(possiblities.OrderBy((p) => random.NextDouble()).First(), (uint)specialPartId); } } if (this.Prize == null) { if (random.Next(3333) == 0) { this.Prize = new MatchPrize("hat", (uint)new Hat[] { Hat.None, Hat.BaseballCap, Hat.Cowboy, Hat.Crown }.OrderBy((h) => random.NextDouble()).First()); } } if (this.Prize == null) //No special part was choosen, fallback to default { double prizeTypeChance = random.NextDouble() * 100; if (prizeTypeChance >= 0 && prizeTypeChance <= 89) //Parts { Part part = new Part[] { Part.Brain, Part.Cactus, Part.Cthulhu, Part.Dino, Part.Eye, Part.Hare, Part.Monster, Part.Mushroom, Part.Panda, Part.Platypus, Part.Robot, Part.Skeleton, Part.Spartan, Part.Tiki, Part.Tortoise, Part.Penguin, Part.Dragon, Part.Meteor, Part.Donkey, Part.Sword, Part.Snowman, }.OrderBy((p) => random.NextDouble()).First(); if (prizeTypeChance > 40 && prizeTypeChance <= 67) //Body { this.Prize = new MatchPrize("body", (uint)part); } else if (prizeTypeChance > 67 && prizeTypeChance <= 89) //Head { this.Prize = new MatchPrize("head", (uint)part); } else //Feet { this.Prize = new MatchPrize("feet", (uint)part); } } else if (prizeTypeChance > 89 && prizeTypeChance <= 100) //Hat { Hat hat = new Hat[] { Hat.Propeller, Hat.Santa, Hat.PedroTheSnail, Hat.Top, Hat.Party, Hat.Pirate, Hat.Nurse, Hat.Bouncy, Hat.Shark, Hat.Happy, Hat.Police, Hat.Ushanka, Hat.Toque, Hat.Fez, Hat.Witch, Hat.Halo, }.OrderBy((h) => random.NextDouble()).First(); this.Prize = new MatchPrize("hat", (uint)hat); } } } } } if (this.Prize != null) { this.Clients.SendPacket(new PrizeOutgoingMessage(this.Prize, "available")); } new Timer(this.GameBegun, null, 2664, 0); this.Clients.SendPackets(new EventsOutgoingMessage(events), new BeginMatchOutgoingMessage()); LevelManager.AddPlaysAsync(this.LevelData.Id, (uint)this.Players.Count); //Lets do the most important thing now! }