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;
|
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[] = [
|
export const badgeDefs: BadgeDef[] = [
|
||||||
{
|
{
|
||||||
id: "mvp",
|
id: "mvp",
|
||||||
@@ -119,57 +129,57 @@ export const badgeSegreti: BadgeDef[] = [
|
|||||||
{
|
{
|
||||||
id: "s-tiebreak",
|
id: "s-tiebreak",
|
||||||
nome: "Uomo tie-break",
|
nome: "Uomo tie-break",
|
||||||
descrizione:
|
descrizione: `Sbloccato da chi ha almeno ${SEGRETO_TIEBREAK_MVP} MVP e una media voto alta: nei momenti caldi ci sei sempre.`,
|
||||||
"Sbloccato da chi ha almeno 2 MVP e una media voto alta: nei momenti caldi ci sei sempre.",
|
|
||||||
unita: "MVP con media alta",
|
unita: "MVP con media alta",
|
||||||
icon: Ghost,
|
icon: Ghost,
|
||||||
segreto: true,
|
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
|
// Stessa soglia minima di voti del badge Pagellone: sotto VOTI_MINIMI_PAGELLA la media
|
||||||
// non è statisticamente significativa, non deve poter sbloccare nemmeno questo segreto.
|
// 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.",
|
celebrazione: "Nei momenti caldi ci sei sempre.",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: "s-infermeria",
|
id: "s-infermeria",
|
||||||
nome: "Cliente VIP dell'Infermeria",
|
nome: "Cliente VIP dell'Infermeria",
|
||||||
descrizione:
|
descrizione: `Hai saltato almeno ${SEGRETO_INFORTUNI} allenamenti o partite per infortunio. L'infermeria ormai ti aspetta con il caffè pronto ☕😂`,
|
||||||
"Hai saltato almeno 3 allenamenti o partite per infortunio. L'infermeria ormai ti aspetta con il caffè pronto ☕😂",
|
|
||||||
unita: "eventi da infortunato",
|
unita: "eventi da infortunato",
|
||||||
icon: Stethoscope,
|
icon: Stethoscope,
|
||||||
segreto: true,
|
segreto: true,
|
||||||
emoji: "🩺",
|
emoji: "🩺",
|
||||||
soglie: { bronzo: 1, argento: 1, oro: 1 },
|
soglie: unaSoglia,
|
||||||
valore: (g) => (g.infortuni >= 3 ? 1 : 0),
|
valore: (g) => (g.infortuni >= SEGRETO_INFORTUNI ? 1 : 0),
|
||||||
celebrazione: "L'infermeria ormai ti aspetta con il caffè pronto ☕😂",
|
celebrazione: "L'infermeria ormai ti aspetta con il caffè pronto ☕😂",
|
||||||
notificaPush: "Speriamo che sia l'ultimo! 😅",
|
notificaPush: "Speriamo che sia l'ultimo! 😅",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: "s-ritardi",
|
id: "s-ritardi",
|
||||||
nome: "Aspettate, arrivo!",
|
nome: "Aspettate, arrivo!",
|
||||||
descrizione:
|
descrizione: `Hai collezionato almeno ${SEGRETO_RITARDI} ritardi. Il tuo messaggio preferito è: 'Aspettate, arrivo!' 😅`,
|
||||||
"Hai collezionato almeno 5 ritardi. Il tuo messaggio preferito è: 'Aspettate, arrivo!' 😅",
|
|
||||||
unita: "eventi in ritardo",
|
unita: "eventi in ritardo",
|
||||||
icon: AlarmClock,
|
icon: AlarmClock,
|
||||||
segreto: true,
|
segreto: true,
|
||||||
emoji: "⏰",
|
emoji: "⏰",
|
||||||
soglie: { bronzo: 1, argento: 1, oro: 1 },
|
soglie: unaSoglia,
|
||||||
valore: (g) => (g.ritardi >= 5 ? 1 : 0),
|
valore: (g) => (g.ritardi >= SEGRETO_RITARDI ? 1 : 0),
|
||||||
celebrazione:
|
celebrazione: "Il tuo messaggio preferito è: 'Aspettate, arrivo!' 😅",
|
||||||
"Hai collezionato almeno 5 ritardi. Il tuo messaggio preferito è: 'Aspettate, arrivo!' 😅",
|
|
||||||
notificaPush: "Forse è il momento di puntare la sveglia 10 minuti prima! 😄",
|
notificaPush: "Forse è il momento di puntare la sveglia 10 minuti prima! 😄",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: "s-cacche",
|
id: "s-cacche",
|
||||||
nome: "Trono di ferro",
|
nome: "Trono di ferro",
|
||||||
descrizione:
|
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 🚽😂`,
|
||||||
"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 🚽😂",
|
|
||||||
unita: "partite da record",
|
unita: "partite da record",
|
||||||
icon: Toilet,
|
icon: Toilet,
|
||||||
segreto: true,
|
segreto: true,
|
||||||
emoji: "🚽",
|
emoji: "🚽",
|
||||||
soglie: { bronzo: 1, argento: 1, oro: 1 },
|
soglie: unaSoglia,
|
||||||
valore: (g) => (g.cacche >= 3 ? 1 : 0),
|
valore: (g) => (g.cacche >= SEGRETO_CACCHE_PARTITE ? 1 : 0),
|
||||||
celebrazione: "Il bagno del PalaCRAP porta ufficialmente il tuo nome 🚽😂",
|
celebrazione: "Il bagno del PalaCRAP porta ufficialmente il tuo nome 🚽😂",
|
||||||
notificaPush: "Scarico completo: badge segreto sbloccato! 😄",
|
notificaPush: "Scarico completo: badge segreto sbloccato! 😄",
|
||||||
},
|
},
|
||||||
|
|||||||
+47
-67
@@ -124,6 +124,37 @@ function percentualeRisposte(ctx: ContestoObiettivi, rosaSize: number) {
|
|||||||
return Math.round((risposte / posti) * 100);
|
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. */
|
/** Obiettivi collaborativi: si muovono con il contributo di tutta la rosa. */
|
||||||
export function obiettiviSquadra(
|
export function obiettiviSquadra(
|
||||||
rosa: Giocatore[] = giocatori,
|
rosa: Giocatore[] = giocatori,
|
||||||
@@ -136,10 +167,10 @@ export function obiettiviSquadra(
|
|||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
id: "o1",
|
id: "o1",
|
||||||
titolo: `90% di presenze ${aMese(oggi)}`,
|
titolo: `${TARGET_PRESENZE}% di presenze ${aMese(oggi)}`,
|
||||||
descrizione: "Media presenze su partite e allenamenti del mese",
|
descrizione: "Media presenze su partite e allenamenti del mese",
|
||||||
valore: percentualePresenze(ctx, rosa, (e) => e.data.startsWith(mese)),
|
valore: percentualePresenze(ctx, rosa, (e) => e.data.startsWith(mese)),
|
||||||
target: 90,
|
target: TARGET_PRESENZE,
|
||||||
unita: "%",
|
unita: "%",
|
||||||
scadenza: fineMese(oggi),
|
scadenza: fineMese(oggi),
|
||||||
emoji: "📣",
|
emoji: "📣",
|
||||||
@@ -173,7 +204,7 @@ export function obiettiviSquadra(
|
|||||||
titolo: "Tutti rispondono alle convocazioni",
|
titolo: "Tutti rispondono alle convocazioni",
|
||||||
descrizione: "Percentuale di risposte date sugli eventi in programma",
|
descrizione: "Percentuale di risposte date sugli eventi in programma",
|
||||||
valore: percentualeRisposte(ctx, rosa.length),
|
valore: percentualeRisposte(ctx, rosa.length),
|
||||||
target: 90,
|
target: TARGET_PRESENZE,
|
||||||
unita: "%",
|
unita: "%",
|
||||||
scadenza: fineMese(oggi),
|
scadenza: fineMese(oggi),
|
||||||
emoji: "⚡",
|
emoji: "⚡",
|
||||||
@@ -201,7 +232,7 @@ export function obiettiviSquadra(
|
|||||||
titolo: "Presenze collettive",
|
titolo: "Presenze collettive",
|
||||||
descrizione: "Presenze di tutta la rosa su allenamenti e partite definiti in stagione",
|
descrizione: "Presenze di tutta la rosa su allenamenti e partite definiti in stagione",
|
||||||
valore: percentualePresenze(ctx, rosa),
|
valore: percentualePresenze(ctx, rosa),
|
||||||
target: 90,
|
target: TARGET_PRESENZE,
|
||||||
unita: "%",
|
unita: "%",
|
||||||
emoji: "🤝",
|
emoji: "🤝",
|
||||||
impatto: "Ogni allenamento a cui vieni vale +1 per il gruppo.",
|
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.",
|
"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",
|
id: "o3",
|
||||||
|
target: 1,
|
||||||
titolo: "Prima vittoria del campionato",
|
titolo: "Prima vittoria del campionato",
|
||||||
descrizione: "Sbloccare la stagione con i primi 3 punti",
|
descrizione: "Sbloccare la stagione con i primi 3 punti",
|
||||||
valore: Math.min(vittorie, 1),
|
|
||||||
target: 1,
|
|
||||||
unita: "vittorie",
|
|
||||||
emoji: "🎉",
|
emoji: "🎉",
|
||||||
impatto: "Una prestazione di gruppo e il primo passo è fatto.",
|
impatto: "Una prestazione di gruppo e il primo passo è fatto.",
|
||||||
dettaglio: {
|
completaCon: "la prima vittoria",
|
||||||
comeSiCalcola:
|
}),
|
||||||
"Si contano le partite di campionato vinte dalla squadra: vince chi si aggiudica più set. L'obiettivo si completa con la prima vittoria.",
|
obiettivoVittorie(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.",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "o4",
|
id: "o4",
|
||||||
|
target: 5,
|
||||||
titolo: "5 vittorie in campionato",
|
titolo: "5 vittorie in campionato",
|
||||||
descrizione: "Metà strada verso la zona playoff",
|
descrizione: "Metà strada verso la zona playoff",
|
||||||
valore: Math.min(vittorie, 5),
|
|
||||||
target: 5,
|
|
||||||
unita: "vittorie",
|
|
||||||
emoji: "🔥",
|
emoji: "🔥",
|
||||||
impatto: "Ogni vittoria ci avvicina ai playoff.",
|
impatto: "Ogni vittoria ci avvicina ai playoff.",
|
||||||
dettaglio: {
|
completaCon: "5 vittorie",
|
||||||
comeSiCalcola:
|
}),
|
||||||
"Si contano le partite di campionato vinte dalla squadra: vince chi si aggiudica più set. L'obiettivo si completa con 5 vittorie.",
|
obiettivoVittorie(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.",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "o5",
|
id: "o5",
|
||||||
|
target: 10,
|
||||||
titolo: "10 vittorie in campionato",
|
titolo: "10 vittorie in campionato",
|
||||||
descrizione: "Obiettivo stagionale per il podio",
|
descrizione: "Obiettivo stagionale per il podio",
|
||||||
valore: Math.min(vittorie, 10),
|
|
||||||
target: 10,
|
|
||||||
unita: "vittorie",
|
|
||||||
emoji: "🏆",
|
emoji: "🏆",
|
||||||
impatto: "L'obiettivo grande: serve tutta la stagione insieme.",
|
impatto: "L'obiettivo grande: serve tutta la stagione insieme.",
|
||||||
dettaglio: {
|
completaCon: "10 vittorie",
|
||||||
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.",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
id: "o6",
|
id: "o6",
|
||||||
titolo: "1 evento di squadra al mese",
|
titolo: "1 evento di squadra al mese",
|
||||||
|
|||||||
Reference in new issue
Block a user