Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9f0f60d186 | ||
|
|
5135689293 | ||
|
|
8693bff0c7 | ||
|
|
c6812db291 | ||
|
|
670626afa5 | ||
|
|
9bf41d01af | ||
|
|
16252fb04a | ||
|
|
99d4dede80 | ||
|
|
36eda83fe4 | ||
|
|
58174e68d2 | ||
|
|
ff770af3b5 | ||
|
|
41e5fe2f6b | ||
|
|
9d823375aa | ||
|
|
00f9f15370 | ||
|
|
9fe6e8d0ff | ||
|
|
0f8081d8f0 | ||
|
|
500885ffe0 | ||
|
|
259be2c8b0 | ||
|
|
1706592b81 | ||
|
|
6758e6287e | ||
|
|
a699115a03 | ||
|
|
bb8e6a8885 | ||
|
|
81a1dd1bc3 | ||
|
|
0f1740a7ad | ||
|
|
3d61fc3954 | ||
|
|
6226de3795 | ||
|
|
17824963aa | ||
|
|
75cbe8250f | ||
|
|
6b17288962 | ||
|
|
262c774718 | ||
|
|
4a2c88f0e3 | ||
|
|
c395b4e890 | ||
|
|
818af5b36f | ||
|
|
a080c0ea56 |
@@ -0,0 +1,70 @@
|
||||
{
|
||||
"image": "pierino_parigi.png",
|
||||
"height": 120,
|
||||
"frames": {
|
||||
"explain": {
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"w": 61,
|
||||
"h": 120,
|
||||
"ax": 29.3,
|
||||
"ay": 120
|
||||
},
|
||||
"talk": {
|
||||
"x": 63,
|
||||
"y": 0,
|
||||
"w": 69,
|
||||
"h": 120,
|
||||
"ax": 26.6,
|
||||
"ay": 120
|
||||
},
|
||||
"blink": {
|
||||
"x": 134,
|
||||
"y": 0,
|
||||
"w": 44,
|
||||
"h": 120,
|
||||
"ax": 25.0,
|
||||
"ay": 120
|
||||
},
|
||||
"stand": {
|
||||
"x": 180,
|
||||
"y": 0,
|
||||
"w": 44,
|
||||
"h": 120,
|
||||
"ax": 24.9,
|
||||
"ay": 120
|
||||
},
|
||||
"cheer": {
|
||||
"x": 226,
|
||||
"y": 0,
|
||||
"w": 66,
|
||||
"h": 128,
|
||||
"ax": 34.6,
|
||||
"ay": 128
|
||||
},
|
||||
"shrug": {
|
||||
"x": 294,
|
||||
"y": 0,
|
||||
"w": 89,
|
||||
"h": 120,
|
||||
"ax": 43.8,
|
||||
"ay": 120
|
||||
},
|
||||
"cards": {
|
||||
"x": 385,
|
||||
"y": 0,
|
||||
"w": 50,
|
||||
"h": 120,
|
||||
"ax": 26.2,
|
||||
"ay": 120
|
||||
},
|
||||
"laugh": {
|
||||
"x": 437,
|
||||
"y": 0,
|
||||
"w": 54,
|
||||
"h": 123,
|
||||
"ax": 24.4,
|
||||
"ay": 123
|
||||
}
|
||||
}
|
||||
}
|
||||
|
After Width: | Height: | Size: 105 KiB |
@@ -0,0 +1,70 @@
|
||||
{
|
||||
"image": "taglia.png",
|
||||
"height": 120,
|
||||
"frames": {
|
||||
"stand": {
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"w": 54,
|
||||
"h": 120,
|
||||
"ax": 27.7,
|
||||
"ay": 120
|
||||
},
|
||||
"blink": {
|
||||
"x": 56,
|
||||
"y": 0,
|
||||
"w": 54,
|
||||
"h": 120,
|
||||
"ax": 27.7,
|
||||
"ay": 120
|
||||
},
|
||||
"talk": {
|
||||
"x": 112,
|
||||
"y": 0,
|
||||
"w": 75,
|
||||
"h": 120,
|
||||
"ax": 32.2,
|
||||
"ay": 120
|
||||
},
|
||||
"explain": {
|
||||
"x": 189,
|
||||
"y": 0,
|
||||
"w": 64,
|
||||
"h": 120,
|
||||
"ax": 33.6,
|
||||
"ay": 120
|
||||
},
|
||||
"laugh": {
|
||||
"x": 255,
|
||||
"y": 0,
|
||||
"w": 59,
|
||||
"h": 121,
|
||||
"ax": 25.2,
|
||||
"ay": 121
|
||||
},
|
||||
"aim": {
|
||||
"x": 316,
|
||||
"y": 0,
|
||||
"w": 97,
|
||||
"h": 114,
|
||||
"ax": 55.6,
|
||||
"ay": 114
|
||||
},
|
||||
"shrug": {
|
||||
"x": 415,
|
||||
"y": 0,
|
||||
"w": 91,
|
||||
"h": 117,
|
||||
"ax": 44.2,
|
||||
"ay": 117
|
||||
},
|
||||
"throw": {
|
||||
"x": 508,
|
||||
"y": 0,
|
||||
"w": 71,
|
||||
"h": 120,
|
||||
"ax": 30.3,
|
||||
"ay": 120
|
||||
}
|
||||
}
|
||||
}
|
||||
|
After Width: | Height: | Size: 102 KiB |
@@ -0,0 +1,70 @@
|
||||
{
|
||||
"image": "vannino.png",
|
||||
"height": 120,
|
||||
"frames": {
|
||||
"explain": {
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"w": 56,
|
||||
"h": 120,
|
||||
"ax": 28.6,
|
||||
"ay": 120
|
||||
},
|
||||
"talk": {
|
||||
"x": 58,
|
||||
"y": 0,
|
||||
"w": 64,
|
||||
"h": 120,
|
||||
"ax": 25.6,
|
||||
"ay": 120
|
||||
},
|
||||
"blink": {
|
||||
"x": 124,
|
||||
"y": 0,
|
||||
"w": 45,
|
||||
"h": 120,
|
||||
"ax": 25.0,
|
||||
"ay": 120
|
||||
},
|
||||
"stand": {
|
||||
"x": 171,
|
||||
"y": 0,
|
||||
"w": 46,
|
||||
"h": 120,
|
||||
"ax": 25.3,
|
||||
"ay": 120
|
||||
},
|
||||
"cheer": {
|
||||
"x": 219,
|
||||
"y": 0,
|
||||
"w": 52,
|
||||
"h": 120,
|
||||
"ax": 26.8,
|
||||
"ay": 120
|
||||
},
|
||||
"shrug": {
|
||||
"x": 273,
|
||||
"y": 0,
|
||||
"w": 80,
|
||||
"h": 120,
|
||||
"ax": 40.7,
|
||||
"ay": 120
|
||||
},
|
||||
"cards": {
|
||||
"x": 355,
|
||||
"y": 0,
|
||||
"w": 45,
|
||||
"h": 121,
|
||||
"ax": 22.7,
|
||||
"ay": 121
|
||||
},
|
||||
"laugh": {
|
||||
"x": 402,
|
||||
"y": 0,
|
||||
"w": 46,
|
||||
"h": 121,
|
||||
"ax": 22.7,
|
||||
"ay": 121
|
||||
}
|
||||
}
|
||||
}
|
||||
|
After Width: | Height: | Size: 76 KiB |
|
After Width: | Height: | Size: 324 KiB |
|
After Width: | Height: | Size: 537 KiB |
|
After Width: | Height: | Size: 233 KiB |
|
After Width: | Height: | Size: 75 KiB |
|
After Width: | Height: | Size: 56 KiB |
|
After Width: | Height: | Size: 71 KiB |
|
After Width: | Height: | Size: 190 KiB |
@@ -683,6 +683,10 @@
|
||||
"file": "andrea-c716ab2381.mp3",
|
||||
"sec": 7.95
|
||||
},
|
||||
"andrea|Il Taglia. Io sono un metro e ottanta, e lui mi guarda dall'alto. Con la Condor in mano.": {
|
||||
"file": "andrea-f1663e7892.mp3",
|
||||
"sec": 8.52
|
||||
},
|
||||
"andrea|Il giardino coi cedri e le panchine. All'ombra, d'estate, ci si fa la siesta a turno.": {
|
||||
"file": "andrea-4fd811d0c7.mp3",
|
||||
"sec": 6.43
|
||||
@@ -1603,9 +1607,9 @@
|
||||
"file": "andrea-a93c65234e.mp3",
|
||||
"sec": 4.28
|
||||
},
|
||||
"andrea|Di chi è quell'Audi nera?": {
|
||||
"file": "andrea-b9a784137e.mp3",
|
||||
"sec": 1.63
|
||||
"andrea|Di chi è quell'Audi lì?": {
|
||||
"file": "andrea-cc8a61a779.mp3",
|
||||
"sec": 1.4
|
||||
},
|
||||
"arcu|Let it be.": {
|
||||
"file": "arcu-6ba2f5285a.mp3",
|
||||
@@ -1631,6 +1635,18 @@
|
||||
"file": "andrea-a193a43f3e.mp3",
|
||||
"sec": 3.78
|
||||
},
|
||||
"andrea|La macchina del tempo, parcheggiata davanti al Trappola. Sul cruscotto la data è già pronta.": {
|
||||
"file": "andrea-5e16aca755.mp3",
|
||||
"sec": 6.33
|
||||
},
|
||||
"andrea|Imposto: 10 luglio 1997, ore 18 e 30. Il pokerino da Vannino.": {
|
||||
"file": "andrea-3e60a383c4.mp3",
|
||||
"sec": 8.2
|
||||
},
|
||||
"arcu|Monto anch'io: davanti, però.": {
|
||||
"file": "arcu-664d65b6d1.mp3",
|
||||
"sec": 2.34
|
||||
},
|
||||
"andrea|Nessuno ha mai capito davvero il tuo immenso valore.": {
|
||||
"file": "andrea-3e85200509.mp3",
|
||||
"sec": 2.93
|
||||
@@ -1747,6 +1763,14 @@
|
||||
"file": "andrea-c633ffc747.mp3",
|
||||
"sec": 3.12
|
||||
},
|
||||
"andrea|Il cancello della palestra. Per la scuola si passa dalla stradina più in là.": {
|
||||
"file": "andrea-f91d1262a4.mp3",
|
||||
"sec": 5.19
|
||||
},
|
||||
"andrea|Chiuso. Per la scuola si passa dalla stradina più in là.": {
|
||||
"file": "andrea-237197db3a.mp3",
|
||||
"sec": 4.32
|
||||
},
|
||||
"andrea|Una siepe alta come una casa, e l'edera che si mangia il muro.": {
|
||||
"file": "andrea-2544c4c379.mp3",
|
||||
"sec": 3.89
|
||||
@@ -1863,6 +1887,38 @@
|
||||
"file": "andrea-d38b6e49ef.mp3",
|
||||
"sec": 3.49
|
||||
},
|
||||
"andrea|Lo zio Mario nel suo orto, col sole che va giù dietro la casa.": {
|
||||
"file": "andrea-9309e50d5c.mp3",
|
||||
"sec": 3.78
|
||||
},
|
||||
"zio_mario|Ti s'aspetta a cena, che c'è la vitella di maiale.": {
|
||||
"file": "zio_mario-39ff0c666f.mp3",
|
||||
"sec": 2.71
|
||||
},
|
||||
"andrea|Non ti avevo visto, pensavo tu fossi andato all'estero.": {
|
||||
"file": "andrea-f847f224df.mp3",
|
||||
"sec": 3.35
|
||||
},
|
||||
"zio_mario|Io ho girato tanto... il Falcione.": {
|
||||
"file": "zio_mario-d0d592db52.mp3",
|
||||
"sec": 2.73
|
||||
},
|
||||
"andrea|Zio, che sei stanco?": {
|
||||
"file": "andrea-21195c6cac.mp3",
|
||||
"sec": 2.31
|
||||
},
|
||||
"zio_mario|No, dormo!": {
|
||||
"file": "zio_mario-a852e9c43f.mp3",
|
||||
"sec": 1.19
|
||||
},
|
||||
"andrea|Zio, a me mi garba Michael Jackson!": {
|
||||
"file": "andrea-599b75d7c7.mp3",
|
||||
"sec": 2.6
|
||||
},
|
||||
"zio_mario|Mai col gesso!": {
|
||||
"file": "zio_mario-5773e3350f.mp3",
|
||||
"sec": 1.13
|
||||
},
|
||||
"andrea|Le case coi balconi pieni di vasi: qui ogni finestra è un giardino.": {
|
||||
"file": "andrea-ec81875c47.mp3",
|
||||
"sec": 5.22
|
||||
@@ -1871,6 +1927,54 @@
|
||||
"file": "andrea-d32e1a2a87.mp3",
|
||||
"sec": 3.45
|
||||
},
|
||||
"andrea|Si torna nel 2007. Ciao Vannino, ciao Pierino.": {
|
||||
"file": "andrea-baa95acb36.mp3",
|
||||
"sec": 4.41
|
||||
},
|
||||
"arcu|Riportata dove l'ho presa. Se ti riviene voglia di pokerini, chiedi.": {
|
||||
"file": "arcu-5df7e4b863.mp3",
|
||||
"sec": 4.24
|
||||
},
|
||||
"andrea|Il Barrettino. Nel 1997. Si sente ancora l'odore del caffè e delle sigarette.": {
|
||||
"file": "andrea-e9ea220852.mp3",
|
||||
"sec": 7.94
|
||||
},
|
||||
"andrea|Il panno verde, le fiches in pila, il mazzo e il posacenere pieno. Una sedia è vuota: è per me.": {
|
||||
"file": "andrea-8c283ea588.mp3",
|
||||
"sec": 8.13
|
||||
},
|
||||
"andrea|Vannino, alto e secco, col canovaccio sulla spalla. E quella fossetta nel mento.": {
|
||||
"file": "andrea-c342d764ea.mp3",
|
||||
"sec": 6.77
|
||||
},
|
||||
"andrea|Pierino Parigi, con gli occhiali sul naso, che guarda le carte come se lo tradissero.": {
|
||||
"file": "andrea-a1771b44e8.mp3",
|
||||
"sec": 5.22
|
||||
},
|
||||
"andrea|L'Arcu, venuto con me nel 1997. Guarda le carte di tutti e non dice nulla. Per ora.": {
|
||||
"file": "andrea-4175b94c54.mp3",
|
||||
"sec": 8.75
|
||||
},
|
||||
"andrea|Arcu, tu non giochi?": {
|
||||
"file": "andrea-833a07768c.mp3",
|
||||
"sec": 1.81
|
||||
},
|
||||
"arcu|Io guardo. Chi guarda un perde mai.": {
|
||||
"file": "arcu-8a1840569a.mp3",
|
||||
"sec": 3.46
|
||||
},
|
||||
"arcu|E quando vuoi si torna: la macchina è fuori, basta dirlo.": {
|
||||
"file": "arcu-89d19833e7.mp3",
|
||||
"sec": 3.71
|
||||
},
|
||||
"andrea|Il televisore a tubo. È il 1997: niente smartphone, solo il televideo.": {
|
||||
"file": "andrea-64b8a38c86.mp3",
|
||||
"sec": 7.87
|
||||
},
|
||||
"andrea|Fuori c'è la sera del 1997. E parcheggiata lì, la macchina del tempo.": {
|
||||
"file": "andrea-1efd47285d.mp3",
|
||||
"sec": 5.94
|
||||
},
|
||||
"andrea|Un pino a ombrello enorme. Alla ricreazione, tutti all'ombra lì sotto. Sembra ieri.": {
|
||||
"file": "andrea-0a073729fd.mp3",
|
||||
"sec": 7.3
|
||||
@@ -2503,6 +2607,10 @@
|
||||
"file": "andrea-a960f89e7a.mp3",
|
||||
"sec": 3.45
|
||||
},
|
||||
"andrea|Bei tempi quando qui si faceva i pokerini...": {
|
||||
"file": "andrea-2e7cda51c4.mp3",
|
||||
"sec": 2.55
|
||||
},
|
||||
"andrea|Ci si vede dopo, Arcu.": {
|
||||
"file": "andrea-191021ad7c.mp3",
|
||||
"sec": 1.68
|
||||
@@ -2531,6 +2639,30 @@
|
||||
"file": "arcu-fcaee733df.mp3",
|
||||
"sec": 0.92
|
||||
},
|
||||
"arcu|La macchina è sempre lì. La data è già impostata.": {
|
||||
"file": "arcu-2ddbc3341d.mp3",
|
||||
"sec": 3.69
|
||||
},
|
||||
"arcu|I pokerini da Vannino, col Pierino che bluffava anche a briscola.": {
|
||||
"file": "arcu-9924ed4281.mp3",
|
||||
"sec": 3.83
|
||||
},
|
||||
"arcu|Ci vuoi tornare? Aspetta.": {
|
||||
"file": "arcu-00f5e0a28f.mp3",
|
||||
"sec": 3.73
|
||||
},
|
||||
"andrea|Ma quella è... la macchina del tempo!": {
|
||||
"file": "andrea-a748d9ad25.mp3",
|
||||
"sec": 3.13
|
||||
},
|
||||
"arcu|Il plutonio l'ho trovato da Alvarino. Per un pelo stavano arrivando i Libici a prenderglielo tutto.": {
|
||||
"file": "arcu-c294047de1.mp3",
|
||||
"sec": 6.09
|
||||
},
|
||||
"arcu|Basta salire e mettere la data.": {
|
||||
"file": "arcu-dd10a321b8.mp3",
|
||||
"sec": 2.9
|
||||
},
|
||||
"andrea|Alla bona, un giro di paese.": {
|
||||
"file": "andrea-b35a4d8cc0.mp3",
|
||||
"sec": 2.15
|
||||
@@ -2651,6 +2783,122 @@
|
||||
"file": "andrea-78ad61a67a.mp3",
|
||||
"sec": 1.22
|
||||
},
|
||||
"andrea|C'è posto per uno?": {
|
||||
"file": "andrea-f7481e5519.mp3",
|
||||
"sec": 1.81
|
||||
},
|
||||
"andrea|Vannino, un caffè?": {
|
||||
"file": "andrea-23e4ec2f09.mp3",
|
||||
"sec": 1.86
|
||||
},
|
||||
"andrea|Pierino, come va la mano?": {
|
||||
"file": "andrea-34d248b998.mp3",
|
||||
"sec": 1.59
|
||||
},
|
||||
"andrea|Dopo.": {
|
||||
"file": "andrea-b410f40be6.mp3",
|
||||
"sec": 1.73
|
||||
},
|
||||
"vannino|La sedia è lì. Invito due, punto cinque. Come la vuoi?": {
|
||||
"file": "vannino-225c8700a1.mp3",
|
||||
"sec": 5.37
|
||||
},
|
||||
"vannino|Subito. Ma prima una mano, sennò che ci fai qui?": {
|
||||
"file": "vannino-cd3ce69939.mp3",
|
||||
"sec": 3.21
|
||||
},
|
||||
"pierino_parigi|Bene. O male. Con me un si sa mai, ed è questo il bello.": {
|
||||
"file": "pierino_parigi-46d59a6a61.mp3",
|
||||
"sec": 5.7
|
||||
},
|
||||
"andrea|No, aspetta.": {
|
||||
"file": "andrea-04890c1d8e.mp3",
|
||||
"sec": 1.39
|
||||
},
|
||||
"pierino_parigi|Alla bona: si gioca per il caffè.": {
|
||||
"file": "pierino_parigi-9b57763042.mp3",
|
||||
"sec": 2.33
|
||||
},
|
||||
"pierino_parigi|Seria. Carte, Vannino.": {
|
||||
"file": "pierino_parigi-259f48a09a.mp3",
|
||||
"sec": 2.55
|
||||
},
|
||||
"pierino_parigi|A fassi male? Allora io bluffo.": {
|
||||
"file": "pierino_parigi-8104163151.mp3",
|
||||
"sec": 3.3
|
||||
},
|
||||
"andrea|Taglia! Si fa una gara con la Condor?": {
|
||||
"file": "andrea-99f683209e.mp3",
|
||||
"sec": 3.41
|
||||
},
|
||||
"andrea|A cosa si tira?": {
|
||||
"file": "andrea-3f77b83f35.mp3",
|
||||
"sec": 0.87
|
||||
},
|
||||
"andrea|E una partita a campana, Taglia?": {
|
||||
"file": "andrea-595df0a426.mp3",
|
||||
"sec": 2.23
|
||||
},
|
||||
"andrea|Ma quanto sei alto, Taglia?": {
|
||||
"file": "andrea-01ecdf3ed8.mp3",
|
||||
"sec": 1.96
|
||||
},
|
||||
"andrea|Ci si vede, Taglia.": {
|
||||
"file": "andrea-5d4d911c06.mp3",
|
||||
"sec": 1.42
|
||||
},
|
||||
"taglia|Io ho già tirato: ora tocca a te. Dodici pallini gialli, e devi fare più di me.": {
|
||||
"file": "taglia-2658ec8482.mp3",
|
||||
"sec": 6.05
|
||||
},
|
||||
"taglia|Come la vuoi?": {
|
||||
"file": "taglia-32a067db10.mp3",
|
||||
"sec": 0.62
|
||||
},
|
||||
"taglia|Il cartone sull'albero, le lattine sulla panchina, le bottigliette sulla porta e il palloncino all'altalena.": {
|
||||
"file": "taglia-670f9b4ef8.mp3",
|
||||
"sec": 7.15
|
||||
},
|
||||
"taglia|E se la vuoi seria, ogni tanto ti tiro una lattina in aria.": {
|
||||
"file": "taglia-ac012a1066.mp3",
|
||||
"sec": 4.21
|
||||
},
|
||||
"taglia|A campana? Alla nostra età?": {
|
||||
"file": "taglia-0a7f69770d.mp3",
|
||||
"sec": 2.77
|
||||
},
|
||||
"taglia|Va bene: il gesso ce l'ho in tasca, il sassolino lo scelgo io. Sul vialetto, dalla 1 alla 8, e chi pesta la riga passa la mano.": {
|
||||
"file": "taglia-c00be84faf.mp3",
|
||||
"sec": 11.54
|
||||
},
|
||||
"taglia|Abbastanza da vedere i pallini arrivare prima di te.": {
|
||||
"file": "taglia-d99c875252.mp3",
|
||||
"sec": 2.57
|
||||
},
|
||||
"taglia|Alla bona: ti faccio vedere dove arriva il pallino.": {
|
||||
"file": "taglia-757564b65e.mp3",
|
||||
"sec": 3.12
|
||||
},
|
||||
"taglia|Seria. Occhio alla lattina in aria.": {
|
||||
"file": "taglia-06abe0c427.mp3",
|
||||
"sec": 3.06
|
||||
},
|
||||
"taglia|A fassi male? Allora tiro più forte, e più spesso.": {
|
||||
"file": "taglia-4117f6613d.mp3",
|
||||
"sec": 4.84
|
||||
},
|
||||
"taglia|Alla bona: le righe un contano. Comincia te.": {
|
||||
"file": "taglia-328d930124.mp3",
|
||||
"sec": 4.12
|
||||
},
|
||||
"taglia|Seria: chi tocca la riga è fuori. Comincia te.": {
|
||||
"file": "taglia-1266463538.mp3",
|
||||
"sec": 4.23
|
||||
},
|
||||
"taglia|A fassi male? Io la campana la facevo a occhi chiusi.": {
|
||||
"file": "taglia-7938d8d5e4.mp3",
|
||||
"sec": 5.05
|
||||
},
|
||||
"andrea|Si fa una gara alle macchinine?!?!": {
|
||||
"file": "andrea-17216997e2.mp3",
|
||||
"sec": 2.74
|
||||
@@ -2699,10 +2947,6 @@
|
||||
"file": "andrea-fc5a08bbd6.mp3",
|
||||
"sec": 0.73
|
||||
},
|
||||
"andrea|No, aspetta.": {
|
||||
"file": "andrea-04890c1d8e.mp3",
|
||||
"sec": 1.39
|
||||
},
|
||||
"chiaru|Alla bona: ti faccio vedere dove si ferma. E io vado piano.": {
|
||||
"file": "chiaru-d31cc223f6.mp3",
|
||||
"sec": 5.08
|
||||
@@ -3067,6 +3311,22 @@
|
||||
"file": "bertovo-ca941bee91.mp3",
|
||||
"sec": 5.41
|
||||
},
|
||||
"vannino|Tu m'ha pelato. La prossima volta porta il Barone.": {
|
||||
"file": "vannino-2267bb5adf.mp3",
|
||||
"sec": 3.18
|
||||
},
|
||||
"pierino_parigi|Le fiches restano al banco. E tu torna quando hai imparato a bluffare.": {
|
||||
"file": "pierino_parigi-a80d04fe5b.mp3",
|
||||
"sec": 5.41
|
||||
},
|
||||
"vannino|Già finito? E il caffè chi lo paga?": {
|
||||
"file": "vannino-3307746bb8.mp3",
|
||||
"sec": 3.98
|
||||
},
|
||||
"pierino_parigi|Pari. Si rifà domani sera, alla stess'ora.": {
|
||||
"file": "pierino_parigi-75a2b84953.mp3",
|
||||
"sec": 3.8
|
||||
},
|
||||
"andrea|Tutti sul muro, verdi in fila. Lo stucco di Pierino un tradisce mai.": {
|
||||
"file": "andrea-585cd65f93.mp3",
|
||||
"sec": 5.2
|
||||
@@ -3079,6 +3339,54 @@
|
||||
"file": "andrea-c7dcb11e66.mp3",
|
||||
"sec": 5.52
|
||||
},
|
||||
"andrea|Battuto il Taglia! Con la sua Condor, per giunta.": {
|
||||
"file": "andrea-3ff6547461.mp3",
|
||||
"sec": 3.73
|
||||
},
|
||||
"taglia|Fortuna. Domani la rivinco.": {
|
||||
"file": "taglia-39627c5b3a.mp3",
|
||||
"sec": 2.78
|
||||
},
|
||||
"andrea|Il Taglia ha la mano ferma. Io ho il fiatone.": {
|
||||
"file": "andrea-6eabf3443c.mp3",
|
||||
"sec": 3.83
|
||||
},
|
||||
"taglia|Si torna quando vuoi. I pallini gialli un mancano mai.": {
|
||||
"file": "taglia-c3c705219c.mp3",
|
||||
"sec": 4.52
|
||||
},
|
||||
"andrea|Pari. Si rifà?": {
|
||||
"file": "andrea-5625b5f1fd.mp3",
|
||||
"sec": 2.21
|
||||
},
|
||||
"taglia|Si rifà.": {
|
||||
"file": "taglia-18973374a5.mp3",
|
||||
"sec": 0.76
|
||||
},
|
||||
"andrea|La Condor la rendo al Taglia. Per ora.": {
|
||||
"file": "andrea-aba12c5241.mp3",
|
||||
"sec": 3.1
|
||||
},
|
||||
"andrea|Dalla 1 fino in cima, e ritorno. A ventisett'anni, davanti alle poste.": {
|
||||
"file": "andrea-68378e4c21.mp3",
|
||||
"sec": 6.15
|
||||
},
|
||||
"taglia|Te lo dico io: se ti vede qualcuno, domani lo sa tutto il paese.": {
|
||||
"file": "taglia-1e6660932d.mp3",
|
||||
"sec": 3.34
|
||||
},
|
||||
"andrea|Il Taglia, su un piede solo, è più alto di me su due.": {
|
||||
"file": "andrea-3ed6165062.mp3",
|
||||
"sec": 3.31
|
||||
},
|
||||
"taglia|È questione di gambe lunghe.": {
|
||||
"file": "taglia-9782816264.mp3",
|
||||
"sec": 1.71
|
||||
},
|
||||
"andrea|Il gesso lo lascio lì. Ci giocherà qualche bambino, che è più in allenamento di me.": {
|
||||
"file": "andrea-356a1afe8d.mp3",
|
||||
"sec": 5.91
|
||||
},
|
||||
"chiaru|Hai vinto te. Ma la mia aveva le ruote piene di gesso, sia chiaro.": {
|
||||
"file": "chiaru-91a4b23b22.mp3",
|
||||
"sec": 4.44
|
||||
|
||||
@@ -31,10 +31,16 @@ ne è un'opera derivata. Le foto scattate da Andrea non hanno problemi; quelle p
|
||||
| `provinciale-pignone.png`, `piazzetta-cambray-digny.png`, `via-cipriani.png`, `via-massorondinaio.png`, `mozzete.png`, `ponticino-mozzete.png`, `coldaia.png`, `falegnameria-coldaia.png`, `gabbiano.png` | Codex | screenshot di Google Street View | Google | **no**: da rifare con foto di Andrea |
|
||||
| `closeups/micro-parcheggio.png`, `closeups/micro/*.png` (macchinine) | Codex, solo testo | nessuna | — | sì |
|
||||
| `characters/chiaru.png` | Codex | `foto/chiaru.jpg` | Andrea (29 ottobre) | sì (il Chiaru consenziente) |
|
||||
| `characters/taglia.png` | Codex | `foto/taglia.png` | Andrea (29 ottobre) | sì (il Taglia consenziente) |
|
||||
| `via-liguri-magelli-muro.png` | Codex, ritocco di `via-liguri-magelli.png` con la Ghiacciomobile nel muro | come `via-liguri-magelli.png` | Street View | **no**: come lo sfondo da cui viene |
|
||||
| `characters/zio_mario.png` | Codex | `foto/zio-mario.png` | Andrea (29 ottobre) | sì (famiglia di Andrea) |
|
||||
| `terrazza-cardetole.png` | Codex (dalla foto, poi il terrazzo davanti) | `cardetole-finestra.jpg` | Andrea (29 ottobre) | **da decidere**: come `cardetole.png`, dice dove abita Andrea |
|
||||
| `closeups/muro-cerbottana.png` | Codex, solo testo (stile dalla piazza) | nessuna | — | sì |
|
||||
| `closeups/macchina-dietro.png`, `macchina-lampi.png`, `macchina-davanti.png` | Codex, dallo sprite della macchina del tempo | nessuna | — | sì |
|
||||
| `closeups/campone-condor.png` | Codex, dallo sfondo del campone delle poste | nessuna | — | sì |
|
||||
| `closeups/campone-campana.png` | Codex, solo testo (stile dal campone delle poste) | nessuna | — | sì |
|
||||
| `barrettino-1997.png`, `closeups/cruscotto-tempo.png` | Codex, solo testo | nessuna | — | sì |
|
||||
| `characters/vannino.png`, `characters/pierino_parigi.png` | Codex, dalla descrizione di Andrea (niente foto) | nessuna | — | sì (Pierino: consenso del figlio Marco) |
|
||||
| `cardetole.png` | Codex | `cardetole.jpg` | Andrea (EXIF) | **da decidere**: è la casa vera di Andrea, pubblicarla dice dove abita |
|
||||
| `pieve-interno.png` | Codex | `pieve-interno.png` | Mariano Mirannalti (mandata ad Andrea su WhatsApp) | sì, se Mariano è d'accordo; citarlo nei crediti |
|
||||
| `panorama-intro.png` | Codex | `altre/panorama-intro.png` | da internet (screenshot con l'icona di Google Lens) | **no**, finché non si sostituisce |
|
||||
|
||||
@@ -18,6 +18,39 @@ Online su 50037.manzolo.it tutto fino agli effetti ambientali di Codex. Aperto,
|
||||
|
||||
## Dove siamo arrivati
|
||||
|
||||
- **La campana al campone delle poste (30 ottobre)**: dal Taglia, «E una partita a campana, Taglia?», poi il livello.
|
||||
Primo piano `campana` visto dall'alto sul vialetto (`campone-campana.png`, Codex); la campana col gesso la disegna il
|
||||
codice (`campana.js`, `campana-render.js`): 1-2-3, coppia 4-5, 6, coppia 7-8 e in cima il mezzo cerchio con scritto
|
||||
CAMPANA (Andrea: non «cielo»), ogni casella tinta tenue col suo gesso. Il sassolino: la mira dà la direzione, tenendo
|
||||
premuto la forza va e torna, si lascia; deve cadere nella casella che tocca senza toccare le righe (alla bona le
|
||||
righe non contano e il puntino giallo mostra dove cade). I salti: la lancetta dell'equilibrio attraversa la barra e
|
||||
si preme nel verde (presto: giù l'altro piede; tardi: pestata la riga); si scavalca la casella col sassolino e
|
||||
tornando lo si raccoglie. Chi ce la fa passa alla casella dopo e ritira, chi sbaglia passa la mano; il Taglia gioca
|
||||
da solo (in simulazione gli servono circa 22, 10 e 6 turni secondo il livello). Vince chi finisce la 8 (flag
|
||||
`campana_vinta`). Test `campana.test.mjs`, prova `npm run browser:campana`. [DA ANDREA] le battute.
|
||||
- **La macchina del tempo da fuori (30 ottobre)**: dopo il cruscotto, la partenza giù per Via Liguri Magelli
|
||||
(primo piano `corsa`, `src/engine/corsa.js`): accelera, il fulmine la prende, il bianco, e restano due sgommate di
|
||||
fuoco che bruciano e si spengono; al ritorno dal 1997 l'arrivo: il fulmine in fondo alla strada, lei viene avanti e
|
||||
ci passa accanto lasciando le strisce. La macchina da dietro e davanti (coi lampi) è di Codex.
|
||||
- **Lo zio Mario negli orti al tramonto (30 ottobre)**: dal tramonto (`indizio_regolo`) non è più davanti alla
|
||||
Ghiacciomobile ma accanto al suo orto (`orti_zio_mario`), con una battuta provvisoria [DA ANDREA].
|
||||
- **La Condor al campone delle poste (29 ottobre)**: la gara col Taglia (Andrea Tagliaferri, consenso dato) con la
|
||||
pistola ad aria compressa coi pallini gialli (`condor.js`, `condor-render.js`, primo piano `condor`, sfondo di Codex).
|
||||
Come la cerbottana: il mirino ondeggia col respiro; tenere premuto trattiene il fiato (il mirino si ferma), lasciare
|
||||
spara, troppo e il colpo parte da solo. Il pallino cala con la distanza (alla porta in fondo si mira sopra). Il
|
||||
cartone sull'albero (10/5/2), le lattine sulla panchina (3), le bottigliette sulla traversa (5), il palloncino
|
||||
all'altalena (6), la lattina tirata in aria dal Taglia a seria e a fassi male (8). Si deve battere il punteggio del
|
||||
Taglia (22, 34, 44 secondo il livello, ±3). Il Taglia sta al campone (sprite di Codex dalla sua foto, più alto di Andrea); si gareggia
|
||||
parlandogli. [DA ANDREA] le battute.
|
||||
- **La macchina del tempo e il pokerino del 1997 (29 ottobre)**: dall'Arcu sotto la tenda del Trappola, «Bei tempi
|
||||
quando qui si faceva i pokerini…»: compare la macchina del tempo in Via Liguri Magelli. Dentro, il cruscotto (Codex)
|
||||
compone 10/07/1997 18:30, poi tremori, lampi e il bianco (primo piano `viaggio`, `src/engine/viaggio.js`, tempi in
|
||||
`TRIP` di `game.js`): si arriva al Barrettino del 1997 (`barrettino_1997`, scena `viaggio: true`: niente mappa né
|
||||
strade; la porta o il pulsante «Torna al 2007», `scene.back` e `game.goBack()`, riportano nel 2007 e la macchina
|
||||
sparisce: per rifare il viaggio si richiede all'Arcu), con l'Arcu che viene a guardare, Vannino (dalla descrizione di Andrea) e Pierino Parigi (consenso del figlio
|
||||
Marco, 29 ottobre), sprite di Codex. Il pokerino (`poker.js`, `poker-render.js`): cinque carte col cambio, mazzo
|
||||
corto dal 7 all'asso (colore sopra il full, A-7-8-9-10 scala), invito 2, punto 5, cinque mani. [DA ANDREA] l'interno
|
||||
del Barrettino (è una proposta di Codex) e le battute.
|
||||
- **Nuovi posti dalle foto di Andrea (29 ottobre, sfondi di Codex)**: Via della Compagnia (fra Via de' Medici, la
|
||||
Pieve e Villa Adami), Via Cafaggio in tre tratti fino alla rotonda, la Provinciale sotto i platani, la passeggiata
|
||||
sulla Carza (cascatella, orti, dietro le poste, sotto il ponte delle poste, gli orti dello zio Mario), la strada fra
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
<button id="map-button" hidden title="Mappa (P)">Mappa</button>
|
||||
<button id="notebook-button" hidden title="Taccuino (N)">Taccuino</button>
|
||||
<button id="spots-button" hidden title="Mostra cosa si può toccare (H)">?</button>
|
||||
<button id="back-button" hidden></button>
|
||||
</div>
|
||||
<div id="sound">
|
||||
<button id="mute" aria-label="Togli l'audio" title="Audio (M)">♪</button>
|
||||
@@ -171,6 +172,22 @@
|
||||
Tastiera: B, S, V; frecce e 1–0 scelgono, Invio gioca, Esc lascia il tavolo.</p>
|
||||
</details>
|
||||
</section>
|
||||
<section id="poker-controls" hidden aria-label="Comandi del pokerino">
|
||||
<p id="poker-status" role="status"></p>
|
||||
<div class="card-buttons">
|
||||
<button id="poker-move-0" type="button" hidden></button>
|
||||
<button id="poker-move-1" type="button" hidden></button>
|
||||
<button id="poker-move-2" type="button" hidden></button>
|
||||
</div>
|
||||
<details><summary>Come si gioca</summary>
|
||||
<p>Il pokerino del Barrettino: cinque carte coperte col cambio, mazzo corto dal 7 all'asso. Ognuno mette l'invito
|
||||
(2 fiches) nel piatto. Primo giro di puntate: Parola se non c'è niente da mettere, Apro per puntare 5, Vedo per
|
||||
mettere quanto gli altri, Rilancio per alzare di 5, Lascio per uscire dalla mano. Poi il cambio: tocca le carte da
|
||||
cambiare (al massimo 4) e premi Cambia (Servito se le tieni tutte). Secondo giro di puntate, poi chi resta mostra.</p>
|
||||
<p>Punti, dal più basso: carta alta, coppia, doppia coppia, tris, scala, full, colore, poker, scala colore. Col mazzo
|
||||
corto il colore batte il full, e A-7-8-9-10 è la scala più bassa. Cinque mani: vince chi ha più fiches. Esc esce.</p>
|
||||
</details>
|
||||
</section>
|
||||
<section id="briscola-controls" hidden aria-label="Comandi della briscola">
|
||||
<p id="briscola-status" role="status"></p>
|
||||
<div class="card-hand" aria-label="La mano di Andrea">
|
||||
@@ -255,6 +272,28 @@
|
||||
il pulsante alterna Recupera e Molla. Sei lanci. La gloria: 2 pesci alla bona, 3 seria, 4 a fassi male (lo stivale
|
||||
non conta, e non pesa). Frecce ← →: distanza del lancio; Esc esce.</p>
|
||||
</details>
|
||||
<details id="condor-help" hidden><summary>Come si gioca</summary>
|
||||
<p>La Condor, la pistola ad aria compressa coi pallini gialli, al campone delle poste: dodici pallini, e il Taglia ha
|
||||
già tirato. Il suo punteggio è in alto: per vincere bisogna fare di più. Il cartone sull'albero vale 10, 5 o 2 punti
|
||||
secondo il cerchio, ogni lattina sulla panchina 3, ogni bottiglietta sulla traversa della porta 5, il palloncino
|
||||
legato all'altalena 6, la lattina che il Taglia tira in aria (Seria e A fassi male) 8.</p>
|
||||
<p>Muovi il mouse o tocca il campo per mirare: il mirino ondeggia col respiro (di più salendo di livello). Tieni
|
||||
premuto per trattenere il fiato: il mirino si ferma (diventa verde); lascia per sparare. Se lo trattieni troppo il
|
||||
fiato finisce, il mirino trema e il colpo parte da solo. Il pallino cala con la distanza: alla porta in fondo si
|
||||
mira un po' più sopra; alla bona il puntino giallo segna dove arriva. Il palloncino e la lattina in aria si
|
||||
muovono: si mira dove saranno. Si può anche premere Spara, senza trattenere il fiato. Frecce per spostare il mirino.</p>
|
||||
</details>
|
||||
<details id="campana-help" hidden><summary>Come si gioca</summary>
|
||||
<p>La campana col gesso sul vialetto del campone, a turni col Taglia. Si tira il sassolino nella casella che tocca,
|
||||
dalla 1 alla 8: deve cadere dentro, senza toccare le righe (alla bona le righe non contano). Poi si salta tutta la
|
||||
campana fino in cima (il mezzo cerchio) e indietro, su un piede nelle caselle sole e a gambe larghe nella 4-5 e nella 7-8, senza mai
|
||||
mettere il piede dove sta il sassolino; tornando lo si raccoglie dalla casella prima. Chi ce la fa passa alla casella
|
||||
dopo e ritira; chi sbaglia passa la mano. Vince chi finisce la 8.</p>
|
||||
<p>Il tiro: muovi il mouse o tocca la campana per mirare, tieni premuto per la forza (sale e scende) e lascia; oppure
|
||||
regola la forza e premi Tira. Alla bona il puntino giallo segna dove cade. Frecce su e giù per la mira, destra e
|
||||
sinistra per la forza. I salti: la lancetta dell'equilibrio attraversa la barra; premi (o Spazio, o Salta) quando è
|
||||
nel verde. Troppo presto metti giù l'altro piede, troppo tardi pesti la riga.</p>
|
||||
</details>
|
||||
<details id="cerbottana-help" hidden><summary>Come si gioca</summary>
|
||||
<p>La cerbottana, con lo stucco verde di Pierin di Frilli: dodici pallini contro il muro della piazza. Il bersaglio
|
||||
di gesso vale 10, 5 o 2 punti secondo il cerchio, ogni lattina sul muretto 3, il barattolo appeso che dondola (Seria
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "leggenda-del-regolo",
|
||||
"version": "0.1.48",
|
||||
"version": "0.1.57",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
@@ -10,6 +10,8 @@
|
||||
"browser:micro": "node tests/micro.browser.mjs",
|
||||
"browser:gara": "node tests/gara.browser.mjs",
|
||||
"browser:cerbottana": "node tests/cerbottana.browser.mjs",
|
||||
"browser:condor": "node tests/condor.browser.mjs",
|
||||
"browser:campana": "node tests/campana.browser.mjs",
|
||||
"browser:tressette": "node tests/tressette.browser.mjs",
|
||||
"browser:scopa": "node tests/scopa.browser.mjs",
|
||||
"browser:briscola": "node tests/briscola.browser.mjs",
|
||||
|
||||
@@ -0,0 +1,141 @@
|
||||
import { W, CY, START, CIELO, FROM, BOXES, LAST, FLIGHT, HOP, center, landing, needle, canAdjust } from './campana.js';
|
||||
import { text, panel } from './bocce-render.js';
|
||||
|
||||
function rect(ctx, x, y, w, h, color) { ctx.fillStyle = color; ctx.fillRect(Math.round(x), Math.round(y), Math.round(w), Math.round(h)); }
|
||||
// Il gesso: tratti a puntini un po' storti, con dei buchi (sempre gli stessi, da un piccolo hash: non tremano).
|
||||
const hash = n => { const s = Math.sin(n * 127.1 + 311.7) * 43758.5453; return s - Math.floor(s); };
|
||||
function chalkLine(ctx, x1, y1, x2, y2, seed) {
|
||||
const n = Math.max(2, Math.round(Math.hypot(x2 - x1, y2 - y1)));
|
||||
for (let i = 0; i <= n; i++) {
|
||||
const k = i / n, h = hash(seed * 1000 + i);
|
||||
if (h < 0.07) continue;
|
||||
ctx.fillStyle = h > 0.8 ? 'rgba(255,255,250,0.95)' : 'rgba(240,238,228,0.78)';
|
||||
ctx.fillRect(Math.round(x1 + (x2 - x1) * k + (hash(seed + i) - 0.5)), Math.round(y1 + (y2 - y1) * k + (hash(seed * 7 + i) - 0.5)), 2, 2);
|
||||
}
|
||||
}
|
||||
// I gessi colorati: ogni casella ripassata tenue col suo colore, a puntini come il gesso sull'asfalto (idea di Andrea).
|
||||
const TINTS = { 1: [244, 160, 180], 2: [250, 222, 120], 3: [150, 200, 240], 4: [160, 220, 150], 5: [200, 170, 230], 6: [250, 180, 120], 7: [140, 220, 210], 8: [240, 150, 150], top: [255, 240, 200] };
|
||||
function tint(ctx, [r, g, b], x, y, w, h, seed, inside = () => true) {
|
||||
ctx.fillStyle = `rgba(${r},${g},${b},0.16)`;
|
||||
for (let yy = y; yy < y + h; yy += 2) for (let xx = x; xx < x + w; xx += 2) {
|
||||
if (!inside(xx, yy)) continue;
|
||||
const k = hash(seed * 7777 + xx * 13 + yy * 7);
|
||||
if (k < 0.18) continue; // l'asfalto che spunta fra il gesso
|
||||
ctx.fillStyle = `rgba(${r},${g},${b},${k > 0.85 ? 0.42 : 0.24})`; ctx.fillRect(xx, yy, 2, 2);
|
||||
}
|
||||
}
|
||||
// Il gesso non cambia mai: tinte e righe si disegnano una volta su una tela a parte (a puntini, a ogni fotogramma,
|
||||
// rallentavano la pagina). Fuori dal browser (nei test) si disegnano direttamente.
|
||||
let layer = null;
|
||||
function chalkwork(ctx) {
|
||||
let s = 1;
|
||||
for (const [id, b] of Object.entries(BOXES)) tint(ctx, TINTS[id], b.x + 1, b.y + 1, W - 2, W - 2, Number(id));
|
||||
tint(ctx, TINTS.top, CIELO.x + 1, CY - CIELO.r, CIELO.r, CIELO.r * 2, 9, (x, y) => Math.hypot(x + 1 - CIELO.x, y + 1 - CY) < CIELO.r - 2);
|
||||
for (const b of Object.values(BOXES)) {
|
||||
chalkLine(ctx, b.x, b.y, b.x + W, b.y, s++); chalkLine(ctx, b.x, b.y + W, b.x + W, b.y + W, s++);
|
||||
chalkLine(ctx, b.x, b.y, b.x, b.y + W, s++); chalkLine(ctx, b.x + W, b.y, b.x + W, b.y + W, s++);
|
||||
}
|
||||
// In cima la campana: il mezzo cerchio in fondo, dove ci si gira.
|
||||
for (let i = 0; i < 40; i++) {
|
||||
const a1 = -Math.PI / 2 + i / 40 * Math.PI, a2 = -Math.PI / 2 + (i + 1) / 40 * Math.PI;
|
||||
chalkLine(ctx, CIELO.x + Math.cos(a1) * CIELO.r, CY + Math.sin(a1) * CIELO.r, CIELO.x + Math.cos(a2) * CIELO.r, CY + Math.sin(a2) * CIELO.r, 200 + i);
|
||||
}
|
||||
// La riga di partenza.
|
||||
chalkLine(ctx, START - 14, CY - W, START - 14, CY + W, 300);
|
||||
}
|
||||
function grid(ctx, c) {
|
||||
if (typeof document === 'undefined') chalkwork(ctx);
|
||||
else {
|
||||
if (!layer) { layer = document.createElement('canvas'); layer.width = 640; layer.height = 360; chalkwork(layer.getContext('2d')); }
|
||||
ctx.drawImage(layer, 0, 0);
|
||||
}
|
||||
// Il numero in alto nella casella: il mezzo resta libero per il sassolino e i piedi. Quella che tocca ha il bordo giallo.
|
||||
for (const [id, b] of Object.entries(BOXES)) {
|
||||
const p = center(id), next = Number(id) === c.target[c.current] && c.step !== 'result';
|
||||
if (next) { ctx.strokeStyle = 'rgba(255,236,140,0.55)'; ctx.lineWidth = 2; ctx.strokeRect(b.x + 4, b.y + 4, W - 8, W - 8); }
|
||||
text(ctx, id, p.x, p.y - 17, 14, next ? '#fff3a8' : 'rgba(245,243,232,0.88)', 'center');
|
||||
}
|
||||
text(ctx, 'CAMPANA', CIELO.x + W * 0.53, CY - 26, 8, 'rgba(245,243,232,0.88)', 'center');
|
||||
}
|
||||
// Il sassolino: grigio, col lume in alto; in volo, più su e con l'ombra sotto.
|
||||
function stone(ctx, x, y, lift = 0) {
|
||||
ctx.fillStyle = 'rgba(30,25,20,0.35)'; ctx.beginPath(); ctx.ellipse(x + 1, y + 2, 5, 3, 0, 0, Math.PI * 2); ctx.fill();
|
||||
const s = 1 + lift / 60, yy = y - lift;
|
||||
ctx.fillStyle = '#4a4744'; ctx.beginPath(); ctx.ellipse(x, yy, 5 * s, 4 * s, 0.3, 0, Math.PI * 2); ctx.fill();
|
||||
ctx.fillStyle = '#8d8984'; ctx.beginPath(); ctx.ellipse(x - 0.5, yy - 0.5, 4 * s, 3 * s, 0.3, 0, Math.PI * 2); ctx.fill();
|
||||
rect(ctx, x - 2 * s, yy - 2 * s, 2, 1, '#cfcac2');
|
||||
}
|
||||
// Dove stanno i piedi: a gambe larghe nelle coppie e nel cielo, su un piede nelle caselle sole, alla partenza tutti e due.
|
||||
function feet(beat) {
|
||||
if (!beat || beat.out) return [{ x: FROM.x + 2, y: CY - 9 }, { x: FROM.x + 2, y: CY + 9 }];
|
||||
if (beat.boxes[0] === 'cielo') { const p = center('cielo'); return [{ x: p.x, y: p.y - 12 }, { x: p.x, y: p.y + 12 }]; }
|
||||
return beat.boxes.map(id => center(id));
|
||||
}
|
||||
// Una scarpa vista dall'alto: la punta verso dove si va.
|
||||
function shoe(ctx, x, y, dir, scale, [sole, upper, lace]) {
|
||||
ctx.save(); ctx.translate(Math.round(x), Math.round(y)); ctx.scale(dir * scale, scale);
|
||||
ctx.fillStyle = 'rgba(30,25,20,0.3)'; ctx.fillRect(-9, -3, 21, 9);
|
||||
ctx.fillStyle = sole; ctx.fillRect(-10, -5, 20, 10); ctx.fillRect(10, -4, 2, 8);
|
||||
ctx.fillStyle = upper; ctx.fillRect(-9, -4, 18, 8);
|
||||
ctx.fillStyle = lace; ctx.fillRect(-1, -2, 7, 1); ctx.fillRect(-1, 1, 7, 1);
|
||||
ctx.fillStyle = '#2a2420'; ctx.fillRect(-8, -2, 4, 4); // la caviglia, il buco della scarpa
|
||||
ctx.restore();
|
||||
}
|
||||
const SHOES = { player: ['#e8e6e0', '#3d6fb8', '#ffffff'], cpu: ['#2b2b2b', '#b8322a', '#f0d8a8'] };
|
||||
function walker(ctx, c) {
|
||||
const beat = c.beats?.[c.beat], prev = c.beat > 0 ? c.beats[c.beat - 1] : null, now = feet(c.beat >= 0 ? beat : null);
|
||||
const k = c.hop ? Math.min(1, c.hop.t / HOP) : 1, from = feet(c.beat > 0 ? prev : null);
|
||||
const mid = list => list.reduce((a, p) => ({ x: a.x + p.x / list.length, y: a.y + p.y / list.length }), { x: 0, y: 0 });
|
||||
const a = mid(from), b = mid(now), off = { x: (a.x - b.x) * (1 - k), y: (a.y - b.y) * (1 - k) };
|
||||
const scale = (c.current === 'cpu' ? 1.45 : 1.3) * (1 + 0.35 * Math.sin(Math.PI * k));
|
||||
const dir = beat?.back ? -1 : 1;
|
||||
for (const p of now) shoe(ctx, p.x + off.x, p.y + off.y, dir, scale, SHOES[c.current]);
|
||||
}
|
||||
|
||||
export function drawCampana(ctx, c, def, bg) {
|
||||
ctx.save(); ctx.imageSmoothingEnabled = false;
|
||||
if (bg) ctx.drawImage(bg, 0, 0, 640, 360); else { ctx.fillStyle = '#9a948a'; ctx.fillRect(0, 0, 640, 360); }
|
||||
grid(ctx, c);
|
||||
if (c.stone) stone(ctx, c.stone.x, c.stone.y);
|
||||
walker(ctx, c);
|
||||
if (c.shot) {
|
||||
const k = Math.min(1, c.shot.t / FLIGHT), { from, to } = c.shot;
|
||||
stone(ctx, from.x + (to.x - from.x) * k, from.y + (to.y - from.y) * k, 40 * Math.sin(Math.PI * k));
|
||||
}
|
||||
// La mira: un cerchietto di gesso dove si punta; alla bona, il puntino dove cade il sassolino con questa forza.
|
||||
if (canAdjust(c)) {
|
||||
ctx.strokeStyle = '#fff8dc'; ctx.lineWidth = 1;
|
||||
ctx.beginPath(); ctx.arc(c.aim.x, c.aim.y, 6, 0, Math.PI * 2); ctx.stroke();
|
||||
if (c.skill.guide) { const l = landing(c); rect(ctx, l.x - 2, l.y - 2, 4, 4, '#f5d02a'); rect(ctx, l.x - 1, l.y - 1, 2, 2, '#7a5a10'); }
|
||||
// La forza: la barra in basso a sinistra.
|
||||
const x = 16, y = 296, h = 50, f = Math.round(h * c.power);
|
||||
rect(ctx, x - 3, y - 3, 18, h + 6, '#17160fd0');
|
||||
rect(ctx, x, y + h - f, 12, f, c.holding ? '#ffd23c' : '#d9ccba');
|
||||
text(ctx, 'FORZA', x + 6, y - 9, 6, '#efd49e', 'center');
|
||||
}
|
||||
// L'equilibrio: la lancetta attraversa la barra; si salta quando è nel verde.
|
||||
if (c.step === 'hop' && c.meter) {
|
||||
const x = 220, y = 318, w = 200, zone = c.skill.zone * w / 2, u = needle(c);
|
||||
rect(ctx, x - 4, y - 14, w + 8, 30, '#17160fd8');
|
||||
rect(ctx, x, y, w, 8, '#7a3a2a'); rect(ctx, x + w / 2 - zone, y, zone * 2, 8, '#5fae4a');
|
||||
rect(ctx, x + w / 2 + u * w / 2 - 1, y - 3, 3, 14, '#fff3a8');
|
||||
text(ctx, 'EQUILIBRIO', x + w / 2, y - 7, 6, '#efd49e', 'center');
|
||||
}
|
||||
// In alto: a che casella è ciascuno, di chi è il turno, cosa è successo.
|
||||
rect(ctx, 0, 0, 640, 22, '#17160fe8');
|
||||
text(ctx, 'LA CAMPANA', 8, 7, 8, '#efd49e');
|
||||
text(ctx, { bona: 'alla bona', seria: 'seria', male: 'a fassi male' }[c.level], 8, 16, 7, '#d9ccba');
|
||||
const at = n => n > LAST ? 'finita' : `alla ${n}`;
|
||||
text(ctx, `Andrea ${at(c.target.player)}`, 220, 11, 9, c.current === 'player' ? '#fff0c8' : '#a8a08c', 'center');
|
||||
text(ctx, `Il Taglia ${at(c.target.cpu)}`, 360, 11, 9, c.current === 'cpu' ? '#9fd0ff' : '#7f95a8', 'center');
|
||||
text(ctx, c.current === 'player' ? 'tocca a te' : 'tocca al Taglia', 560, 11, 8, '#d9ccba', 'center');
|
||||
if (c.line) { rect(ctx, 150, 24, 340, 14, '#17160fd0'); text(ctx, c.line, 320, 31, 8, /riga|fuori|Troppo|equilibrio|piede|non nella/i.test(c.line) ? '#ffbf9f' : '#9fd0ff', 'center'); }
|
||||
if (c.step === 'result') {
|
||||
const won = c.result.winner === 'player';
|
||||
panel(ctx, 170, 140, 300, 76);
|
||||
text(ctx, won ? 'BATTUTO IL TAGLIA!' : 'HA VINTO IL TAGLIA', 320, 160, 12, won ? '#b9e5b3' : '#efd49e', 'center');
|
||||
text(ctx, won ? 'Tutta la campana, dalla 1 alla 8.' : `Tu eri arrivato alla ${c.target.player}.`, 320, 182, 8, '#efd49e', 'center');
|
||||
text(ctx, 'Torna al campone per uscire.', 320, 200, 8, '#d9ccba', 'center');
|
||||
}
|
||||
ctx.restore();
|
||||
}
|
||||
@@ -0,0 +1,220 @@
|
||||
// La campana al campone delle poste (idea di Andrea, 30 ottobre): disegnata col gesso sul vialetto, a turni col Taglia.
|
||||
// Si tira il sassolino nella casella che tocca (dalla 1 alla 8): se cade dentro, senza toccare le righe, si salta tutta
|
||||
// la campana fino in cima e indietro, su un piede nelle caselle sole e a gambe larghe nelle coppie, senza mai mettere
|
||||
// il piede dove sta il sassolino; tornando, lo si raccoglie dalla casella prima. Chi sbaglia (sassolino fuori o sulla
|
||||
// riga, salto fuori tempo) passa la mano; chi ce la fa va avanti alla casella dopo e ritira. Vince chi finisce la 8.
|
||||
// Il tiro: la mira dà la direzione, tenere premuto carica la forza (va e torna), lasciare tira. I salti: a ogni salto
|
||||
// la lancetta dell'equilibrio attraversa la barra; si preme quando passa nel verde. Unità: i pixel del primo piano
|
||||
// 640×360, visto dall'alto (sfondo di Codex: assets/closeups/campone-campana.png).
|
||||
|
||||
export const W = 66, CY = 181, START = 80, CIELO = { x: START + 6 * W, r: W }, FROM = { x: 40, y: CY }, REACH = 520;
|
||||
export const TAP = 0.14, CHARGE = 1.3, FLIGHT = 0.55, HOP = 0.22, REST = 1.6, DONE = 1.1, CPU_WAIT = 0.9, CPU_BEAT = 0.42;
|
||||
// Le caselle: 1, 2, 3 da sole; 4 e 5 in coppia (la 4 a sinistra di chi salta, cioè in alto); la 6; 7 e 8 in coppia;
|
||||
// in fondo la campana (il mezzo cerchio dove ci si gira; nel codice «cielo», come la chiamano in altri posti).
|
||||
export const BOXES = {
|
||||
1: { x: START, y: CY - W / 2 }, 2: { x: START + W, y: CY - W / 2 }, 3: { x: START + 2 * W, y: CY - W / 2 },
|
||||
4: { x: START + 3 * W, y: CY - W }, 5: { x: START + 3 * W, y: CY }, 6: { x: START + 4 * W, y: CY - W / 2 },
|
||||
7: { x: START + 5 * W, y: CY - W }, 8: { x: START + 5 * W, y: CY },
|
||||
};
|
||||
export const GROUPS = [[1], [2], [3], [4, 5], [6], [7, 8], ['cielo']];
|
||||
export const LAST = 8;
|
||||
// I livelli: quanto si sparpaglia il sassolino (px), se si vede dove cade, quanto è larga la riga che non si può
|
||||
// toccare, quanto ci mette la lancetta dell'equilibrio e quanto è largo il verde; il Taglia: quante volte il sassolino
|
||||
// va dove vuole e quanto spesso, a ogni salto, mette giù il piede.
|
||||
export const LEVELS = {
|
||||
bona: { scatter: 4, guide: true, line: 0, sweep: 1.25, zone: 0.32, cpu: { throw: 0.5, slip: 0.045 } },
|
||||
seria: { scatter: 7, guide: false, line: 3, sweep: 1, zone: 0.2, cpu: { throw: 0.7, slip: 0.025 } },
|
||||
male: { scatter: 9, guide: false, line: 4, sweep: 0.8, zone: 0.15, cpu: { throw: 0.8, slip: 0.018 } },
|
||||
};
|
||||
const clamp = (v, lo, hi) => Math.max(lo, Math.min(hi, v));
|
||||
function random(c) { c.seed = (Math.imul(c.seed, 1664525) + 1013904223) >>> 0; return c.seed / 4294967296; }
|
||||
|
||||
export function center(id) {
|
||||
if (id === 'cielo') return { x: CIELO.x + W * 0.42, y: CY };
|
||||
const b = BOXES[id]; return { x: b.x + W / 2, y: b.y + W / 2 };
|
||||
}
|
||||
// In che casella cade un punto, e se tocca la riga (entro `tol` pixel da un bordo).
|
||||
export function boxAt([x, y], tol = 0) {
|
||||
for (const [id, b] of Object.entries(BOXES)) {
|
||||
if (x < b.x || x > b.x + W || y < b.y || y > b.y + W) continue;
|
||||
return { id: Number(id), line: Math.min(x - b.x, b.x + W - x, y - b.y, b.y + W - y) < tol };
|
||||
}
|
||||
const d = Math.hypot(x - CIELO.x, y - CY);
|
||||
if (x >= CIELO.x && d <= CIELO.r) return { id: 'cielo', line: Math.min(x - CIELO.x, CIELO.r - d) < tol };
|
||||
return null;
|
||||
}
|
||||
|
||||
// I salti per la casella `n`: all'andata tutte le caselle, saltando quella col sassolino (nella coppia si mette un
|
||||
// piede solo nell'altra); il cielo; al ritorno, dalla casella prima si raccoglie il sassolino; poi fuori.
|
||||
export function beats(n) {
|
||||
const step = (g, back) => g.includes(n) ? (g.length > 1 ? [{ boxes: g.filter(k => k !== n), back }] : []) : [{ boxes: g, back }];
|
||||
const out = GROUPS.flatMap(g => step(g, false));
|
||||
for (let i = GROUPS.length - 2; i >= 0; i--) {
|
||||
if (GROUPS[i].includes(n)) out.push({ ...out[out.length - 1], back: true, pick: true });
|
||||
out.push(...step(GROUPS[i], true));
|
||||
}
|
||||
out.push({ boxes: [], back: true, out: true });
|
||||
return out;
|
||||
}
|
||||
|
||||
export function newCampana(seed = Date.now() >>> 0, def = {}) {
|
||||
const level = LEVELS[def.level] ? def.level : 'seria';
|
||||
return { step: 'aim', t: 0, seed, level, skill: LEVELS[level], current: 'player', target: { player: 1, cpu: 1 },
|
||||
aim: center(1), power: 0.2, holding: false, holdTime: 0, charging: false, stone: null, shot: null,
|
||||
beats: null, beat: -1, meter: null, hop: null, line: null, next: null, events: [], visual: { time: 0 } };
|
||||
}
|
||||
export const canThrow = c => c.current === 'player' && (c.step === 'aim' || c.step === 'hop');
|
||||
export const canAdjust = c => c.current === 'player' && c.step === 'aim';
|
||||
export const aimFree = c => !canAdjust(c);
|
||||
|
||||
// Dove cade il sassolino tirato con questa forza, senza lo sparpaglio.
|
||||
export function landing(c, power = c.power) {
|
||||
const dx = c.aim.x - FROM.x, dy = c.aim.y - FROM.y, d = Math.hypot(dx, dy) || 1;
|
||||
return { x: FROM.x + dx / d * power * REACH, y: FROM.y + dy / d * power * REACH };
|
||||
}
|
||||
function toss(c, to) {
|
||||
c.shot = { from: { ...FROM }, to, t: 0 }; c.stone = null;
|
||||
c.step = 'flying'; c.line = null;
|
||||
c.events.push({ kind: 'campana-lancio', power: 0.6 });
|
||||
}
|
||||
function throwStone(c) {
|
||||
const p = landing(c), s = c.skill.scatter, spread = () => (random(c) + random(c) + random(c) - 1.5) * s * 1.4;
|
||||
toss(c, { x: p.x + spread(), y: p.y + spread() });
|
||||
return true;
|
||||
}
|
||||
const who = c => c.current === 'cpu' ? 'Il Taglia: ' : '';
|
||||
const cap = line => line[0].toUpperCase() + line.slice(1);
|
||||
// Il sassolino è arrivato: nella casella giusta si salta, se no passa la mano.
|
||||
function land(c) {
|
||||
const to = c.shot.to, n = c.target[c.current], hit = boxAt([to.x, to.y], c.skill.line);
|
||||
c.shot = null; c.stone = to;
|
||||
c.events.push({ kind: 'campana-sasso', power: 0.8 });
|
||||
if (hit && hit.id === n && !hit.line) {
|
||||
c.line = cap(`${who(c)}il sassolino è nella ${n}. Salta!`);
|
||||
c.beats = beats(n); c.beat = -1; c.hop = null; c.t = 0;
|
||||
c.step = c.current === 'cpu' ? 'cpuHop' : 'hop';
|
||||
if (c.step === 'hop') c.meter = { t: -0.5, dir: 1 };
|
||||
return;
|
||||
}
|
||||
fail(c, `${who(c)}${hit?.line ? 'sulla riga!' : hit ? `nella ${hit.id === 'cielo' ? 'campana in cima' : hit.id}, non nella ${n}.` : 'fuori dalla campana.'}`);
|
||||
}
|
||||
function fail(c, line) {
|
||||
c.line = cap(line); c.step = 'rest'; c.t = 0; c.meter = null;
|
||||
c.next = c.current === 'player' ? 'cpu' : 'player';
|
||||
c.events.push({ kind: 'campana-riga', power: 0.7 });
|
||||
}
|
||||
// Un salto riuscito: la casella dopo, o il sassolino raccolto, o fuori dalla campana (e la casella è fatta).
|
||||
function advance(c) {
|
||||
c.beat++;
|
||||
const b = c.beats[c.beat];
|
||||
c.hop = { t: 0 };
|
||||
if (b.pick) { c.stone = null; c.line = cap(`${who(c)}preso il sassolino!`); c.events.push({ kind: 'campana-sasso', power: 0.5 }); }
|
||||
else c.events.push({ kind: 'campana-salto', power: 0.6 });
|
||||
if (b.out) {
|
||||
const n = c.target[c.current]++;
|
||||
if (n >= LAST) {
|
||||
c.step = 'result'; c.meter = null;
|
||||
c.result = { winner: c.current, player: c.target.player - 1, cpu: c.target.cpu - 1 };
|
||||
return;
|
||||
}
|
||||
c.line = cap(`${who(c)}fatta la ${n}! Ora la ${n + 1}.`); c.step = 'done'; c.t = 0; c.meter = null;
|
||||
return;
|
||||
}
|
||||
if (c.meter) c.meter = { t: 0, dir: -c.meter.dir };
|
||||
}
|
||||
// La lancetta dell'equilibrio, da -1 a 1 (o al contrario, un salto sì e uno no).
|
||||
export function needle(c) {
|
||||
if (!c.meter) return 0;
|
||||
return c.meter.dir * (-1 + 2 * clamp(c.meter.t, 0, c.skill.sweep) / c.skill.sweep);
|
||||
}
|
||||
function jump(c) {
|
||||
if (c.hop && c.hop.t < HOP) return true; // ancora in aria: il tocco non conta
|
||||
const u = needle(c);
|
||||
if (Math.abs(u) <= c.skill.zone) { advance(c); return true; }
|
||||
const early = u * c.meter.dir < 0;
|
||||
fail(c, early ? 'Troppo presto: giù l\'altro piede!' : 'Troppo tardi: pestata la riga!');
|
||||
return true;
|
||||
}
|
||||
// Tocca all'altro, o allo stesso per la casella dopo: dalla partenza, senza sassolino.
|
||||
function turn(c, current) {
|
||||
Object.assign(c, { current, stone: null, beats: null, beat: -1, hop: null, meter: null, t: 0, next: null,
|
||||
step: current === 'player' ? 'aim' : 'cpuAim' });
|
||||
if (current === 'player') c.aim = center(c.target.player);
|
||||
}
|
||||
|
||||
export function update(c, dt) {
|
||||
if (!Number.isFinite(dt) || dt <= 0) return;
|
||||
dt = Math.min(dt, 0.25); c.t += dt; c.visual.time += dt;
|
||||
if (c.hop) c.hop.t += dt;
|
||||
if (c.holding) {
|
||||
c.holdTime += dt; c.charging = c.holdTime >= TAP;
|
||||
const k = (c.holdTime / CHARGE) % 2; c.power = k <= 1 ? k : 2 - k;
|
||||
}
|
||||
if (c.step === 'flying') { c.shot.t += dt; if (c.shot.t >= FLIGHT) land(c); }
|
||||
else if (c.step === 'hop') {
|
||||
if (!c.hop || c.hop.t >= HOP) c.meter.t += dt;
|
||||
if (c.meter.t > c.skill.sweep) fail(c, 'Hai perso l\'equilibrio!');
|
||||
} else if (c.step === 'cpuAim' && c.t >= CPU_WAIT) {
|
||||
// Il Taglia: o nella casella, ben dentro, o mezza casella più in là (sulla riga o nell'altra).
|
||||
const n = c.target.cpu, p = center(n), ok = random(c) < c.skill.cpu.throw, j = () => (random(c) - 0.5) * 20;
|
||||
toss(c, ok ? { x: p.x + j(), y: p.y + j() } : { x: p.x + (random(c) < 0.5 ? -1 : 1) * W * (0.5 + random(c) * 0.3), y: p.y + j() });
|
||||
} else if (c.step === 'cpuHop' && c.t >= CPU_BEAT) {
|
||||
c.t = 0;
|
||||
if (random(c) < c.skill.cpu.slip) fail(c, random(c) < 0.5 ? 'Il Taglia ha pestato la riga!' : 'Il Taglia ha messo giù l\'altro piede!');
|
||||
else advance(c);
|
||||
} else if (c.step === 'rest' && c.t >= REST) turn(c, c.next);
|
||||
else if (c.step === 'done' && c.t >= DONE) turn(c, c.current);
|
||||
}
|
||||
|
||||
// --- Comandi: la mira segue il mouse o il dito; tenere premuto carica la forza, lasciare tira; ai salti si preme.
|
||||
export function aimScreen(c, [x, y]) {
|
||||
if (!canAdjust(c) || c.holding || !Number.isFinite(x) || !Number.isFinite(y)) return false;
|
||||
c.aim = { x: clamp(x, FROM.x + 30, 630), y: clamp(y, 80, 285) }; return true;
|
||||
}
|
||||
export function setPower(c, v) { if (!canAdjust(c) || c.holding) return false; c.power = clamp(v, 0, 1); return true; }
|
||||
export function nudge(c, dir) { if (!canAdjust(c) || c.holding) return false; c.aim.y = clamp(c.aim.y + dir * 3, 80, 285); return true; }
|
||||
// Frecce: su e giù la mira, destra e sinistra la forza (più in là, più in qua).
|
||||
export function key(c, key, down) {
|
||||
const move = { ArrowUp: [0, -3], ArrowDown: [0, 3], ArrowLeft: [-0.01, 0], ArrowRight: [0.01, 0] }[key];
|
||||
if (!move) return false;
|
||||
if (down && canAdjust(c) && !c.holding) { c.aim.y = clamp(c.aim.y + move[1], 80, 285); c.power = clamp(c.power + move[0], 0, 1); }
|
||||
return true;
|
||||
}
|
||||
export function press(c, pointerId) {
|
||||
if (c.current !== 'player') return false;
|
||||
if (c.step === 'hop') return jump(c);
|
||||
if (!canAdjust(c) || c.holding) return false;
|
||||
c.pointerId = pointerId; c.holding = true; c.charging = false; c.holdTime = 0; c.power = 0;
|
||||
return true;
|
||||
}
|
||||
export function cancel(c, pointerId) {
|
||||
if (pointerId !== undefined && c.pointerId !== pointerId) return false;
|
||||
if (!c.holding) return false;
|
||||
c.holding = c.charging = false; c.holdTime = 0; return true;
|
||||
}
|
||||
export function release(c, pointerId) {
|
||||
if (c.pointerId !== pointerId || !c.holding) return false;
|
||||
if (c.holdTime < TAP) return cancel(c, pointerId); // il tocco secco mira soltanto
|
||||
c.holding = c.charging = false; c.holdTime = 0;
|
||||
return throwStone(c);
|
||||
}
|
||||
// Il pulsante: tira con la forza del cursore, o salta.
|
||||
export function shoot(c) {
|
||||
if (c.current !== 'player' || c.holding) return false;
|
||||
if (c.step === 'hop') return jump(c);
|
||||
return canAdjust(c) && throwStone(c);
|
||||
}
|
||||
|
||||
const box = n => n > LAST ? 'finito' : `alla ${n}`;
|
||||
export function button(c) {
|
||||
if (c.step === 'result') return 'Finita';
|
||||
if (c.current === 'cpu') return 'Tocca al Taglia…';
|
||||
return { aim: 'Tira', flying: 'In volo…', hop: 'Salta' }[c.step] ?? 'Aspetta…';
|
||||
}
|
||||
export function status(c) {
|
||||
const score = `Andrea ${box(c.target.player)}, il Taglia ${box(c.target.cpu)}.`;
|
||||
if (c.step === 'result') return `${c.result.winner === 'player' ? 'Campana finita: battuto il Taglia! ' : 'Il Taglia ha finito la campana. '}${score}`;
|
||||
const hint = c.current === 'cpu' ? 'Tocca al Taglia.' : c.step === 'hop' ? 'Salta quando la lancetta è nel verde.'
|
||||
: `Tira il sassolino nella ${c.target.player}: mira, tieni premuto per la forza e lascia.`;
|
||||
return `${score} ${c.line ?? hint}`;
|
||||
}
|
||||
@@ -0,0 +1,118 @@
|
||||
import { CARTONE, BENCH, CAN, BAR, BOTTLE, BALLOON, VOLO, PELLETS, STILL, BREATH, GASP, rings, reticle, landing, balloon, voloAt, canThrow, breathless } from './condor.js';
|
||||
import { text, panel } from './bocce-render.js';
|
||||
|
||||
function rect(ctx, x, y, w, h, color) { ctx.fillStyle = color; ctx.fillRect(Math.round(x), Math.round(y), Math.round(w), Math.round(h)); }
|
||||
// Il cartone inchiodato al tronco: tre cerchi col pennarello, i chiodini in alto e i buchi dei pallini.
|
||||
function cartone(ctx, c) {
|
||||
const { x, y, w, h } = CARTONE;
|
||||
rect(ctx, x - w / 2 + 2, y - h / 2 + 2, w, h, 'rgba(30,20,10,0.35)');
|
||||
rect(ctx, x - w / 2, y - h / 2, w, h, '#c9a46a');
|
||||
rect(ctx, x - w / 2, y - h / 2, w, 2, '#e0bf86'); rect(ctx, x - w / 2, y + h / 2 - 2, w, 2, '#a8844e');
|
||||
rect(ctx, x - w / 2 + 3, y - h / 2 + 2, 2, 2, '#5a5a5a'); rect(ctx, x + w / 2 - 5, y - h / 2 + 2, 2, 2, '#5a5a5a');
|
||||
ctx.strokeStyle = '#2a1f1a'; ctx.lineWidth = 1.2;
|
||||
for (const [r] of rings(c)) { ctx.beginPath(); ctx.arc(x, y, r, 0, Math.PI * 2); ctx.stroke(); }
|
||||
ctx.fillStyle = '#2a1f1a'; ctx.beginPath(); ctx.arc(x, y, 2, 0, Math.PI * 2); ctx.fill();
|
||||
for (const p of c.holes) { rect(ctx, p.x - 1, p.y - 1, 2, 2, '#1a120c'); rect(ctx, p.x, p.y - 1, 1, 1, '#f2d24a'); }
|
||||
}
|
||||
// Una lattina (sulla panchina o in aria), rossa con la fascia chiara.
|
||||
function can(ctx, x, bottom, angle = 0, w = CAN.w, h = CAN.h, color = '#c8321e') {
|
||||
ctx.save(); ctx.translate(Math.round(x), Math.round(bottom)); ctx.rotate(angle);
|
||||
ctx.fillStyle = color; ctx.fillRect(-w / 2, -h, w, h);
|
||||
ctx.fillStyle = '#f2e6c8'; ctx.fillRect(-w / 2, -h + Math.round(h * 0.35), w, 3);
|
||||
ctx.fillStyle = '#c9cdd2'; ctx.fillRect(-w / 2, -h, w, 2); ctx.fillRect(-w / 2, -2, w, 2);
|
||||
ctx.fillStyle = 'rgba(255,255,255,0.35)'; ctx.fillRect(-w / 2 + 2, -h + 2, 1, h - 4);
|
||||
ctx.restore();
|
||||
}
|
||||
// Una bottiglietta d'acqua, vuota: plastica azzurrina e il tappo blu.
|
||||
function bottle(ctx, x, bottom, angle = 0) {
|
||||
const { w, h } = BOTTLE;
|
||||
ctx.save(); ctx.translate(Math.round(x), Math.round(bottom)); ctx.rotate(angle);
|
||||
ctx.fillStyle = 'rgba(190,228,240,0.85)'; ctx.fillRect(-w / 2, -h + 4, w, h - 4); ctx.fillRect(-w / 2 + 1, -h + 2, w - 2, 2);
|
||||
ctx.fillStyle = '#2f6fb0'; ctx.fillRect(-1, -h, 3, 2);
|
||||
ctx.fillStyle = '#ffffff'; ctx.fillRect(-w / 2 + 1, -h + 5, 1, h - 7);
|
||||
ctx.restore();
|
||||
}
|
||||
// Il pallino giallo.
|
||||
function pellet(ctx, x, y, r) {
|
||||
ctx.fillStyle = '#7a5a10'; ctx.beginPath(); ctx.arc(x, y, r + 0.7, 0, Math.PI * 2); ctx.fill();
|
||||
ctx.fillStyle = '#f5d02a'; ctx.beginPath(); ctx.arc(x, y, r, 0, Math.PI * 2); ctx.fill();
|
||||
if (r > 1.5) rect(ctx, x - r / 2, y - r / 2, 1, 1, '#fff6b0');
|
||||
}
|
||||
// La Condor in basso, nera, puntata verso il mirino: il calcio di legno dritto in giù (la mano lo tiene così), la canna
|
||||
// che gira verso il mirino, il mirino in punta.
|
||||
function pistol(ctx, to) {
|
||||
const from = { x: 430, y: 330 }, a = Math.atan2(to.y - from.y, to.x - from.x);
|
||||
rect(ctx, from.x - 13, from.y + 2, 26, 34, '#1a120c'); rect(ctx, from.x - 12, from.y + 2, 24, 32, '#5a3a22');
|
||||
rect(ctx, from.x - 9, from.y + 5, 4, 26, '#7a5232'); rect(ctx, from.x - 2, from.y + 8, 2, 20, '#3e2816');
|
||||
ctx.save(); ctx.translate(from.x, from.y); ctx.rotate(a);
|
||||
ctx.fillStyle = '#0b0b0e'; ctx.fillRect(-16, -11, 84, 20);
|
||||
ctx.fillStyle = '#26252c'; ctx.fillRect(-14, -9, 80, 5);
|
||||
ctx.fillStyle = '#4a4955'; ctx.fillRect(-14, -9, 80, 1);
|
||||
ctx.fillStyle = '#0b0b0e'; ctx.fillRect(62, -14, 5, 4); ctx.fillRect(66, -5, 6, 10);
|
||||
ctx.restore();
|
||||
}
|
||||
|
||||
export function drawCondor(ctx, c, def, bg) {
|
||||
ctx.save(); ctx.imageSmoothingEnabled = false;
|
||||
if (bg) ctx.drawImage(bg, 0, 0, 640, 360); else { ctx.fillStyle = '#7fb24a'; ctx.fillRect(0, 0, 640, 360); }
|
||||
cartone(ctx, c);
|
||||
for (const k of c.bottles) if (k.fall < 1) bottle(ctx, k.x + k.fall * 6, BAR + k.fall * 10, k.fall * 1.6);
|
||||
for (const k of c.cans) if (k.fall < 1) can(ctx, k.x, BENCH + k.fall * 8, -k.fall * 1.4);
|
||||
// Il palloncino rosso legato alla sbarra dell'altalena; scoppiato, resta lo spago e qualche brandello.
|
||||
const b = balloon(c);
|
||||
ctx.strokeStyle = '#e8e2d0'; ctx.lineWidth = 1; ctx.beginPath(); ctx.moveTo(BALLOON.x, BALLOON.knot);
|
||||
ctx.quadraticCurveTo(BALLOON.x + (b.x - BALLOON.x) * 0.3 + 3, (BALLOON.knot + b.y) / 2, b.x, c.balloon.popped ? b.y + 14 : b.y + BALLOON.r); ctx.stroke();
|
||||
if (!c.balloon.popped) {
|
||||
ctx.fillStyle = '#d8283a'; ctx.beginPath(); ctx.ellipse(b.x, b.y, BALLOON.r, BALLOON.r * 1.2, 0, 0, Math.PI * 2); ctx.fill();
|
||||
ctx.fillStyle = '#ff8a8a'; ctx.fillRect(Math.round(b.x - 4), Math.round(b.y - 6), 2, 3);
|
||||
rect(ctx, b.x - 1, b.y + BALLOON.r * 1.2 - 1, 3, 2, '#a01828');
|
||||
} else if (c.balloon.pop < 1) {
|
||||
ctx.fillStyle = '#d8283a';
|
||||
for (let i = 0; i < 6; i++) { const a = i / 6 * Math.PI * 2, d = 4 + c.balloon.pop * 14; ctx.fillRect(Math.round(b.x + Math.cos(a) * d), Math.round(b.y + Math.sin(a) * d), 2, 2); }
|
||||
}
|
||||
// La lattina tirata in aria dal Taglia (o che ricade, colpita).
|
||||
const v = voloAt(c);
|
||||
if (c.volo?.fall) can(ctx, c.volo.fall.x, c.volo.fall.y + VOLO.h / 2, c.visual.time * 14, VOLO.w, VOLO.h, '#2f6fb0');
|
||||
else if (v) can(ctx, v.x, v.y + VOLO.h / 2, v.a, VOLO.w, VOLO.h, '#2f6fb0');
|
||||
// Il pallino in volo: grande vicino alla pistola, piccolo verso il bersaglio.
|
||||
if (c.shot) {
|
||||
const k = Math.min(1, c.shot.t / c.shot.time), { from, to } = c.shot;
|
||||
pellet(ctx, from.x + (to.x - from.x) * k, from.y + (to.y - from.y) * k, 4 - 2.8 * k);
|
||||
}
|
||||
const r = reticle(c);
|
||||
if (canThrow(c)) {
|
||||
// Alla bona: dove arriva il pallino, un puntino giallo sotto il mirino.
|
||||
if (c.skill.guide) { const l = landing(c); rect(ctx, l.x - 1, l.y - 1, 3, 3, '#f5d02a'); }
|
||||
const out = breathless(c);
|
||||
ctx.strokeStyle = out ? '#ff6a4a' : c.holding && c.holdTime >= STILL ? '#b9e5b3' : '#fff8dc'; ctx.lineWidth = 1;
|
||||
ctx.beginPath(); ctx.arc(r.x, r.y, 7, 0, Math.PI * 2); ctx.stroke();
|
||||
ctx.beginPath(); ctx.moveTo(r.x - 11, r.y); ctx.lineTo(r.x - 3, r.y); ctx.moveTo(r.x + 3, r.y); ctx.lineTo(r.x + 11, r.y);
|
||||
ctx.moveTo(r.x, r.y - 11); ctx.lineTo(r.x, r.y - 3); ctx.moveTo(r.x, r.y + 3); ctx.lineTo(r.x, r.y + 11); ctx.stroke();
|
||||
}
|
||||
pistol(ctx, r);
|
||||
// Il fiato trattenuto: la barra si riempie fino a «fermo» (verde), poi si svuota in rosso finché il colpo parte.
|
||||
if (canThrow(c) && c.holding) {
|
||||
const x = 16, y = 300, h = 50, still = Math.min(1, c.holdTime / STILL), left = c.holdTime > BREATH ? 1 - (c.holdTime - BREATH) / GASP : 1;
|
||||
rect(ctx, x - 3, y - 3, 18, h + 6, '#17160fd0');
|
||||
const f = Math.round(h * (c.holdTime > BREATH ? left : still));
|
||||
rect(ctx, x, y + h - f, 12, f, c.holdTime > BREATH ? '#ff6a4a' : still >= 1 ? '#9be07c' : '#ffd23c');
|
||||
text(ctx, 'FIATO', x + 6, y - 9, 6, '#efd49e', 'center');
|
||||
}
|
||||
// In alto: i punti, quelli del Taglia, i pallini rimasti e cosa è successo.
|
||||
rect(ctx, 0, 0, 640, 22, '#17160fe8');
|
||||
text(ctx, 'LA CONDOR', 8, 7, 8, '#efd49e');
|
||||
text(ctx, { bona: 'alla bona', seria: 'seria', male: 'a fassi male' }[c.level], 8, 16, 7, '#d9ccba');
|
||||
text(ctx, `Punti ${c.points}`, 200, 11, 9, c.points > c.taglia ? '#b9e5b3' : '#fff0c8', 'center');
|
||||
text(ctx, `Il Taglia ${c.taglia}`, 310, 11, 9, '#9fd0ff', 'center');
|
||||
for (let i = 0; i < PELLETS; i++) pellet(ctx, 430 + i * 15, 11, i < c.left ? 3 : 1.2);
|
||||
const line = breathless(c) ? 'Il fiato finisce: spara!' : c.line;
|
||||
if (line) { rect(ctx, 170, 24, 300, 14, '#17160fd0'); text(ctx, line, 320, 31, 8, breathless(c) || /Niente|fuori|Senza/.test(line) ? '#ffbf9f' : '#9fd0ff', 'center'); }
|
||||
if (c.step === 'result') {
|
||||
const w = c.result.winner;
|
||||
panel(ctx, 170, 140, 300, 76);
|
||||
text(ctx, { player: 'BATTUTO IL TAGLIA!', draw: 'PARI COL TAGLIA', cpu: 'HA VINTO IL TAGLIA' }[w], 320, 160, 12, w === 'player' ? '#b9e5b3' : '#efd49e', 'center');
|
||||
text(ctx, `Tu ${c.result.points}, il Taglia ${c.result.taglia}`, 320, 182, 8, '#efd49e', 'center');
|
||||
text(ctx, 'Torna al campone per uscire.', 320, 200, 8, '#d9ccba', 'center');
|
||||
}
|
||||
ctx.restore();
|
||||
}
|
||||