Presentation timing helper for a card pack opening. Takes a committed PackOpening receipt, picks the star card, orders the remaining rewards and computes when each card reveals based on tier and animation age.
using System;
using System.Linq;
namespace Socer;
// Presentation only. The receipt has already been committed by ClubCareer.OpenOwnedPack.
public sealed class PackOpeningPresentation
{
public PackOpening Receipt { get; }
public PackReward[] Rewards { get; }
public PackReward Star { get; }
public int Tier { get; }
public float RevealAt { get; }
public float CompleteAt => RevealAt + .3f;
public float SpreadDuration => Math.Max(.7f,.18f+Math.Max(0,Rewards.Length-2)*.14f+.62f);
public float SignalAt => Math.Max(1.55f, RevealAt - 1.65f);
public float HoldAt => RevealAt - .38f;
public string Material => Tier switch {4=>"legendary",3=>"elite",2=>"gold",1=>"silver",_=>"bronze"};
public PackOpeningPresentation(PackOpening receipt)
{
Receipt=receipt;
var items=receipt?.Items?.Where(i=>i!=null).ToArray()??Array.Empty<PackReward>();
Star=items.Where(i=>i.Player!=null).OrderByDescending(i=>CardRatings.RevealRank(i.Player))
.ThenByDescending(i=>i.Player.Overall).ThenBy(i=>i.Player.CatalogId,StringComparer.Ordinal).FirstOrDefault()
??items.OrderByDescending(i=>i.RevealValue).FirstOrDefault();
Rewards=(Star==null?Array.Empty<PackReward>():new[]{Star}).Concat(items.Where(i=>!ReferenceEquals(i,Star))
.OrderByDescending(i=>i.Player!=null).ThenByDescending(i=>i.RevealValue).ThenBy(i=>i.Name,StringComparer.Ordinal)).ToArray();
Tier=Star?.Player==null?Math.Clamp((Star?.RevealValue??0)/1000-1,0,2):CardRatings.RevealRank(Star.Player);
RevealAt=Tier switch {4=>6.9f,3=>5.25f,2=>3.45f,_=>2.15f};
}
public float OtherRevealAt(int index)=>.18f+Math.Max(0,index-1)*.14f;
public bool Visible(int index,float age,float spreadAge=-1)
{
if(index<0 || index>=Rewards.Length)return false;
if(ReferenceEquals(Rewards[index],Star))return age>=RevealAt;
return age>=RevealAt && spreadAge>=OtherRevealAt(index);
}
public int Revealed(float age,float spreadAge=-1)=>Enumerable.Range(0,Rewards.Length).Count(i=>Visible(i,age,spreadAge));
public float Next(float age)
{
foreach(float milestone in new[]{.95f,1.55f,SignalAt,HoldAt,RevealAt+.01f,CompleteAt})
if(milestone>age+.08f)return milestone;
return CompleteAt;
}
}