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