Badge e obiettivi: soglie in costanti, obiettivi a vittorie da una sola funzione
Soglie dei badge segreti e target presenze (90) in costanti usate anche nei testi; o3/o4/o5 generati da obiettivoVittorie. Unica differenza visibile: la celebrazione di «Aspettate, arrivo!» non ripete più la descrizione. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
99265f6a1e
commit
50930ac142
2 files changed
+75
-85
No files matched your search
+28
-18
@@ -62,6 +62,16 @@ export type BadgeDef = {
|
||||
*/
|
||||
export const VOTI_MINIMI_PAGELLA = 5;
|
||||
|
||||
/** Soglie dei badge segreti: usate sia per sbloccarli sia nei loro testi. */
|
||||
const SEGRETO_TIEBREAK_MVP = 2;
|
||||
const SEGRETO_TIEBREAK_MEDIA = 8;
|
||||
const SEGRETO_INFORTUNI = 3;
|
||||
const SEGRETO_RITARDI = 5;
|
||||
const SEGRETO_CACCHE_PARTITE = 3;
|
||||
|
||||
/** I badge segreti sono tutto-o-niente: una sola soglia, uguale per i tre gradi. */
|
||||
const unaSoglia: Record<Grado, number> = { bronzo: 1, argento: 1, oro: 1 };
|
||||
|
||||
export const badgeDefs: BadgeDef[] = [
|
||||
{
|
||||
id: "mvp",
|
||||
@@ -119,57 +129,57 @@ export const badgeSegreti: BadgeDef[] = [
|
||||
{
|
||||
id: "s-tiebreak",
|
||||
nome: "Uomo tie-break",
|
||||
descrizione:
|
||||
"Sbloccato da chi ha almeno 2 MVP e una media voto alta: nei momenti caldi ci sei sempre.",
|
||||
descrizione: `Sbloccato da chi ha almeno ${SEGRETO_TIEBREAK_MVP} MVP e una media voto alta: nei momenti caldi ci sei sempre.`,
|
||||
unita: "MVP con media alta",
|
||||
icon: Ghost,
|
||||
segreto: true,
|
||||
soglie: { bronzo: 1, argento: 1, oro: 1 },
|
||||
soglie: unaSoglia,
|
||||
// Stessa soglia minima di voti del badge Pagellone: sotto VOTI_MINIMI_PAGELLA la media
|
||||
// non è statisticamente significativa, non deve poter sbloccare nemmeno questo segreto.
|
||||
valore: (g) => (g.mvp >= 2 && g.votiPagella >= VOTI_MINIMI_PAGELLA && g.mediaVoto >= 8 ? 1 : 0),
|
||||
valore: (g) =>
|
||||
g.mvp >= SEGRETO_TIEBREAK_MVP &&
|
||||
g.votiPagella >= VOTI_MINIMI_PAGELLA &&
|
||||
g.mediaVoto >= SEGRETO_TIEBREAK_MEDIA
|
||||
? 1
|
||||
: 0,
|
||||
celebrazione: "Nei momenti caldi ci sei sempre.",
|
||||
},
|
||||
{
|
||||
id: "s-infermeria",
|
||||
nome: "Cliente VIP dell'Infermeria",
|
||||
descrizione:
|
||||
"Hai saltato almeno 3 allenamenti o partite per infortunio. L'infermeria ormai ti aspetta con il caffè pronto ☕😂",
|
||||
descrizione: `Hai saltato almeno ${SEGRETO_INFORTUNI} allenamenti o partite per infortunio. L'infermeria ormai ti aspetta con il caffè pronto ☕😂`,
|
||||
unita: "eventi da infortunato",
|
||||
icon: Stethoscope,
|
||||
segreto: true,
|
||||
emoji: "🩺",
|
||||
soglie: { bronzo: 1, argento: 1, oro: 1 },
|
||||
valore: (g) => (g.infortuni >= 3 ? 1 : 0),
|
||||
soglie: unaSoglia,
|
||||
valore: (g) => (g.infortuni >= SEGRETO_INFORTUNI ? 1 : 0),
|
||||
celebrazione: "L'infermeria ormai ti aspetta con il caffè pronto ☕😂",
|
||||
notificaPush: "Speriamo che sia l'ultimo! 😅",
|
||||
},
|
||||
{
|
||||
id: "s-ritardi",
|
||||
nome: "Aspettate, arrivo!",
|
||||
descrizione:
|
||||
"Hai collezionato almeno 5 ritardi. Il tuo messaggio preferito è: 'Aspettate, arrivo!' 😅",
|
||||
descrizione: `Hai collezionato almeno ${SEGRETO_RITARDI} ritardi. Il tuo messaggio preferito è: 'Aspettate, arrivo!' 😅`,
|
||||
unita: "eventi in ritardo",
|
||||
icon: AlarmClock,
|
||||
segreto: true,
|
||||
emoji: "⏰",
|
||||
soglie: { bronzo: 1, argento: 1, oro: 1 },
|
||||
valore: (g) => (g.ritardi >= 5 ? 1 : 0),
|
||||
celebrazione:
|
||||
"Hai collezionato almeno 5 ritardi. Il tuo messaggio preferito è: 'Aspettate, arrivo!' 😅",
|
||||
soglie: unaSoglia,
|
||||
valore: (g) => (g.ritardi >= SEGRETO_RITARDI ? 1 : 0),
|
||||
celebrazione: "Il tuo messaggio preferito è: 'Aspettate, arrivo!' 😅",
|
||||
notificaPush: "Forse è il momento di puntare la sveglia 10 minuti prima! 😄",
|
||||
},
|
||||
{
|
||||
id: "s-cacche",
|
||||
nome: "Trono di ferro",
|
||||
descrizione:
|
||||
"Almeno 3 partite affrontate con 3 o più cacche pre-gara (campionato o amichevole, qui non si fanno sconti). Il bagno del PalaCRAP porta il tuo nome 🚽😂",
|
||||
descrizione: `Almeno ${SEGRETO_CACCHE_PARTITE} partite affrontate con 3 o più cacche pre-gara (campionato o amichevole, qui non si fanno sconti). Il bagno del PalaCRAP porta il tuo nome 🚽😂`,
|
||||
unita: "partite da record",
|
||||
icon: Toilet,
|
||||
segreto: true,
|
||||
emoji: "🚽",
|
||||
soglie: { bronzo: 1, argento: 1, oro: 1 },
|
||||
valore: (g) => (g.cacche >= 3 ? 1 : 0),
|
||||
soglie: unaSoglia,
|
||||
valore: (g) => (g.cacche >= SEGRETO_CACCHE_PARTITE ? 1 : 0),
|
||||
celebrazione: "Il bagno del PalaCRAP porta ufficialmente il tuo nome 🚽😂",
|
||||
notificaPush: "Scarico completo: badge segreto sbloccato! 😄",
|
||||
},
|
||||
|
||||
+47
-67
@@ -124,6 +124,37 @@ function percentualeRisposte(ctx: ContestoObiettivi, rosaSize: number) {
|
||||
return Math.round((risposte / posti) * 100);
|
||||
}
|
||||
|
||||
/** Percentuale di presenze (e di risposte) da raggiungere negli obiettivi o1, o2 e o7. */
|
||||
const TARGET_PRESENZE = 90;
|
||||
|
||||
/** Obiettivi a vittorie: stessa spiegazione, cambiano solo target e testi. */
|
||||
function obiettivoVittorie(
|
||||
vittorie: number,
|
||||
o: Pick<ObiettivoSquadra, "id" | "titolo" | "descrizione" | "emoji" | "impatto" | "target"> & {
|
||||
completaCon: string;
|
||||
},
|
||||
): ObiettivoSquadra {
|
||||
const { completaCon, ...base } = o;
|
||||
return {
|
||||
...base,
|
||||
valore: Math.min(vittorie, o.target),
|
||||
unita: "vittorie",
|
||||
dettaglio: {
|
||||
comeSiCalcola: `Si contano le partite di campionato vinte dalla squadra: vince chi si aggiudica più set. L'obiettivo si completa con ${completaCon}.`,
|
||||
conta: ["Ogni partita ufficiale di campionato in cui abbiamo vinto più set degli avversari."],
|
||||
nonConta: [
|
||||
"Le sconfitte e le partite non ancora giocate.",
|
||||
"Amichevoli e allenamenti.",
|
||||
"Le vittorie oltre il target: il contatore si ferma al traguardo.",
|
||||
],
|
||||
periodo: "Tutta la stagione di campionato. Non si azzera.",
|
||||
fonte:
|
||||
"Risultati ufficiali del portale CSI Bologna. Si aggiorna quando il portale pubblica il risultato, quindi può esserci un ritardo.",
|
||||
esempio: "Un 3-1 è una vittoria. Un 2-3 non lo è, anche se abbiamo vinto due set.",
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
/** Obiettivi collaborativi: si muovono con il contributo di tutta la rosa. */
|
||||
export function obiettiviSquadra(
|
||||
rosa: Giocatore[] = giocatori,
|
||||
@@ -136,10 +167,10 @@ export function obiettiviSquadra(
|
||||
return [
|
||||
{
|
||||
id: "o1",
|
||||
titolo: `90% di presenze ${aMese(oggi)}`,
|
||||
titolo: `${TARGET_PRESENZE}% di presenze ${aMese(oggi)}`,
|
||||
descrizione: "Media presenze su partite e allenamenti del mese",
|
||||
valore: percentualePresenze(ctx, rosa, (e) => e.data.startsWith(mese)),
|
||||
target: 90,
|
||||
target: TARGET_PRESENZE,
|
||||
unita: "%",
|
||||
scadenza: fineMese(oggi),
|
||||
emoji: "📣",
|
||||
@@ -173,7 +204,7 @@ export function obiettiviSquadra(
|
||||
titolo: "Tutti rispondono alle convocazioni",
|
||||
descrizione: "Percentuale di risposte date sugli eventi in programma",
|
||||
valore: percentualeRisposte(ctx, rosa.length),
|
||||
target: 90,
|
||||
target: TARGET_PRESENZE,
|
||||
unita: "%",
|
||||
scadenza: fineMese(oggi),
|
||||
emoji: "⚡",
|
||||
@@ -201,7 +232,7 @@ export function obiettiviSquadra(
|
||||
titolo: "Presenze collettive",
|
||||
descrizione: "Presenze di tutta la rosa su allenamenti e partite definiti in stagione",
|
||||
valore: percentualePresenze(ctx, rosa),
|
||||
target: 90,
|
||||
target: TARGET_PRESENZE,
|
||||
unita: "%",
|
||||
emoji: "🤝",
|
||||
impatto: "Ogni allenamento a cui vieni vale +1 per il gruppo.",
|
||||
@@ -296,84 +327,33 @@ export function obiettiviSquadra(
|
||||
"Il target è 12 perché è il numero minimo per un allenamento 6 contro 6. Con 9 giocatori in serie ne mancano 3.",
|
||||
},
|
||||
},
|
||||
{
|
||||
obiettivoVittorie(vittorie, {
|
||||
id: "o3",
|
||||
target: 1,
|
||||
titolo: "Prima vittoria del campionato",
|
||||
descrizione: "Sbloccare la stagione con i primi 3 punti",
|
||||
valore: Math.min(vittorie, 1),
|
||||
target: 1,
|
||||
unita: "vittorie",
|
||||
emoji: "🎉",
|
||||
impatto: "Una prestazione di gruppo e il primo passo è fatto.",
|
||||
dettaglio: {
|
||||
comeSiCalcola:
|
||||
"Si contano le partite di campionato vinte dalla squadra: vince chi si aggiudica più set. L'obiettivo si completa con la prima vittoria.",
|
||||
conta: [
|
||||
"Ogni partita ufficiale di campionato in cui abbiamo vinto più set degli avversari.",
|
||||
],
|
||||
nonConta: [
|
||||
"Le sconfitte e le partite non ancora giocate.",
|
||||
"Amichevoli e allenamenti.",
|
||||
"Le vittorie oltre il target: il contatore si ferma al traguardo.",
|
||||
],
|
||||
periodo: "Tutta la stagione di campionato. Non si azzera.",
|
||||
fonte:
|
||||
"Risultati ufficiali del portale CSI Bologna. Si aggiorna quando il portale pubblica il risultato, quindi può esserci un ritardo.",
|
||||
esempio: "Un 3-1 è una vittoria. Un 2-3 non lo è, anche se abbiamo vinto due set.",
|
||||
},
|
||||
},
|
||||
{
|
||||
completaCon: "la prima vittoria",
|
||||
}),
|
||||
obiettivoVittorie(vittorie, {
|
||||
id: "o4",
|
||||
target: 5,
|
||||
titolo: "5 vittorie in campionato",
|
||||
descrizione: "Metà strada verso la zona playoff",
|
||||
valore: Math.min(vittorie, 5),
|
||||
target: 5,
|
||||
unita: "vittorie",
|
||||
emoji: "🔥",
|
||||
impatto: "Ogni vittoria ci avvicina ai playoff.",
|
||||
dettaglio: {
|
||||
comeSiCalcola:
|
||||
"Si contano le partite di campionato vinte dalla squadra: vince chi si aggiudica più set. L'obiettivo si completa con 5 vittorie.",
|
||||
conta: [
|
||||
"Ogni partita ufficiale di campionato in cui abbiamo vinto più set degli avversari.",
|
||||
],
|
||||
nonConta: [
|
||||
"Le sconfitte e le partite non ancora giocate.",
|
||||
"Amichevoli e allenamenti.",
|
||||
"Le vittorie oltre il target: il contatore si ferma al traguardo.",
|
||||
],
|
||||
periodo: "Tutta la stagione di campionato. Non si azzera.",
|
||||
fonte:
|
||||
"Risultati ufficiali del portale CSI Bologna. Si aggiorna quando il portale pubblica il risultato, quindi può esserci un ritardo.",
|
||||
esempio: "Un 3-1 è una vittoria. Un 2-3 non lo è, anche se abbiamo vinto due set.",
|
||||
},
|
||||
},
|
||||
{
|
||||
completaCon: "5 vittorie",
|
||||
}),
|
||||
obiettivoVittorie(vittorie, {
|
||||
id: "o5",
|
||||
target: 10,
|
||||
titolo: "10 vittorie in campionato",
|
||||
descrizione: "Obiettivo stagionale per il podio",
|
||||
valore: Math.min(vittorie, 10),
|
||||
target: 10,
|
||||
unita: "vittorie",
|
||||
emoji: "🏆",
|
||||
impatto: "L'obiettivo grande: serve tutta la stagione insieme.",
|
||||
dettaglio: {
|
||||
comeSiCalcola:
|
||||
"Si contano le partite di campionato vinte dalla squadra: vince chi si aggiudica più set. L'obiettivo si completa con 10 vittorie.",
|
||||
conta: [
|
||||
"Ogni partita ufficiale di campionato in cui abbiamo vinto più set degli avversari.",
|
||||
],
|
||||
nonConta: [
|
||||
"Le sconfitte e le partite non ancora giocate.",
|
||||
"Amichevoli e allenamenti.",
|
||||
"Le vittorie oltre il target: il contatore si ferma al traguardo.",
|
||||
],
|
||||
periodo: "Tutta la stagione di campionato. Non si azzera.",
|
||||
fonte:
|
||||
"Risultati ufficiali del portale CSI Bologna. Si aggiorna quando il portale pubblica il risultato, quindi può esserci un ritardo.",
|
||||
esempio: "Un 3-1 è una vittoria. Un 2-3 non lo è, anche se abbiamo vinto due set.",
|
||||
},
|
||||
},
|
||||
completaCon: "10 vittorie",
|
||||
}),
|
||||
{
|
||||
id: "o6",
|
||||
titolo: "1 evento di squadra al mese",
|
||||
|
||||
Reference in new issue
Block a user