lilgotchi 0.0.0-stage → 3.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE.md +21 -0
- package/README.md +69 -3
- package/dist/LICENSE.md +21 -0
- package/dist/README.md +69 -0
- package/dist/design/evolution/README.md +7 -0
- package/dist/design/evolution/cypunk.js +3 -0
- package/dist/design/evolution/cypunk.md +20 -0
- package/dist/design/evolution/index.html +20 -0
- package/dist/design/evolution/lilgotchi.js +3 -0
- package/dist/design/evolution/lilgotchi.md +20 -0
- package/dist/design/evolution/preview.css +3 -0
- package/dist/design/evolution/preview.js +47 -0
- package/dist/design/evolution/slice.js +3 -0
- package/dist/design/evolution/slice.md +14 -0
- package/dist/design/games/README.md +52 -0
- package/dist/design/games/bump.md +23 -0
- package/dist/design/games/catalog.md +24 -0
- package/dist/design/games/flag.md +19 -0
- package/dist/design/games/get.md +21 -0
- package/dist/design/games/heading.md +23 -0
- package/dist/design/games/hoops.md +17 -0
- package/dist/design/games/left-right.md +30 -0
- package/dist/design/games/memory.md +21 -0
- package/dist/design/games/polish-review.md +11 -0
- package/dist/design/games/release-checklist.md +52 -0
- package/dist/design/games/sprint.md +21 -0
- package/dist/docs/README.md +14 -0
- package/dist/docs/care.md +51 -0
- package/dist/docs/characters.md +51 -0
- package/dist/docs/credits.md +17 -0
- package/dist/docs/development.md +87 -0
- package/dist/docs/frame-contract.md +38 -0
- package/dist/docs/images/cypunk-family.jpg +0 -0
- package/dist/docs/images/lilgotchi-family.jpg +0 -0
- package/dist/docs/images/original-family.jpg +0 -0
- package/dist/docs/images/slice-family.jpg +0 -0
- package/dist/docs/install.md +41 -0
- package/dist/docs/release-review.md +47 -0
- package/dist/embed.js +21 -0
- package/dist/examples/cross-origin.html +7 -0
- package/dist/examples/curated.html +12 -0
- package/dist/examples/duplicate.html +3 -0
- package/dist/examples/install.html +11 -0
- package/dist/examples/launcher-review.html +23 -0
- package/dist/examples/launchers.html +10 -0
- package/dist/examples/nested/index.html +6 -0
- package/dist/examples/one-line.html +9 -0
- package/dist/index.html +100 -0
- package/dist/lilgotchi.js +437 -0
- package/dist/pets/NOTICE.md +19 -0
- package/dist/pets/README.md +7 -0
- package/dist/pets/arcade-catalog.js +52 -0
- package/dist/pets/arcade-geometry.js +18 -0
- package/dist/pets/arcade-opponents.js +16 -0
- package/dist/pets/arcade-renderer.js +116 -0
- package/dist/pets/arcade-sprites.js +64 -0
- package/dist/pets/arcade.js +393 -0
- package/dist/pets/away.js +20 -0
- package/dist/pets/boot.js +161 -0
- package/dist/pets/catalog.js +32 -0
- package/dist/pets/celebrations.js +54 -0
- package/dist/pets/classic-sprites.js +672 -0
- package/dist/pets/clock.js +3 -0
- package/dist/pets/colors.js +38 -0
- package/dist/pets/constants.js +20 -0
- package/dist/pets/custom-themes.css +80 -0
- package/dist/pets/cyberpunk-sprites.js +68 -0
- package/dist/pets/cypunk-original.js +2 -0
- package/dist/pets/embed.css +130 -0
- package/dist/pets/engine.js +38 -0
- package/dist/pets/evolution.js +46 -0
- package/dist/pets/focus.js +27 -0
- package/dist/pets/font.js +185 -0
- package/dist/pets/game.css +275 -0
- package/dist/pets/game.html +148 -0
- package/dist/pets/game.js +626 -0
- package/dist/pets/layout.js +53 -0
- package/dist/pets/lilgotchi-sprites.js +62 -0
- package/dist/pets/minigames/bump.js +52 -0
- package/dist/pets/minigames/flag.js +87 -0
- package/dist/pets/minigames/get.js +59 -0
- package/dist/pets/minigames/heading.js +117 -0
- package/dist/pets/minigames/hoops.js +96 -0
- package/dist/pets/minigames/memory.js +81 -0
- package/dist/pets/minigames/model.js +40 -0
- package/dist/pets/minigames/sprint.js +103 -0
- package/dist/pets/original-roster.js +46 -0
- package/dist/pets/original-sprites.js +3861 -0
- package/dist/pets/overlay-size.js +13 -0
- package/dist/pets/pixel-size.js +6 -0
- package/dist/pets/presentation.js +80 -0
- package/dist/pets/renderer.js +100 -0
- package/dist/pets/scenery.css +24 -0
- package/dist/pets/simulation.js +185 -0
- package/dist/pets/skins.js +14 -0
- package/dist/pets/slice-sprites.js +38 -0
- package/dist/pets/sound.js +33 -0
- package/dist/pets/status.js +28 -0
- package/dist/pets/storage.js +49 -0
- package/dist/pets/valid-state.js +26 -0
- package/dist/pets/wellbeing.js +73 -0
- package/dist/reference/source.json +8 -0
- package/dist/version.json +5 -0
- package/dist/widget/care-guide.js +50 -0
- package/dist/widget/care-monitor.js +52 -0
- package/dist/widget/color-controls.js +15 -0
- package/dist/widget/configurator.js +24 -0
- package/dist/widget/egg.svg +1 -0
- package/dist/widget/focus.js +6 -0
- package/dist/widget/gallery.js +17 -0
- package/dist/widget/inactive.js +24 -0
- package/dist/widget/install-snippet.js +14 -0
- package/dist/widget/launcher.js +63 -0
- package/dist/widget/pet-history.js +57 -0
- package/dist/widget/pet-label.js +12 -0
- package/dist/widget/save-store.js +198 -0
- package/dist/widget/scroll-lock.js +11 -0
- package/dist/widget/settings.js +48 -0
- package/dist/widget/shell.css +63 -0
- package/package.json +43 -6
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export const C = {
|
|
2
|
+
W: 32, H: 16, SCALE: 8,
|
|
3
|
+
MAX_HUNGER: 4, MAX_HAPPY: 4, MAX_DISC: 100, DISC_INC: 25,
|
|
4
|
+
MAX_WEIGHT: 99, MAX_POOP: 4,
|
|
5
|
+
MEAL_WT: 1, SNACK_WT: 2, GAME_WT_LOSS: 1,
|
|
6
|
+
EGG_MS: 90000, // 90 seconds
|
|
7
|
+
BABY_MS: 3600000, // 1 hr
|
|
8
|
+
CHILD_MS: 86400000, // 24 hr
|
|
9
|
+
TEEN_MS: 86400000, // 24 hr
|
|
10
|
+
HUNGER_DECAY: { baby:1800000, child:3600000, teen:3600000, adult:3600000 },
|
|
11
|
+
HAPPY_DECAY: { baby:1800000, child:3600000, teen:3600000, adult:4200000 },
|
|
12
|
+
POOP_RATE: { baby:900000, child:10800000, teen:10800000, adult:10800000 },
|
|
13
|
+
SLEEP: { baby:{s:20,w:9}, child:{s:20,w:9}, teen:{s:21,w:9}, adult:{s:22,w:9} },
|
|
14
|
+
BASE_WT: { baby:5, child:10, teen:20, adult:30 },
|
|
15
|
+
CARE_WINDOW: 900000, // 15 min
|
|
16
|
+
ADULT_MAX_MISTAKES: 5,
|
|
17
|
+
MAX_AGE: 25,
|
|
18
|
+
SNACK_SICK: 10,
|
|
19
|
+
};
|
|
20
|
+
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
/* Dark embedded version. Gameplay and control layout come from the P1 clone. */
|
|
2
|
+
:root {
|
|
3
|
+
--bg-page:#080a09;
|
|
4
|
+
--device-bg:linear-gradient(145deg,#594632,#302820);
|
|
5
|
+
--device-shadow:none;
|
|
6
|
+
--device-inset:inset 0 2px 4px #ffffff18;
|
|
7
|
+
--screen-frame:#1b201b;
|
|
8
|
+
--lcd-bg:#29231c;
|
|
9
|
+
--lcd-fg:#e6c79d;
|
|
10
|
+
--accent:#ffbb79;
|
|
11
|
+
--accent-dark:#29231c;
|
|
12
|
+
--btn-bg:#141815;
|
|
13
|
+
--btn-border:#41483f;
|
|
14
|
+
--btn-color:#e7e5df;
|
|
15
|
+
--btn-active-bg:#242a25;
|
|
16
|
+
--btn-shadow:none;
|
|
17
|
+
--btn-inset:none;
|
|
18
|
+
--overlay-bg:#080a09;
|
|
19
|
+
--overlay-color:#e7e5df;
|
|
20
|
+
--overlay-btn-bg:#141815;
|
|
21
|
+
--overlay-btn-border:#535d50;
|
|
22
|
+
--overlay-btn-color:#e7e5df;
|
|
23
|
+
--overlay-btn-active-bg:#29231c;
|
|
24
|
+
--overlay-btn-active-color:#ffbb79;
|
|
25
|
+
--overlay-close-color:#b5beb0;
|
|
26
|
+
--overlay-close-border:#535d50;
|
|
27
|
+
--overlay-close-active:#242a25;
|
|
28
|
+
--stat-border:#343a34;
|
|
29
|
+
--stat-hearts:#ffbb79;
|
|
30
|
+
--settings-btn-color:#b5beb0;
|
|
31
|
+
--info-color:#aeb5ad;
|
|
32
|
+
--death-msg:#c6cbbf;
|
|
33
|
+
--toast-bg:#141815;
|
|
34
|
+
--toast-border:#535d50;
|
|
35
|
+
--toast-color:#ffbb79;
|
|
36
|
+
}
|
|
37
|
+
:root[data-pet="classic"] { --lcd-bg:#20281d; --lcd-fg:#b4ce83; --accent:#b4ce83; --stat-hearts:#b4ce83; }
|
|
38
|
+
:root[data-pet="cyberpunk"] { --device-bg:linear-gradient(145deg,#304e59,#172c36); --lcd-bg:#0b1c24; --lcd-fg:#8cebdc; --accent:#83e8d7; --stat-hearts:#83e8d7; }
|
|
39
|
+
html,body { height:auto; overflow-x:hidden; overflow-y:auto; color-scheme:dark; }
|
|
40
|
+
body { min-height:0; display:block; padding:0; color:#e7e5df; }
|
|
41
|
+
/* Keep the shared egg silhouette and spacing for every character family. */
|
|
42
|
+
#settings-btn { top:0; right:3px; width:32px; height:30px; opacity:1; }
|
|
43
|
+
html[data-embedded="true"] #settings-btn { color:#e7e5df; }
|
|
44
|
+
.ctrl-btn .icon-color { display:none; }
|
|
45
|
+
.ctrl-btn .icon-mono { display:block; color:var(--accent); }
|
|
46
|
+
#pet-status { min-height:38px; margin:12px 2px 4px; font-size:11px; line-height:1.6; color:var(--lcd-fg); }
|
|
47
|
+
#save-status { margin:4px 2px; font-size:10px; color:#99a197; }
|
|
48
|
+
.overlay { padding:16px 8px; overflow:auto; justify-content:flex-start; }
|
|
49
|
+
.overlay-title { font-size:14px; margin:12px 0; letter-spacing:1px; }
|
|
50
|
+
.overlay-close { background:transparent; font:inherit; }
|
|
51
|
+
.overlay-btn { max-width:100%; padding:12px; font-size:13px; }
|
|
52
|
+
#stats-overlay .stat-row { max-width:100%; font-size:12px; padding:6px 0; }
|
|
53
|
+
#game-overlay .game-area { gap:12px; }
|
|
54
|
+
#game-overlay .game-arrow { width:60px; height:60px; font-size:26px; }
|
|
55
|
+
#game-overlay .game-score { font-size:13px; }
|
|
56
|
+
#game-overlay .game-result { font-size:12px; text-align:center; }
|
|
57
|
+
#toast { max-width:95%; white-space:normal; text-align:center; font-size:11px; padding:8px 10px; }
|
|
58
|
+
button:focus-visible { outline:2px solid var(--accent); outline-offset:2px; }
|
|
59
|
+
:root[data-scene="morning"] { --scene-top:#79633f; --lcd-bg:#332b20; }
|
|
60
|
+
:root[data-scene="afternoon"] { --scene-top:#635c3c; --lcd-bg:#292b20; }
|
|
61
|
+
:root[data-scene="evening"] { --scene-top:#805440; --lcd-bg:#35231f; }
|
|
62
|
+
:root[data-scene="night"],:root[data-scene="sleep"],:root[data-scene="dark"] { --scene-top:#3d4759; --lcd-bg:#1b202b; }
|
|
63
|
+
:root[data-pet="cyberpunk"][data-scene="morning"] { --scene-top:#4e7478; --lcd-bg:#153039; }
|
|
64
|
+
:root[data-pet="cyberpunk"][data-scene="afternoon"] { --scene-top:#426d74; --lcd-bg:#0c2932; }
|
|
65
|
+
:root[data-pet="cyberpunk"][data-scene="evening"] { --scene-top:#625678; --lcd-bg:#241d35; }
|
|
66
|
+
:root[data-pet="cyberpunk"][data-scene="night"],:root[data-pet="cyberpunk"][data-scene="sleep"],:root[data-pet="cyberpunk"][data-scene="dark"] { --scene-top:#304755; --lcd-bg:#0b1c24; }
|
|
67
|
+
#pet-clock { color:#f0e9df; }
|
|
68
|
+
@media(prefers-reduced-motion:reduce) { * { animation:none!important; transition:none!important; } }
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
:root[data-pet="lilgotchi"] { --device-bg:linear-gradient(145deg,#fff0cc,#e7c88d); --lcd-bg:#20281d; --lcd-fg:#fff0cc; --accent:#e7c88d; --stat-hearts:#e7c88d; }
|
|
72
|
+
:root[data-pet="lilgotchi"] #pet-clock { color:#3d4937; }
|
|
73
|
+
|
|
74
|
+
/* Cool daylight keeps the warm pizza pixels separate from their surroundings. */
|
|
75
|
+
:root[data-pet="pizza"] { --device-bg:linear-gradient(145deg,#839c98,#526f70); --screen-frame:#38545a; }
|
|
76
|
+
:root[data-pet="pizza"][data-scene="morning"] { --scene-top:#a1c1be; --lcd-bg:#779c9e; }
|
|
77
|
+
:root[data-pet="pizza"][data-scene="afternoon"] { --scene-top:#8db8bc; --lcd-bg:#648e97; }
|
|
78
|
+
:root[data-pet="pizza"][data-scene="evening"] { --scene-top:#939eb7; --lcd-bg:#657e97; }
|
|
79
|
+
:root[data-pet="pizza"][data-scene="night"] { --scene-top:#596d88; --lcd-bg:#344d68; }
|
|
80
|
+
:root[data-pet="pizza"][data-scene="sleep"],:root[data-pet="pizza"][data-scene="dark"] { --scene-top:#34475a; --lcd-bg:#192a3a; }
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { originalCypunk } from './cypunk-original.js';
|
|
2
|
+
const palette = ['', '#d9fcff', '#102238', '#22dbe7', '#ec4cb4', '#53718c', '#70f79a', '#f4d45b', '#a97ef5', '#3569c8'];
|
|
3
|
+
const expressions = {
|
|
4
|
+
idle1:['101','000','010'], idle2:['101','000','111'],
|
|
5
|
+
happy:['101','000','101'], sad:['000','101','010'],
|
|
6
|
+
eat:['101','010','111'], sleep:['000','101','000'],
|
|
7
|
+
lookLeft:['110','100','010'],lookRight:['011','001','010'],lookUp:['101','000','010'],
|
|
8
|
+
};
|
|
9
|
+
const drawings = [
|
|
10
|
+
{id:'egg',name:'Binary Seed',stage:'egg',rows:['000033330000','000322223000','003212122300','032112122230','032212112230','032212122230','032111122230','003222222300','000333333000','000000000000']},
|
|
11
|
+
{id:'babytchi',name:'Bit',stage:'baby',face:[4,6],rows:['000000000000','000000000000','000000000000','000333330000','003222223000','003222223000','003222223000','003222223000','003222223000','000333330000','000320230000','000330330000']},
|
|
12
|
+
{id:'marutchi',name:'Byte',stage:'child',face:[4,5],rows:['000004000000','000003000000','003333333000','032222222300','032222222300','332222222330','322222222230','332222222330','032222222300','003333333000','000320230000','000330330000']},
|
|
13
|
+
{id:'tamatchi',name:'Compiler',stage:'teen',face:[4,5],rows:['000033330000','000322223000','003222222300','003333333300','003222222300','033222222330','032222222230','003222222300','000344430000','000322230000','003300033000','003000003000']},
|
|
14
|
+
{id:'kuchitamatchi',name:'Syntax Error',stage:'teen',face:[4,5],rows:['000440000000','000030330000','000333223000','043222222300','003222222300','003222222340','003222222300','003222222300','000334433000','003220030000','000330233000','000030003000']},
|
|
15
|
+
{id:'mametchi',name:'JavaScript',stage:'adult',face:[4,3],faceWidth:5,rows:['000070070000','000333333300','003222222230','003222222230','003222222230','003333333330','073032230370','033037730330','000032230000','000032230000','000032023000','000333033300']},
|
|
16
|
+
{id:'ginjirotchi',name:'Sentinel',stage:'adult',original:true},
|
|
17
|
+
{id:'maskutchi',name:'Matrix',stage:'adult',face:[4,3],faceWidth:5,rows:['000060060000','000666666600','006222222260','006222222260','006222222260','066666666660','062062260260','066061160660','000062260000','000061260000','000062026000','000666066600']},
|
|
18
|
+
{id:'kuchipatchi',name:'404',stage:'adult',face:[4,3],faceWidth:5,rows:['000440000000','000033333300','003222222230','003222222230','003222222230','003333333330','003032230300','043032230340','003034430300','000032230000','000032023000','000333033300']},
|
|
19
|
+
{id:'nyorotchi',name:'MissingNumber',stage:'adult',face:[4,5],rows:['033000000000','032300040000','033330033000','032233322300','043222222330','003222222230','033222222300','032222222330','033444333030','000322233000','000033003300','000330000030']},
|
|
20
|
+
{id:'tarakotchi',name:'Blue Screen',stage:'adult',face:[3,3],faceWidth:5,background:9,rows:['055555555550','559999999955','599999999995','599999999995','599999999995','599999999995','559999999955','055555555550','033053350330','000052250000','000032023000','000333033300']},
|
|
21
|
+
{id:'oyajitchi',name:'Glitch Elder',stage:'adult',face:[4,4],rows:['003000004000','004033330000','000322223300','043222222300','003222222340','003222222300','003222222300','000334443330','043222230000','000322223040','003330033000','000300003300']},
|
|
22
|
+
];
|
|
23
|
+
function canvas(rows) {
|
|
24
|
+
if(rows.length>12||rows.some(row=>row.length>12))throw new Error('Proposal exceeds 12 by 12');
|
|
25
|
+
return [...Array(12-rows.length).fill(''),...rows].map(row=>[...row.padEnd(12,'0')].map(Number));
|
|
26
|
+
}
|
|
27
|
+
function draw(definition,expression) {
|
|
28
|
+
if(definition.id==='egg')return originalCypunk.egg[expression];
|
|
29
|
+
if(definition.original){
|
|
30
|
+
if(!expression.startsWith('look'))return originalCypunk.mametchi[expression];
|
|
31
|
+
const frame=originalCypunk.mametchi.idle1.map(row=>[...row]);
|
|
32
|
+
for(let y=3;y<=5;y++)for(let x=3;x<=8;x++)frame[y][x]=2;
|
|
33
|
+
if(expression==='lookUp'){frame[2][4]=3;frame[2][7]=3;frame[4][5]=1;return frame;}
|
|
34
|
+
const left=expression==='lookLeft',x=left?3:6;
|
|
35
|
+
frame[3][x]=3;frame[3][x+2]=3;
|
|
36
|
+
frame[4][left?3:8]=3;frame[5][left?4:7]=1;
|
|
37
|
+
return frame;
|
|
38
|
+
}
|
|
39
|
+
const pixels=canvas(definition.rows);
|
|
40
|
+
if(definition.face){
|
|
41
|
+
const [x,faceY]=definition.face,y=faceY-(expression==='lookUp'?1:0);
|
|
42
|
+
const wide={idle1:['10001','00000','00100'],idle2:['10001','00000','01110'],happy:['01010','10001','01110'],sad:['00000','10001','01110'],eat:['10001','00100','01110'],sleep:['00000','11011','00000'],lookLeft:['10100','10000','01000'],lookRight:['00101','00001','00010'],lookUp:['10001','00000','00100']};
|
|
43
|
+
const face=definition.faceWidth===5?wide[expression]:expressions[expression];
|
|
44
|
+
face.forEach((row,dy)=>[...row].forEach((pixel,dx)=>{
|
|
45
|
+
pixels[y+dy][x+dx]=pixel==='1'?(definition.ink||1):(definition.background||2);
|
|
46
|
+
}));
|
|
47
|
+
}
|
|
48
|
+
// Small antenna and code movements keep the face and silhouette steady.
|
|
49
|
+
if(expression==='idle2'){
|
|
50
|
+
if(definition.id==='egg')pixels[9][7]=4;
|
|
51
|
+
else if(definition.id==='maskutchi'){pixels[8][5]=1;pixels[9][5]=2;}
|
|
52
|
+
else if(definition.id==='oyajitchi'){pixels[0][8]=0;pixels[0][9]=4;}
|
|
53
|
+
else if(definition.id==='nyorotchi'){pixels[1][7]=0;pixels[1][8]=4;}
|
|
54
|
+
}
|
|
55
|
+
return pixels.map(Object.freeze);
|
|
56
|
+
}
|
|
57
|
+
const artwork = {
|
|
58
|
+
type:'Cypunk', palette,
|
|
59
|
+
pets:drawings.map(definition=>({
|
|
60
|
+
id:definition.id,name:definition.name,stage:definition.stage,
|
|
61
|
+
frames:Object.fromEntries((definition.stage==='egg'?['idle1','idle2']:Object.keys(expressions)).map(expression=>[expression,draw(definition,expression)])),
|
|
62
|
+
})),
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
const freezeFrame=frame=>Object.freeze(frame.map(row=>Object.freeze([...row])));
|
|
66
|
+
export const cyberpunkPalette=Object.freeze(artwork.palette);
|
|
67
|
+
export const cyberpunkNames=Object.freeze(Object.fromEntries(artwork.pets.map(pet=>[pet.id,pet.name])));
|
|
68
|
+
export const cyberpunkSprites=Object.freeze(Object.fromEntries(artwork.pets.map(pet=>[pet.id,Object.freeze(Object.fromEntries(Object.entries(pet.frames).map(([key,frame])=>[key,freezeFrame(frame)])))])));
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
// Original Binary Seed and Sentinel poses retained across releases.
|
|
2
|
+
export const originalCypunk = {"egg":{"idle1":[[0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,3,3,3,3,3,3,0,0,0],[0,0,3,2,2,2,2,2,2,3,0,0],[0,3,2,1,1,1,2,2,1,2,3,0],[0,3,2,1,2,1,2,1,1,2,3,0],[0,3,2,1,2,1,2,2,1,2,3,0],[0,3,2,1,2,1,2,2,1,2,3,0],[0,3,2,1,1,1,2,1,1,1,3,0],[0,0,3,2,2,2,2,2,2,3,0,0],[0,0,0,3,3,3,3,3,3,0,0,0]],"idle2":[[0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,3,3,3,3,3,3,0,0,0],[0,0,3,2,2,2,2,2,2,3,0,0],[0,3,2,1,1,1,2,2,1,2,3,0],[0,3,2,1,2,1,2,1,1,2,3,0],[0,3,2,1,2,1,2,2,1,2,3,0],[0,3,2,1,2,1,2,2,1,2,3,0],[0,3,2,1,1,1,2,1,1,1,3,0],[0,0,3,2,4,2,2,3,2,3,0,0],[0,0,0,3,3,3,3,3,3,0,0,0]]},"mametchi":{"idle1":[[0,0,0,0,3,0,0,3,0,0,0,0],[0,0,0,3,3,3,3,3,3,3,0,0],[0,0,3,2,2,2,2,2,2,2,3,0],[0,0,3,2,3,2,2,2,3,2,3,0],[0,0,3,2,2,2,2,2,2,2,3,0],[3,3,3,3,2,2,1,2,2,3,3,3],[3,2,2,0,3,2,2,3,0,2,2,3],[0,3,3,0,3,2,2,3,0,3,3,0],[0,0,0,0,3,4,4,3,0,0,0,0],[0,0,0,0,3,2,2,3,0,0,0,0],[0,0,0,0,3,2,0,2,3,0,0,0],[0,0,0,3,3,3,0,3,3,3,0,0]],"idle2":[[0,0,0,0,3,0,0,3,0,0,0,0],[0,0,0,3,3,3,3,3,3,3,0,0],[0,0,3,2,2,2,2,2,2,2,3,0],[0,0,3,2,3,2,2,2,3,2,3,0],[0,0,3,2,2,2,2,2,2,2,3,0],[3,3,3,3,2,1,1,1,2,3,3,3],[3,2,2,0,3,2,2,3,0,2,2,3],[0,3,3,0,3,2,2,3,0,3,3,0],[0,0,0,0,3,4,4,3,0,0,0,0],[0,0,0,0,3,2,2,3,0,0,0,0],[0,0,0,0,3,2,0,2,3,0,0,0],[0,0,3,0,3,3,0,3,3,3,0,0]],"happy":[[0,0,0,0,3,0,0,3,0,0,0,0],[0,0,0,3,3,3,3,3,3,3,0,0],[0,0,3,2,2,2,2,2,2,2,3,0],[0,0,3,2,2,3,2,3,2,2,3,0],[0,0,3,2,3,2,2,2,3,2,3,0],[3,3,3,3,2,1,1,1,2,3,3,3],[3,2,2,0,3,2,2,3,0,2,2,3],[0,3,3,0,3,2,2,3,0,3,3,0],[0,0,0,0,3,4,4,3,0,0,0,0],[0,0,0,0,3,2,2,3,0,0,0,0],[0,0,0,0,3,2,0,2,3,0,0,0],[0,0,0,3,3,3,0,3,3,3,0,0]],"sad":[[0,0,0,0,3,0,0,3,0,0,0,0],[0,0,0,3,3,3,3,3,3,3,0,0],[0,0,3,2,2,2,2,2,2,2,3,0],[0,0,3,2,2,2,2,2,2,2,3,0],[0,0,3,2,3,2,2,2,3,2,3,0],[3,3,3,3,2,4,4,4,2,3,3,3],[3,2,2,0,3,2,2,3,0,2,2,3],[0,3,3,0,3,2,2,3,0,3,3,0],[0,0,0,0,3,4,4,3,0,0,0,0],[0,0,0,0,3,2,2,3,0,0,0,0],[0,0,0,0,3,2,0,2,3,0,0,0],[0,0,0,3,3,3,0,3,3,3,0,0]],"eat":[[0,0,0,0,3,0,0,3,0,0,0,0],[0,0,0,3,3,3,3,3,3,3,0,0],[0,0,3,2,2,2,2,2,2,2,3,0],[0,0,3,2,3,2,2,2,3,2,3,0],[0,0,3,2,2,2,1,2,2,2,3,0],[3,3,3,3,2,1,3,1,2,3,3,3],[3,2,2,0,3,2,2,3,0,2,2,3],[0,3,3,0,3,2,2,3,0,3,3,0],[0,0,0,0,3,4,4,3,0,0,0,0],[0,0,0,0,3,2,2,3,0,0,0,0],[0,0,0,0,3,2,0,2,3,0,0,0],[0,0,0,3,3,3,0,3,3,3,0,0]],"sleep":[[0,0,0,0,3,0,0,3,0,0,0,0],[0,0,0,3,3,3,3,3,3,3,0,0],[0,0,3,2,2,2,2,2,2,2,3,0],[0,0,3,2,2,2,2,2,2,2,3,0],[0,0,3,2,5,5,2,5,5,2,3,0],[3,3,3,3,2,2,2,2,2,3,3,3],[3,2,2,0,3,2,2,3,0,2,2,3],[0,3,3,0,3,2,2,3,0,3,3,0],[0,0,0,0,3,4,4,3,0,0,0,0],[0,0,0,0,3,2,2,3,0,0,0,0],[0,0,0,0,3,2,0,2,3,0,0,0],[0,0,0,3,3,3,0,3,3,3,0,0]]}};
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
/* The source stylesheet stays intact. These are embedding and access exceptions. */
|
|
2
|
+
[hidden] { display:none!important; }
|
|
3
|
+
html[data-embedded="true"] #settings-btn { display:none; }
|
|
4
|
+
button:focus-visible { outline:2px solid var(--accent); outline-offset:2px; }
|
|
5
|
+
.overlay-close { background:transparent; font-family:inherit; }
|
|
6
|
+
.overlay { overflow:auto; }
|
|
7
|
+
.settings-row[hidden] { display:none; }
|
|
8
|
+
#pet-needs { width:94%; min-height:24px; padding:4px 0; text-align:center; color:var(--lcd-fg); font-size:10px; line-height:1.5; }
|
|
9
|
+
#lcd { margin-inline:auto; max-width:100%; }
|
|
10
|
+
#pet-status, #save-status { position:absolute; width:1px; height:1px; padding:0; overflow:hidden; clip-path:inset(50%); white-space:nowrap; }
|
|
11
|
+
html[data-embedded="true"], html[data-embedded="true"] body { height:100%; min-height:0; }
|
|
12
|
+
html[data-embedded="true"] body { justify-content:flex-start; padding:12px 0; }
|
|
13
|
+
html[data-embedded="true"] #device { box-shadow:var(--device-inset); }
|
|
14
|
+
html[data-embedded="true"] .overlay { padding:12px 8px; }
|
|
15
|
+
html[data-embedded="true"] .overlay-title { margin-top:12px; }
|
|
16
|
+
html[data-embedded="true"] #settings-btn { top:8px; right:10px; }
|
|
17
|
+
@media(max-width:359px) {
|
|
18
|
+
.overlay-title { font-size:15px; }
|
|
19
|
+
#game-overlay .game-area { gap:12px; }
|
|
20
|
+
#game-overlay .game-arrow { width:56px; height:56px; font-size:28px; }
|
|
21
|
+
#stats-overlay .stat-row, .settings-row { max-width:100%; }
|
|
22
|
+
#toast { max-width:95%; white-space:normal; text-align:center; }
|
|
23
|
+
}
|
|
24
|
+
@media(max-height:400px) { .overlay { justify-content:flex-start; padding:12px 8px; } }
|
|
25
|
+
@media(prefers-reduced-motion:reduce) { * { animation:none!important; transition:none!important; } }
|
|
26
|
+
/* The host owns scrolling. Height comes from the private frame channel. */
|
|
27
|
+
html[data-embedded="true"], html[data-embedded="true"] body { height:auto; overflow:hidden; }
|
|
28
|
+
html[data-embedded="true"] #device { flex-shrink:0; }
|
|
29
|
+
html[data-embedded="true"] .overlay { overflow:hidden; }
|
|
30
|
+
html[data-embedded="true"] #save-status { display:none; }
|
|
31
|
+
html[data-embedded="true"] #settings-btn { width:44px; height:44px; top:0; }
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
/* Leave a visible shell around the display and both rows of controls. */
|
|
35
|
+
#device { padding:44px 14px 38px; }
|
|
36
|
+
#screen-frame { width:82%; border-radius:22px; padding:7px; }
|
|
37
|
+
#lcd { border-radius:15px; }
|
|
38
|
+
#attention-bar { width:76%; }
|
|
39
|
+
#controls { width:82%; gap:8px; margin-top:8px; }
|
|
40
|
+
.ctrl-btn { border-radius:22px; min-height:52px; padding:8px 2px; }
|
|
41
|
+
html[data-embedded="true"] #settings-btn { top:2px; right:calc(50% - 22px); }
|
|
42
|
+
|
|
43
|
+
/* The pet has its own screen. Information and secondary care sit below the shell. */
|
|
44
|
+
html[data-embedded="true"] #device,#device { padding:0; border-radius:0; background:transparent; box-shadow:none; width:100%; }
|
|
45
|
+
#egg-shell { box-sizing:border-box; width:100%; padding:42px 14px 32px; position:relative; display:flex; flex-direction:column; align-items:center; border-radius:48% 48% 44% 44% / 52% 52% 42% 42%; background:var(--device-bg); box-shadow:var(--device-inset); }
|
|
46
|
+
#pet-clock { position:absolute; top:17px; left:0; right:0; text-align:center; font:12px/1.3 system-ui,sans-serif; color:#28352b; }
|
|
47
|
+
.keychain { position:absolute; width:78px; height:73px; top:0; right:0; pointer-events:none; opacity:.82; }
|
|
48
|
+
#device { position:relative; isolation:isolate; }
|
|
49
|
+
#egg-shell { z-index:1; }
|
|
50
|
+
html[data-embedded="true"] #settings-btn { top:5px; right:23%; width:44px; height:44px; font-size:19px; opacity:1; color:#28352b; }
|
|
51
|
+
#screen-frame { position:relative; width:80%; padding:12px; border-radius:24px; overflow:visible; background:linear-gradient(150deg,var(--scene-top,#a8b69a),var(--screen-frame)); }
|
|
52
|
+
#lcd { border-radius:0; position:relative; }
|
|
53
|
+
#attention-bar { width:68%; height:4px; margin:8px 0; }
|
|
54
|
+
#controls { width:78%; grid-template-columns:repeat(3,minmax(0,1fr)); margin-top:2px; gap:10px; }
|
|
55
|
+
.ctrl-btn { min-height:56px; padding:8px 3px; border-radius:24px; }
|
|
56
|
+
.ctrl-btn .label { font:11px/1.3 system-ui,sans-serif; letter-spacing:0; opacity:1; }
|
|
57
|
+
.ctrl-btn .icon-color { display:none; }
|
|
58
|
+
.ctrl-btn .icon-mono { display:block; width:20px; height:20px; }
|
|
59
|
+
.ctrl-btn:disabled { opacity:.58; }
|
|
60
|
+
.care-symbol { font:24px/1 system-ui,sans-serif; margin-bottom:3px; }
|
|
61
|
+
#care-panel { width:100%; padding:12px 8px 0; box-sizing:border-box; color:#e7e5df; font:12px/1.5 system-ui,sans-serif; }
|
|
62
|
+
#pet-identity { text-align:center; font-weight:600; font-size:13px; margin-bottom:8px; text-transform:capitalize; }
|
|
63
|
+
#pet-needs { width:100%; color:inherit; font:12px/1.5 system-ui,sans-serif; min-height:0; }
|
|
64
|
+
#care-meters { display:grid; grid-template-columns:repeat(2,minmax(0,1fr)); gap:4px 16px; }
|
|
65
|
+
.need { display:flex; justify-content:space-between; gap:6px; }
|
|
66
|
+
.need strong { font-variant-numeric:tabular-nums; }
|
|
67
|
+
.care-grade { grid-column:1/-1; text-align:center; font-size:11px; color:#bac7bc; margin-top:3px; }
|
|
68
|
+
#care-hint { margin:8px 0; text-align:center; color:#c6cfc7; font-size:12px; }
|
|
69
|
+
#more-care { border-top:1px solid #414941; }
|
|
70
|
+
/* Match the 12px frame space below the care row. */
|
|
71
|
+
#more-care summary { box-sizing:border-box; min-height:56px; padding-top:12px; display:flex; align-items:center; justify-content:center; cursor:pointer; }
|
|
72
|
+
#more-care summary::after { content:' +'; margin-left:6px; }
|
|
73
|
+
#more-care[open] summary::after { content:' −'; }
|
|
74
|
+
.secondary-controls { display:grid; grid-template-columns:repeat(3,minmax(0,1fr)); gap:8px; padding-bottom:8px; }
|
|
75
|
+
.secondary-controls .ctrl-btn { border-radius:14px; }
|
|
76
|
+
:root[data-scene="morning"] { --scene-top:#b8b389; --lcd-bg:#c6cfa7; }
|
|
77
|
+
:root[data-scene="afternoon"] { --scene-top:#9fb6ac; --lcd-bg:#c4cfa1; }
|
|
78
|
+
:root[data-scene="evening"] { --scene-top:#ba9c86; --lcd-bg:#c9b89b; }
|
|
79
|
+
:root[data-scene="night"],:root[data-scene="sleep"],:root[data-scene="dark"] { --scene-top:#697c79; --lcd-bg:#a4b2a0; }
|
|
80
|
+
:root.eink { --scene-top:#ddd; --lcd-bg:#f0f0f0; }
|
|
81
|
+
.scanlines:not(.eink) #screen-frame::after { content:''; position:absolute; inset:12px; pointer-events:none; background:repeating-linear-gradient(transparent 0 3px,#0000000b 3px 4px); }
|
|
82
|
+
html[data-embedded="true"],html[data-embedded="true"] body { background:#121619; }
|
|
83
|
+
@media(max-width:300px) { #egg-shell {padding-inline:8px;} #controls{width:86%;gap:6px;} #screen-frame{width:84%;padding:10px;} #care-panel{padding-inline:3px;} }
|
|
84
|
+
|
|
85
|
+
/* Dialog text needs the same readable contrast and sizing as the care panel. */
|
|
86
|
+
.overlay { background:#121619; color:#eef1ed; font:14px/1.6 system-ui,sans-serif; gap:12px; }
|
|
87
|
+
.overlay-title { color:#e7c88d; font:700 18px/1.4 system-ui,sans-serif; letter-spacing:.04em; }
|
|
88
|
+
#settings-overlay .settings-info,#death-overlay .death-msg { color:#c6cfc7; font:14px/1.6 system-ui,sans-serif; max-width:30ch; }
|
|
89
|
+
.settings-row { font:14px/1.5 system-ui,sans-serif; min-height:44px; gap:12px; }
|
|
90
|
+
.overlay-btn,.overlay-close { font:14px/1.5 system-ui,sans-serif; min-height:44px; padding:10px 14px; }
|
|
91
|
+
.overlay-btn { color:#eef1ed; background:#27332b; border-color:#9ba996; }
|
|
92
|
+
.overlay-close { color:#eef1ed; border-color:#9ba996; }
|
|
93
|
+
.stat-row,.game-score,.game-result { font:14px/1.5 system-ui,sans-serif; color:#eef1ed; }
|
|
94
|
+
.toggle { flex-shrink:0; min-width:48px; min-height:28px; }
|
|
95
|
+
html[data-embedded="true"] .overlay { padding:20px 12px; }
|
|
96
|
+
/* Let the host size and scroll the entire dialog without squeezing its controls. */
|
|
97
|
+
html[data-embedded="true"] .overlay { position:absolute; height:auto; min-height:100%; box-sizing:border-box; justify-content:flex-start; }
|
|
98
|
+
html[data-embedded="true"] .overlay > * { flex-shrink:0; }
|
|
99
|
+
.settings-header { display:flex; align-items:center; justify-content:space-between; gap:12px; width:100%; max-width:280px; }
|
|
100
|
+
.settings-header .overlay-title { margin:0; }
|
|
101
|
+
.settings-header .overlay-close { margin:0; }
|
|
102
|
+
#settings-overlay .settings-row { max-width:280px; width:100%; margin:0; padding:6px 0; }
|
|
103
|
+
#settings-overlay .settings-info { max-width:280px; width:100%; margin:0 0 6px; text-align:left; }
|
|
104
|
+
#settings-overlay #reset-game-btn { margin:8px 0 0; max-width:100%; }
|
|
105
|
+
@media(forced-colors:active) { .overlay,.overlay-btn,.overlay-close { forced-color-adjust:auto; } .toggle { border:2px solid ButtonText; } }
|
|
106
|
+
|
|
107
|
+
.arcade-picker{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:8px;width:100%}.arcade-instruction,.arcade-score{margin:0;text-align:center;max-width:30ch}.arcade-actions{display:flex;gap:8px;width:100%}.arcade-actions button{flex:1}.arcade-field{width:100%;max-width:320px;image-rendering:pixelated;aspect-ratio:2}.arcade-pet{width:64px;height:64px;object-fit:contain;image-rendering:pixelated}.arcade-cue{min-height:28px;font-size:20px;text-align:center}.arcade-options{font-size:13px}
|
|
108
|
+
|
|
109
|
+
.arcade-meter{height:24px;width:90%;position:relative;background:#283b45;border:1px solid #96aaa4}.arcade-meter span{position:absolute;inset-block:0;background:#5e9c70}.arcade-meter i{position:absolute;top:0;bottom:0;width:3px;background:white}.arcade-actions button{touch-action:none}
|
|
110
|
+
/* Full size guessing pets keep their own pixels and leave room for both arrows. */
|
|
111
|
+
#game-overlay .game-area { gap:8px; max-width:100%; }
|
|
112
|
+
#game-overlay .game-pet { width:128px; height:128px; flex:none; }
|
|
113
|
+
#game-overlay .game-arrow { width:48px; height:48px; flex:none; font-size:28px; }
|
|
114
|
+
|
|
115
|
+
/* Game controls fit the drawer instead of inheriting fixed menu button widths. */
|
|
116
|
+
#arcade-overlay, #game-overlay { box-sizing:border-box; gap:12px; justify-content:flex-start; padding:16px 0; }
|
|
117
|
+
html[data-embedded="true"] #arcade-overlay, html[data-embedded="true"] #game-overlay { padding:16px 0; }
|
|
118
|
+
#arcade-overlay .overlay-title, #game-overlay .overlay-title { margin:0; font-size:18px; line-height:1.4; letter-spacing:0; }
|
|
119
|
+
#arcade-overlay .overlay-btn, #game-overlay .overlay-btn { box-sizing:border-box; width:100%; min-width:0; min-height:48px; margin:0; padding:12px 8px; font:inherit; line-height:1.25; border-radius:12px; }
|
|
120
|
+
#arcade-overlay .arcade-picker { width:100%; gap:10px; grid-template-columns:repeat(2,minmax(0,1fr)); }
|
|
121
|
+
#arcade-overlay .arcade-picker button { min-height:60px; }
|
|
122
|
+
#arcade-overlay .arcade-actions, #game-overlay .game-area { display:flex; width:100%; gap:8px; margin:0; }
|
|
123
|
+
#arcade-overlay .arcade-actions button, #game-overlay .game-arrow { flex:1 1 0; width:0; min-width:0; font-size:14px; border-radius:12px; }
|
|
124
|
+
#arcade-overlay .arcade-field, #game-overlay .guess-field { width:100%; max-width:100%; height:auto; aspect-ratio:4/3; display:block; image-rendering:pixelated; border-radius:12px; }
|
|
125
|
+
#arcade-overlay .arcade-cue { min-height:0; font-size:16px; line-height:1.4; }
|
|
126
|
+
#arcade-overlay .arcade-score, #game-overlay .game-score, #game-overlay .game-result { margin:0; font-size:14px; line-height:1.4; text-align:center; color:inherit; }
|
|
127
|
+
#arcade-overlay .arcade-pause { width:auto; min-width:96px; padding:8px 16px; background:transparent; }
|
|
128
|
+
#arcade-overlay .arcade-exit, #game-overlay #guess-exit { box-sizing:border-box; margin:0; min-height:44px; padding:10px 16px; }
|
|
129
|
+
#arcade-overlay .arcade-instruction { max-width:100%; font-size:14px; line-height:1.5; }
|
|
130
|
+
#arcade-overlay .arcade-options { font-size:14px; min-height:36px; display:flex; align-items:center; gap:6px; }
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { now as clockNow } from './clock.js';
|
|
2
|
+
import { initializeWellbeing } from './wellbeing.js';
|
|
3
|
+
import { C } from './constants.js';
|
|
4
|
+
import { saveState, loadState, clearState, selectedCharacter } from './storage.js';
|
|
5
|
+
|
|
6
|
+
export class GameState {
|
|
7
|
+
constructor(choice=selectedCharacter){ Object.defineProperty(this,'preset',{value:choice}); this.reset(); }
|
|
8
|
+
reset(){
|
|
9
|
+
const now=clockNow();
|
|
10
|
+
Object.assign(this,{
|
|
11
|
+
stage:this.preset.stage, character:this.preset.character, age:0, weight:C.BASE_WT[this.preset.stage] || 5,
|
|
12
|
+
hunger:0, happiness:0, discipline:0,
|
|
13
|
+
careMistakes:0, poopCount:0,
|
|
14
|
+
isSick:false, isSleeping:false, lightOn:true,
|
|
15
|
+
isDead:false, isMisbehaving:false,
|
|
16
|
+
bornAt:now, stageStartTime:now, lastProcessed:now,
|
|
17
|
+
lastHungerDecay:now, lastHappyDecay:now,
|
|
18
|
+
lastPoopTime:now, lastAgeInc:now,
|
|
19
|
+
attentionCallTime:null, attentionReason:null,
|
|
20
|
+
snacksInWindow:0, snackWindowStart:now,
|
|
21
|
+
medDoses:0, prevTeen:null, sickCount:0,
|
|
22
|
+
energy:100, health:100, wellbeingUpdatedAt:now, careTotal:0, careDuration:0,
|
|
23
|
+
sleepOverride:'auto', sleepOverrideUntil:0,
|
|
24
|
+
vacationAt:0,
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
save(){ return saveState(this); }
|
|
28
|
+
load(){
|
|
29
|
+
// Leave known fields enumerable so the storage adapter can copy new saves.
|
|
30
|
+
this.energy=undefined; this.health=undefined; this.wellbeingUpdatedAt=undefined;
|
|
31
|
+
const loaded=loadState(this);
|
|
32
|
+
initializeWellbeing(this,this.lastProcessed);
|
|
33
|
+
return loaded;
|
|
34
|
+
}
|
|
35
|
+
clearSave(){ clearState(); }
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export { Evo } from './evolution.js';
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { now as clockNow } from './clock.js';
|
|
2
|
+
import { C } from './constants.js';
|
|
3
|
+
import { isP2, evolveP2 } from './original-roster.js';
|
|
4
|
+
export const Evo = {
|
|
5
|
+
evolve(st){
|
|
6
|
+
if(isP2(st))return evolveP2(st);
|
|
7
|
+
switch(st.stage){
|
|
8
|
+
case 'egg': return {stage:'baby',character:'babytchi',weight:C.BASE_WT.baby};
|
|
9
|
+
case 'baby': return {stage:'child',character:'marutchi',weight:C.BASE_WT.child};
|
|
10
|
+
case 'child':
|
|
11
|
+
if(st.careMistakes<=1)
|
|
12
|
+
return {stage:'teen',character:'tamatchi',weight:C.BASE_WT.teen};
|
|
13
|
+
return {stage:'teen',character:'kuchitamatchi',weight:C.BASE_WT.teen};
|
|
14
|
+
case 'teen': return Evo.toAdult(st);
|
|
15
|
+
default: return null;
|
|
16
|
+
}
|
|
17
|
+
},
|
|
18
|
+
toAdult(st){
|
|
19
|
+
const d=st.discipline, cm=st.careMistakes;
|
|
20
|
+
if(st.character==='tamatchi'){
|
|
21
|
+
if(cm<=2&&d>=100) return {stage:'adult',character:'mametchi',weight:25};
|
|
22
|
+
if(cm<=2&&d>=75) return {stage:'adult',character:'ginjirotchi',weight:30};
|
|
23
|
+
if(cm<=4&&d>=50) return {stage:'adult',character:'maskutchi',weight:30};
|
|
24
|
+
if(d>=50) return {stage:'adult',character:'kuchipatchi',weight:35};
|
|
25
|
+
if(d>=25) return {stage:'adult',character:'nyorotchi',weight:30};
|
|
26
|
+
return {stage:'adult',character:'tarakotchi',weight:35};
|
|
27
|
+
}
|
|
28
|
+
if(d>=75) return {stage:'adult',character:'kuchipatchi',weight:35};
|
|
29
|
+
if(d>=50) return {stage:'adult',character:'nyorotchi',weight:30};
|
|
30
|
+
return {stage:'adult',character:'tarakotchi',weight:35};
|
|
31
|
+
},
|
|
32
|
+
shouldEvolve(st){
|
|
33
|
+
const e=clockNow()-st.stageStartTime;
|
|
34
|
+
switch(st.stage){
|
|
35
|
+
case 'egg': return e>=C.EGG_MS;
|
|
36
|
+
case 'baby': return e>=C.BABY_MS;
|
|
37
|
+
case 'child': return e>=C.CHILD_MS;
|
|
38
|
+
case 'teen': return e>=C.TEEN_MS;
|
|
39
|
+
default: return false;
|
|
40
|
+
}
|
|
41
|
+
},
|
|
42
|
+
checkOyajitchi(st){
|
|
43
|
+
return st.character==='maskutchi'&&st.discipline>=100&&st.age>=10;
|
|
44
|
+
}
|
|
45
|
+
};
|
|
46
|
+
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
export function visibleEnabledControl(node) {
|
|
2
|
+
if(node.disabled || node.hidden || node.closest?.('[hidden], [inert]'))return false;
|
|
3
|
+
if(node.getClientRects && !node.getClientRects().length)return false;
|
|
4
|
+
if(typeof getComputedStyle==='function' && getComputedStyle(node).visibility==='hidden')return false;
|
|
5
|
+
const closed=node.closest?.('details:not([open])');
|
|
6
|
+
return !closed || (node.tagName==='SUMMARY' && node.parentElement===closed);
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export function overlayControls(overlay) {
|
|
10
|
+
const nodes=overlay.querySelectorAll?.('button, input, select, textarea, a[href], summary') || [overlay.querySelector?.('button')].filter(Boolean);
|
|
11
|
+
return [...nodes].filter(visibleEnabledControl);
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
// A game can focus its dialog rather than a button when a round starts.
|
|
15
|
+
export function trapOverlayTab(event,overlay,active=document.activeElement) {
|
|
16
|
+
if(event.key!=='Tab')return;
|
|
17
|
+
const controls=overlayControls(overlay);
|
|
18
|
+
const first=controls[0],last=controls.at(-1);
|
|
19
|
+
if(!controls.includes(active)){
|
|
20
|
+
event.preventDefault();
|
|
21
|
+
(event.shiftKey?last:first)?.focus();
|
|
22
|
+
}else if(event.shiftKey&&active===first){
|
|
23
|
+
event.preventDefault();last.focus();
|
|
24
|
+
}else if(!event.shiftKey&&active===last){
|
|
25
|
+
event.preventDefault();first.focus();
|
|
26
|
+
}
|
|
27
|
+
}
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
export const PF = {};
|
|
2
|
+
const _f = s => s.trim().split('\n').map(r => r.trim().split('').map(Number));
|
|
3
|
+
const FONT_DATA = {
|
|
4
|
+
A:`010
|
|
5
|
+
101
|
|
6
|
+
111
|
|
7
|
+
101
|
|
8
|
+
101`,B:`110
|
|
9
|
+
101
|
|
10
|
+
110
|
|
11
|
+
101
|
|
12
|
+
110`,C:`011
|
|
13
|
+
100
|
|
14
|
+
100
|
|
15
|
+
100
|
|
16
|
+
011`,D:`110
|
|
17
|
+
101
|
|
18
|
+
101
|
|
19
|
+
101
|
|
20
|
+
110`,E:`111
|
|
21
|
+
100
|
|
22
|
+
110
|
|
23
|
+
100
|
|
24
|
+
111`,F:`111
|
|
25
|
+
100
|
|
26
|
+
110
|
|
27
|
+
100
|
|
28
|
+
100`,G:`011
|
|
29
|
+
100
|
|
30
|
+
101
|
|
31
|
+
101
|
|
32
|
+
011`,H:`101
|
|
33
|
+
101
|
|
34
|
+
111
|
|
35
|
+
101
|
|
36
|
+
101`,I:`111
|
|
37
|
+
010
|
|
38
|
+
010
|
|
39
|
+
010
|
|
40
|
+
111`,J:`001
|
|
41
|
+
001
|
|
42
|
+
001
|
|
43
|
+
101
|
|
44
|
+
010`,K:`101
|
|
45
|
+
110
|
|
46
|
+
100
|
|
47
|
+
110
|
|
48
|
+
101`,L:`100
|
|
49
|
+
100
|
|
50
|
+
100
|
|
51
|
+
100
|
|
52
|
+
111`,M:`10001
|
|
53
|
+
11011
|
|
54
|
+
10101
|
|
55
|
+
10001
|
|
56
|
+
10001`,N:`101
|
|
57
|
+
111
|
|
58
|
+
111
|
|
59
|
+
101
|
|
60
|
+
101`,O:`010
|
|
61
|
+
101
|
|
62
|
+
101
|
|
63
|
+
101
|
|
64
|
+
010`,P:`110
|
|
65
|
+
101
|
|
66
|
+
110
|
|
67
|
+
100
|
|
68
|
+
100`,Q:`010
|
|
69
|
+
101
|
|
70
|
+
101
|
|
71
|
+
011
|
|
72
|
+
001`,R:`110
|
|
73
|
+
101
|
|
74
|
+
110
|
|
75
|
+
101
|
|
76
|
+
101`,S:`011
|
|
77
|
+
100
|
|
78
|
+
010
|
|
79
|
+
001
|
|
80
|
+
110`,T:`111
|
|
81
|
+
010
|
|
82
|
+
010
|
|
83
|
+
010
|
|
84
|
+
010`,U:`101
|
|
85
|
+
101
|
|
86
|
+
101
|
|
87
|
+
101
|
|
88
|
+
010`,V:`101
|
|
89
|
+
101
|
|
90
|
+
101
|
|
91
|
+
010
|
|
92
|
+
010`,W:`10001
|
|
93
|
+
10001
|
|
94
|
+
10101
|
|
95
|
+
10101
|
|
96
|
+
01010`,X:`101
|
|
97
|
+
101
|
|
98
|
+
010
|
|
99
|
+
101
|
|
100
|
+
101`,Y:`101
|
|
101
|
+
101
|
|
102
|
+
010
|
|
103
|
+
010
|
|
104
|
+
010`,Z:`111
|
|
105
|
+
001
|
|
106
|
+
010
|
|
107
|
+
100
|
|
108
|
+
111`,
|
|
109
|
+
'0':`111
|
|
110
|
+
101
|
|
111
|
+
101
|
|
112
|
+
101
|
|
113
|
+
111`,'1':`010
|
|
114
|
+
110
|
|
115
|
+
010
|
|
116
|
+
010
|
|
117
|
+
111`,'2':`110
|
|
118
|
+
001
|
|
119
|
+
010
|
|
120
|
+
100
|
|
121
|
+
111`,'3':`110
|
|
122
|
+
001
|
|
123
|
+
010
|
|
124
|
+
001
|
|
125
|
+
110`,'4':`101
|
|
126
|
+
101
|
|
127
|
+
111
|
|
128
|
+
001
|
|
129
|
+
001`,'5':`111
|
|
130
|
+
100
|
|
131
|
+
110
|
|
132
|
+
001
|
|
133
|
+
110`,'6':`011
|
|
134
|
+
100
|
|
135
|
+
110
|
|
136
|
+
101
|
|
137
|
+
010`,'7':`111
|
|
138
|
+
001
|
|
139
|
+
010
|
|
140
|
+
010
|
|
141
|
+
010`,'8':`010
|
|
142
|
+
101
|
|
143
|
+
010
|
|
144
|
+
101
|
|
145
|
+
010`,'9':`010
|
|
146
|
+
101
|
|
147
|
+
011
|
|
148
|
+
001
|
|
149
|
+
110`,
|
|
150
|
+
'%':`101
|
|
151
|
+
001
|
|
152
|
+
010
|
|
153
|
+
100
|
|
154
|
+
101`,'/':`001
|
|
155
|
+
001
|
|
156
|
+
010
|
|
157
|
+
100
|
|
158
|
+
100`,':':`0
|
|
159
|
+
1
|
|
160
|
+
0
|
|
161
|
+
1
|
|
162
|
+
0`,'!':`1
|
|
163
|
+
1
|
|
164
|
+
1
|
|
165
|
+
0
|
|
166
|
+
1`,'-':`000
|
|
167
|
+
000
|
|
168
|
+
111
|
|
169
|
+
000
|
|
170
|
+
000`,' ':`00
|
|
171
|
+
00
|
|
172
|
+
00
|
|
173
|
+
00
|
|
174
|
+
00`,'?':`110
|
|
175
|
+
001
|
|
176
|
+
010
|
|
177
|
+
000
|
|
178
|
+
010`,'.':`0
|
|
179
|
+
0
|
|
180
|
+
0
|
|
181
|
+
0
|
|
182
|
+
1`,
|
|
183
|
+
};
|
|
184
|
+
for(const[k,v] of Object.entries(FONT_DATA)) PF[k]=_f(v);
|
|
185
|
+
|