PlayerCatalog.cs

Static catalogue of player cards for a football game. Builds academy players procedurally per country, adds curated professional entries with real names and portrait data, and generates detailed attribute breakdowns for cards.

Rough Code
using System;
using System.Collections.Generic;
using System.Linq;

namespace Socer;

// Original, finite player identities. A catalogue entry has one immutable base card.
// Professional entries use real names and countries with original game ratings and procedural portraits.
public static partial class PlayerCatalog
{
    sealed record CountryNames(string Country, string Code, string Flag, string[] First, string[] Last);
    static readonly CountryNames[] Countries={
        new("Russia","RU","🇷🇺",new[]{"Alexei","Mikhail","Dmitri","Pavel","Ilya","Nikita","Roman","Artem"},new[]{"Belov","Morozov","Sokolov","Lebedev","Orlov","Volkov","Kuznetsov","Zaitsev"}),
        new("England","GB","🇬🇧",new[]{"Oliver","Harry","Jack","Ethan","George","Noah","Oscar","Lewis"},new[]{"Bennett","Palmer","Fletcher","Hayes","Turner","Cooper","Dawson","Brooks"}),
        new("Spain","ES","🇪🇸",new[]{"Alejandro","Hugo","Daniel","Pablo","Sergio","Marcos","Diego","Adrian"},new[]{"Navarro","Serrano","Romero","Cabrera","Molina","Vega","Iglesias","Paredes"}),
        new("France","FR","🇫🇷",new[]{"Lucas","Theo","Hugo","Louis","Gabriel","Maxime","Enzo","Raphael"},new[]{"Moreau","Laurent","Lefevre","Roux","Faure","Garnier","Brunet","Chevalier"}),
        new("Germany","DE","🇩🇪",new[]{"Lukas","Leon","Felix","Jonas","Finn","Maximilian","Moritz","Julian"},new[]{"Schneider","Fischer","Weber","Hoffmann","Becker","Schulz","Hartmann","Krause"}),
        new("Brazil","BR","🇧🇷",new[]{"Mateus","Gabriel","Lucas","Rafael","Joao","Bruno","Caio","Pedro"},new[]{"Almeida","Carvalho","Pereira","Barbosa","Monteiro","Cardoso","Teixeira","Andrade"}),
        new("Argentina","AR","🇦🇷",new[]{"Tomas","Mateo","Santiago","Nicolas","Facundo","Lautaro","Emiliano","Joaquin"},new[]{"Acosta","Benitez","Ferreyra","Sosa","Rojas","Quiroga","Peralta","Medina"}),
        new("Japan","JP","🇯🇵",new[]{"Haruto","Ren","Takumi","Daichi","Yuto","Kaito","Sota","Riku"},new[]{"Tanaka","Yamamoto","Nakamura","Kobayashi","Sato","Matsumoto","Inoue","Shimizu"})
    };
    static readonly string[] Roles={"ВР","КЗ","ЦЗ","ЦП","КП","НП"};
    static List<PlayerCard> cards;
    static PlayerCard[] legendaryCards;
    static bool building;
    public static IReadOnlyList<PlayerCard> All=>cards??=Build();
    public static PlayerCard Find(string catalogId)=>(building?cards?.FirstOrDefault(c=>c.CatalogId==catalogId):All.FirstOrDefault(c=>c.CatalogId==catalogId))??FindHistorical(catalogId);
    public static void Reload(){faceData=null;historicalIdentities=null;cards=Build();legendaryCards=null;}
    // Red editions share a football identity with their base card, but have an
    // authored match profile. Pack and rival pools still use All.
    public static IReadOnlyList<PlayerCard> LegendaryCards=>legendaryCards??=LegendaryAbilities.All.Select(info=>{
        string id=info.CatalogId;
        var card=Clone(Find(id));card.Edition=CardRatings.Legendary;ApplyLegendaryProfile(card);return card;
    }).ToArray();
    public static IEnumerable<PlayerCard> CardVariants=>All.Concat(LegendaryCards);
    public static PlayerCard FindVariant(string key)=>string.IsNullOrEmpty(key)?null:CardVariants.FirstOrDefault(card=>card.CardKey==key);
    public static IEnumerable<PlayerCard> SortCardVariants(IEnumerable<PlayerCard> source,bool byType)=>byType
        ? source.OrderBy(CardRatings.TypeRank).ThenByDescending(p=>p.Overall).ThenBy(p=>p.Name)
        : source.OrderByDescending(p=>p.Overall).ThenBy(p=>p.Name).ThenByDescending(CardRatings.TypeRank);

    public static void ApplyLegendaryProfile(PlayerCard card)
    {
        if(card?.Edition!=CardRatings.Legendary)return;
        // Profiles retain position-specific weaknesses. The red rating is the
        // authored edition quality; football still uses each detailed attribute.
        var target=card.CatalogId switch
        {
            "PRO-12"=>new[]{98,99,82,97,47,98,96,92,97},
            "PRO-24"=>new[]{99,99,88,97,29,88,95,83,97},
            "PRO-53"=>new[]{88,99,83,93,34,89,95,94,97},
            "PRO-23"=>new[]{94,98,99,99,33,72,95,64,99},
            "PRO-54"=>new[]{91,99,86,95,36,99,96,92,98},
            "PRO-55"=>new[]{78,88,99,97,75,76,97,64,99},
            "PRO-56"=>new[]{94,62,86,83,99,97,98,84,99},
            "PRO-57"=>new[]{64,14,88,29,19,86,96,62,99},
            _=>null
        };
        if(target==null)return;
        card.Pace=Math.Max(card.Pace,target[0]);card.Shooting=Math.Max(card.Shooting,target[1]);
        card.Passing=Math.Max(card.Passing,target[2]);card.Dribbling=Math.Max(card.Dribbling,target[3]);
        card.Defence=Math.Max(card.Defence,target[4]);card.Physical=Math.Max(card.Physical,target[5]);
        card.Endurance=Math.Max(card.Endurance,target[6]);card.Aggression=Math.Max(card.Aggression,target[7]);
        card.Composure=Math.Max(card.Composure,target[8]);
        if(card.CatalogId=="PRO-57")card.Keeping=98;
        card.Potential=99;card.StatCaps=Array.Empty<int>();card.TrainingTargets=Array.Empty<int>();
        CardDevelopment.Initialize(card);
        card.Details=PlayerCardDetails.Generate(card);
    }

    static List<PlayerCard> Build()
    {
        building=true;
        var result=new List<PlayerCard>();
        foreach(var country in Countries)
        for(int index=0;index<28;index++)
        {
            // Twenty-eight distinct first/last pairs per country; existing catalogue IDs stay stable.
            string id=$"{country.Code}-{index:00}";
            uint hash=Hash(id);
            int tier=index<24?index/12:index%2;
            int quality=tier==0?48+(int)(hash%17):65+(int)(hash%10);
            var rng=new Random(unchecked((int)hash));
            int Stat(int offset)=>Math.Clamp(quality+offset+rng.Next(-4,5),1,CardRatings.Max);
            string role=Roles[(index+(index>=24?(int)(Hash(country.Code)%6):0))%6];
            string preferred=PlayerPositions.ForRole(role,hash);
            // Academy ratings are shaped by football position, not a shared all-round roll.
            var offsets=preferred switch
            {
                "GK" => new[]{-14,-32,-15,-24,-22,-2,-10,3},
                "CB" => new[]{-6,-26,-10,-11,5,6,3,-40},
                "LB" or "RB" or "LWB" or "RWB" => new[]{5,-19,-2,1,4,-2,4,-40},
                "CDM" => new[]{-8,-14,4,-5,4,4,4,-40},
                "CAM" => new[]{2,4,6,7,-22,-10,-3,-40},
                "LM" or "RM" => new[]{7,-4,3,6,-20,-8,2,-40},
                "LW" or "RW" => new[]{8,5,-2,7,-27,-10,0,-40},
                "ST" => new[]{4,8,-12,1,-30,0,2,-40},
                _ => new[]{-3,-6,6,4,-9,-3,4,-40}
            };
            var card=new PlayerCard {
                CatalogId=id, Name=country.First[index%8]+" "+country.Last[(index/8*3+index%8*5)%8],
                Country=country.Country, CountryCode=country.Code, Flag=country.Flag,
                Position=role,PreferredPosition=preferred,
                Pace=Stat(offsets[0]),Shooting=Stat(offsets[1]),Passing=Stat(offsets[2]),
                Dribbling=Stat(offsets[3]),Defence=Stat(offsets[4]),Physical=Stat(offsets[5]),
                Endurance=Stat(offsets[6]),Keeping=preferred=="GK"?Stat(offsets[7]):rng.Next(5,19),
                Aggression=Stat(preferred=="CB" || preferred=="CDM"?1:-9),Composure=Stat(preferred=="GK" || preferred=="ST"?1:3),
                Foot=rng.Next(5)==0?"Left":"Right",WeakFoot=1+rng.Next(5),SkillMoves=1+rng.Next(5),
                Age=18+rng.Next(18),HeightCm=166+rng.Next(31)
            };
            int specialty=(int)((hash/31)%4);
            if(preferred!="GK")
            {
                if(specialty==0){card.Pace=Math.Min(99,card.Pace+12);card.Physical=Math.Max(1,card.Physical-12);}
                if(specialty==1){card.Physical=Math.Min(99,card.Physical+12);card.Pace=Math.Max(1,card.Pace-12);}
                if(specialty==2){card.Passing=Math.Min(99,card.Passing+10);card.Dribbling=Math.Max(1,card.Dribbling-10);}
                if(specialty==3){card.Dribbling=Math.Min(99,card.Dribbling+10);card.Passing=Math.Max(1,card.Passing-10);}
            }
            card.SkillMoves=preferred is "LW" or "RW" or "CAM"?2+rng.Next(3):preferred=="GK"?1:1+rng.Next(3);
            TuneOverall(card,quality);
            CardDevelopment.Initialize(card);
            card.Details=PlayerCardDetails.Generate(card);
            result.Add(card);
        }
        AddProfessionals(result);
        AddMoreProfessionals(result);
        building=false;return result;
    }
    static void AddProfessionals(List<PlayerCard> result)
    {
        int professionalId=1;
        // Historical values below are converted to the game's 99-point scale on insertion.
        void Add(string name,string country,string code,string flag,string role,string preferred,bool elite,
            int pace,int shooting,int passing,int defence,int endurance,int keeping,
            string foot,int skin,int hair,int style,int beard)
        {
            string id=$"PRO-{professionalId++:00}";
            uint hash=Hash(id);
            var card=new PlayerCard{
                CatalogId=id,Name=name,Country=country,CountryCode=code,Flag=flag,Position=role,PreferredPosition=preferred,
                Pace=pace,Shooting=shooting,Passing=passing,Defence=defence,Endurance=endurance,Keeping=keeping,
                Aggression=elite?89:82,Composure=elite?112:98,Foot=foot,
                WeakFoot=2+(int)(hash%4),SkillMoves=2+(int)((hash/7)%4),Age=0,HeightCm=0,
                PortraitSkin=skin,PortraitHair=hair,PortraitStyle=style,PortraitBeard=beard
            };
            ScaleCard(card);
            if(name=="Erling Haaland")
            {
                // The supplied FUTBIN screenshot is the face-rating reference for this archetype.
                card.Pace=87;card.Shooting=92;card.Passing=71;card.Dribbling=80;
                card.Defence=47;card.Physical=89;card.Endurance=80;card.Aggression=88;card.Composure=86;
                // Explicit card data from the supplied player reference.
                card.PlayStyles=PlayStyle.ChipShot|PlayStyle.PowerShot|PlayStyle.PrecisionHeader|
                    PlayStyle.Acrobatic|PlayStyle.Enforcer;
                card.PlayStylesPlus=PlayStyle.Enforcer;
            }
            else if(name=="Kylian Mbappé")
            {
                card.Pace=96;card.Shooting=91;card.Passing=80;card.Dribbling=92;
                card.Defence=29;card.Physical=76;
            }
            CuratedFace(card);
            CardDevelopment.Initialize(card);
            card.Details=PlayerCardDetails.Generate(card);
            result.Add(card);
        }
        // PortraitBeard: 0 draws a beard; 2 keeps the face clean.
        // Gold: two athletes for each of the six broad positions.
        Add("Gianluigi Donnarumma","Italy","IT","🇮🇹","ВР","GK",false,80,45,86,50,92,108,"Right",1,0,2,0);
        Add("Alisson Becker","Brazil","BR","🇧🇷","ВР","GK",false,84,50,91,55,94,109,"Right",2,0,2,0);
        Add("Achraf Hakimi","Morocco","MA","🇲🇦","КЗ","RB",false,112,82,95,95,100,20,"Right",3,0,2,2);
        Add("Trent Alexander-Arnold","England","GB","🇬🇧","КЗ","RB",false,91,88,110,95,98,20,"Right",2,0,1,2);
        Add("Virgil van Dijk","Netherlands","NL","🇳🇱","ЦЗ","CB",false,91,75,94,105,98,20,"Right",3,0,2,2);
        Add("Antonio Rüdiger","Germany","DE","🇩🇪","ЦЗ","CB",false,96,70,92,103,99,20,"Right",4,0,4,2);
        Add("Jude Bellingham","England","GB","🇬🇧","ЦП","CM",false,102,95,104,90,104,20,"Right",3,0,2,2);
        Add("Rodri","Spain","ES","🇪🇸","ЦП","CDM",false,89,88,110,104,103,20,"Right",1,0,2,2);
        Add("Mohamed Salah","Egypt","EG","🇪🇬","КП","RW",false,110,110,102,55,100,20,"Left",3,0,1,0);
        Add("Bukayo Saka","England","GB","🇬🇧","КП","RW",false,109,99,103,70,102,20,"Left",3,0,2,2);
        Add("Harry Kane","England","GB","🇬🇧","НП","ST",false,85,112,102,60,100,20,"Right",1,1,0,2);
        Add("Erling Haaland","Norway","NO","🇳🇴","НП","ST",true,104,109,83,52,105,20,"Left",0,3,5,2);
        // Every identity retains a single football profile across artwork editions.
        Add("Thibaut Courtois","Belgium","BE","🇧🇪","ВР","GK",true,85,48,93,56,100,118,"Left",1,0,2,2);
        Add("Manuel Neuer","Germany","DE","🇩🇪","ВР","GK",false,95,60,110,65,102,116,"Right",0,2,2,2);
        Add("Theo Hernández","France","FR","🇫🇷","КЗ","LB",true,118,93,104,108,110,20,"Left",2,0,2,0);
        Add("Alphonso Davies","Canada","CA","🇨🇦","КЗ","LB",true,120,90,106,106,112,20,"Left",4,0,2,2);
        Add("Rúben Dias","Portugal","PT","🇵🇹","ЦЗ","CB",true,96,75,105,116,108,20,"Right",1,0,2,2);
        Add("William Saliba","France","FR","🇫🇷","ЦЗ","CB",true,103,74,104,114,110,20,"Right",3,0,2,2);
        Add("Kevin De Bruyne","Belgium","BE","🇧🇪","ЦП","CAM",true,98,110,119,75,105,20,"Right",0,3,0,2);
        Add("Pedri","Spain","ES","🇪🇸","ЦП","CM",true,111,99,117,85,109,20,"Right",1,0,2,2);
        Add("Vinícius Júnior","Brazil","BR","🇧🇷","КП","LW",true,120,110,110,55,110,20,"Right",4,0,1,2);
        Add("Lamine Yamal","Spain","ES","🇪🇸","КП","RW",true,118,107,116,60,108,20,"Left",2,0,1,2);
        Add("Lionel Messi","Argentina","AR","🇦🇷","НП","ST",true,110,118,120,48,100,20,"Left",1,0,0,0);
        Add("Kylian Mbappé","France","FR","🇫🇷","НП","ST",true,120,118,104,50,113,20,"Right",3,0,4,2);
    }
    public static PlayerCard Draw(Random rng, IEnumerable<string> excluded, string role, int quality)
    {
        var used=new HashSet<string>(excluded??Array.Empty<string>(),StringComparer.Ordinal);
        int tier=quality>=CardRatings.Elite?3:quality>=CardRatings.Gold?2:quality>=CardRatings.Silver?1:0;
        int CardTier(PlayerCard c)=>c.Overall>=CardRatings.Elite?3:c.Overall>=CardRatings.Gold?2:c.Overall>=CardRatings.Silver?1:0;
        var pool=All.Where(c=>c.Position==role && CardTier(c)==tier && !used.Contains(c.CatalogId)).ToList();
        if(pool.Count==0)pool=All.Where(c=>CardTier(c)==tier && !used.Contains(c.CatalogId)).ToList();
        if(pool.Count==0)return null;
        int nearest=pool.Min(c=>Math.Abs(c.Overall-quality));
        pool=pool.Where(c=>Math.Abs(c.Overall-quality)<=nearest+2).ToList();
        var baseCard=pool[rng.Next(pool.Count)];
        return Clone(baseCard);
    }
    public static PlayerCard Clone(PlayerCard c)=>new(){
        CatalogId=c.CatalogId,IsAcademyLoan=c.IsAcademyLoan,AcademyPortraitId=c.AcademyPortraitId,
        Name=c.Name,Country=c.Country,CountryCode=c.CountryCode,Flag=c.Flag,PreferredPosition=c.PreferredPosition,
        Position=c.Position,Pace=c.Pace,Shooting=c.Shooting,Passing=c.Passing,Dribbling=c.Dribbling,Defence=c.Defence,Physical=c.Physical,
        Endurance=c.Endurance,Keeping=c.Keeping,Aggression=c.Aggression,Composure=c.Composure,
        Foot=c.Foot,WeakFoot=c.WeakFoot,SkillMoves=c.SkillMoves,Age=c.Age,HeightCm=c.HeightCm,
        PortraitSkin=c.PortraitSkin,PortraitHair=c.PortraitHair,PortraitStyle=c.PortraitStyle,PortraitBeard=c.PortraitBeard,
        Details=PlayerCardDetails.Generate(c),PlayStyles=c.PlayStyles,PlayStylesPlus=c.PlayStylesPlus,
        Potential=c.Potential,StatCaps=c.StatCaps?.ToArray()??Array.Empty<int>(),TrainingTargets=c.TrainingTargets?.ToArray()??Array.Empty<int>(),Edition=c.Edition,UniqueSkill=c.UniqueSkill,
        SkillLoadout=UniqueSkills.CloneLoadout(c.SkillLoadout),SkillLoadoutVersion=c.SkillLoadoutVersion,SkillRerolls=c.SkillRerolls
    };
    static void ScaleCard(PlayerCard card)
    {
        card.Pace=CardRatings.FromLegacy(card.Pace);card.Shooting=CardRatings.FromLegacy(card.Shooting);
        card.Passing=CardRatings.FromLegacy(card.Passing);card.Defence=CardRatings.FromLegacy(card.Defence);
        card.Endurance=CardRatings.FromLegacy(card.Endurance);card.Keeping=CardRatings.FromLegacy(card.Keeping);
        card.Aggression=CardRatings.FromLegacy(card.Aggression);card.Composure=CardRatings.FromLegacy(card.Composure);
        card.Dribbling=Math.Clamp((card.Pace+card.Passing+card.Composure)/3,1,CardRatings.Max);
        card.Physical=Math.Clamp((card.Endurance+card.Aggression)/2,1,CardRatings.Max);
    }
    public static void TuneOverall(PlayerCard card,int target)
    {
        string role=PlayerPositions.Card(card);
        for(int attempt=0;attempt<6 && card.Overall!=target;attempt++)
        {
            int delta=target-card.Overall;
            static int Shift(int stat,int change)=>Math.Clamp(stat+change,1,CardRatings.Max);
            // Only move attributes that matter to this position. The weak side stays weak.
            if(role=="GK")card.Keeping=Shift(card.Keeping,delta);
            else if(role=="CB"){card.Defence=Shift(card.Defence,delta);card.Physical=Shift(card.Physical,delta);}
            else if(role is "LB" or "RB" or "LWB" or "RWB" or "CDM")
            {card.Defence=Shift(card.Defence,delta);card.Pace=Shift(card.Pace,delta);card.Passing=Shift(card.Passing,delta);card.Dribbling=Shift(card.Dribbling,delta);card.Physical=Shift(card.Physical,delta);}
            else if(role=="ST")
            {card.Shooting=Shift(card.Shooting,delta);card.Pace=Shift(card.Pace,delta);card.Dribbling=Shift(card.Dribbling,delta);card.Physical=Shift(card.Physical,delta);}
            else
            {card.Passing=Shift(card.Passing,delta);card.Pace=Shift(card.Pace,delta);card.Shooting=Shift(card.Shooting,delta);card.Dribbling=Shift(card.Dribbling,delta);}
        }
    }
    public static uint Hash(string value)
    {
        uint h=2166136261;
        foreach(char c in value.ToUpperInvariant()){h^=c;h*=16777619;}
        return h;
    }
}

public static class PlayerCardDetails
{
    public static (string Name,int Value)[] Summary(PlayerCard p)
    {
        if(PlayerPositions.Card(p)=="GK")
        {
            var g=Get(p);
            return new[]{("DIV",g.GkDiving),("HAN",g.GkHandling),("KIC",g.GkKicking),
                ("REF",g.GkReflexes),("SPD",p.Pace),("POS",g.GkPositioning)};
        }
        return new[]{("PAC",p.Pace),("SHO",p.Shooting),("PAS",p.Passing),
            ("DRI",Dribbling(p)),("DEF",p.Defence),("PHY",Physical(p))};
    }
    public static int Dribbling(PlayerCard p)=>p.Dribbling>0?Math.Clamp(p.Dribbling,1,CardRatings.Max):Math.Clamp((p.Pace+p.Passing+p.Composure)/3,1,CardRatings.Max);
    public static int Physical(PlayerCard p)=>p.Physical>0?Math.Clamp(p.Physical,1,CardRatings.Max):Math.Clamp((p.Endurance+p.Aggression)/2,1,CardRatings.Max);
    public static PlayerDetailStats Get(PlayerCard p)=>p.Details is {Acceleration:>0}?p.Details:Generate(p);
    public static PlayerDetailStats Generate(PlayerCard p)
    {
        int C(int value)=>Math.Clamp(value,1,CardRatings.Max);
        int V(int id)=>(int)(PlayerCatalog.Hash(p.CatalogId+":"+id)%13)-6;
        string role=PlayerPositions.Card(p);
        bool striker=role=="ST",centreBack=role=="CB",keeper=role=="GK";
        bool wide=role is "LB" or "RB" or "LWB" or "RWB" or "LM" or "RM" or "LW" or "RW";
        int d=Dribbling(p),phy=Physical(p),height=p.HeightCm>0?p.HeightCm:180;
        var s=new PlayerDetailStats{
            Acceleration=C(p.Pace+(height>190?-5:height<175?3:0)+V(1)),SprintSpeed=C(p.Pace+(height>190?4:1)+V(2)),
            Positioning=C(p.Shooting+(striker?5:centreBack?-11:0)+V(3)),Finishing=C(p.Shooting+(striker?5:centreBack?-10:0)+V(4)),
            ShotPower=C(p.Shooting+(phy>80?3:0)+V(5)),LongShots=C(p.Shooting-5+V(6)),
            Volleys=C(p.Shooting-4+V(7)),Penalties=C(p.Shooting-6+V(8)),
            Vision=C(p.Passing+(wide?-1:3)+V(9)),Crossing=C(p.Passing+(wide?4:-12)+V(10)),
            FreeKickAccuracy=C(p.Passing-12+V(11)),ShortPassing=C(p.Passing+(wide?-1:5)+V(12)),
            LongPassing=C(p.Passing+(role=="CDM"?4:-3)+V(13)),Curve=C(p.Passing-4+V(14)),
            Agility=C(d+(height>190?-11:height<175?5:0)+V(15)),Balance=C(d+(height>190?-9:0)+V(16)),
            Reactions=C(d+5+V(17)),BallControl=C(d+3+V(18)),Dribbling=C(d+(wide?2:-2)+V(19)),Composure=C(p.Composure),
            Interceptions=C(p.Defence+2+V(20)),HeadingAccuracy=C((int)Math.Round((centreBack?p.Defence*.50+phy*.50:striker?p.Shooting*.50+phy*.50:p.Defence*.45+phy*.55)+(height-180)*.35)+V(21)),
            DefensiveAwareness=C(p.Defence+V(22)),StandingTackle=C(p.Defence+3+V(23)),SlidingTackle=C(p.Defence-5+V(24)),
            Jumping=C(phy+(height-180)/3+V(25)),Stamina=C(p.Endurance),Strength=C(phy+(height-180)/4+V(26)),Aggression=C(p.Aggression),
            GkDiving=C(p.Keeping+V(27)),GkHandling=C(p.Keeping-3+V(28)),GkKicking=C(p.Passing+V(29)),
            GkPositioning=C(p.Keeping+V(30)),GkReflexes=C(p.Keeping+3+V(31))
        };
        if(p.Name=="Erling Haaland")
        {
            s.Acceleration=81;s.SprintSpeed=92;s.Positioning=95;s.Finishing=96;s.ShotPower=94;s.LongShots=83;s.Volleys=90;s.Penalties=89;
            s.Vision=75;s.Crossing=58;s.FreeKickAccuracy=62;s.ShortPassing=78;s.LongPassing=66;s.Curve=77;
            s.Agility=66;s.Balance=69;s.Reactions=94;s.BallControl=83;s.Dribbling=79;s.Composure=86;
            s.Interceptions=43;s.HeadingAccuracy=85;s.DefensiveAwareness=42;s.StandingTackle=47;s.SlidingTackle=33;
            s.Jumping=93;s.Stamina=80;s.Strength=93;s.Aggression=88;
            int paceGain=p.Pace-87,shootGain=p.Shooting-92,passGain=p.Passing-71,driGain=d-80,defGain=p.Defence-47,phyGain=phy-89;
            s.Acceleration=C(s.Acceleration+paceGain);s.SprintSpeed=C(s.SprintSpeed+paceGain);
            s.Positioning=C(s.Positioning+shootGain);s.Finishing=C(s.Finishing+shootGain);s.ShotPower=C(s.ShotPower+shootGain);
            s.LongShots=C(s.LongShots+shootGain);s.Volleys=C(s.Volleys+shootGain);s.Penalties=C(s.Penalties+shootGain);
            s.Vision=C(s.Vision+passGain);s.Crossing=C(s.Crossing+passGain);s.FreeKickAccuracy=C(s.FreeKickAccuracy+passGain);
            s.ShortPassing=C(s.ShortPassing+passGain);s.LongPassing=C(s.LongPassing+passGain);s.Curve=C(s.Curve+passGain);
            s.Agility=C(s.Agility+driGain);s.Balance=C(s.Balance+driGain);s.Reactions=C(s.Reactions+driGain);
            s.BallControl=C(s.BallControl+driGain);s.Dribbling=C(s.Dribbling+driGain);s.Composure=C(p.Composure);
            s.Interceptions=C(s.Interceptions+defGain);s.DefensiveAwareness=C(s.DefensiveAwareness+defGain);
            s.StandingTackle=C(s.StandingTackle+defGain);s.SlidingTackle=C(s.SlidingTackle+defGain);
            s.Jumping=C(s.Jumping+phyGain);s.Strength=C(s.Strength+phyGain);s.Stamina=C(p.Endurance);s.Aggression=C(p.Aggression);
        }
        PlayerCatalog.KeeperReference(p,s);
        LegendaryAbilities.ApplyDetailProfile(p,s);
        return s;
    }
    public static (string Group,string Name,int Value)[] Breakdown(PlayerCard p)
    {
        var s=Get(p);
        return new[]{
            ("Pace","Acceleration",s.Acceleration),("Pace","Sprint speed",s.SprintSpeed),
            ("Shooting","Positioning",s.Positioning),("Shooting","Finishing",s.Finishing),
            ("Shooting","Shot power",s.ShotPower),("Shooting","Long shots",s.LongShots),
            ("Shooting","Volleys",s.Volleys),("Shooting","Penalties",s.Penalties),
            ("Passing","Vision",s.Vision),("Passing","Crossing",s.Crossing),
            ("Passing","Free kick accuracy",s.FreeKickAccuracy),("Passing","Short pass",s.ShortPassing),
            ("Passing","Long pass",s.LongPassing),("Passing","Curve",s.Curve),
            ("Dribbling","Agility",s.Agility),("Dribbling","Balance",s.Balance),
            ("Dribbling","Reactions",s.Reactions),("Dribbling","Ball control",s.BallControl),
            ("Dribbling","Dribbling",s.Dribbling),("Dribbling","Composure",s.Composure),
            ("Defending","Interceptions",s.Interceptions),("Defending","Heading accuracy",s.HeadingAccuracy),
            ("Defending","Defensive awareness",s.DefensiveAwareness),("Defending","Standing tackle",s.StandingTackle),("Defending","Sliding tackle",s.SlidingTackle),
            ("Physical","Jumping",s.Jumping),("Physical","Stamina",s.Stamina),
            ("Physical","Strength",s.Strength),("Physical","Aggression",s.Aggression),
            ("Goalkeeping","GK diving",s.GkDiving),("Goalkeeping","GK handling",s.GkHandling),
            ("Goalkeeping","GK kicking",s.GkKicking),("Goalkeeping","GK positioning",s.GkPositioning),("Goalkeeping","GK reflexes",s.GkReflexes)
        };
    }
}