public override List <RewardPart> calculateRewardParts(EventDefinition eventDefinition, out Int32 finalExp, out Int32 finalCash)
        {
            List <RewardPart> rewardParts = new List <RewardPart>();
            Int32             level       = Access.CurrentSession.ActivePersona.Level;
            Boolean           repLimited  = level >= Data.DataEx.maxLevel;
            Int32             laps        = Math.Max(1, eventDefinition.laps);

            finalExp  = 0;
            finalCash = 0;

            // Base reward
            Reward baseReward = calculateBaseReward(eventDefinition);

            rewardParts.Add(new RewardPart()
            {
                repPart        = baseReward.rep,
                rewardCategory = rank > 3 ? RewardCategory.Objective : RewardCategory.Rank,
                rewardType     = rank > 3 ? RewardType.Finished : RewardType.None,
                tokenPart      = baseReward.tokens
            });

            // Perfect start bonus
            if (perfectStart == 1)
            {
                rewardParts.Add(new RewardPart()
                {
                    repPart        = repLimited ? 0 : 300 * level,
                    rewardCategory = RewardCategory.Bonus,
                    rewardType     = RewardType.PowerupBonus,
                    tokenPart      = 400 * level
                });
            }

            if (numberOfCollisions > 0)
            {
                // Collision penalty
                rewardParts.Add(new RewardPart()
                {
                    repPart        = numberOfCollisions * ((-10 + laps) * 3) * level,
                    rewardCategory = RewardCategory.Base,
                    rewardType     = RewardType.Infractions,
                    tokenPart      = numberOfCollisions * ((-25 + laps) * 6) * level
                });
            }
            else
            {
                // No collision bonus
                rewardParts.Add(new RewardPart()
                {
                    repPart        = repLimited ? 0 : 500 * level * laps,
                    rewardCategory = RewardCategory.Base,
                    rewardType     = RewardType.Infractions,
                    tokenPart      = 600 * level * laps
                });
            }

            if (laps > 1)
            {
                // Best lap time better than third of the circuit race time
                // Second check is to block any abuse; e.g. Doing a lap in a minute and roaming for 2 minutes
                if (bestLapDurationInMilliseconds < eventDurationInMilliseconds / 3 &&
                    bestLapDurationInMilliseconds * laps > eventDurationInMilliseconds - bestLapDurationInMilliseconds)
                {
                    rewardParts.Add(new RewardPart()
                    {
                        repPart        = 2 * Access.CurrentSession.ActivePersona.ReputationRequiredToPassTheLevel / 100,
                        rewardCategory = RewardCategory.Bonus,
                        rewardType     = RewardType.TimeBonus,
                        tokenPart      = 2000 * Access.CurrentSession.ActivePersona.Level
                    });
                }
            }

            foreach (RewardPart rewardPart in rewardParts)
            {
                finalExp  += rewardPart.repPart;
                finalCash += rewardPart.tokenPart;
            }

            return(rewardParts);
        }