BroadcastTeamPlan.cs

Partial class for the soccer match simulation. Adds a broadcast tactical plan per team, storing tempo and mentality, adjusting pass decisions, off ball movement and effort.

Rough Code
using System;
namespace Socer;

public sealed partial class MatchSimulation
{
    public float[] TeamTempo={.5f,.5f},TeamMentality={.5f,.5f};
    public bool[] BroadcastPlanActive=new bool[2];
    public void SetBroadcastPlan(float tempo,float mentality,int team=0)
    {
        tempo=Math.Clamp(tempo,0,1);mentality=Math.Clamp(mentality,0,1);
        SetClubPlan(mentality<.3f?0:mentality>.7f?2:1,team);
        TeamTempo[team]=tempo;TeamMentality[team]=mentality;BroadcastPlanActive[team]=true;
    }
    public float DecisionTempo(int team)=>BroadcastPlanActive[team]?1.55f-TeamTempo[team]*1.1f:1;
    float PlanPassValue(Footballer p,float gain,float safety,float distance)
    {
        if(!BroadcastPlanActive[p.Team])return 0;
        float tempo=TeamTempo[p.Team]-.5f,attack=TeamMentality[p.Team]-.5f;
        // Quick progression competes with carrying; patient play rewards safe recycling.
        return tempo*(3+safety*5+Math.Clamp(gain,-4,10)*.4f)+
            attack*Math.Clamp(gain,-6,12)*.65f-Math.Max(0,-tempo)*(1-safety)*7-
            (tempo<0 && distance>26?-tempo*3:0);
    }
    Point BroadcastPlanMovement(Footballer p,Point target,int possessionTeam)
    {
        if(!BroadcastPlanActive[p.Team] || p.Keeper || Owner<0 || p.Id==Owner ||
            WindupPlayer==p.Id || DuelDefender==p.Id || p.DirectOrderUntil>Seconds ||
            p.BoxRole>0 || p.RunUntil>Seconds || p.FootballRunUntil>Seconds)return target;
        float attack=TeamMentality[p.Team]-.5f;
        if(possessionTeam==p.Team)
            target.X+=Direction(p.Team)*attack*(BackLine(p)?8:14);
        else if(p.Id!=chasers[p.Team] && p.Id!=secondChasers[p.Team])
        {
            var local=World(target,p.Team);var ball=World(Ball,p.Team);
            if(attack<0)
            {
                local.X=Math.Max(StrikerRole(p)?38:9,Math.Min(local.X+attack*12,ball.X-4+attack*12));
                local.Y=34+(local.Y-34)*(1+attack*.35f);
            }
            else local.X+=attack*12;
            target=World(local,p.Team);
        }
        else if(p.Id==secondChasers[p.Team] && attack>.2f && (p.Position-Ball).Length<12+attack*12)
        {target=Ball;p.Action="Прессинг";}
        return target;
    }
    float PlanEffort(int team)=>BroadcastPlanActive[team]?
        1+(TeamTempo[team]-.5f)*.32f+(TeamMentality[team]-.5f)*.36f:1;
}