SquadSkillConnections.cs

Static helper that builds skill connections between neighbouring squad slots in a ClubCareer. Pairs two equipped SkillInstances whose UniqueSkills are linked, and generates Russian/English description text for each pair. Also hashes the current lineup and formation into a Stamp used to detect changes.

using System;
using System.Collections.Generic;
using System.Linq;

namespace Socer;

// Connections describe existing skill combinations, not an extra chemistry bonus.
public sealed record SquadSkillPair(SkillInstance First,SkillInstance Second)
{
    public string Effect(bool russian)
    {
        bool Has(UniqueSkill skill)=>First.Skill==skill || Second.Skill==skill;
        string ru,en;
        if(Has(UniqueSkill.CoverGuard))
        {
            bool interception=Has(UniqueSkill.Interceptor);
            ru=interception?"Подстраховка закрывает зону за партнёром, вышедшим на перехват.":"Подстраховка закрывает зону за партнёром, вышедшим в прессинг.";
            en=interception?"Cover Guard protects the space behind the teammate stepping out to intercept.":"Cover Guard protects the space behind the pressing teammate.";
        }
        else if(Has(UniqueSkill.KeeperDistributor))
        {
            ru=Has(UniqueSkill.OutletRunner)?"Партнёр раньше открывается под ввод вратаря.":"Вратарь чаще выбирает открывшегося партнёра для ввода мяча.";
            en=Has(UniqueSkill.OutletRunner)?"The teammate opens earlier for goalkeeper distribution.":"The goalkeeper favours the teammate opening into space.";
        }
        else if(Has(UniqueSkill.AerialFinisher))
        {
            ru="Навес в штрафную подстраивается под удар партнёра головой.";
            en="Penalty-area deliveries are shaped for the teammate's header.";
        }
        else if(Has(UniqueSkill.WallPass))
        {
            ru="Согласуют открывания и чаще начинают короткую комбинацию с ответным пасом.";
            en="Coordinate supporting runs and initiate more short give-and-go combinations.";
        }
        else
        {
            ru=Has(UniqueSkill.LongDistributor)?"Лучше рассчитывают дальнюю передачу в движение открывающегося партнёра.":"Точнее направляют разрезающую передачу под забегание партнёра.";
            en=Has(UniqueSkill.LongDistributor)?"Better lead targeting on long passes to the moving teammate.":"Better through-pass targeting for the teammate's forward run.";
        }
        return russian?ru:en;
    }
}

public sealed record SquadSkillConnection(int FirstSlot,int SecondSlot,PlayerCard First,PlayerCard Second,SquadSkillPair[] Pairs)
{
    public int Key=>FirstSlot*11+SecondSlot;
    public bool Golden=>Pairs.Any(p=>p.First.Grade>=2 && p.Second.Grade>=2);
}

public static class SquadSkillConnections
{
    public static int Stamp(ClubCareer career)
    {
        if(career==null)return 0;
        var hash=new HashCode();hash.Add(career.FormationIndex);
        for(int slot=0;slot<11;slot++)
        {
            var card=career.Card(slot);hash.Add(card?.Id);hash.Add(card?.CardKey);hash.Add(card?.Name);
            if(card?.SkillLoadout==null)continue;
            foreach(var skill in card.SkillLoadout){hash.Add(skill.Skill);hash.Add(skill.Grade);}
        }
        return hash.ToHashCode();
    }

    public static SquadSkillConnection[] Build(ClubCareer career)
    {
        if(career==null)return Array.Empty<SquadSkillConnection>();
        var links=new List<SquadSkillConnection>();
        for(int first=0;first<11;first++)
        {
            var a=career.Card(first);if(a?.SkillLoadout==null || a.SkillLoadout.Count==0)continue;
            for(int second=first+1;second<11;second++)
            {
                if(!FormationSkillNeighbors.AreNeighbors(career.FormationIndex,first,second))continue;
                var b=career.Card(second);if(b==null || b.Id==a.Id || b.SkillLoadout==null || b.SkillLoadout.Count==0)continue;
                var pairs=new List<SquadSkillPair>();
                foreach(var left in a.SkillLoadout)
                foreach(var right in b.SkillLoadout)
                    if(UniqueSkills.LinkedSkills(left.Skill).Contains(right.Skill))pairs.Add(new(left,right));
                if(pairs.Count>0)links.Add(new(first,second,a,b,pairs.ToArray()));
            }
        }
        return links.ToArray();
    }
}