Compare commits
216 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 066f1fd060 | |||
| 162eaffd1d | |||
| b5a4db5224 | |||
| 09b3aeb8c5 | |||
| c83ceef3c4 | |||
| 221e5219f0 | |||
| 145dfe964d | |||
| bf9702e3a1 | |||
| b3f1e6c9c5 | |||
| 960f3137c6 | |||
| e38daf3ebb | |||
| e72d16f811 | |||
| dea6001234 | |||
| 67d7584a6e | |||
| 417e386412 | |||
| c3d556ed80 | |||
| af24e69848 | |||
| 6d2f1df0da | |||
| 037db837b2 | |||
| e91fab8a94 | |||
| b65ef06acd | |||
| 10527e4480 | |||
| 25d1d4f4bc | |||
| b8fcb7203d | |||
| 79e21a1156 | |||
| 70d0b4460a | |||
| 40b1ba3542 | |||
| 274290cc5b | |||
| fa6aa9bc7d | |||
| b18c41349d | |||
| b36f20c0d7 | |||
| 75a1d3c5aa | |||
| 78ab0fee06 | |||
| 1b8fe068f7 | |||
| 204635a84b | |||
| 21d6df56a4 | |||
| 514adffb9c | |||
| 0006634e5d | |||
| fe79670273 | |||
| f11af0da02 | |||
| fbd56604c0 | |||
| 296e2665b5 | |||
| 70b6129c6e | |||
| aa84c5f8a2 | |||
| 8b0a237ce4 | |||
| 6f89bc68fe | |||
| 48f7941e64 | |||
| 2557e76761 | |||
| b2d556a9f4 | |||
| b1faf87dc0 | |||
| 12b5d2d042 | |||
| 64dc0a5b1d | |||
| 4e63afbfc6 | |||
| f8f863cada | |||
| 441e67a462 | |||
| c01cdfd4e6 | |||
| a4e609f927 | |||
| ccb8be24d5 | |||
| 8d4cd08e2e | |||
| a40c5e3951 | |||
| 06de7417a8 | |||
| b4d1d757e1 | |||
| 574df2b670 | |||
| a5c26a8d68 | |||
| 866acdb8b2 | |||
| b833713afe | |||
| 7db04c03d7 | |||
| b13c6aa488 | |||
| 1c1a2315a0 | |||
| 38ac352795 | |||
| 2c9392de8d | |||
| 71507e0164 | |||
| 74e8a7b34f | |||
| 5031b089ff | |||
| 8a265a2e84 | |||
| fb7d78ef83 | |||
| 65be1b4f40 | |||
| 77f483bd18 | |||
| a52178b5f8 | |||
| 1e4670c112 | |||
| ed0a5de025 | |||
| c73d2ebae6 | |||
| f048e0bbc2 | |||
| 7654b2a212 | |||
| cf1acb64bf | |||
| 6433c737d7 | |||
| 1e816faf00 | |||
| e876fc7768 | |||
| a59bce865f | |||
| 1003a78a2a | |||
| 92d739ce24 | |||
| 5754749af2 | |||
| 398be68058 | |||
| efcae96a5a | |||
| 55caf12417 | |||
| 166f3b8a58 | |||
| 7330c24635 | |||
| d2f3392722 | |||
| e06139d5c0 | |||
| d72b6c553f | |||
| 3727c5077b | |||
| 6234612bef | |||
| 85ea1c9149 | |||
| 44e05a166e | |||
| 3a9149e9a4 | |||
| 20288a686b | |||
| 8d280345ed | |||
| 0e22119a38 | |||
| 0ba0286d9c | |||
| bbb49741cf | |||
| 538bd7caee | |||
| f63bcad8eb | |||
| e420fdf8fd | |||
| 418734cfce | |||
| d08efd4d3c | |||
| 0e919dcb8a | |||
| 31034b064d | |||
| a36ef5953b | |||
| 73405837c9 | |||
| aa887b5b08 | |||
| 59b8d32232 | |||
| 4c0fc07ff8 | |||
| e18c730d1e | |||
| 37196e1924 | |||
| 96178012d4 | |||
| 6e135949fe | |||
| 4964b01eac | |||
| 40ad57dd93 | |||
| 3f3d6dda0f | |||
| 476cafdc4a | |||
| 01d6cdbff4 | |||
| df6b130b56 | |||
| 32d7d4b824 | |||
| 3b83c7b9e3 | |||
| e3f93818d6 | |||
| 598601cbf2 | |||
| 7766ceb607 | |||
| 3b20e05769 | |||
| b6bbdde260 | |||
| 824a4a229f | |||
| 2a3d811187 | |||
| 403621be40 | |||
| 84785f3e40 | |||
| 1b7ae5f1ff | |||
| 4a5127fecf | |||
| 1c8628bb3d | |||
| 160aab5bc2 | |||
| eff286199f | |||
| 175f9f869f | |||
| 43d621324a | |||
| d60d8bab51 | |||
| b849b6bf7e | |||
| 1cf073bc51 | |||
| d86f2330d5 | |||
| ee461384b2 | |||
| 6928367884 | |||
| caf08695d1 | |||
| 2ec9fc5412 | |||
| 156ef662f4 | |||
| 16bda15111 | |||
| 6789db0997 | |||
| cea157765e | |||
| bcdb452aa3 | |||
| 2346935149 | |||
| f730eaa0e6 | |||
| 7e808e1bde | |||
| 22794d3f71 | |||
| 0195c857d5 | |||
| f105be1882 | |||
| 313dc29a9a | |||
| ac78231a78 | |||
| b73e547732 | |||
| 94781e78b0 | |||
| 86126e7444 | |||
| c758f13a10 | |||
| d866dc6d7b | |||
| c358af923a | |||
| 666862a6b2 | |||
| 325146e161 | |||
| 48c1b9a6cc | |||
| 2c4b276686 | |||
| dbac251c76 | |||
| 0cee643697 | |||
| d3eddf16d3 | |||
| a90f88049b | |||
| af4fca2e71 | |||
| e2fe7ef955 | |||
| 59678748a8 | |||
| d719f2fcbf | |||
| f1f8172f4e | |||
| cbe51784ba | |||
| c27bac4ea1 | |||
| da874adcad | |||
| 4b1433f22a | |||
| 4d22567ad4 | |||
| 3c42cfb546 | |||
| b0ef08c0c2 | |||
| a839eb18cd | |||
| dcba35d5ae | |||
| 5778ddc0b9 | |||
| bc4244c99a | |||
| 5191569e3e | |||
| bb830fa313 | |||
| e7427f564c | |||
| 0350ec09c4 | |||
| 99d445638f | |||
| 6cb60663b6 | |||
| fe761241b3 | |||
| 549d9de5ca | |||
| 36d8f30fe2 | |||
| a0974704c3 | |||
| 177cd4c34e | |||
| b3dd499e17 | |||
| ee5842bb1f | |||
| 62acdc845f | |||
| 1583a631a5 |
@@ -0,0 +1,2 @@
|
||||
node_modules
|
||||
npm-debug.log
|
||||
@@ -0,0 +1,31 @@
|
||||
# This workflow will do a clean install of node dependencies, cache/restore them, build the source code and run tests across different versions of node
|
||||
# For more information see: https://help.github.com/actions/language-and-framework-guides/using-nodejs-with-github-actions
|
||||
|
||||
name: Node.js CI
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ master ]
|
||||
pull_request:
|
||||
branches: [ master ]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
node-version: [14.x, 16.x]
|
||||
# See supported Node.js release schedule at https://nodejs.org/en/about/releases/
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Use Node.js ${{ matrix.node-version }}
|
||||
uses: actions/setup-node@v2
|
||||
with:
|
||||
node-version: ${{ matrix.node-version }}
|
||||
cache: 'npm'
|
||||
- run: npm install
|
||||
- run: npm run build --if-present
|
||||
- run: npm test
|
||||
@@ -103,4 +103,8 @@ dist
|
||||
# TernJS port file
|
||||
.tern-port
|
||||
|
||||
utils/xlsxTransform-*
|
||||
utils/xlsxTransform-*
|
||||
|
||||
/.idea
|
||||
|
||||
__localStorage.json
|
||||
@@ -22,6 +22,15 @@
|
||||
"skipFiles": [
|
||||
"<node_internals>/**"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Attach by Process ID",
|
||||
"processId": "${command:PickProcess}",
|
||||
"request": "attach",
|
||||
"skipFiles": [
|
||||
"<node_internals>/**"
|
||||
],
|
||||
"type": "node"
|
||||
},
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
FROM node:alpine
|
||||
|
||||
ENV NPM_CONFIG_LOGLEVEL info
|
||||
|
||||
WORKDIR /usr/src/app
|
||||
|
||||
COPY package*.json ./
|
||||
|
||||
RUN npm install
|
||||
|
||||
COPY . .
|
||||
|
||||
EXPOSE 8080
|
||||
CMD ["yarn", "dev"]
|
||||
|
||||
@@ -0,0 +1,72 @@
|
||||
# Life Restart
|
||||
|
||||
<a href="https://discord.gg/U3qrf49NMQ"><img src="https://img.shields.io/discord/883382868427014255?color=%23FEE75C&label=Discord&logo=discord&logoColor=white&style=for-the-badge" /></a>
|
||||
|
||||
[English](./README.md) | 简体中文
|
||||
|
||||
## 简介
|
||||
|
||||
- Game Life Restart
|
||||
|
||||
## 使用
|
||||
|
||||
<details>
|
||||
<summary><strong>网页版</strong></summary>
|
||||
<br />
|
||||
|
||||
1. 下载项目代码。
|
||||
|
||||
```bash
|
||||
git clone https://github.com/VickScarlet/lifeRestart.git my-project
|
||||
cd my-project
|
||||
```
|
||||
|
||||
2. 进入目录安装依赖。
|
||||
|
||||
```bash
|
||||
yarn install
|
||||
```
|
||||
|
||||
或者
|
||||
|
||||
```bash
|
||||
npm install
|
||||
```
|
||||
|
||||
3. 启动本地服务器。
|
||||
|
||||
```bash
|
||||
yarn dev
|
||||
```
|
||||
|
||||
或者
|
||||
|
||||
```bash
|
||||
npm run dev
|
||||
```
|
||||
|
||||
4. 启动完成后会自动打开浏览器访问 [http://localhost:8081/view/index.html](http://localhost:8081/view/index.html)。
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary><strong>控制台版本</strong></summary>
|
||||
<br />
|
||||
|
||||
```bash
|
||||
node repl
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
## 其他版本
|
||||
|
||||
<details>
|
||||
<summary><strong>版本列表</strong></summary>
|
||||
<br />
|
||||
|
||||
- Cocos版:[gameall3d/LifeRestart_Cocos](https://github.com/gameall3d/LifeRestart_Cocos)
|
||||
|
||||
</details>
|
||||
|
||||
> 更多信息请参考 [官网文档](https://liferestart.syaro.io/)。
|
||||
@@ -1,2 +1,71 @@
|
||||
# lifeRestart
|
||||
Game Life Restart
|
||||
# Life Restart
|
||||
|
||||
<a href="https://discord.gg/U3qrf49NMQ"><img src="https://img.shields.io/discord/883382868427014255?color=%23FEE75C&label=Discord&logo=discord&logoColor=white&style=for-the-badge" /></a>
|
||||
|
||||
English | [简体中文](./README-zh_CN.md)
|
||||
|
||||
## Introduction
|
||||
|
||||
- Game Life Restart
|
||||
|
||||
## Usage
|
||||
|
||||
<details>
|
||||
<summary><strong>Web Version</strong></summary>
|
||||
<br />
|
||||
|
||||
1. Clone project code.
|
||||
|
||||
```bash
|
||||
git clone git@github.com:VickScarlet/lifeRestart.git my-project
|
||||
cd my-project
|
||||
```
|
||||
|
||||
2. Installation dependence.
|
||||
|
||||
```bash
|
||||
yarn install
|
||||
```
|
||||
|
||||
Or
|
||||
|
||||
```bash
|
||||
npm install
|
||||
```
|
||||
|
||||
3. Start local server.
|
||||
|
||||
```bash
|
||||
yarn dev
|
||||
```
|
||||
|
||||
Or
|
||||
|
||||
```bash
|
||||
npm run dev
|
||||
```
|
||||
|
||||
4. After the startup is complete, will automatically open a browser and visit [http://localhost:8081/view/index.html](http://localhost:8081/view/index.html).
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary><strong>Command Line Version</strong></summary>
|
||||
<br />
|
||||
|
||||
```bash
|
||||
node repl
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
## Other Version
|
||||
|
||||
<details>
|
||||
<summary><strong>Versions</strong></summary>
|
||||
<br />
|
||||
|
||||
- Cocos Ver: [gameall3d/LifeRestart_Cocos](https://github.com/gameall3d/LifeRestart_Cocos)
|
||||
|
||||
</details>
|
||||
|
||||
> More instructions at [documentation](https://liferestart.syaro.io/).
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<html lang="{{ site.lang | default: "en-US" }}">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
|
||||
<script data-ad-client="ca-pub-9857163863537600" async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js"></script>
|
||||
{% seo %}
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com">
|
||||
<link rel="preload" href="https://fonts.googleapis.com/css?family=Open+Sans:400,700&display=swap" as="style" type="text/css" crossorigin>
|
||||
@@ -19,6 +19,7 @@
|
||||
<h1 class="project-name">{{ page.title | default: site.title | default: site.github.repository_name }}</h1>
|
||||
<h2 class="project-tagline">{{ page.description | default: site.description | default: site.github.project_tagline }}</h2>
|
||||
<a href="/view/" class="btn">RESTART</a>
|
||||
<a href="/view/test.html" class="btn">Source Version</a>
|
||||
{% if site.github.is_project_page %}
|
||||
<a href="{{ site.github.repository_url }}" class="btn">View on GitHub</a>
|
||||
{% endif %}
|
||||
|
||||
@@ -0,0 +1,136 @@
|
||||
$id,name,description,condition,grade,status,effect:SPR,effect:MNY,effect:CHR,effect:STR,effect:INT,exclusive[],exclusive[],exclusive[],exclusive[],exclusive[],exclusive[]
|
||||
序号,天赋名,括号中的内容,触发条件,稀有度,初始可用属性点,额外快乐,额外家境,额外颜值,额外体质,额外智力,互斥天赋,互斥天赋,互斥天赋,互斥天赋,互斥天赋,互斥天赋
|
||||
1001,随身玉佩,或许有护佑作用,,0,,,,,,,,,,,,
|
||||
1002,红肚兜,小时候死亡率降低,,0,,,,,,,,,,,,
|
||||
1003,生而为男,性别一定为男,,1,,,,,,,1004,1025,1024,1113,,
|
||||
1004,生而为女,性别一定为女,,1,,,,,,,1003,1024,1025,,,
|
||||
1005,动漫高手,入宅的可能性翻6倍,,2,,,,,,,,,,,,
|
||||
1006,乐观,快乐+1,,0,,1,,,,,,,,,,
|
||||
1007,天赋异禀,初始可用属性点+2,,1,2,,,,,,,,,,,
|
||||
1008,天生抑郁,快乐-3,,0,,-3,,,,,,,,,,
|
||||
1009,网络巨魔,快乐+2,,1,,2,,,,,,,,,,
|
||||
1010,天龙人,你拥有北京户口,,2,,,,,,,1012,1013,1014,,,
|
||||
1011,独生子女,你没有兄弟姐妹,,0,,,,,,,,,,,,
|
||||
1012,乡间微风,你出生在农村,,0,,,,,,,1010,1013,1014,,,
|
||||
1013,城中高楼,你出生在城市,,0,,,,,,,1010,1012,1014,,,
|
||||
1014,美籍华人,你有美国国籍,,2,,,3,,,,1010,1012,1013,,,
|
||||
1015,家中老大,你最受父母宠爱,,1,,,,,,,,,,,,
|
||||
1016,水性良好,不会被淹死,,0,,,,,,,,,,,,
|
||||
1017,先天免疫,你不会得艾滋病,,0,,,,,,,,,,,,
|
||||
1018,人类进化,所有属性+1,,2,,1,1,1,1,1,,,,,,
|
||||
1019,超凡,初始可用属性点+4,,2,4,,,,,,,,,,,
|
||||
1020,父母美貌,颜值+2,,1,,,,2,,,,,,,,
|
||||
1021,红颜薄命,颜值+2,体质-2,,0,,,,2,-2,,,,,,,
|
||||
1022,属蛇,不会被蛇咬死,,0,,,,,,,,,,,,
|
||||
1023,半神,所有属性+2,,3,,2,2,2,2,2,,,,,,
|
||||
1024,人中龙凤,天生双重性别,,2,,,,,,,1003,1004,1025,,,
|
||||
1025,阴阳之外,天生无性别,,2,,,,,,,1003,1024,1004,1113,,
|
||||
1026,彩虹之下,可能和同性交往,,0,,,,,,,1113,,,,,
|
||||
1027,斩情证道,终生不恋爱结婚,,1,,,,,,,1113,,,,,
|
||||
1028,桃花连连,恋爱机会提升,,0,,,,,,,,,,,,
|
||||
1029,平安童年,12岁前父母都健在,,1,,,,,,,,,,,,
|
||||
1030,宠物大师,宠物不会意外死亡,,0,,,,,,,,,,,,
|
||||
1031,天生残疾,体质-2,,0,,,,,-2,,,,,,,
|
||||
1032,早产儿,所有属性-1,,0,,-1,-1,-1,-1,-1,,,,,,
|
||||
1033,十死无生,体质-10,,0,,,,,-10,,,,,,,
|
||||
1034,家运不顺,家境-2,,0,,,-2,,,,,,,,,
|
||||
1035,头着地,智力-2,,0,,,,,,-2,,,,,,
|
||||
1036,胎教,智力+1,,0,,,,,,1,,,,,,
|
||||
1037,班中红人,和同学容易处好关系,,0,,,,,,,,,,,,
|
||||
1038,骑士,能轻松学会骑车,,0,,,,,,,,,,,,
|
||||
1039,永远的神,电竞天才,,1,,,,,,,,,,,,
|
||||
1040,戒律,赌毒不沾,,0,,,,,,,,,,,,
|
||||
1041,丁克,不生孩子,,1,,,,,,,1113,,,,,
|
||||
1042,少数民族,高考+5分,,0,,,,,,,,,,,,
|
||||
1043,老司机,你和家人不会发生车祸,,0,,,,,,,,,,,,
|
||||
1044,低压,你的家人不会心脏病,,0,,,,,,,,,,,,
|
||||
1045,战功,你退伍后会当官,,0,,,,,,,,,,,,
|
||||
1046,不孕不育,你生不出孩子,,1,,,,,,,1113,,,,,
|
||||
1047,白头偕老,爱人至少能活到70岁,,1,,,,,,,,,,,,
|
||||
1048,神秘的小盒子,100岁时才能开启,,3,,,,,,,,,,,,
|
||||
1049,三十而立,30岁时家境+2,AGE?[30],0,,,2,,,,,,,,,
|
||||
1050,四十不惑,40岁时智力+2,AGE?[40],0,,,,,,2,,,,,,
|
||||
1051,知天命,50岁时智力、快乐+1,AGE?[50],0,,1,,,,1,,,,,,
|
||||
1052,耳顺,60岁时快乐+2,AGE?[60],0,,2,,,,,,,,,,
|
||||
1053,从心所欲,70岁时快乐+3,AGE?[70],0,,3,,,,,,,,,,
|
||||
1054,老当益壮,60岁时体质+2,AGE?[60],1,,,,,2,,,,,,,
|
||||
1055,鹤发童颜,70岁时颜值+3,AGE?[70],0,,,,3,,,,,,,,
|
||||
1056,学前启蒙,5岁时智力+2,AGE?[5],1,,,,,,2,,,,,,
|
||||
1057,十八变,18岁时颜值+2,AGE?[18],1,,,,2,,,,,,,,
|
||||
1058,迟来之财,90岁时家境+4,AGE?[90],0,,,4,,,,,,,,,
|
||||
1059,理财达人,40岁时家境+3,AGE?[40],0,,,3,,,,,,,,,
|
||||
1060,成熟,18岁时智力+2,AGE?[18],1,,,,,,2,,,,,,
|
||||
1061,形象管理,24岁时颜值+2,AGE?[24],1,,,,2,,,,,,,,
|
||||
1062,成年礼,18岁时快乐+1,AGE?[18],0,,1,,,,,,,,,,
|
||||
1063,开光之胎,初始可用属性点+1,,0,1,,,,,,,,,,,
|
||||
1064,天命,初始可用属性点+8,,3,8,,,,,,,,,,,
|
||||
1065,祖传药丸,功能不明,,1,,,,,,,,,,,,
|
||||
1066,精准扶贫,家境为0时家境+1,(MNY<1)&(MNY>-1),0,,,1,,,,,,,,,
|
||||
1067,乐天派,快乐为0时快乐+1,(SPR<1)&(SPR>-1),1,,1,,,,,,,,,,
|
||||
1068,命悬一线,体质为0时体质+1,(STR<1)&(STR>-1),0,,,,,1,,,,,,,
|
||||
1069,智可生财,若20岁时智力>8,家境+2,(AGE?[20])&(INT>8),0,,,2,,,,,,,,,
|
||||
1070,舔狗甚多,若20岁时颜值>8,快乐+2,(AGE?[20])&(CHR>8),0,,2,,,,,,,,,,
|
||||
1071,保胎丸,你不会胎死腹中,,0,,,,,,,,,,,,
|
||||
1072,白化病,你不会遭遇枪击,,0,,,,,,,,,,,,
|
||||
1073,佛宗,考上哈佛大学的几率提高,,0,,,,,,,,,,,,
|
||||
1074,悟道,智力>10时快乐+3,INT>10,1,,3,,,,,,,,,,
|
||||
1075,驻颜,体质>10时颜值+3,STR>10,0,,,,3,,,,,,,,
|
||||
1076,界限突破,体质>10时快乐+3,STR>10,1,,3,,,,,,,,,,
|
||||
1077,倾城,颜值>10时快乐+3,CHR>10,1,,3,,,,,,,,,,
|
||||
1078,训练有方,智力>10时体质+3,INT>10,0,,,,,3,,,,,,,
|
||||
1079,相由心生,智力>10时颜值+3,INT>10,0,,,,3,,,,,,,,
|
||||
1080,智多鑫,智力>10时家境+3,INT>10,0,,,3,,,,,,,,,
|
||||
1081,灵光,快乐>10时其他属性+1,SPR>10,0,,,1,1,1,1,,,,,,
|
||||
1082,天启,快乐>10时其他属性+2,SPR>10,1,,,2,2,2,2,,,,,,
|
||||
1083,神谕,快乐>10时其他属性+3,SPR>10,2,,,3,3,3,3,,,,,,
|
||||
1084,献祭,初始可用属性点-2,快乐+2,,0,-2,2,,,,,1122,,,,,
|
||||
1085,幸运儿,初始可用属性点-3,快乐+5,,1,-3,5,,,,,1122,,,,,
|
||||
1086,挑战者,初始可用点-10,,0,-10,,,,,,1122,,,,,
|
||||
1087,你不懂,家境>10时快乐+3,MNY>10,1,,3,,,,,,,,,,
|
||||
1088,整容,家境>10时颜值+3,MNY>10,0,,,,3,,,,,,,,
|
||||
1089,钻石健身卡,家境>10时体质+3,MNY>10,0,,,,,3,,,,,,,
|
||||
1090,身残志坚,体质<0时其他属性+1,STR<0,0,,1,1,1,,1,,,,,,
|
||||
1091,活死人,体质<0时其他属性+2,STR<0,1,,2,2,2,,2,,,,,,
|
||||
1092,开一扇窗,颜值<0时其他属性+1,CHR<0,0,,1,1,,1,1,,,,,,
|
||||
1093,大额头,颜值-2,智力+2,,0,,,,-2,,2,,,,,,
|
||||
1094,痘痘脸,颜值-1,,0,,,,-1,,,,,,,,
|
||||
1095,潜能,家境<0时其他属性+1,MNY<0,0,,1,,1,1,1,,,,,,
|
||||
1096,哀兵,快乐<0时其他属性+1,SPR<0,0,,,1,1,1,1,,,,,,
|
||||
1097,苦痛侍僧,快乐<-1时其他属性+2,SPR<-1,1,,,2,2,2,2,,,,,,
|
||||
1098,觉醒,家境<-1时其他属性+2,MNY<-1,1,,2,,2,2,2,,,,,,
|
||||
1099,抖M,家境-2,快乐+2,,0,,2,-2,,,,,,,,,
|
||||
1100,海的女儿,颜值-2,初始可用属性点+1,,0,1,,,-2,,,,,,,,
|
||||
1101,进阶,所有属性>5时,所有属性+1,(SPR>5)&(MNY>5)&(CHR>5)&(STR>5)&(INT>5),0,,1,1,1,1,1,,,,,,
|
||||
1102,超进化,所有属性>5时,所有属性+2,(SPR>5)&(MNY>5)&(CHR>5)&(STR>5)&(INT>5),1,,2,2,2,2,2,,,,,,
|
||||
1103,白色胶囊,你10岁时无事发生,AGE?[10],0,,,,,,,,,,,,
|
||||
1104,紫色胶囊,跳过你的40~50岁,"AGE?[40,41,42,43,44,45,46,47,48,49,50]",2,,,,,,,,,,,,
|
||||
1105,蓝色胶囊,你20、30岁时无事发生,"AGE?[20,30]",1,,,,,,,,,,,,
|
||||
1106,健康饮食,你不吃洋快餐,,0,,,,,,,,,,,,
|
||||
1107,不想罢了,你不会上清华大学,,0,,,,,,,,,,,,
|
||||
1108,挑衅,你喜欢没事找事,,0,,,,,,,,,,,,
|
||||
1109,旅行者,你喜欢旅游,,0,,,,,,,,,,,,
|
||||
1110,水仙,你比较自恋,,0,,,,,,,,,,,,
|
||||
1111,缺一门,无效果,,0,,,,,,,,,,,,
|
||||
1112,异界来客,你可能听到一些绝密消息,,2,,,,,,,,,,,,
|
||||
1113,三胎人生,你尽可能生三胎,,1,,,,,,,1003,1025,1026,1027,1041,1046
|
||||
1114,橙色胶囊,跳过你的60~90岁,"AGE?[60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90]",3,,,,,,,,,,,,
|
||||
1115,宙斯,参加奥赛的几率提高,,0,,,,,,,,,,,,
|
||||
1116,为人民服务,考公务员时一定能考上,,0,,,,,,,,,,,,
|
||||
1117,表现良好,入狱会减刑,,0,,,,,,,,,,,,
|
||||
1118,小吉,运气稍微提升,,0,,,,,,,,,,,,
|
||||
1119,天秤座,据说做事很公平,,0,,,,,,,,,,,,
|
||||
1120,万里挑一,你很攻,,0,,,,,,,,,,,,
|
||||
1121,把握不住,你有强迫症,,0,,,,,,,,,,,,
|
||||
1122,急了急了,赶着投胎,不要初始属性了,,1,-20,,,,,,1084,1085,1086,,,
|
||||
1123,不离不弃,你不会离婚,,0,,,,,,,,,,,,
|
||||
1124,足量,身高不矮,,0,,,,,,,,,,,,
|
||||
1125,易胖体质,颜值更容易降低,,0,,,,,,,,,,,,
|
||||
1126,黄帝,种族主义者,,0,,,,,,,,,,,,
|
||||
1127,左撇子,习惯使用左手,,0,,,,,,,,,,,,
|
||||
1128,克苏鲁,&▓▓▓◆▓▓▓¥#▓@■.◆,,2,,,,,,,,,,,,
|
||||
1129,不连续存在,你还拥有其他人格,,1,,,,,,,,,,,,
|
||||
1130,占位符,少一个可选天赋,,0,,,,,,,,,,,,
|
||||
1131,魔法棒,不知道有什么用……,,2,,,,,,,,,,,,
|
||||
1132,返老还童,可能会回到年轻的时候,,1,,,,,,,,,,,,
|
||||
1133,时光倒流,或许时间会倒流,,0,,,,,,,,,,,,
|
||||
1134,转世重修,渡劫失败重生,,2,,,,,,,,,,,,
|
||||
|
@@ -19,8 +19,7 @@
|
||||
"exclusive": [
|
||||
"1004",
|
||||
"1025",
|
||||
"1024",
|
||||
1113
|
||||
"1024"
|
||||
]
|
||||
},
|
||||
"1004": {
|
||||
@@ -42,7 +41,7 @@
|
||||
},
|
||||
"1006": {
|
||||
"id": "1006",
|
||||
"name": "乐天派",
|
||||
"name": "乐观",
|
||||
"description": "快乐+1",
|
||||
"grade": 0,
|
||||
"effect": {
|
||||
@@ -79,6 +78,9 @@
|
||||
"name": "天龙人",
|
||||
"description": "你拥有北京户口",
|
||||
"grade": 2,
|
||||
"effect": {
|
||||
"MNY": 1
|
||||
},
|
||||
"exclusive": [
|
||||
"1012",
|
||||
"1013",
|
||||
@@ -119,7 +121,7 @@
|
||||
"description": "你有美国国籍",
|
||||
"grade": 2,
|
||||
"effect": {
|
||||
"MNY": 3
|
||||
"MNY": 1
|
||||
},
|
||||
"exclusive": [
|
||||
"1010",
|
||||
@@ -502,31 +504,31 @@
|
||||
"1059": {
|
||||
"id": "1059",
|
||||
"name": "理财达人",
|
||||
"description": "30、40、50岁时家境+1",
|
||||
"condition": "AGE?[30,40,50]",
|
||||
"description": "40岁时家境+3",
|
||||
"condition": "AGE?[40]",
|
||||
"grade": 0,
|
||||
"effect": {
|
||||
"MNY": 1
|
||||
"MNY": 3
|
||||
}
|
||||
},
|
||||
"1060": {
|
||||
"id": "1060",
|
||||
"name": "成熟",
|
||||
"description": "12、18岁时智力+1",
|
||||
"condition": "AGE?[12,18]",
|
||||
"description": "18岁时智力+2",
|
||||
"condition": "AGE?[18]",
|
||||
"grade": 1,
|
||||
"effect": {
|
||||
"INT": 1
|
||||
"INT": 2
|
||||
}
|
||||
},
|
||||
"1061": {
|
||||
"id": "1061",
|
||||
"name": "形象管理",
|
||||
"description": "16、24岁时颜值+1",
|
||||
"condition": "AGE?[16,24]",
|
||||
"description": "24岁时颜值+2",
|
||||
"condition": "AGE?[24]",
|
||||
"grade": 1,
|
||||
"effect": {
|
||||
"CHR": 1
|
||||
"CHR": 2
|
||||
}
|
||||
},
|
||||
"1062": {
|
||||
@@ -818,7 +820,7 @@
|
||||
"1091": {
|
||||
"id": "1091",
|
||||
"name": "活死人",
|
||||
"description": "体质<-1时其他属性+2",
|
||||
"description": "体质<0时其他属性+2",
|
||||
"condition": "STR<0",
|
||||
"grade": 1,
|
||||
"effect": {
|
||||
@@ -901,7 +903,7 @@
|
||||
},
|
||||
"1098": {
|
||||
"id": "1098",
|
||||
"name": "觉醒",
|
||||
"name": "艰苦奋斗",
|
||||
"description": "家境<-1时其他属性+2",
|
||||
"condition": "MNY<-1",
|
||||
"grade": 1,
|
||||
@@ -971,14 +973,14 @@
|
||||
"id": "1104",
|
||||
"name": "紫色胶囊",
|
||||
"description": "跳过你的40~50岁",
|
||||
"condition": "AGE?[40,41,42,43,44,45,46,47,48,49,50]",
|
||||
"condition": "AGE?[40]",
|
||||
"grade": 2
|
||||
},
|
||||
"1105": {
|
||||
"id": "1105",
|
||||
"name": "蓝色胶囊",
|
||||
"description": "你20、30岁时无事发生",
|
||||
"condition": "AGE?[20,30]",
|
||||
"condition": "AGE?[20]",
|
||||
"grade": 1
|
||||
},
|
||||
"1106": {
|
||||
@@ -1041,7 +1043,7 @@
|
||||
"id": "1114",
|
||||
"name": "橙色胶囊",
|
||||
"description": "跳过你的60~90岁",
|
||||
"condition": "AGE?[60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90]",
|
||||
"condition": "AGE?[60]",
|
||||
"grade": 3
|
||||
},
|
||||
"1115": {
|
||||
@@ -1138,7 +1140,7 @@
|
||||
"id": "1129",
|
||||
"name": "不连续存在",
|
||||
"description": "你还拥有其他人格",
|
||||
"grade": 2
|
||||
"grade": 1
|
||||
},
|
||||
"1130": {
|
||||
"id": "1130",
|
||||
@@ -1151,5 +1153,183 @@
|
||||
"name": "魔法棒",
|
||||
"description": "不知道有什么用……",
|
||||
"grade": 2
|
||||
},
|
||||
"1132": {
|
||||
"id": 1132,
|
||||
"name": "返老还童",
|
||||
"description": "可能会回到年轻的时候",
|
||||
"grade": 1
|
||||
},
|
||||
"1133": {
|
||||
"id": 1133,
|
||||
"name": "时光倒流",
|
||||
"description": "或许时间会倒流",
|
||||
"grade": 0
|
||||
},
|
||||
"1134": {
|
||||
"id": 1134,
|
||||
"name": "转世重修",
|
||||
"description": "渡劫失败重生",
|
||||
"grade": 2
|
||||
},
|
||||
"1135": {
|
||||
"id": 1135,
|
||||
"name": "轮回之外",
|
||||
"description": "死后可能灵魂离体",
|
||||
"grade": 3
|
||||
},
|
||||
"1136": {
|
||||
"id": 1136,
|
||||
"name": "贪婪",
|
||||
"description": "家境+10",
|
||||
"grade": 0,
|
||||
"effect": {
|
||||
"INT": -5
|
||||
}
|
||||
},
|
||||
"1137": {
|
||||
"id": 1137,
|
||||
"name": "百岁百世丸",
|
||||
"description": "某条件下所有属性+2",
|
||||
"condition": "(AGE?[100])&(TMS>99)",
|
||||
"grade": 1,
|
||||
"effect": {
|
||||
"SPR": 2,
|
||||
"MNY": 2,
|
||||
"CHR": 2,
|
||||
"STR": 2,
|
||||
"INT": 2
|
||||
}
|
||||
},
|
||||
"1138": {
|
||||
"id": 1138,
|
||||
"name": "意外之喜",
|
||||
"description": "随机属性+1",
|
||||
"grade": 0,
|
||||
"effect": {
|
||||
"RDM": 1
|
||||
}
|
||||
},
|
||||
"1139": {
|
||||
"id": 1139,
|
||||
"name": "培养爱好",
|
||||
"description": "随机属性+2",
|
||||
"grade": 1,
|
||||
"effect": {
|
||||
"RDM": 2
|
||||
}
|
||||
},
|
||||
"1140": {
|
||||
"id": 1140,
|
||||
"name": "觉醒",
|
||||
"description": "随机属性+4",
|
||||
"grade": 2,
|
||||
"effect": {
|
||||
"RDM": 4
|
||||
}
|
||||
},
|
||||
"1141": {
|
||||
"id": 1141,
|
||||
"name": "阴间大会员",
|
||||
"description": "随机属性+8",
|
||||
"grade": 3,
|
||||
"effect": {
|
||||
"RDM": 8
|
||||
}
|
||||
},
|
||||
"1142": {
|
||||
"id": 1142,
|
||||
"name": "蓝色转盘",
|
||||
"description": "变成随机蓝色天赋",
|
||||
"grade": 0,
|
||||
"replacement": {
|
||||
"grade": [
|
||||
1
|
||||
]
|
||||
},
|
||||
"exclusive": [
|
||||
"1012",
|
||||
"1013",
|
||||
"1014",
|
||||
1110,
|
||||
1003,
|
||||
1004,
|
||||
1124,
|
||||
1125
|
||||
]
|
||||
},
|
||||
"1143": {
|
||||
"id": 1143,
|
||||
"name": "紫色转盘",
|
||||
"description": "变成随机紫色天赋",
|
||||
"grade": 1,
|
||||
"replacement": {
|
||||
"grade": [
|
||||
2
|
||||
]
|
||||
},
|
||||
"exclusive": [
|
||||
"1012",
|
||||
"1013",
|
||||
"1014",
|
||||
1110,
|
||||
1003,
|
||||
1004,
|
||||
1124,
|
||||
1125
|
||||
]
|
||||
},
|
||||
"1144": {
|
||||
"id": 1144,
|
||||
"name": "橙色转盘",
|
||||
"description": "变成随机橙色天赋",
|
||||
"grade": 2,
|
||||
"replacement": {
|
||||
"grade": [
|
||||
3
|
||||
]
|
||||
}
|
||||
},
|
||||
"1145": {
|
||||
"id": 1145,
|
||||
"name": "阴间福袋",
|
||||
"description": "可能开出好天赋",
|
||||
"grade": 1,
|
||||
"replacement": {
|
||||
"talent": [
|
||||
1138,
|
||||
1133,
|
||||
1125,
|
||||
1128,
|
||||
1129,
|
||||
1131,
|
||||
1111,
|
||||
1108,
|
||||
1071,
|
||||
1072,
|
||||
1044,
|
||||
1039,
|
||||
1040,
|
||||
1033,
|
||||
1031,
|
||||
1002
|
||||
]
|
||||
}
|
||||
},
|
||||
"1146": {
|
||||
"id": 1146,
|
||||
"name": "轮盘赌",
|
||||
"description": "1/6几率变橙色天赋",
|
||||
"grade": 1,
|
||||
"replacement": {
|
||||
"talent": [
|
||||
"1141*0.2",
|
||||
"1135*0.2",
|
||||
"1114*0.2",
|
||||
"1023*0.2",
|
||||
"1048*0.2",
|
||||
"1033*5"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,5 @@
|
||||
# Life Restart
|
||||
|
||||
やり直すんだ。そして、次はうまくやる。[RESTART](view/index.html)
|
||||
|
||||
<iframe src="https://discord.com/widget?id=883382868427014255&theme=dark" width="350" height="500" allowtransparency="true" frameborder="0" sandbox="allow-popups allow-popups-to-escape-sandbox allow-same-origin allow-scripts"></iframe>
|
||||
@@ -1,12 +1,23 @@
|
||||
{
|
||||
"name": "xlsx_transform",
|
||||
"name": "life_restart",
|
||||
"type": "module",
|
||||
"bin": "test/index.js",
|
||||
"bin": "repl/index.js",
|
||||
"scripts": {
|
||||
"test": "node test",
|
||||
"xlsxTransform": "node utils/xlsxTransform.js data"
|
||||
"xlsxTransform": "vt transform data",
|
||||
"dev": "webpack serve --open /view/index.html",
|
||||
"build": "webpack --mode production"
|
||||
},
|
||||
"dependencies": {
|
||||
"xlsx": "^0.17.0"
|
||||
"@babel/core": "^7.15.4",
|
||||
"@babel/preset-env": "^7.15.4",
|
||||
"babel-loader": "^8.2.2",
|
||||
"core-js": "^3.17.2",
|
||||
"v-transform": "^1.0.1",
|
||||
"webpack": "^5.64.2",
|
||||
"webpack-dev-server": "^4.1.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"webpack-cli": "^4.8.0"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,639 @@
|
||||
import { summary } from '../src/functions/summary.js'
|
||||
import { readFile } from 'fs/promises';
|
||||
import Life from '../src/life.js';
|
||||
|
||||
globalThis.json = async fileName => JSON.parse(await readFile(`data/${fileName}.json`));
|
||||
|
||||
globalThis.$$eventMap = new Map();
|
||||
globalThis.$$event = (tag, data) => {
|
||||
const listener = $$eventMap.get(tag);
|
||||
if(listener) listener.forEach(fn=>fn(data));
|
||||
}
|
||||
globalThis.$$on = (tag, fn) => {
|
||||
let listener = $$eventMap.get(tag);
|
||||
if(!listener) {
|
||||
listener = new Set();
|
||||
$$eventMap.set(tag, listener);
|
||||
}
|
||||
listener.add(fn);
|
||||
}
|
||||
globalThis.$$off = (tag, fn) => {
|
||||
const listener = $$eventMap.get(tag);
|
||||
if(listener) listener.delete(fn);
|
||||
}
|
||||
|
||||
class App {
|
||||
constructor() {
|
||||
this.#life = new Life();
|
||||
}
|
||||
|
||||
Steps= {
|
||||
TALENT: 'talent',
|
||||
PROPERTY: 'property',
|
||||
TRAJECTORY: 'trajectory',
|
||||
SUMMARY: 'summary',
|
||||
};
|
||||
|
||||
#step = this.Steps.SUMMARY;
|
||||
#life;
|
||||
#talentSelected = new Set();
|
||||
#talentExtend = new Set();
|
||||
#input;
|
||||
#auto;
|
||||
#isEnd;
|
||||
#propertyAllocation;
|
||||
#output;
|
||||
#exit;
|
||||
#interval;
|
||||
#style = {
|
||||
warn: ['\x1B[93m', '\x1B[39m'], // Bright Yellow
|
||||
grade1: ['\x1B[94m', '\x1B[39m'], // Bright Blue
|
||||
grade2: ['\x1B[95m', '\x1B[39m'], // Bright Magenta
|
||||
grade3: ['\x1B[93m', '\x1B[39m'], // Bright Yellow
|
||||
grade1b: ['\x1B[94m\x1B[7m', '\x1B[0m'], // Bright Blue BG
|
||||
grade2b: ['\x1B[95m\x1B[7m', '\x1B[0m'], // Bright Magenta BG
|
||||
grade3b: ['\x1B[93m\x1B[7m', '\x1B[0m'], // Bright Yellow BG
|
||||
};
|
||||
#randomTalents;
|
||||
|
||||
style(type, str) {
|
||||
const style = this.#style[type];
|
||||
if(!style) return str;
|
||||
return `${style[0]}${str}${style[1]}`;
|
||||
}
|
||||
|
||||
async initial() {
|
||||
this.output('Now Loading...');
|
||||
this.#talentExtend = localStorage.talentExtend;
|
||||
await this.#life.initial();
|
||||
this.output(`\rLoading Complete.
|
||||
人生重开模拟器
|
||||
这垃圾人生一秒也不想待了
|
||||
|
||||
键入 \x1B[4m/remake\x1B[24m 开始游戏
|
||||
键入 \x1B[4m/help\x1B[24m 获取帮助`,
|
||||
true
|
||||
);
|
||||
$$on('achievement', ({name})=>this.output(`
|
||||
-------------------------
|
||||
解锁成就【${name}】
|
||||
-------------------------
|
||||
`))
|
||||
}
|
||||
|
||||
io(input, output, exit) {
|
||||
this.#input = input;
|
||||
this.#output = output;
|
||||
this.#exit = exit;
|
||||
input(command=>{
|
||||
const ret = this.repl(command);
|
||||
if(!ret) return;
|
||||
if(typeof ret == 'string') return this.output(ret, true);
|
||||
if(Array.isArray(ret)) return this.output(...ret);
|
||||
const { message, isRepl } = ret;
|
||||
return this.output(message, isRepl);
|
||||
});
|
||||
}
|
||||
|
||||
output(data, isRepl) {
|
||||
if(!this.#output) return;
|
||||
this.#output(data, isRepl);
|
||||
}
|
||||
|
||||
exit(code) {
|
||||
if(this.#exit) this.#exit(code);
|
||||
process.exit(code);
|
||||
}
|
||||
|
||||
repl(command) {
|
||||
command = command.split(/\s+/);
|
||||
switch(command.shift()) {
|
||||
|
||||
case 'r':
|
||||
case 'remake':
|
||||
case '/remake':return this.remake();
|
||||
|
||||
case 's':
|
||||
case 'select':
|
||||
case '/select': return this.select(...command);
|
||||
|
||||
case 'u':
|
||||
case 'unselect':
|
||||
case '/unselect': return this.unselect(...command);
|
||||
|
||||
case 'n':
|
||||
case 'next':
|
||||
case '/next':
|
||||
case '': return this.next(true);
|
||||
|
||||
case 'a':
|
||||
case 'alloc':
|
||||
case 'allocate':
|
||||
case 'attrib':
|
||||
case 'attribute':
|
||||
case '/alloc':
|
||||
case '/allocate':
|
||||
case '/attrib':
|
||||
case '/attribute': return this.attrib(...command);
|
||||
|
||||
case 'rd':
|
||||
case 'random':
|
||||
case '/random': return this.random();
|
||||
|
||||
case 'at':
|
||||
case 'auto':
|
||||
case '/auto': return this.auto(...command);
|
||||
|
||||
case 'x':
|
||||
case 'exit':
|
||||
case '/exit': return this.exit(0);
|
||||
|
||||
case '?':
|
||||
case 'h':
|
||||
case 'help':
|
||||
case '/?':
|
||||
case '/h':
|
||||
case '/help':
|
||||
default: return this.help(...command);
|
||||
}
|
||||
}
|
||||
|
||||
help(key) {
|
||||
|
||||
switch(key) {
|
||||
case 'x':
|
||||
case 'exit':
|
||||
case '/exit': return `退出
|
||||
x, exit, /exit 命令同等效果`;
|
||||
|
||||
case 'r':
|
||||
case 'remake':
|
||||
case '/remake': return `重开
|
||||
r, remake, /remake 命令同等效果`;
|
||||
|
||||
case 's':
|
||||
case 'select':
|
||||
case '/select': return `选择
|
||||
s, select, /select 命令同等效果
|
||||
|
||||
Example: /select 1 2 3 意味着选择 1 2 3 三个天赋
|
||||
|
||||
/select <id1> [id2] [id3]
|
||||
|
||||
参数解释 <id1> 通常来说要指定至少一个id
|
||||
虽然不指定也可以
|
||||
[id2]
|
||||
[id3] 可以不指定`;
|
||||
|
||||
case 'u':
|
||||
case 'unselect':
|
||||
case '/unselect': return `取消选择
|
||||
u, unselect,
|
||||
/unselect 命令同等效果
|
||||
|
||||
Example: /unselect 1 2 3
|
||||
意味着取消选择 1 2 3 三个天赋
|
||||
|
||||
参数解释 /unselect <id1> [id2] [id3]
|
||||
|
||||
<id1> 通常来说要指定至少一个id
|
||||
虽然不指定也可以
|
||||
[id2]
|
||||
[id3] 可以不指定`;
|
||||
|
||||
|
||||
case 'a':
|
||||
case 'alloc':
|
||||
case 'allocate':
|
||||
case 'attrib':
|
||||
case 'attribute':
|
||||
case '/alloc':
|
||||
case '/allocate':
|
||||
case '/attrib':
|
||||
case '/attribute': return `分配或查看属性点
|
||||
a, alloc, allocate, attrib, attribute
|
||||
/alloc, /allocate, /attrib, /attribute 命令同等效果
|
||||
|
||||
Example: /attribute
|
||||
/allocate STR 1
|
||||
/allocate INT -3
|
||||
/allocate CHR +5
|
||||
|
||||
效果 在属性分配时分配属性点
|
||||
在人生的过程中查看当前属性点
|
||||
|
||||
参数解释 /allocate <TAG> <[+/-]value>
|
||||
|
||||
<TAG> 表示要分配的属性标签
|
||||
可选有
|
||||
CHR, chr, c, C 表示颜值
|
||||
INT, int, i, I 表示智力
|
||||
STR, str, s, S 表示体质
|
||||
MNY, mny, m, M 表示家境
|
||||
必填
|
||||
|
||||
<[+/-]value>
|
||||
表示属性的调整
|
||||
其中
|
||||
+ 表示在当前基础上增加
|
||||
- 表示在当前基础上减少
|
||||
无符号表示直接设置为此值
|
||||
必填`;
|
||||
|
||||
case 'n':
|
||||
case 'next':
|
||||
case '/next': return `继续
|
||||
n, next, /next 命令同等效果
|
||||
|
||||
效果 通常用于各步骤结束后
|
||||
例如: 选择天赋后
|
||||
分配属性后
|
||||
每个年龄事件后
|
||||
总评后
|
||||
继承天赋后`;
|
||||
|
||||
case 'at':
|
||||
case 'auto':
|
||||
case '/auto': return `自动播放
|
||||
at, auto, /auto 命令同等效果
|
||||
|
||||
效果 用于人生的过程中
|
||||
每个年龄会自动下一年
|
||||
播放速度 1 秒 1 年`;
|
||||
|
||||
case '?':
|
||||
case 'h':
|
||||
case 'help':
|
||||
case '/?':
|
||||
case '/h':
|
||||
case '/help': return `显示帮助
|
||||
?, h, help
|
||||
/?, /h, /help 命令同等效果
|
||||
|
||||
Example: /help
|
||||
/help /select
|
||||
|
||||
参数解释 /help [command]
|
||||
|
||||
[command] 要详细显示帮助的命令
|
||||
可以不填`;
|
||||
}
|
||||
return `Help ---
|
||||
命令 说明 示例
|
||||
x
|
||||
exit
|
||||
/exit 退出 /exit
|
||||
|
||||
r
|
||||
remake
|
||||
/remake 重开 /remake
|
||||
|
||||
s
|
||||
select
|
||||
/select 选择天赋 /select <id1> [id2] [id3]
|
||||
|
||||
u
|
||||
unselect
|
||||
/unselect 取消选择 /unselect <id1> [id2] [id3]
|
||||
|
||||
a
|
||||
alloc
|
||||
allocate
|
||||
attrib
|
||||
attribute
|
||||
/alloc
|
||||
/allocate
|
||||
/attrib
|
||||
/attribute 分配或查看属性点 /allocate <TAG> <[+/-]value>
|
||||
|
||||
n
|
||||
next
|
||||
/next 继续 /next
|
||||
|
||||
at
|
||||
auto
|
||||
/auto 自动播放 /auto
|
||||
|
||||
?
|
||||
h
|
||||
help
|
||||
/?
|
||||
/h
|
||||
/help 显示帮助 /help [command]`;
|
||||
}
|
||||
|
||||
auto(arg) {
|
||||
this.#auto = arg != 'off';
|
||||
return this.next(true);
|
||||
}
|
||||
|
||||
remake() {
|
||||
if(this.#talentExtend) {
|
||||
this.#life.talentExtend(this.#talentExtend)
|
||||
dumpLocalStorage();
|
||||
this.#talentExtend = null;
|
||||
}
|
||||
|
||||
this.#isEnd = false;
|
||||
this.#talentSelected.clear();
|
||||
this.#propertyAllocation = {CHR:0,INT:0,STR:0,MNY:0,SPR:5};
|
||||
this.#step = this.Steps.TALENT;
|
||||
this.#randomTalents = this.#life.talentRandom();
|
||||
return this.list();
|
||||
}
|
||||
|
||||
select(...select) {
|
||||
switch(this.#step) {
|
||||
case this.Steps.TALENT: return this.talentSelect(...select);
|
||||
case this.Steps.SUMMARY: return this.talentExtend(...select);
|
||||
}
|
||||
}
|
||||
|
||||
unselect(...select) {
|
||||
switch(this.#step) {
|
||||
case this.Steps.TALENT: return this.talentUnSelect(...select);
|
||||
case this.Steps.SUMMARY: return this.talentExtendCancle(...select);
|
||||
}
|
||||
}
|
||||
|
||||
talentSelect(...select) {
|
||||
const warn = str => `${this.list()}\n${this.style('warn', str)}`;
|
||||
for(const number of select) {
|
||||
const s = this.#randomTalents[number];
|
||||
if(!s) return warn(`${number} 为未知天赋`);
|
||||
if(this.#talentSelected.has(s)) continue;
|
||||
if(this.#talentSelected.size == 3)
|
||||
return warn('你只能选3个天赋。请使用 \x1B[4m/unselect\x1B[24m 取消选择你不想要的天赋');
|
||||
|
||||
const exclusive = this.#life.exclusive(
|
||||
Array.from(this.#talentSelected).map(({id})=>id),
|
||||
s.id
|
||||
);
|
||||
|
||||
if(exclusive != null)
|
||||
for(const { name, id } of this.#talentSelected)
|
||||
if(id == exclusive)
|
||||
return warn(`天赋【${s.name}】与已选择的天赋【${name}】冲突`);
|
||||
|
||||
this.#talentSelected.add(s);
|
||||
}
|
||||
|
||||
return this.list();
|
||||
}
|
||||
|
||||
talentUnSelect(...select) {
|
||||
for(const number of select) {
|
||||
const s = this.#randomTalents[number];
|
||||
if(this.#talentSelected.has(s))
|
||||
this.#talentSelected.delete(s);
|
||||
}
|
||||
|
||||
return this.list();
|
||||
}
|
||||
|
||||
talentExtend(select) {
|
||||
const warn = str => `${this.list()}\n${this.style('warn', str)}`;
|
||||
const list = Array.from(this.#talentSelected);
|
||||
const s = list[select];
|
||||
if(!s) return warn(`${select} 为未知天赋`);
|
||||
this.#talentExtend = s.id;
|
||||
return this.list();
|
||||
}
|
||||
|
||||
talentExtendCancle() {
|
||||
this.#talentExtend = null;
|
||||
}
|
||||
|
||||
list() {
|
||||
let description, list, check;
|
||||
switch(this.#step) {
|
||||
case this.Steps.TALENT:
|
||||
description = '🎉 请选择(\x1B[4m/select\x1B[24m)3 个天赋';
|
||||
list = this.#randomTalents;
|
||||
check = talent=>this.#talentSelected.has(talent);
|
||||
break;
|
||||
case this.Steps.SUMMARY:
|
||||
description = '🎉 你可以选(\x1B[4m/select\x1B[24m)一个天赋继承';
|
||||
list = Array.from(this.#talentSelected);
|
||||
check = ({id})=>this.#talentExtend == id;
|
||||
break;
|
||||
}
|
||||
if(!list) return '';
|
||||
|
||||
return [description, list.map(
|
||||
(talent, i) =>
|
||||
this.style(
|
||||
`grade${talent.grade}b`,
|
||||
`${check(talent)?'√':' '} ${i} ${talent.name}(${talent.description})`
|
||||
)
|
||||
)]
|
||||
.flat()
|
||||
.join('\n');
|
||||
}
|
||||
|
||||
next(enter) {
|
||||
const warn = (a, b) => `${a}\n${this.style('warn', this.style('warn', b))}`;
|
||||
switch(this.#step) {
|
||||
case this.Steps.TALENT:
|
||||
if(this.#talentSelected.size != 3) return warn(this.list(), `请选择 3 个天赋`);
|
||||
this.#step = this.Steps.PROPERTY;
|
||||
this.#propertyAllocation.total = 20 + this.#life.getTalentAllocationAddition(
|
||||
Array.from(this.#talentSelected).map(({id})=>id)
|
||||
);
|
||||
this.#propertyAllocation.TLT = Array.from(this.#talentSelected).map(({id})=>id);
|
||||
return this.prop();
|
||||
case this.Steps.PROPERTY:
|
||||
const less = this.less();
|
||||
if(less > 0) return warn(this.prop(), `你还有 ${less} 属性点没有分配完`);
|
||||
this.#step = this.Steps.TRAJECTORY;
|
||||
delete this.#propertyAllocation.total;
|
||||
this.#life.restart(this.#propertyAllocation);
|
||||
return this.trajectory(enter);
|
||||
case this.Steps.TRAJECTORY:
|
||||
if(!this.#isEnd) return this.trajectory(enter);
|
||||
this.#step = this.Steps.SUMMARY;
|
||||
return `${
|
||||
this.summary()
|
||||
}\n\n${
|
||||
this.list()
|
||||
}`;
|
||||
case this.Steps.SUMMARY:
|
||||
return this.remake();
|
||||
}
|
||||
}
|
||||
|
||||
trajectory(enter) {
|
||||
if(enter) {
|
||||
if(this.#interval) {
|
||||
clearInterval(this.#interval);
|
||||
this.#interval = null;
|
||||
this.#auto = false;
|
||||
} else if(this.#auto) {
|
||||
this.#interval = setInterval(
|
||||
()=>{
|
||||
const trajectory = this.next();
|
||||
if(this.#isEnd && this.#interval) {
|
||||
clearInterval(this.#interval);
|
||||
this.#interval = null;
|
||||
}
|
||||
if(!this.#isEnd) return this.output(`${trajectory}\n`);
|
||||
return this.output(trajectory, true);
|
||||
}
|
||||
, 1000);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
const trajectory = this.#life.next();
|
||||
const { age, content, isEnd } = trajectory;
|
||||
if(isEnd) this.#isEnd = true;
|
||||
return `${age}岁:\t${
|
||||
content.map(
|
||||
({type, description, grade, name, postEvent}) => {
|
||||
switch(type) {
|
||||
case 'TLT':
|
||||
return `天赋【${name}】发动:${description}`;
|
||||
case 'EVT':
|
||||
return description + (postEvent?`\n\t${postEvent}`:'');
|
||||
}
|
||||
}
|
||||
).join('\n\t')
|
||||
}`;
|
||||
}
|
||||
|
||||
prop() {
|
||||
const { CHR, INT, STR, MNY } = this.#propertyAllocation;
|
||||
return `🎉 属性分配
|
||||
请使用 \x1B[4m/alloc\x1B[24m <TAG> <value> 分配属性
|
||||
剩余点数 ${this.less()}
|
||||
|
||||
属性(TAG) 当前值
|
||||
颜值(CHR) ${CHR}
|
||||
智力(INT) ${INT}
|
||||
体质(STR) ${STR}
|
||||
家境(MNY) ${MNY}
|
||||
`
|
||||
}
|
||||
|
||||
less() {
|
||||
const { total, CHR, INT, STR, MNY } = this.#propertyAllocation;
|
||||
return total - CHR - INT - STR - MNY;
|
||||
}
|
||||
|
||||
attrib(tag, value) {
|
||||
switch (this.#step) {
|
||||
case this.Steps.PROPERTY:
|
||||
return this.alloc(tag, value);
|
||||
|
||||
case this.Steps.TRAJECTORY:
|
||||
return this.showProperty();
|
||||
|
||||
default:
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
showProperty() {
|
||||
let property = this.#life.getLastRecord();
|
||||
return `当前属性
|
||||
|
||||
属性(TAG) 当前值
|
||||
颜值(CHR) ${property.CHR}
|
||||
智力(INT) ${property.INT}
|
||||
体质(STR) ${property.STR}
|
||||
家境(MNY) ${property.MNY}
|
||||
快乐(SPR) ${property.SPR}`
|
||||
}
|
||||
|
||||
alloc(tag, value) {
|
||||
const warn = str => `${this.prop()}\n${this.style('warn', str)}`
|
||||
if(!value) return warn('⚠ 分配的数值没有给定');
|
||||
const isSet = !(value[0] == '-'|| value[0] == '+');
|
||||
|
||||
value = Number(value);
|
||||
if(isNaN(value)) return warn('⚠ 分配的数值不正确');
|
||||
|
||||
switch(tag) {
|
||||
case 'c':
|
||||
case 'chr':
|
||||
case 'C': tag = 'CHR'; break;
|
||||
case 'i':
|
||||
case 'int':
|
||||
case 'I': tag = 'INT'; break;
|
||||
case 's':
|
||||
case 'S':
|
||||
case 'str': tag = 'STR'; break;
|
||||
case 'm':
|
||||
case 'M':
|
||||
case 'mny': tag = 'MNY'; break;
|
||||
}
|
||||
|
||||
|
||||
switch(tag) {
|
||||
case 'CHR':
|
||||
case 'INT':
|
||||
case 'STR':
|
||||
case 'MNY':
|
||||
if(isSet) value = value - this.#propertyAllocation[tag];
|
||||
|
||||
const tempLess = this.less() - value;
|
||||
const tempSet = this.#propertyAllocation[tag] + value;
|
||||
|
||||
if(tempLess<0) return warn('⚠ 你没有更多的点数可以分配了');
|
||||
if(
|
||||
tempLess>this.#propertyAllocation.total
|
||||
|| tempSet < 0
|
||||
) return warn('⚠ 不能分配负数属性');
|
||||
if(tempSet>10) return warn('⚠ 单项属性最高分配10点');
|
||||
|
||||
this.#propertyAllocation[tag] += value;
|
||||
|
||||
return this.prop();
|
||||
|
||||
default:
|
||||
return warn('⚠ 未知的tag');
|
||||
}
|
||||
}
|
||||
|
||||
random() {
|
||||
let t = this.#propertyAllocation.total;
|
||||
const arr = [10, 10, 10, 10];
|
||||
while(t>0) {
|
||||
const sub = Math.round(Math.random() * (Math.min(t, 10) - 1)) + 1;
|
||||
while(true) {
|
||||
const select = Math.floor(Math.random() * 4) % 4;
|
||||
if(arr[select] - sub <0) continue;
|
||||
arr[select] -= sub;
|
||||
t -= sub;
|
||||
break;
|
||||
}
|
||||
}
|
||||
this.#propertyAllocation.CHR = 10 - arr[0];
|
||||
this.#propertyAllocation.INT = 10 - arr[1];
|
||||
this.#propertyAllocation.STR = 10 - arr[2];
|
||||
this.#propertyAllocation.MNY = 10 - arr[3];
|
||||
return this.prop();
|
||||
}
|
||||
|
||||
summary() {
|
||||
const summaryData = this.#life.getSummary();
|
||||
const format = (name, type) => {
|
||||
const value = summaryData[type];
|
||||
const { judge, grade } = summary(type, value);
|
||||
return this.style(`grade${grade}b`, `${name}:${value} ${judge}`);
|
||||
}
|
||||
|
||||
return [
|
||||
'🎉 总评',
|
||||
format('颜值', 'CHR'),
|
||||
format('智力', 'INT'),
|
||||
format('体质', 'STR'),
|
||||
format('家境', 'MNY'),
|
||||
format('快乐', 'SPR'),
|
||||
format('享年', 'AGE'),
|
||||
format('总评', 'SUM'),
|
||||
].join('\n');
|
||||
}
|
||||
}
|
||||
|
||||
export default App;
|
||||
@@ -0,0 +1,32 @@
|
||||
import App from './app.js';
|
||||
import { readFile, writeFile } from 'fs/promises';
|
||||
|
||||
async function main() {
|
||||
|
||||
try {
|
||||
globalThis.localStorage = JSON.parse(await readFile('__localStorage.json'));
|
||||
} catch (e) {
|
||||
globalThis.localStorage = {};
|
||||
}
|
||||
localStorage.getItem = key => localStorage[key]===void 0? null: localStorage[key];
|
||||
localStorage.setItem = (key, value) => (localStorage[key] = value);
|
||||
|
||||
globalThis.dumpLocalStorage = async ()=>await writeFile('__localStorage.json', JSON.stringify( global.localStorage))
|
||||
|
||||
const app = new App();
|
||||
app.io(
|
||||
repl => process.stdin.on('data', data=>repl(data.toString().trim())),
|
||||
(data, isRepl) => process.stdout.write(`${data}${isRepl?'\n>':''}`),
|
||||
code=>process.exit(code)
|
||||
)
|
||||
await app.initial();
|
||||
}
|
||||
|
||||
main();
|
||||
|
||||
// process.stdin.setRawMode(true);
|
||||
|
||||
// process.openStdin().on('keypress', function (chunk, key) {
|
||||
// process.stdout.write('Get Chunk: ' + chunk + '\n');
|
||||
// if (key && key.ctrl && key.name == 'c') process.exit();
|
||||
// });
|
||||
@@ -0,0 +1,67 @@
|
||||
import { clone } from './functions/util.js';
|
||||
import { checkCondition } from './functions/condition.js';
|
||||
|
||||
class Achievement {
|
||||
constructor() {}
|
||||
|
||||
// 时机
|
||||
Opportunity = {
|
||||
START: "START", // 分配完成点数,点击开始新人生后
|
||||
TRAJECTORY: "TRAJECTORY", // 每一年的人生经历中
|
||||
SUMMARY: "SUMMARY", // 人生结束,点击人生总结后
|
||||
END: "END", // 游戏完成,点击重开 重开次数在这之后才会+1
|
||||
};
|
||||
|
||||
#achievements;
|
||||
|
||||
initial({achievements}) {
|
||||
this.#achievements = achievements;
|
||||
}
|
||||
|
||||
count() {
|
||||
return Object.keys(this.#achievements).length;
|
||||
}
|
||||
|
||||
list(property) {
|
||||
return Object
|
||||
.values(this.#achievements)
|
||||
.map(({
|
||||
id, name, opportunity,
|
||||
description, hide, grade,
|
||||
})=>({
|
||||
id, name, opportunity,
|
||||
description, hide, grade,
|
||||
isAchieved: this.isAchieved(id, property),
|
||||
}));
|
||||
}
|
||||
|
||||
get(achievementId) {
|
||||
const achievement = this.#achievements[achievementId];
|
||||
if(!achievement) throw new Error(`[ERROR] No Achievement[${achievementId}]`);
|
||||
return clone(achievement);
|
||||
}
|
||||
|
||||
check(achievementId, property) {
|
||||
const { condition } = this.get(achievementId);
|
||||
return checkCondition(property, condition);
|
||||
}
|
||||
|
||||
isAchieved(achievementId, property) {
|
||||
for(const [achieved] of (property.get(property.TYPES.ACHV)||[]))
|
||||
if(achieved == achievementId) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
achieve(opportunity, property) {
|
||||
this.list(property)
|
||||
.filter(({isAchieved})=>!isAchieved)
|
||||
.filter(({opportunity: o})=>o==opportunity)
|
||||
.filter(({id})=>this.check(id, property))
|
||||
.forEach(({id})=>{
|
||||
property.achieve(property.TYPES.ACHV, id)
|
||||
$$event('achievement', this.get(id))
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export default Achievement;
|
||||
@@ -1,6 +1,7 @@
|
||||
import { max, sum } from './functions/util.js';
|
||||
import { summary } from './functions/summary.js'
|
||||
import Life from './life.js'
|
||||
import { summary } from './functions/summary.js';
|
||||
import { getRate, getGrade } from './functions/addition.js';
|
||||
import Life from './life.js';
|
||||
|
||||
class App{
|
||||
constructor(){
|
||||
this.#life = new Life();
|
||||
@@ -8,20 +9,35 @@ class App{
|
||||
|
||||
#life;
|
||||
#pages;
|
||||
#currentPage;
|
||||
#talentSelected = new Set();
|
||||
#totalMax=20;
|
||||
#isEnd = false;
|
||||
#selectedExtendTalent = null;
|
||||
#hintTimeout;
|
||||
#specialthanks;
|
||||
#autoTrajectory;
|
||||
|
||||
async initial() {
|
||||
this.initPages();
|
||||
this.switch('loading');
|
||||
await this.#life.initial();
|
||||
const [,specialthanks] = await Promise.all([
|
||||
this.#life.initial(),
|
||||
json('specialthanks')
|
||||
]);
|
||||
this.#specialthanks = specialthanks;
|
||||
this.switch('index');
|
||||
window.onerror = (event, source, lineno, colno, error) => {
|
||||
globalThis.onerror = (event, source, lineno, colno, error) => {
|
||||
this.hint(`[ERROR] at (${source}:${lineno}:${colno})\n\n${error?.stack||error||'unknow Error'}`, 'error');
|
||||
}
|
||||
const keyDownCallback = ({which: w, keyCode: k}) => {
|
||||
if ( w === 13 || k === 13 || w === 32 || k === 32 ) {
|
||||
const pressEnterFunc = this.#pages[this.#currentPage]?.pressEnter;
|
||||
pressEnterFunc && typeof pressEnterFunc === 'function' && pressEnterFunc();
|
||||
}
|
||||
}
|
||||
globalThis.removeEventListener('keydown', keyDownCallback);
|
||||
globalThis.addEventListener('keydown', keyDownCallback);
|
||||
}
|
||||
|
||||
initPages() {
|
||||
@@ -39,31 +55,154 @@ class App{
|
||||
// Index
|
||||
const indexPage = $(`
|
||||
<div id="main">
|
||||
<div id="cnt" class="head">已重开1次</div>
|
||||
<button id="rank">排行榜</button>
|
||||
<button id="achievement">成就</button>
|
||||
<button id="specialthanks">特别感谢</button>
|
||||
<button id="themeToggleBtn">黑</button>
|
||||
<button id="save">Save</button>
|
||||
<button id="load">Load</button>
|
||||
<div id="title">
|
||||
人生重开模拟器<br>
|
||||
<div style="font-size:1.5rem; font-weight:normal;">这垃圾人生一秒也不想呆了</div>
|
||||
</div>
|
||||
<button id="restart" class="mainbtn"><span class="iconfont"></span>立即重开</button>
|
||||
<a id="discord" href="https://discord.gg/U3qrf49NMQ" style="z-index: 9999;" aria-label="Chat on Discord"><button class="discord-btn"><svg width="50%" height="55" viewBox="0 0 71 55" fill="none" xmlns="http://www.w3.org/2000/svg"><g clip-path="url(#clip0)"><path d="M60.1045 4.8978C55.5792 2.8214 50.7265 1.2916 45.6527 0.41542C45.5603 0.39851 45.468 0.440769 45.4204 0.525289C44.7963 1.6353 44.105 3.0834 43.6209 4.2216C38.1637 3.4046 32.7345 3.4046 27.3892 4.2216C26.905 3.0581 26.1886 1.6353 25.5617 0.525289C25.5141 0.443589 25.4218 0.40133 25.3294 0.41542C20.2584 1.2888 15.4057 2.8186 10.8776 4.8978C10.8384 4.9147 10.8048 4.9429 10.7825 4.9795C1.57795 18.7309 -0.943561 32.1443 0.293408 45.3914C0.299005 45.4562 0.335386 45.5182 0.385761 45.5576C6.45866 50.0174 12.3413 52.7249 18.1147 54.5195C18.2071 54.5477 18.305 54.5139 18.3638 54.4378C19.7295 52.5728 20.9469 50.6063 21.9907 48.5383C22.0523 48.4172 21.9935 48.2735 21.8676 48.2256C19.9366 47.4931 18.0979 46.6 16.3292 45.5858C16.1893 45.5041 16.1781 45.304 16.3068 45.2082C16.679 44.9293 17.0513 44.6391 17.4067 44.3461C17.471 44.2926 17.5606 44.2813 17.6362 44.3151C29.2558 49.6202 41.8354 49.6202 53.3179 44.3151C53.3935 44.2785 53.4831 44.2898 53.5502 44.3433C53.9057 44.6363 54.2779 44.9293 54.6529 45.2082C54.7816 45.304 54.7732 45.5041 54.6333 45.5858C52.8646 46.6197 51.0259 47.4931 49.0921 48.2228C48.9662 48.2707 48.9102 48.4172 48.9718 48.5383C50.038 50.6034 51.2554 52.5699 52.5959 54.435C52.6519 54.5139 52.7526 54.5477 52.845 54.5195C58.6464 52.7249 64.529 50.0174 70.6019 45.5576C70.6551 45.5182 70.6887 45.459 70.6943 45.3942C72.1747 30.0791 68.2147 16.7757 60.1968 4.9823C60.1772 4.9429 60.1437 4.9147 60.1045 4.8978ZM23.7259 37.3253C20.2276 37.3253 17.3451 34.1136 17.3451 30.1693C17.3451 26.225 20.1717 23.0133 23.7259 23.0133C27.308 23.0133 30.1626 26.2532 30.1066 30.1693C30.1066 34.1136 27.28 37.3253 23.7259 37.3253ZM47.3178 37.3253C43.8196 37.3253 40.9371 34.1136 40.9371 30.1693C40.9371 26.225 43.7636 23.0133 47.3178 23.0133C50.9 23.0133 53.7545 26.2532 53.6986 30.1693C53.6986 34.1136 50.9 37.3253 47.3178 37.3253Z" fill="#ffffff"/></g><defs><clipPath id="clip0"><rect width="71" height="55" fill="white"/></clipPath></defs></svg>CHAT</button><style>.discord-btn {position: fixed;bottom: 0.5rem;left: 0.5rem;background-color: #5865F2;padding: 0.7rem;height: auto;color: white;text-align: right;vertical-align: middle;border: none;width: 6.5rem;font-size: 1rem;border-radius: 4px;}.discord-btn svg {height: 1.5rem;position: absolute;top: 50%;left: 0;transform: translateY(-50%);}.discord-btn:hover svg{animation:discord-wave 560ms ease-in-out;}@keyframes discord-wave{0%,100%{transform:translateY(-50%) rotate(0)}20%,60%{transform:translateY(-50%) rotate(-25deg)}40%,80%{transform:translateY(-50%) rotate(10deg)}}@media (max-width:500px){.discord-btn:hover svg{animation:none}.discord-btn svg{animation:discord-wave 560ms ease-in-out}}</style></a>
|
||||
</div>
|
||||
`);
|
||||
|
||||
// Init theme
|
||||
let date = new Date();
|
||||
if( date.getMonth() == 9 && date.getDate() == 31
|
||||
|| date.getMonth() == 10 && date.getDate() == 1
|
||||
){
|
||||
this.setTheme('halloween');
|
||||
} else {
|
||||
this.setTheme(localStorage.getItem('theme'))
|
||||
}
|
||||
|
||||
indexPage
|
||||
.find('#restart')
|
||||
.click(()=>this.switch('talent'));
|
||||
|
||||
indexPage
|
||||
.find('#rank')
|
||||
.click(()=>this.hint('别卷了!没有排行榜'));
|
||||
.find('#achievement')
|
||||
.click(()=>this.switch('achievement'));
|
||||
|
||||
|
||||
indexPage
|
||||
.find('#save')
|
||||
.click(()=>{
|
||||
const data = {};
|
||||
Object
|
||||
.keys(localStorage)
|
||||
.filter(v=>v.substr(0,4)!='goog')
|
||||
.forEach(key=>data[key] = localStorage[key]);
|
||||
|
||||
let blob = new Blob([JSON.stringify(data)], { type: 'application/json' });
|
||||
const slice = blob.slice || blob.webkitSlice || blob.mozSlice;
|
||||
blob = slice.call(blob, 0, blob.size, 'application/octet-stream');
|
||||
const a = document.createElementNS('http://www.w3.org/1999/xhtml', 'a');
|
||||
a.href = URL.createObjectURL(blob);
|
||||
a.download = `Remake_save_${new Date().toISOString().replace(':','.')}.json`;
|
||||
|
||||
document.body.appendChild(a);
|
||||
a.click();
|
||||
document.body.removeChild(a);
|
||||
URL.revokeObjectURL(a.href);
|
||||
});
|
||||
|
||||
indexPage
|
||||
.find('#load')
|
||||
.click(()=>{
|
||||
const file = $(`<input type="file" name="file" accept="application/json" style="display: none;" />`)
|
||||
file.appendTo('body');
|
||||
file.click();
|
||||
file.on('change', (e)=>{
|
||||
this.switch('loading');
|
||||
const file = e.target.files[0];
|
||||
if(!file) return;
|
||||
const reader = new FileReader();
|
||||
reader.onload = () => {
|
||||
const data = JSON.parse(reader.result);
|
||||
for(const key in data) {
|
||||
localStorage[key] = data[key];
|
||||
}
|
||||
this.switch('index');
|
||||
this.setTheme(localStorage.getItem('theme'))
|
||||
if(localStorage.getItem('theme') == 'light') {
|
||||
indexPage.find('#themeToggleBtn').text('黑')
|
||||
} else{
|
||||
indexPage.find('#themeToggleBtn').text('白')
|
||||
}
|
||||
this.hint('加载存档成功', 'success');
|
||||
}
|
||||
reader.readAsText(file);
|
||||
});
|
||||
});
|
||||
|
||||
if(localStorage.getItem('theme') == 'light') {
|
||||
indexPage.find('#themeToggleBtn').text('黑')
|
||||
} else{
|
||||
indexPage.find('#themeToggleBtn').text('白')
|
||||
}
|
||||
|
||||
indexPage
|
||||
.find("#themeToggleBtn")
|
||||
.click(() => {
|
||||
if(localStorage.getItem('theme') == 'light') {
|
||||
localStorage.setItem('theme', 'dark');
|
||||
indexPage.find('#themeToggleBtn').text('白')
|
||||
} else {
|
||||
localStorage.setItem('theme', 'light');
|
||||
indexPage.find('#themeToggleBtn').text('黑')
|
||||
}
|
||||
|
||||
this.setTheme(localStorage.getItem('theme'))
|
||||
});
|
||||
|
||||
indexPage
|
||||
.find('#specialthanks')
|
||||
.click(()=>this.switch('specialthanks'));
|
||||
|
||||
const specialThanksPage = $(`
|
||||
<div id="main">
|
||||
<button id="specialthanks">返回</button>
|
||||
<div id="spthx">
|
||||
<ul class="g1"></ul>
|
||||
<ul class="g2"></ul>
|
||||
</div>
|
||||
<button class="sponsor" onclick="globalThis.open('https://afdian.net/@LifeRestart')" style="background: linear-gradient(90deg,#946ce6,#7e5fd9); left:auto; right:50%; transform: translate(-2rem,-50%);">打赏策划(爱发电)</button>
|
||||
<button class="sponsor" onclick="globalThis.open('https://dun.mianbaoduo.com/@vickscarlet')" style="background-color:#c69; left:50%; right:auto; transform: translate(2rem,-50%);">打赏程序(顿顿饭)</button>
|
||||
</div>
|
||||
`);
|
||||
|
||||
specialThanksPage
|
||||
.find('#specialthanks')
|
||||
.click(()=>this.switch('index'));
|
||||
|
||||
const achievementPage = $(`
|
||||
<div id="main">
|
||||
<button id="specialthanks">返回</button>
|
||||
<span class="title">统计</span>
|
||||
<ul id="total"></ul>
|
||||
<span style="padding:0.25rem; margin: 0.5rem 0; border: none; background: #ccc;"></span>
|
||||
<span class="title">成就<button id="rank">排行榜</button></span>
|
||||
<ul id="achievements"></ul>
|
||||
`)
|
||||
|
||||
achievementPage
|
||||
.find('#specialthanks')
|
||||
.click(()=>this.switch('index'));
|
||||
|
||||
achievementPage
|
||||
.find('#rank')
|
||||
.click(()=>this.hint('别卷了,没有排行榜'));
|
||||
// Talent
|
||||
const talentPage = $(`
|
||||
<div id="main">
|
||||
<div class="head" style="font-size: 1.6rem">天赋抽卡</div>
|
||||
<button id="random" class="mainbtn" style="top: 50%;">10连抽!</button>
|
||||
<button id="random" class="mainbtn" style="position: fixed; top: 50%; left: 50%; transform: translate(-50%, -50%);"">10连抽!</button>
|
||||
<ul id="talents" class="selectlist"></ul>
|
||||
<button id="next" class="mainbtn" style="top:auto; bottom:0.1em">请选择3个</button>
|
||||
<button id="next" class="mainbtn">请选择3个</button>
|
||||
</div>
|
||||
`);
|
||||
|
||||
@@ -84,6 +223,9 @@ class App{
|
||||
if(li.hasClass('selected')) {
|
||||
li.removeClass('selected')
|
||||
this.#talentSelected.delete(talent);
|
||||
if(this.#talentSelected.size<3) {
|
||||
talentPage.find('#next').text('请选择3个')
|
||||
}
|
||||
} else {
|
||||
if(this.#talentSelected.size==3) {
|
||||
this.hint('只能选3个天赋');
|
||||
@@ -105,9 +247,13 @@ class App{
|
||||
}
|
||||
li.addClass('selected');
|
||||
this.#talentSelected.add(talent);
|
||||
if(this.#talentSelected.size==3) {
|
||||
talentPage.find('#next').text('开始新人生')
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
talentPage.find('#next').show()
|
||||
});
|
||||
|
||||
talentPage
|
||||
@@ -117,23 +263,36 @@ class App{
|
||||
this.hint('请选择3个天赋');
|
||||
return;
|
||||
}
|
||||
talentPage.find('#next').hide()
|
||||
this.#totalMax = 20 + this.#life.getTalentAllocationAddition(Array.from(this.#talentSelected).map(({id})=>id));
|
||||
this.switch('property');
|
||||
})
|
||||
|
||||
// Property
|
||||
const propertyPage = $(`
|
||||
// hint of extension tobermory.es6-string-html
|
||||
const propertyPage = $(/*html*/`
|
||||
<div id="main">
|
||||
<div class="head" style="font-size: 1.6rem">
|
||||
调整初始属性<br>
|
||||
<div>调整初始属性</div>
|
||||
<div id="total" style="font-size:1rem; font-weight:normal;">可用属性点:0</div>
|
||||
</div>
|
||||
<ul id="propertyAllocation" class="propinitial"></ul>
|
||||
<button id="random" class="mainbtn" style="top:auto; bottom:7rem">随机分配</button>
|
||||
<button id="start" class="mainbtn" style="top:auto; bottom:0.1rem">开始新人生</button>
|
||||
<ul class="selectlist" id="talentSelectedView"></ul>
|
||||
<div class="btn-area">
|
||||
<button id="random" class="mainbtn">随机分配</button>
|
||||
<button id="start" class="mainbtn">开始新人生</button>
|
||||
</div>
|
||||
</div>
|
||||
`);
|
||||
|
||||
propertyPage.mounted = ()=>{
|
||||
propertyPage
|
||||
.find('#talentSelectedView').append(
|
||||
`<li>已选天赋</li>` +
|
||||
Array.from(this.#talentSelected)
|
||||
.map(({name,description})=>`<li class="grade0b">${name}(${description})</li>`)
|
||||
.join('')
|
||||
)
|
||||
}
|
||||
const groups = {};
|
||||
const total = ()=>{
|
||||
let t = 0;
|
||||
@@ -147,7 +306,7 @@ class App{
|
||||
const getBtnGroups = (name, min, max)=>{
|
||||
const group = $(`<li>${name} </li>`);
|
||||
const btnSub = $(`<span class="iconfont propbtn"></span>`);
|
||||
const inputBox = $(`<input value="0">`);
|
||||
const inputBox = $(`<input value="0" type="number" />`);
|
||||
const btnAdd = $(`<span class="iconfont propbtn"></span>`);
|
||||
group.append(btnSub);
|
||||
group.append(inputBox);
|
||||
@@ -166,8 +325,8 @@ class App{
|
||||
freshTotal();
|
||||
}
|
||||
btnAdd.click(()=>{
|
||||
if(total() == this.#totalMax) {
|
||||
this.hint('没用可分配的点数了');
|
||||
if(total() >= this.#totalMax) {
|
||||
this.hint('没有可分配的点数了');
|
||||
return;
|
||||
}
|
||||
set(get()+1);
|
||||
@@ -223,11 +382,14 @@ class App{
|
||||
propertyPage
|
||||
.find('#start')
|
||||
.click(()=>{
|
||||
if(total()!=this.#totalMax) {
|
||||
if(total() < this.#totalMax) {
|
||||
this.hint(`你还有${this.#totalMax-total()}属性点没有分配完`);
|
||||
return;
|
||||
} else if (total() > this.#totalMax) {
|
||||
this.hint(`你多使用了${total() - this.#totalMax}属性点`);
|
||||
return;
|
||||
}
|
||||
this.#life.restart({
|
||||
const contents = this.#life.restart({
|
||||
CHR: groups.CHR.get(),
|
||||
INT: groups.INT.get(),
|
||||
STR: groups.STR.get(),
|
||||
@@ -236,14 +398,28 @@ class App{
|
||||
TLT: Array.from(this.#talentSelected).map(({id})=>id),
|
||||
});
|
||||
this.switch('trajectory');
|
||||
this.#pages.trajectory.born();
|
||||
this.#pages.trajectory.born(contents);
|
||||
// $(document).keydown(function(event){
|
||||
// if(event.which == 32 || event.which == 13){
|
||||
// $('#lifeTrajectory').click();
|
||||
// }
|
||||
// })
|
||||
});
|
||||
|
||||
// Trajectory
|
||||
const trajectoryPage = $(`
|
||||
<div id="main">
|
||||
<ul id="lifeProperty" class="lifeProperty"></ul>
|
||||
<ul id="lifeTrajectory" class="lifeTrajectory"></ul>
|
||||
<button id="summary" class="mainbtn" style="top:auto; bottom:0.1rem">人生总结</button>
|
||||
<div class="btn-area">
|
||||
<button id="auto" class="mainbtn">自动播放</button>
|
||||
<button id="auto2x" class="mainbtn">自动播放2x</button>
|
||||
<button id="summary" class="mainbtn">人生总结</button>
|
||||
<button id="domToImage" class="mainbtn">人生回放</button>
|
||||
</div>
|
||||
<div class="domToImage2wx">
|
||||
<img src="" id="endImage" />
|
||||
</div>
|
||||
</div>
|
||||
`);
|
||||
|
||||
@@ -253,8 +429,7 @@ class App{
|
||||
if(this.#isEnd) return;
|
||||
const trajectory = this.#life.next();
|
||||
const { age, content, isEnd } = trajectory;
|
||||
|
||||
const li = $(`<li><span>${age}岁:</span>${
|
||||
const li = $(`<li><span>${age}岁:</span><span>${
|
||||
content.map(
|
||||
({type, description, grade, name, postEvent}) => {
|
||||
switch(type) {
|
||||
@@ -265,38 +440,102 @@ class App{
|
||||
}
|
||||
}
|
||||
).join('<br>')
|
||||
}</li>`);
|
||||
}</span></li>`);
|
||||
li.appendTo('#lifeTrajectory');
|
||||
$("#lifeTrajectory").scrollTop($("#lifeTrajectory")[0].scrollHeight);
|
||||
if(isEnd) {
|
||||
$(document).unbind("keydown");
|
||||
this.#isEnd = true;
|
||||
trajectoryPage.find('#summary').show();
|
||||
trajectoryPage.find('#auto').hide();
|
||||
trajectoryPage.find('#auto2x').hide();
|
||||
// trajectoryPage.find('#domToImage').show();
|
||||
}
|
||||
const property = this.#life.getLastRecord();
|
||||
$("#lifeProperty").html(`
|
||||
<li><span>颜值</span><span>${property.CHR}</span></li>
|
||||
<li><span>智力</span><span>${property.INT}</span></li>
|
||||
<li><span>体质</span><span>${property.STR}</span></li>
|
||||
<li><span>家境</span><span>${property.MNY}</span></li>
|
||||
<li><span>快乐</span><span>${property.SPR}</span></li>
|
||||
`);
|
||||
});
|
||||
// html2canvas
|
||||
trajectoryPage
|
||||
.find('#domToImage')
|
||||
.click(()=>{
|
||||
$("#lifeTrajectory").addClass("deleteFixed");
|
||||
const ua = navigator.userAgent.toLowerCase();
|
||||
domtoimage.toJpeg(document.getElementById('lifeTrajectory'))
|
||||
.then(function (dataUrl) {
|
||||
let link = document.createElement('a');
|
||||
link.download = '我的人生回放.jpeg';
|
||||
link.href = dataUrl;
|
||||
link.click();
|
||||
$("#lifeTrajectory").removeClass("deleteFixed");
|
||||
// 微信内置浏览器,显示图片,需要用户单独保存
|
||||
if(ua.match(/MicroMessenger/i)=="micromessenger") {
|
||||
$('#endImage').attr('src', dataUrl);
|
||||
}
|
||||
|
||||
});
|
||||
})
|
||||
.hide();
|
||||
|
||||
trajectoryPage
|
||||
.find('#summary')
|
||||
.click(()=>{
|
||||
clearInterval(this.#autoTrajectory);
|
||||
this.#autoTrajectory = null;
|
||||
this.switch('summary');
|
||||
})
|
||||
});
|
||||
|
||||
const auto = tick=>{
|
||||
if(this.#autoTrajectory) {
|
||||
clearInterval(this.#autoTrajectory);
|
||||
this.#autoTrajectory = null;
|
||||
} else {
|
||||
if(!this.isEnd)
|
||||
trajectoryPage
|
||||
.find('#lifeTrajectory')
|
||||
.click();
|
||||
this.#autoTrajectory = setInterval(()=>{
|
||||
if(this.isEnd) {
|
||||
clearInterval(this.#autoTrajectory);
|
||||
this.#autoTrajectory = null;
|
||||
} else {
|
||||
trajectoryPage
|
||||
.find('#lifeTrajectory')
|
||||
.click();
|
||||
}
|
||||
}, tick);
|
||||
}
|
||||
};
|
||||
|
||||
trajectoryPage
|
||||
.find('#auto')
|
||||
.click(()=>auto(1000));
|
||||
trajectoryPage
|
||||
.find('#auto2x')
|
||||
.click(()=>auto(500));
|
||||
|
||||
// Summary
|
||||
const summaryPage = $(`
|
||||
<div id="main">
|
||||
<div class="head">人生总结</div>
|
||||
<ul id="judge" class="judge" style="bottom: calc(35% + 2.5rem)">
|
||||
<li class="grade2"><span>颜值:</span>9级 美若天仙</li>
|
||||
<li><span>智力:</span>4级 智力一般</li>
|
||||
<li><span>体质:</span>1级 极度虚弱</li>
|
||||
<li><span>家境:</span>6级 小康之家</li>
|
||||
<li><span>享年:</span>3岁 早夭</li>
|
||||
<li><span>快乐:</span>3级 不太幸福的人生</li>
|
||||
<ul id="judge" class="judge">
|
||||
<li class="grade2"><span>颜值:</span><span>9级 美若天仙</span></li>
|
||||
<li class="grade0"><span>智力:</span><span>4级 智力一般</span></li>
|
||||
<li class="grade0"><span>体质:</span><span>1级 极度虚弱</span></li>
|
||||
<li class="grade0"><span>家境:</span><span>6级 小康之家</span></li>
|
||||
<li class="grade0"><span>享年:</span><span>3岁 早夭</span></li>
|
||||
<li class="grade0"><span>快乐:</span><span></span>3级 不太幸福的人生</li>
|
||||
</ul>
|
||||
<div class="head" style="top:auto; bottom:35%">天赋,你可以选一个,下辈子还能抽到</div>
|
||||
<ul id="talents" class="selectlist" style="top:calc(65% + 0.5rem); bottom:8rem">
|
||||
<div class="head" style="height:auto;">天赋,你可以选一个,下辈子还能抽到</div>
|
||||
<ul id="talents" class="selectlist" style="flex: 0 1 auto;">
|
||||
<li class="grade2b">黑幕(面试一定成功)</li>
|
||||
</ul>
|
||||
<button id="again" class="mainbtn" style="top:auto; bottom:0.1em"><span class="iconfont"></span>再次重开</button>
|
||||
<button id="again" class="mainbtn"><span class="iconfont"></span>再次重开</button>
|
||||
</div>
|
||||
`);
|
||||
|
||||
@@ -315,34 +554,126 @@ class App{
|
||||
this.#pages = {
|
||||
loading: {
|
||||
page: loadingPage,
|
||||
clear: ()=>{},
|
||||
clear: ()=>{
|
||||
this.#currentPage = 'loading';
|
||||
},
|
||||
},
|
||||
index: {
|
||||
page: indexPage,
|
||||
btnRank: indexPage.find('#rank'),
|
||||
btnAchievement: indexPage.find('#achievement'),
|
||||
btnRestart: indexPage.find('#restart'),
|
||||
hint: indexPage.find('.hint'),
|
||||
cnt: indexPage.find('#cnt'),
|
||||
pressEnter: ()=>{
|
||||
this.#pages.index.btnRestart.click();
|
||||
},
|
||||
clear: ()=>{
|
||||
this.#currentPage = 'index';
|
||||
indexPage.find('.hint').hide();
|
||||
|
||||
const times = this.times;
|
||||
const btnRank = indexPage.find('#rank');
|
||||
const cnt = indexPage.find('#cnt');
|
||||
const achievement = indexPage.find('#achievement');
|
||||
const discord = indexPage.find('#discord');
|
||||
const specialthanks = indexPage.find('#specialthanks');
|
||||
|
||||
if(times > 0) {
|
||||
btnRank.show();
|
||||
cnt.show();
|
||||
cnt.text(`已重开${times}次`);
|
||||
achievement.show();
|
||||
discord.show();
|
||||
specialthanks.show();
|
||||
return;
|
||||
}
|
||||
|
||||
btnRank.hide();
|
||||
cnt.hide();
|
||||
achievement.hide();
|
||||
discord.hide();
|
||||
specialthanks.hide();
|
||||
},
|
||||
},
|
||||
specialthanks: {
|
||||
page: specialThanksPage,
|
||||
clear: () => {
|
||||
const groups = [
|
||||
specialThanksPage.find('#spthx > ul.g1'),
|
||||
specialThanksPage.find('#spthx > ul.g2'),
|
||||
];
|
||||
groups.forEach(g=>g.empty());
|
||||
this.#specialthanks
|
||||
.sort(()=>0.5-Math.random())
|
||||
.forEach(({group, name, comment, color})=>groups[--group].append(`
|
||||
<li>
|
||||
<span class="name" ${color?('style="color:'+color+'"'):''}>${name}</span>
|
||||
<span class="comment">${comment||''}</span>
|
||||
</li>
|
||||
`))
|
||||
}
|
||||
},
|
||||
achievement: {
|
||||
page: achievementPage,
|
||||
clear: () => {
|
||||
const total = achievementPage.find("ul#total");
|
||||
const achievements = achievementPage.find("ul#achievements");
|
||||
total.empty();
|
||||
achievements.empty();
|
||||
|
||||
const formatRate = (type, value) => {
|
||||
const rate = getRate(type, value);
|
||||
let color = Object.keys(rate)[0];
|
||||
switch(parseInt(color)) {
|
||||
case 0: color = '白色'; break;
|
||||
case 1: color = '蓝色'; break;
|
||||
case 2: color = '紫色'; break;
|
||||
case 3: color = '橙色'; break;
|
||||
default: break;
|
||||
}
|
||||
let r = Object.values(rate)[0];
|
||||
switch(parseInt(r)) {
|
||||
case 1: r = '不变'; break;
|
||||
case 2: r = '翻倍'; break;
|
||||
case 3: r = '三倍'; break;
|
||||
case 4: r = '四倍'; break;
|
||||
case 5: r = '五倍'; break;
|
||||
case 6: r = '六倍'; break;
|
||||
default: break;
|
||||
}
|
||||
return `抽到${color}概率${r}`;
|
||||
}
|
||||
|
||||
const { times, achievement, talentRate, eventRate } = this.#life.getTotal();
|
||||
total.append(`
|
||||
<li class="achvg${getGrade('times', times)}"><span class="achievementtitle">已重开${times}次</span>${formatRate('times', times)}</li>
|
||||
<li class="achvg${getGrade('achievement', achievement)}"><span class="achievementtitle">成就达成${achievement}个</span>${formatRate('achievement', achievement)}</li>
|
||||
<li class="achvg${getGrade('eventRate', eventRate)}"><span class="achievementtitle">事件收集率</span>${Math.floor(eventRate * 100)}%</li>
|
||||
<li class="achvg${getGrade('talentRate', talentRate)}"><span class="achievementtitle">天赋收集率</span>${Math.floor(talentRate * 100)}%</li>
|
||||
`);
|
||||
|
||||
const achievementsData = this.#life.getAchievements();
|
||||
achievementsData.forEach(({
|
||||
name, description, hide,
|
||||
grade, isAchieved
|
||||
})=>{
|
||||
if(hide && !isAchieved) name = description = '???';
|
||||
achievements.append(
|
||||
`<li class="achvg${grade} ${isAchieved?'':'mask'}"><span class="achievementtitle">${name}</span>${description}</li>`
|
||||
);
|
||||
})
|
||||
|
||||
}
|
||||
},
|
||||
talent: {
|
||||
page: talentPage,
|
||||
talentList: talentPage.find('#talents'),
|
||||
btnRandom: talentPage.find('#random'),
|
||||
btnNext: talentPage.find('#next'),
|
||||
pressEnter: ()=>{
|
||||
const talentList = this.#pages.talent.talentList;
|
||||
const btnRandom = this.#pages.talent.btnRandom;
|
||||
const btnNext = this.#pages.talent.btnNext;
|
||||
if (talentList.children().length) {
|
||||
btnNext.click();
|
||||
} else {
|
||||
btnRandom.click();
|
||||
}
|
||||
},
|
||||
clear: ()=>{
|
||||
this.#currentPage = 'talent';
|
||||
talentPage.find('ul.selectlist').empty();
|
||||
talentPage.find('#random').show();
|
||||
this.#totalMax = 20;
|
||||
@@ -350,89 +681,104 @@ class App{
|
||||
},
|
||||
property: {
|
||||
page: propertyPage,
|
||||
btnStart: propertyPage.find('#start'),
|
||||
pressEnter: ()=>{
|
||||
this.#pages.property.btnStart.click();
|
||||
},
|
||||
clear: ()=>{
|
||||
this.#currentPage = 'property';
|
||||
freshTotal();
|
||||
propertyPage
|
||||
.find('#talentSelectedView')
|
||||
.empty();
|
||||
},
|
||||
},
|
||||
trajectory: {
|
||||
page: trajectoryPage,
|
||||
lifeTrajectory: trajectoryPage.find('#lifeTrajectory'),
|
||||
pressEnter: ()=>{
|
||||
this.#pages.trajectory.lifeTrajectory.click();
|
||||
},
|
||||
clear: ()=>{
|
||||
this.#currentPage = 'trajectory';
|
||||
trajectoryPage.find('#lifeTrajectory').empty();
|
||||
trajectoryPage.find('#summary').hide();
|
||||
trajectoryPage.find('#auto').show();
|
||||
trajectoryPage.find('#auto2x').show();
|
||||
this.#isEnd = false;
|
||||
},
|
||||
born: ()=>{
|
||||
born: contents => {
|
||||
if(contents.length > 0)
|
||||
$('#lifeTrajectory')
|
||||
.append(`<li><span>初始:</span><span>${
|
||||
contents.map(
|
||||
({source, target}) => `天赋【${source.name}】发动:替换为天赋【${target.name}】`
|
||||
).join('<br>')
|
||||
}</span></li>`);
|
||||
|
||||
trajectoryPage.find('#lifeTrajectory').trigger("click");
|
||||
}
|
||||
},
|
||||
summary: {
|
||||
page: summaryPage,
|
||||
clear: ()=>{
|
||||
this.#currentPage = 'summary';
|
||||
const judge = summaryPage.find('#judge');
|
||||
const talents = summaryPage.find('#talents');
|
||||
judge.empty();
|
||||
talents.empty();
|
||||
this.#talentSelected.forEach(talent=>{
|
||||
const li = createTalent(talent);
|
||||
talents.append(li);
|
||||
li.click(()=>{
|
||||
if(li.hasClass('selected')) {
|
||||
this.#selectedExtendTalent = null;
|
||||
li.removeClass('selected');
|
||||
} else if(this.#selectedExtendTalent != null) {
|
||||
this.hint('只能继承一个天赋');
|
||||
return;
|
||||
} else {
|
||||
this.#selectedExtendTalent = talent.id;
|
||||
li.addClass('selected');
|
||||
}
|
||||
const lastExtendTalent = this.#life.getLastExtendTalent();
|
||||
Array
|
||||
.from(this.#talentSelected)
|
||||
.sort((
|
||||
{id:a, grade:ag},
|
||||
{id:b, grade:bg},
|
||||
)=>{
|
||||
if(a == lastExtendTalent) return -1;
|
||||
if(b == lastExtendTalent) return 1;
|
||||
return bg - ag;
|
||||
})
|
||||
.forEach((talent, i)=>{
|
||||
const li = createTalent(talent);
|
||||
talents.append(li);
|
||||
li.click(()=>{
|
||||
if(li.hasClass('selected')) {
|
||||
this.#selectedExtendTalent = null;
|
||||
li.removeClass('selected');
|
||||
} else if(this.#selectedExtendTalent != null) {
|
||||
this.hint('只能继承一个天赋');
|
||||
return;
|
||||
} else {
|
||||
this.#selectedExtendTalent = talent.id;
|
||||
li.addClass('selected');
|
||||
}
|
||||
});
|
||||
if(!i) li.click();
|
||||
});
|
||||
});
|
||||
|
||||
const records = this.#life.getRecord();
|
||||
const s = (type, func)=>{
|
||||
const value = func(records.map(({[type]:v})=>v));
|
||||
const summaryData = this.#life.getSummary();
|
||||
const format = (discription, type)=>{
|
||||
const value = summaryData[type];
|
||||
const { judge, grade } = summary(type, value);
|
||||
return { judge, grade, value };
|
||||
return `<li class="grade${grade}"><span>${discription}:</span><span>${value} ${judge}</span></li>`;
|
||||
};
|
||||
console.table(records);
|
||||
console.debug(records);
|
||||
|
||||
judge.append([
|
||||
(()=>{
|
||||
const { judge, grade, value } = s('CHR', max);
|
||||
return `<li class="grade${grade}"><span>颜值:</span>${value} ${judge}</li>`
|
||||
})(),
|
||||
(()=>{
|
||||
const { judge, grade, value } = s('INT', max);
|
||||
return `<li class="grade${grade}"><span>智力:</span>${value} ${judge}</li>`
|
||||
})(),
|
||||
(()=>{
|
||||
const { judge, grade, value } = s('STR', max);
|
||||
return `<li class="grade${grade}"><span>体质:</span>${value} ${judge}</li>`
|
||||
})(),
|
||||
(()=>{
|
||||
const { judge, grade, value } = s('MNY', max);
|
||||
return `<li class="grade${grade}"><span>家境:</span>${value} ${judge}</li>`
|
||||
})(),
|
||||
(()=>{
|
||||
const { judge, grade, value } = s('SPR', max);
|
||||
return `<li class="grade${grade}"><span>快乐:</span>${value} ${judge}</li>`
|
||||
})(),
|
||||
(()=>{
|
||||
const { judge, grade, value } = s('AGE', max);
|
||||
return `<li class="grade${grade}"><span>享年:</span>${value} ${judge}</li>`
|
||||
})(),
|
||||
(()=>{
|
||||
const m = type=>max(records.map(({[type]: value})=>value));
|
||||
const value = Math.floor(sum(m('CHR'), m('INT'), m('STR'), m('MNY'), m('SPR'))*2 + m('AGE')/2);
|
||||
const { judge, grade } = summary('SUM', value);
|
||||
return `<li class="grade${grade}"><span>总评:</span>${value} ${judge}</li>`
|
||||
})(),
|
||||
].join(''));
|
||||
judge.append(`
|
||||
${format('颜值', 'CHR')}
|
||||
${format('智力', 'INT')}
|
||||
${format('体质', 'STR')}
|
||||
${format('家境', 'MNY')}
|
||||
${format('快乐', 'SPR')}
|
||||
${format('享年', 'AGE')}
|
||||
${format('总评', 'SUM')}
|
||||
`);
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
$$on('achievement', ({name})=>{
|
||||
this.hint(`解锁成就【${name}】`, 'success');
|
||||
})
|
||||
}
|
||||
|
||||
switch(page) {
|
||||
@@ -441,6 +787,9 @@ class App{
|
||||
$('#main').detach();
|
||||
p.clear();
|
||||
p.page.appendTo('body');
|
||||
if(typeof p.page.mounted === 'function'){
|
||||
p.page.mounted()
|
||||
}
|
||||
}
|
||||
|
||||
hint(message, type='info') {
|
||||
@@ -459,9 +808,23 @@ class App{
|
||||
});
|
||||
}
|
||||
|
||||
get times() {return JSON.parse(localStorage.times||'0') || 0;}
|
||||
set times(v) {localStorage.times = JSON.stringify(parseInt(v) || 0)};
|
||||
setTheme(theme) {
|
||||
const themeLink = $(document).find('#themeLink');
|
||||
|
||||
switch(theme){
|
||||
case 'dark':
|
||||
case 'light':
|
||||
case 'halloween':
|
||||
themeLink.attr('href', `${theme}.css`);
|
||||
break;
|
||||
default:
|
||||
themeLink.attr('href', 'dark.css');
|
||||
}
|
||||
}
|
||||
|
||||
get times() {return this.#life?.times || 0;}
|
||||
set times(v) { if(this.#life) this.#life.times = v };
|
||||
|
||||
}
|
||||
|
||||
export default App;
|
||||
export default App;
|
||||
|
||||
@@ -19,6 +19,10 @@ class Event {
|
||||
}
|
||||
}
|
||||
|
||||
count() {
|
||||
return Object.keys(this.#events).length;
|
||||
}
|
||||
|
||||
check(eventId, property) {
|
||||
const { include, exclude, NoRandom } = this.get(eventId);
|
||||
if(NoRandom) return false;
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
export function getRate(type, value) {
|
||||
switch(type) {
|
||||
case 'times':
|
||||
if(value >= 100) return {2:6};
|
||||
if(value >= 70) return {2:5};
|
||||
if(value >= 50) return {2:4};
|
||||
if(value >= 30) return {2:3};
|
||||
if(value >= 10) return {2:2};
|
||||
return {2: 1};
|
||||
case 'achievement':
|
||||
if(value >= 100) return {3:6};
|
||||
if(value >= 70) return {3:5};
|
||||
if(value >= 50) return {3:4};
|
||||
if(value >= 30) return {3:3};
|
||||
if(value >= 10) return {3:2};
|
||||
return {3:1};
|
||||
default: return {};
|
||||
}
|
||||
}
|
||||
|
||||
export function getGrade(type, value) {
|
||||
switch(type) {
|
||||
case 'times':
|
||||
case 'achievement':
|
||||
if(value >= 100) return 3;
|
||||
if(value >= 50) return 2;
|
||||
if(value >= 10) return 1;
|
||||
return 0;
|
||||
case 'talentRate':
|
||||
if(value >= 0.9) return 3;
|
||||
if(value >= 0.6) return 2;
|
||||
if(value >= 0.3) return 1;
|
||||
return 0;
|
||||
case 'eventRate':
|
||||
if(value >= 0.6) return 3;
|
||||
if(value >= 0.4) return 2;
|
||||
if(value >= 0.2) return 1;
|
||||
return 0;
|
||||
default: return 0;
|
||||
}
|
||||
}
|
||||
@@ -93,7 +93,7 @@ function checkProp(property, condition) {
|
||||
case '!=':
|
||||
if(Array.isArray(propData))
|
||||
return !propData.includes(conditionData);
|
||||
return propData == conditionData;
|
||||
return propData != conditionData;
|
||||
case '?':
|
||||
if(Array.isArray(propData)) {
|
||||
for(const p of propData)
|
||||
@@ -113,4 +113,17 @@ function checkProp(property, condition) {
|
||||
}
|
||||
}
|
||||
|
||||
export { checkCondition };
|
||||
function extractMaxTriggers(condition) {
|
||||
// Assuming only age related talents can be triggered multiple times.
|
||||
const RE_AGE_CONDITION = /AGE\?\[([0-9\,]+)\]/;
|
||||
const match_object = RE_AGE_CONDITION.exec(condition);
|
||||
if (match_object == null) {
|
||||
// Not age related, single trigger.
|
||||
return 1;
|
||||
}
|
||||
|
||||
const age_list = match_object[1].split(",");
|
||||
return age_list.length;
|
||||
}
|
||||
|
||||
export { checkCondition, extractMaxTriggers };
|
||||
@@ -28,4 +28,20 @@ function average(...arr) {
|
||||
return s / arr.flat().length;
|
||||
}
|
||||
|
||||
export { clone, max, min, sum, average };
|
||||
function weightRandom(list) {
|
||||
let totalWeights = 0;
|
||||
for(const [, weight] of list)
|
||||
totalWeights += weight;
|
||||
|
||||
let random = Math.random() * totalWeights;
|
||||
for(const [id, weight] of list)
|
||||
if((random-=weight)<0)
|
||||
return id;
|
||||
return list[list.length-1];
|
||||
}
|
||||
|
||||
function listRandom(list) {
|
||||
return list[Math.floor(Math.random() * list.length)];
|
||||
}
|
||||
|
||||
export { clone, max, min, sum, average, weightRandom, listRandom };
|
||||
@@ -0,0 +1,31 @@
|
||||
import App from '../src/app.js';
|
||||
|
||||
globalThis.$$eventMap = new Map();
|
||||
globalThis.$$event = (tag, data) => {
|
||||
const listener = $$eventMap.get(tag);
|
||||
if(listener) listener.forEach(fn=>fn(data));
|
||||
}
|
||||
globalThis.$$on = (tag, fn) => {
|
||||
let listener = $$eventMap.get(tag);
|
||||
if(!listener) {
|
||||
listener = new Set();
|
||||
$$eventMap.set(tag, listener);
|
||||
}
|
||||
listener.add(fn);
|
||||
}
|
||||
globalThis.$$off = (tag, fn) => {
|
||||
const listener = $$eventMap.get(tag);
|
||||
if(listener) listener.delete(fn);
|
||||
}
|
||||
|
||||
globalThis.json = async fileName => await (await fetch(`../data/${fileName}.json`)).json();
|
||||
|
||||
// Pssst, I've created a github package - https://github.com/brookesb91/dismissible
|
||||
globalThis.hideBanners = (e) => {
|
||||
document
|
||||
.querySelectorAll(".banner.visible")
|
||||
.forEach((b) => b.classList.remove("visible"));
|
||||
};
|
||||
|
||||
const app = new App();
|
||||
app.initial();
|
||||
@@ -1,63 +1,98 @@
|
||||
import { weightRandom } from './functions/util.js'
|
||||
import Property from './property.js';
|
||||
import Event from './event.js';
|
||||
import Talent from './talent.js';
|
||||
import Achievement from './achievement.js';
|
||||
|
||||
class Life {
|
||||
constructor() {
|
||||
this.#property = new Property();
|
||||
this.#event = new Event();
|
||||
this.#talent = new Talent();
|
||||
this.#achievement = new Achievement();
|
||||
}
|
||||
|
||||
#property;
|
||||
#event;
|
||||
#talent;
|
||||
#achievement;
|
||||
#triggerTalents;
|
||||
|
||||
async initial() {
|
||||
const age = await json('age');
|
||||
const talents = await json('talents');
|
||||
const events = await json('events');
|
||||
|
||||
const [age, talents, events, achievements] = await Promise.all([
|
||||
json('age'),
|
||||
json('talents'),
|
||||
json('events'),
|
||||
json('achievement'),
|
||||
])
|
||||
this.#property.initial({age});
|
||||
this.#talent.initial({talents});
|
||||
this.#event.initial({events});
|
||||
this.#achievement.initial({achievements});
|
||||
}
|
||||
|
||||
restart(allocation) {
|
||||
this.#triggerTalents = new Set();
|
||||
this.#triggerTalents = {};
|
||||
const contents = this.talentReplace(allocation.TLT);
|
||||
this.#property.restart(allocation);
|
||||
this.doTalent();
|
||||
this.#property.record();
|
||||
this.doTalent()
|
||||
this.#property.restartLastStep();
|
||||
this.#achievement.achieve(
|
||||
this.#achievement.Opportunity.START,
|
||||
this.#property
|
||||
)
|
||||
return contents;
|
||||
}
|
||||
|
||||
getTalentAllocationAddition(talents) {
|
||||
return this.#talent.allocationAddition(talents);
|
||||
}
|
||||
|
||||
getTalentCurrentTriggerCount(talentId) {
|
||||
return this.#triggerTalents[talentId] || 0;
|
||||
}
|
||||
|
||||
next() {
|
||||
const {age, event, talent} = this.#property.ageNext();
|
||||
|
||||
const talentContent = this.doTalent(talent);
|
||||
const eventContent = this.doEvent(this.random(event));
|
||||
this.#property.record();
|
||||
|
||||
const isEnd = this.#property.isEnd();
|
||||
|
||||
const content = [talentContent, eventContent].flat();
|
||||
this.#achievement.achieve(
|
||||
this.#achievement.Opportunity.TRAJECTORY,
|
||||
this.#property
|
||||
)
|
||||
return { age, content, isEnd };
|
||||
}
|
||||
|
||||
talentReplace(talents) {
|
||||
const result = this.#talent.replace(talents);
|
||||
const contents = [];
|
||||
for(const id in result) {
|
||||
talents.push(result[id]);
|
||||
const source = this.#talent.get(id);
|
||||
const target = this.#talent.get(result[id]);
|
||||
contents.push({
|
||||
type: 'talentReplace',
|
||||
source, target
|
||||
});
|
||||
}
|
||||
return contents;
|
||||
}
|
||||
|
||||
doTalent(talents) {
|
||||
if(talents) this.#property.change(this.#property.TYPES.TLT, talents);
|
||||
talents = this.#property.get(this.#property.TYPES.TLT)
|
||||
.filter(talentId=>!this.#triggerTalents.has(talentId));
|
||||
.filter(talentId => this.getTalentCurrentTriggerCount(talentId) < this.#talent.get(talentId).max_triggers);
|
||||
|
||||
const contents = [];
|
||||
for(const talentId of talents) {
|
||||
const result = this.#talent.do(talentId, this.#property);
|
||||
if(!result) continue;
|
||||
this.#triggerTalents.add(talentId);
|
||||
this.#triggerTalents[talentId] = this.getTalentCurrentTriggerCount(talentId) + 1;
|
||||
const { effect, name, description, grade } = result;
|
||||
contents.push({
|
||||
type: this.#property.TYPES.TLT,
|
||||
@@ -85,34 +120,102 @@ class Life {
|
||||
}
|
||||
|
||||
random(events) {
|
||||
events = events.filter(([eventId])=>this.#event.check(eventId, this.#property));
|
||||
|
||||
let totalWeights = 0;
|
||||
for(const [, weight] of events)
|
||||
totalWeights += weight;
|
||||
|
||||
let random = Math.random() * totalWeights;
|
||||
for(const [eventId, weight] of events)
|
||||
if((random-=weight)<0)
|
||||
return eventId;
|
||||
return events[events.length-1];
|
||||
return weightRandom(
|
||||
events.filter(
|
||||
([eventId])=>this.#event.check(eventId, this.#property)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
talentRandom() {
|
||||
return this.#talent.talentRandom(JSON.parse(localStorage.extendTalent||'null'));
|
||||
const times = this.#property.get(this.#property.TYPES.TMS);
|
||||
const achievement = this.#property.get(this.#property.TYPES.CACHV);
|
||||
return this.#talent.talentRandom(this.getLastExtendTalent(), { times, achievement });
|
||||
}
|
||||
|
||||
talentExtend(talentId) {
|
||||
localStorage.extendTalent = JSON.stringify(talentId);
|
||||
this.#property.set(this.#property.TYPES.EXT, talentId);
|
||||
}
|
||||
|
||||
getRecord() {
|
||||
return this.#property.getRecord();
|
||||
getLastExtendTalent() {
|
||||
return this.#property.get(this.#property.TYPES.EXT);
|
||||
}
|
||||
|
||||
getSummary() {
|
||||
this.#achievement.achieve(
|
||||
this.#achievement.Opportunity.SUMMARY,
|
||||
this.#property
|
||||
)
|
||||
return {
|
||||
AGE: this.#property.get(this.#property.TYPES.HAGE),
|
||||
CHR: this.#property.get(this.#property.TYPES.HCHR),
|
||||
INT: this.#property.get(this.#property.TYPES.HINT),
|
||||
STR: this.#property.get(this.#property.TYPES.HSTR),
|
||||
MNY: this.#property.get(this.#property.TYPES.HMNY),
|
||||
SPR: this.#property.get(this.#property.TYPES.HSPR),
|
||||
SUM: this.#property.get(this.#property.TYPES.SUM),
|
||||
};
|
||||
}
|
||||
|
||||
getLastRecord() {
|
||||
return this.#property.getLastRecord();
|
||||
}
|
||||
|
||||
exclusive(talents, exclusive) {
|
||||
return this.#talent.exclusive(talents, exclusive);
|
||||
}
|
||||
|
||||
getAchievements() {
|
||||
const ticks = {};
|
||||
this.#property
|
||||
.get(this.#property.TYPES.ACHV)
|
||||
.forEach(([id, tick]) => ticks[id] = tick);
|
||||
return this
|
||||
.#achievement
|
||||
.list(this.#property)
|
||||
.sort((
|
||||
{id: a, grade: ag, hide: ah},
|
||||
{id: b, grade: bg, hide: bh}
|
||||
)=>{
|
||||
a = ticks[a];
|
||||
b = ticks[b];
|
||||
if(a&&b) return b - a;
|
||||
if(!a&&!b) {
|
||||
if(ah&&bh) return bg - ag;
|
||||
if(ah) return 1;
|
||||
if(bh) return -1;
|
||||
return bg - ag;
|
||||
}
|
||||
if(!a) return 1;
|
||||
if(!b) return -1;
|
||||
});
|
||||
}
|
||||
|
||||
getTotal() {
|
||||
const TMS = this.#property.get(this.#property.TYPES.TMS);
|
||||
const CACHV = this.#property.get(this.#property.TYPES.CACHV);
|
||||
const CTLT = this.#property.get(this.#property.TYPES.CTLT);
|
||||
const CEVT = this.#property.get(this.#property.TYPES.CEVT);
|
||||
|
||||
const totalTalent = this.#talent.count();
|
||||
const totalEvent = this.#event.count();
|
||||
|
||||
return {
|
||||
times: TMS,
|
||||
achievement: CACHV,
|
||||
talentRate: CTLT / totalTalent,
|
||||
eventRate: CEVT / totalEvent,
|
||||
}
|
||||
}
|
||||
|
||||
get times() { return this.#property?.get(this.#property.TYPES.TMS) || 0; }
|
||||
set times(v) {
|
||||
this.#property?.set(this.#property.TYPES.TMS, v) || 0;
|
||||
this.#achievement.achieve(
|
||||
this.#achievement.Opportunity.END,
|
||||
this.#property
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default Life;
|
||||
|
||||
@@ -1,23 +1,67 @@
|
||||
import { clone } from './functions/util.js';
|
||||
import { max, min, sum, clone, listRandom } from './functions/util.js';
|
||||
|
||||
class Property {
|
||||
constructor() {}
|
||||
|
||||
TYPES = {
|
||||
AGE: "AGE",
|
||||
CHR: "CHR",
|
||||
INT: "INT",
|
||||
STR: "STR",
|
||||
MNY: "MNY",
|
||||
SPR: "SPR",
|
||||
LIF: "LIF",
|
||||
TLT: "TLT",
|
||||
EVT: "EVT",
|
||||
// 本局
|
||||
AGE: "AGE", // 年龄 age AGE
|
||||
CHR: "CHR", // 颜值 charm CHR
|
||||
INT: "INT", // 智力 intelligence INT
|
||||
STR: "STR", // 体质 strength STR
|
||||
MNY: "MNY", // 家境 money MNY
|
||||
SPR: "SPR", // 快乐 spirit SPR
|
||||
LIF: "LIF", // 生命 life LIFE
|
||||
TLT: "TLT", // 天赋 talent TLT
|
||||
EVT: "EVT", // 事件 event EVT
|
||||
TMS: "TMS", // 次数 times TMS
|
||||
|
||||
// Auto calc
|
||||
LAGE: "LAGE", // 最低年龄 Low Age
|
||||
HAGE: "HAGE", // 最高年龄 High Age
|
||||
LCHR: "LCHR", // 最低颜值 Low Charm
|
||||
HCHR: "HCHR", // 最高颜值 High Charm
|
||||
LINT: "LINT", // 最低智力 Low Intelligence
|
||||
HINT: "HINT", // 最高智力 High Intelligence
|
||||
LSTR: "LSTR", // 最低体质 Low Strength
|
||||
HSTR: "HSTR", // 最高体质 High Strength
|
||||
LMNY: "LMNY", // 最低家境 Low Money
|
||||
HMNY: "HMNY", // 最高家境 High Money
|
||||
LSPR: "LSPR", // 最低快乐 Low Spirit
|
||||
HSPR: "HSPR", // 最高快乐 High Spirit
|
||||
|
||||
SUM: "SUM", // 总评 summary SUM
|
||||
|
||||
EXT: "EXT", // 继承天赋
|
||||
|
||||
// 总计
|
||||
// Achievement Total
|
||||
ATLT: "ATLT", // 拥有过的天赋 Achieve Talent
|
||||
AEVT: "AEVT", // 触发过的事件 Achieve Event
|
||||
ACHV: "ACHV", // 达成的成就 Achievement
|
||||
|
||||
CTLT: "RTLT", // 天赋选择数 Count Talent
|
||||
CEVT: "REVT", // 事件收集数 Count Event
|
||||
CACHV: "CACHV", // 成就达成数 Count Achievement
|
||||
|
||||
// SPECIAL
|
||||
RDM: 'RDM', // 随机属性 random RDM
|
||||
|
||||
};
|
||||
|
||||
// 特殊类型
|
||||
SPECIAL = {
|
||||
RDM: [ // 随机属性 random RDM
|
||||
this.TYPES.CHR,
|
||||
this.TYPES.INT,
|
||||
this.TYPES.STR,
|
||||
this.TYPES.MNY,
|
||||
this.TYPES.SPR,
|
||||
]
|
||||
}
|
||||
|
||||
#ageData;
|
||||
#data;
|
||||
#record;
|
||||
#data = {};
|
||||
|
||||
initial({age}) {
|
||||
|
||||
@@ -45,18 +89,49 @@ class Property {
|
||||
restart(data) {
|
||||
this.#data = {
|
||||
[this.TYPES.AGE]: -1,
|
||||
|
||||
[this.TYPES.CHR]: 0,
|
||||
[this.TYPES.INT]: 0,
|
||||
[this.TYPES.STR]: 0,
|
||||
[this.TYPES.MNY]: 0,
|
||||
[this.TYPES.SPR]: 0,
|
||||
|
||||
[this.TYPES.LIF]: 1,
|
||||
|
||||
[this.TYPES.TLT]: [],
|
||||
[this.TYPES.EVT]: [],
|
||||
|
||||
[this.TYPES.LAGE]: Infinity,
|
||||
[this.TYPES.LCHR]: Infinity,
|
||||
[this.TYPES.LINT]: Infinity,
|
||||
[this.TYPES.LSTR]: Infinity,
|
||||
[this.TYPES.LSPR]: Infinity,
|
||||
[this.TYPES.LMNY]: Infinity,
|
||||
|
||||
[this.TYPES.HAGE]: -Infinity,
|
||||
[this.TYPES.HCHR]: -Infinity,
|
||||
[this.TYPES.HINT]: -Infinity,
|
||||
[this.TYPES.HSTR]: -Infinity,
|
||||
[this.TYPES.HMNY]: -Infinity,
|
||||
[this.TYPES.HSPR]: -Infinity,
|
||||
};
|
||||
for(const key in data)
|
||||
this.change(key, data[key]);
|
||||
this.#record = [];
|
||||
}
|
||||
|
||||
restartLastStep() {
|
||||
this.#data[this.TYPES.LAGE] = this.get(this.TYPES.AGE);
|
||||
this.#data[this.TYPES.LCHR] = this.get(this.TYPES.CHR);
|
||||
this.#data[this.TYPES.LINT] = this.get(this.TYPES.INT);
|
||||
this.#data[this.TYPES.LSTR] = this.get(this.TYPES.STR);
|
||||
this.#data[this.TYPES.LSPR] = this.get(this.TYPES.SPR);
|
||||
this.#data[this.TYPES.LMNY] = this.get(this.TYPES.MNY);
|
||||
this.#data[this.TYPES.HAGE] = this.get(this.TYPES.AGE);
|
||||
this.#data[this.TYPES.HCHR] = this.get(this.TYPES.CHR);
|
||||
this.#data[this.TYPES.HINT] = this.get(this.TYPES.INT);
|
||||
this.#data[this.TYPES.HSTR] = this.get(this.TYPES.STR);
|
||||
this.#data[this.TYPES.HMNY] = this.get(this.TYPES.MNY);
|
||||
this.#data[this.TYPES.HSPR] = this.get(this.TYPES.SPR);
|
||||
}
|
||||
|
||||
get(prop) {
|
||||
@@ -71,10 +146,73 @@ class Property {
|
||||
case this.TYPES.TLT:
|
||||
case this.TYPES.EVT:
|
||||
return clone(this.#data[prop]);
|
||||
case this.TYPES.LAGE:
|
||||
case this.TYPES.LCHR:
|
||||
case this.TYPES.LINT:
|
||||
case this.TYPES.LSTR:
|
||||
case this.TYPES.LMNY:
|
||||
case this.TYPES.LSPR:
|
||||
return min(
|
||||
this.#data[prop],
|
||||
this.get(this.fallback(prop))
|
||||
);
|
||||
case this.TYPES.HAGE:
|
||||
case this.TYPES.HCHR:
|
||||
case this.TYPES.HINT:
|
||||
case this.TYPES.HSTR:
|
||||
case this.TYPES.HMNY:
|
||||
case this.TYPES.HSPR:
|
||||
return max(
|
||||
this.#data[prop],
|
||||
this.get(this.fallback(prop))
|
||||
);
|
||||
case this.TYPES.SUM:
|
||||
const HAGE = this.get(this.TYPES.HAGE);
|
||||
const HCHR = this.get(this.TYPES.HCHR);
|
||||
const HINT = this.get(this.TYPES.HINT);
|
||||
const HSTR = this.get(this.TYPES.HSTR);
|
||||
const HMNY = this.get(this.TYPES.HMNY);
|
||||
const HSPR = this.get(this.TYPES.HSPR);
|
||||
return Math.floor(sum(HCHR, HINT, HSTR, HMNY, HSPR)*2 + HAGE/2);
|
||||
case this.TYPES.TMS:
|
||||
return this.lsget('times') || 0;
|
||||
case this.TYPES.EXT:
|
||||
return this.lsget('extendTalent') || null;
|
||||
case this.TYPES.ATLT:
|
||||
case this.TYPES.AEVT:
|
||||
case this.TYPES.ACHV:
|
||||
return this.lsget(prop) || [];
|
||||
case this.TYPES.CTLT:
|
||||
case this.TYPES.CEVT:
|
||||
case this.TYPES.CACHV:
|
||||
return this.get(
|
||||
this.fallback(prop)
|
||||
).length;
|
||||
default: return 0;
|
||||
}
|
||||
}
|
||||
|
||||
fallback(prop) {
|
||||
switch(prop) {
|
||||
case this.TYPES.LAGE:
|
||||
case this.TYPES.HAGE: return this.TYPES.AGE;
|
||||
case this.TYPES.LCHR:
|
||||
case this.TYPES.HCHR: return this.TYPES.CHR;
|
||||
case this.TYPES.LINT:
|
||||
case this.TYPES.HINT: return this.TYPES.INT;
|
||||
case this.TYPES.LSTR:
|
||||
case this.TYPES.HSTR: return this.TYPES.STR;
|
||||
case this.TYPES.LMNY:
|
||||
case this.TYPES.HMNY: return this.TYPES.MNY;
|
||||
case this.TYPES.LSPR:
|
||||
case this.TYPES.HSPR: return this.TYPES.SPR;
|
||||
case this.TYPES.CTLT: return this.TYPES.ATLT;
|
||||
case this.TYPES.CEVT: return this.TYPES.AEVT;
|
||||
case this.TYPES.CACHV: return this.TYPES.ACHV;
|
||||
default: return;
|
||||
}
|
||||
}
|
||||
|
||||
set(prop, value) {
|
||||
switch(prop) {
|
||||
case this.TYPES.AGE:
|
||||
@@ -86,14 +224,21 @@ class Property {
|
||||
case this.TYPES.LIF:
|
||||
case this.TYPES.TLT:
|
||||
case this.TYPES.EVT:
|
||||
this.#data[prop] = clone(value);
|
||||
break;
|
||||
default: return 0;
|
||||
this.hl(prop, this.#data[prop] = clone(value));
|
||||
this.achieve(prop, value);
|
||||
return;
|
||||
case this.TYPES.TMS:
|
||||
this.lsset('times', parseInt(value) || 0);
|
||||
return;
|
||||
case this.TYPES.EXT:
|
||||
this.lsset('extendTalent', value);
|
||||
return
|
||||
default: return;
|
||||
}
|
||||
}
|
||||
|
||||
record() {
|
||||
this.#record.push({
|
||||
getLastRecord() {
|
||||
return clone({
|
||||
[this.TYPES.AGE]: this.get(this.TYPES.AGE),
|
||||
[this.TYPES.CHR]: this.get(this.TYPES.CHR),
|
||||
[this.TYPES.INT]: this.get(this.TYPES.INT),
|
||||
@@ -103,10 +248,6 @@ class Property {
|
||||
});
|
||||
}
|
||||
|
||||
getRecord() {
|
||||
return clone(this.#record);
|
||||
}
|
||||
|
||||
change(prop, value) {
|
||||
if(Array.isArray(value)) {
|
||||
for(const v of value)
|
||||
@@ -121,8 +262,8 @@ class Property {
|
||||
case this.TYPES.MNY:
|
||||
case this.TYPES.SPR:
|
||||
case this.TYPES.LIF:
|
||||
this.#data[prop] += Number(value);
|
||||
break;
|
||||
this.hl(prop, this.#data[prop] += Number(value));
|
||||
return;
|
||||
case this.TYPES.TLT:
|
||||
case this.TYPES.EVT:
|
||||
const v = this.#data[prop];
|
||||
@@ -131,14 +272,31 @@ class Property {
|
||||
if(index!=-1) v.splice(index,1);
|
||||
}
|
||||
if(!v.includes(value)) v.push(value);
|
||||
break;
|
||||
this.achieve(prop, value);
|
||||
return;
|
||||
case this.TYPES.TMS:
|
||||
this.set(
|
||||
prop,
|
||||
this.get(prop) + parseInt(value)
|
||||
);
|
||||
return;
|
||||
default: return;
|
||||
}
|
||||
}
|
||||
|
||||
hookSpecial(prop) {
|
||||
switch(prop) {
|
||||
case this.TYPES.RDM: return listRandom(this.SPECIAL.RDM);
|
||||
default: return prop;
|
||||
}
|
||||
}
|
||||
|
||||
effect(effects) {
|
||||
for(const prop in effects)
|
||||
this.change(prop, Number(effects[prop]));
|
||||
for(let prop in effects)
|
||||
this.change(
|
||||
this.hookSpecial(prop),
|
||||
Number(effects[prop])
|
||||
);
|
||||
}
|
||||
|
||||
isEnd() {
|
||||
@@ -156,6 +314,61 @@ class Property {
|
||||
return clone(this.#ageData[age]);
|
||||
}
|
||||
|
||||
hl(prop, value) {
|
||||
let keys;
|
||||
switch(prop) {
|
||||
case this.TYPES.AGE: keys = [this.TYPES.LAGE, this.TYPES.HAGE]; break;
|
||||
case this.TYPES.CHR: keys = [this.TYPES.LCHR, this.TYPES.HCHR]; break;
|
||||
case this.TYPES.INT: keys = [this.TYPES.LINT, this.TYPES.HINT]; break;
|
||||
case this.TYPES.STR: keys = [this.TYPES.LSTR, this.TYPES.HSTR]; break;
|
||||
case this.TYPES.MNY: keys = [this.TYPES.LMNY, this.TYPES.HMNY]; break;
|
||||
case this.TYPES.SPR: keys = [this.TYPES.LSPR, this.TYPES.HSPR]; break;
|
||||
default: return;
|
||||
}
|
||||
const [l, h] = keys;
|
||||
this.#data[l] = min(this.#data[l], value);
|
||||
this.#data[h] = max(this.#data[h], value);
|
||||
}
|
||||
|
||||
achieve(prop, newData) {
|
||||
let key;
|
||||
switch(prop) {
|
||||
case this.TYPES.ACHV:
|
||||
const lastData = this.lsget(prop);
|
||||
this.lsset(
|
||||
prop,
|
||||
(lastData || []).concat([[newData, Date.now()]])
|
||||
);
|
||||
return;
|
||||
case this.TYPES.TLT: key = this.TYPES.ATLT; break;
|
||||
case this.TYPES.EVT: key = this.TYPES.AEVT; break;
|
||||
default: return;
|
||||
}
|
||||
const lastData = this.lsget(key) || [];
|
||||
this.lsset(
|
||||
key,
|
||||
Array.from(
|
||||
new Set(
|
||||
lastData
|
||||
.concat(newData||[])
|
||||
.flat()
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
lsget(key) {
|
||||
const data = localStorage.getItem(key);
|
||||
if(data === null) return;
|
||||
return JSON.parse(data);
|
||||
}
|
||||
|
||||
lsset(key, value) {
|
||||
localStorage.setItem(
|
||||
key,
|
||||
JSON.stringify(value)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default Property;
|
||||
@@ -1,5 +1,6 @@
|
||||
import { clone } from './functions/util.js';
|
||||
import { checkCondition } from './functions/condition.js';
|
||||
import { clone, weightRandom } from './functions/util.js';
|
||||
import { checkCondition, extractMaxTriggers } from './functions/condition.js';
|
||||
import { getRate } from './functions/addition.js';
|
||||
|
||||
class Talent {
|
||||
constructor() {}
|
||||
@@ -12,9 +13,24 @@ class Talent {
|
||||
const talent = talents[id];
|
||||
talent.id= Number(id);
|
||||
talent.grade = Number(talent.grade);
|
||||
talent.max_triggers = extractMaxTriggers(talent.condition);
|
||||
if(talent.replacement) {
|
||||
for(let key in talent.replacement) {
|
||||
const obj = {};
|
||||
for(let value of talent.replacement[key]) {
|
||||
value = `${value}`.split('*');
|
||||
obj[value[0]||0] = Number(value[1]) || 1;
|
||||
}
|
||||
talent.replacement[key] = obj;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
count() {
|
||||
return Object.keys(this.#talents).length;
|
||||
}
|
||||
|
||||
check(talentId, property) {
|
||||
const { condition } = this.get(talentId);
|
||||
return checkCondition(property, condition);
|
||||
@@ -42,7 +58,29 @@ class Talent {
|
||||
return null;
|
||||
}
|
||||
|
||||
talentRandom(include) {
|
||||
talentRandom(include, {times = 0, achievement = 0} = {}) {
|
||||
const rate = { 1:100, 2:10, 3:1, };
|
||||
const rateAddition = { 1:1, 2:1, 3:1, };
|
||||
const timesRate = getRate('times', times);
|
||||
const achievementRate = getRate('achievement', achievement);
|
||||
|
||||
for(const grade in timesRate)
|
||||
rateAddition[grade] += timesRate[grade] - 1;
|
||||
|
||||
for(const grade in achievementRate)
|
||||
rateAddition[grade] += achievementRate[grade] - 1;
|
||||
|
||||
for(const grade in rateAddition)
|
||||
rate[grade] *= rateAddition[grade];
|
||||
|
||||
const randomGrade = () => {
|
||||
let randomNumber = Math.floor(Math.random() * 1000);
|
||||
if((randomNumber -= rate[3]) < 0) return 3;
|
||||
if((randomNumber -= rate[2]) < 0) return 2;
|
||||
if((randomNumber -= rate[1]) < 0) return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 1000, 100, 10, 1
|
||||
const talentList = {};
|
||||
for(const talentId in this.#talents) {
|
||||
@@ -58,15 +96,8 @@ class Talent {
|
||||
return new Array(10)
|
||||
.fill(1).map((v, i)=>{
|
||||
if(!i && include) return include;
|
||||
const gradeRandom = Math.random();
|
||||
let grade;
|
||||
if(gradeRandom>=0.111) grade = 0;
|
||||
else if(gradeRandom>=0.011) grade = 1;
|
||||
else if(gradeRandom>=0.001) grade = 2;
|
||||
else grade = 3;
|
||||
|
||||
let grade = randomGrade();
|
||||
while(talentList[grade].length == 0) grade--;
|
||||
|
||||
const length = talentList[grade].length;
|
||||
|
||||
const random = Math.floor(Math.random()*length) % length;
|
||||
@@ -90,6 +121,56 @@ class Talent {
|
||||
return null;
|
||||
return { effect, grade, name, description };
|
||||
}
|
||||
|
||||
replace(talents) {
|
||||
const getReplaceList = (talent, talents) => {
|
||||
const { replacement } = this.get(talent);
|
||||
if(!replacement) return null;
|
||||
const list = [];
|
||||
if(replacement.grade) {
|
||||
this.forEach(({id, grade})=>{
|
||||
if(!replacement.grade[grade]) return;
|
||||
if(this.exclusive(talents, id)) return;
|
||||
list.push([id, replacement.grade[grade]]);
|
||||
})
|
||||
}
|
||||
if(replacement.talent) {
|
||||
for(let id in replacement.talent) {
|
||||
id = Number(id);
|
||||
if(this.exclusive(talents, id)) continue;
|
||||
list.push([id, replacement.talent[id]]);
|
||||
}
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
const replace = (talent, talents) => {
|
||||
const replaceList = getReplaceList(talent, talents);
|
||||
if(!replaceList) return talent;
|
||||
const rand = weightRandom(replaceList);
|
||||
return replace(
|
||||
rand, talents.concat(rand)
|
||||
);
|
||||
}
|
||||
|
||||
const newTalents = clone(talents);
|
||||
const result = {};
|
||||
for(const talent of talents) {
|
||||
const replaceId = replace(talent, newTalents);
|
||||
if(replaceId != talent) {
|
||||
result[talent] = replaceId;
|
||||
newTalents.push(replaceId);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
forEach(callback) {
|
||||
if(typeof callback != 'function') return;
|
||||
for(const id in this.#talents)
|
||||
callback(clone(this.#talents[id]), id);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default Talent;
|
||||
@@ -1,7 +1,30 @@
|
||||
import { readFile } from 'fs/promises';
|
||||
import Life from '../src/life.js'
|
||||
|
||||
global.json = async fileName => JSON.parse(await readFile(`data/${fileName}.json`));
|
||||
globalThis.json = async fileName => JSON.parse(await readFile(`data/${fileName}.json`));
|
||||
|
||||
globalThis.localStorage = {};
|
||||
localStorage.getItem = key => localStorage[key]===void 0? null: localStorage[key];
|
||||
localStorage.setItem = (key, value) => (localStorage[key] = value);
|
||||
|
||||
|
||||
globalThis.$$eventMap = new Map();
|
||||
globalThis.$$event = (tag, data) => {
|
||||
const listener = $$eventMap.get(tag);
|
||||
if(listener) listener.forEach(fn=>fn(data));
|
||||
}
|
||||
globalThis.$$on = (tag, fn) => {
|
||||
let listener = $$eventMap.get(tag);
|
||||
if(!listener) {
|
||||
listener = new Set();
|
||||
$$eventMap.set(tag, listener);
|
||||
}
|
||||
listener.add(fn);
|
||||
}
|
||||
globalThis.$$off = (tag, fn) => {
|
||||
const listener = $$eventMap.get(tag);
|
||||
if(listener) listener.delete(fn);
|
||||
}
|
||||
|
||||
async function debug() {
|
||||
|
||||
@@ -14,7 +37,8 @@ async function debug() {
|
||||
STR: 5, // 体质 strength STR
|
||||
MNY: 5, // 家境 money MNY
|
||||
SPR: 5, // 快乐 spirit SPR
|
||||
TLT: [1004, 1005, 1009], // 天赋 talent TLT
|
||||
// AGE: 100,
|
||||
TLT: [1134, 1048, 1114], // 天赋 talent TLT
|
||||
});
|
||||
const lifeTrajectory = [];
|
||||
let trajectory;
|
||||
@@ -26,7 +50,7 @@ async function debug() {
|
||||
// debugger
|
||||
throw e;
|
||||
}
|
||||
lifeTrajectory.push(lifeTrajectory);
|
||||
lifeTrajectory.push(trajectory);
|
||||
const { age, content } = trajectory;
|
||||
console.debug(
|
||||
`---------------------------------`,
|
||||
@@ -42,6 +66,7 @@ async function debug() {
|
||||
}
|
||||
).join('\n ')
|
||||
);
|
||||
if(age == 60) debugger
|
||||
} while(!trajectory.isEnd)
|
||||
// debugger;
|
||||
}
|
||||
|
||||
@@ -6,58 +6,154 @@ import { join, extname, dirname } from 'path';
|
||||
// const XLSX = require('xlsx');
|
||||
// const { join, extname, dirname } = require('path');
|
||||
|
||||
async function transform(filePath) {
|
||||
const xlsxFileBuffer = await readFile(filePath);
|
||||
async function read(xlsxPath) {
|
||||
const xlsxFileBuffer = await readFile(xlsxPath);
|
||||
const xlsx = XLSX.read(xlsxFileBuffer, {type: 'buffer'});
|
||||
const sheets = xlsx.Sheets;
|
||||
|
||||
const data = {};
|
||||
for(const sheetName in sheets) {
|
||||
const sheetRawData = sheets[sheetName];
|
||||
if(!sheetRawData['!ref']) break;
|
||||
const rawData = XLSX.utils.sheet_to_json(sheetRawData);
|
||||
const newData = {};
|
||||
data[sheetName] = newData;
|
||||
rawData.shift();
|
||||
for(const row of rawData) {
|
||||
const rowData = {};
|
||||
let mainKey;
|
||||
for(let key in row) {
|
||||
const cell = row[key];
|
||||
if(key[0] == "$") {
|
||||
key = key.substr(1);
|
||||
mainKey = cell;
|
||||
}
|
||||
if(key.includes(':')) {
|
||||
const keys = key.split(':');
|
||||
const lastKey = keys.pop();
|
||||
let temp = rowData;
|
||||
for(const subKey of keys) {
|
||||
if(!temp[subKey]) temp[subKey] = {};
|
||||
temp = temp[subKey];
|
||||
}
|
||||
if(lastKey.includes('[]')) {
|
||||
const aKey = lastKey.split('[]')[0];
|
||||
if(!temp[aKey]) temp[aKey] = [cell];
|
||||
else temp[aKey].push(cell);
|
||||
} else {
|
||||
temp[lastKey] = cell;
|
||||
}
|
||||
} else if(key.includes('[]')) {
|
||||
const aKey = key.split('[]')[0];
|
||||
if(!rowData[aKey]) rowData[aKey] = [cell];
|
||||
else rowData[aKey].push(cell);
|
||||
} else {
|
||||
rowData[key] = cell;
|
||||
}
|
||||
}
|
||||
if(mainKey===undefined) return console.error('No Main Key', rowData);
|
||||
newData[mainKey] = rowData;
|
||||
}
|
||||
data[sheetName] = XLSX.utils.sheet_to_json(sheetRawData);
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
async function write(sheets) {
|
||||
for(const sheetName in sheets) {
|
||||
const { dirname, data, source } = sheets[sheetName];
|
||||
const savePath = join(dirname, `${sheetName}.json`);
|
||||
console.info('[Transform] XLSX(', source.map(([p, s])=>`${p}:${s}`).join('\n\t\t '), `) \n\t -> JSON( ${savePath} )`);
|
||||
await writeFile(
|
||||
savePath,
|
||||
JSON.stringify(data, null, 4),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
function format(rawSheet, isArray, xlsxPath, rawSheetName) {
|
||||
const newSheet = isArray?[]:{};
|
||||
rawSheet.shift();
|
||||
for(const index in rawSheet) {
|
||||
const row = rawSheet[index];
|
||||
const rowData = {};
|
||||
let mainKey;
|
||||
for(let key in row) {
|
||||
const cell = row[key];
|
||||
if(key[0] == "$") {
|
||||
key = key.substr(1);
|
||||
mainKey = cell;
|
||||
}
|
||||
if(key.includes(':')) {
|
||||
const keys = key.split(':');
|
||||
const lastKey = keys.pop();
|
||||
let temp = rowData;
|
||||
for(const subKey of keys) {
|
||||
if(!temp[subKey]) temp[subKey] = {};
|
||||
temp = temp[subKey];
|
||||
}
|
||||
if(lastKey.includes('[]')) {
|
||||
const aKey = lastKey.split('[]')[0];
|
||||
if(!temp[aKey]) temp[aKey] = [cell];
|
||||
else temp[aKey].push(cell);
|
||||
} else {
|
||||
temp[lastKey] = cell;
|
||||
}
|
||||
} else if(key.includes('[]')) {
|
||||
const aKey = key.split('[]')[0];
|
||||
if(!rowData[aKey]) rowData[aKey] = [cell];
|
||||
else rowData[aKey].push(cell);
|
||||
} else {
|
||||
rowData[key] = cell;
|
||||
}
|
||||
}
|
||||
if(isArray) {
|
||||
newSheet.push(rowData);
|
||||
continue;
|
||||
}
|
||||
if(mainKey===undefined) {
|
||||
console.warn(`[WARN][No Main Key] ${xlsxPath}:${rawSheetName}`, parseInt(index)+3, rowData);
|
||||
continue;
|
||||
}
|
||||
if(newSheet[mainKey]) console.warn(`[WARN][Duplicate Key] ${mainKey} ${xlsxPath}:${rawSheetName}`, parseInt(index), '\n\t', JSON.stringify(newSheet[mainKey]), '\n\t', JSON.stringify(rowData));
|
||||
newSheet[mainKey] = rowData;
|
||||
}
|
||||
return newSheet;
|
||||
}
|
||||
|
||||
function merge(original, rawData, isMerge, isArray, xlsxPath, rawSheetName) {
|
||||
if(!original)
|
||||
return {
|
||||
isMerge,
|
||||
isArray,
|
||||
source: [[xlsxPath, rawSheetName]],
|
||||
data: format(rawData, isArray, xlsxPath, rawSheetName)
|
||||
};
|
||||
|
||||
|
||||
if(!isMerge) {
|
||||
if(original) {
|
||||
console.warn(`[WARN][Sheet Duplicate] ${xlsxPath}:${rawSheetName}\n\t\t${original.source[0][0]}:${original.source[0][1]}`)
|
||||
return original;
|
||||
}
|
||||
}
|
||||
|
||||
if(!original.isMerge) {
|
||||
console.warn(`[WARN][Sheet Duplicate] ${xlsxPath}:${rawSheetName}\n\t\t${original.source[0][0]}:${original.source[0][1]}`)
|
||||
return original;
|
||||
}
|
||||
|
||||
if(original.isArray != isArray) {
|
||||
console.warn(`[WARN][Sheet Format not pair] ${xlsxPath}:${rawSheetName}\n\t\t${original.source[0][0]}:${original.source[0][1]}`)
|
||||
return original;
|
||||
}
|
||||
|
||||
const formatData = format(rawData, isArray, xlsxPath, rawSheetName);
|
||||
|
||||
original.source.push([xlsxPath, rawSheetName]);
|
||||
|
||||
if(isArray) {
|
||||
original.data = original.data.concat(formatData)
|
||||
} else {
|
||||
for(const key in formatData) {
|
||||
if(original.data[key]) {
|
||||
console.warn(`[WARN][Duplicate key] ${key} ${xlsxPath}:${rawSheetName} ${JSON.stringify(formatData[key])}\n\t\t${original.source[0][0]}:${original.source[0][1]} ${JSON.stringify(original.data[key])}`);
|
||||
continue;
|
||||
}
|
||||
original.data[key] = formatData[key];
|
||||
}
|
||||
}
|
||||
|
||||
return original;
|
||||
}
|
||||
|
||||
function transform(rawSheets) {
|
||||
const sheets = {};
|
||||
for(const xlsxPath in rawSheets) {
|
||||
const {dirname: d, data: rawSheetsData} = rawSheets[xlsxPath];
|
||||
for(const rawSheetName in rawSheetsData) {
|
||||
const rawData = rawSheetsData[rawSheetName];
|
||||
if(rawSheetName[0] === "#") continue;
|
||||
let sheetName = rawSheetName;
|
||||
const isArray = rawSheetName.substr(-5) === "<arr>";
|
||||
if(isArray) sheetName = sheetName.substring(0, sheetName.length - 5);
|
||||
const isMerge = rawSheetName[0] === ">";
|
||||
if(isMerge) sheetName = sheetName.substr(1);
|
||||
sheets[sheetName] = merge(
|
||||
sheets[sheetName],
|
||||
rawData,
|
||||
isMerge,
|
||||
isArray,
|
||||
xlsxPath,
|
||||
rawSheetName
|
||||
);
|
||||
sheets[sheetName].dirname = d;
|
||||
}
|
||||
}
|
||||
|
||||
return sheets;
|
||||
}
|
||||
|
||||
async function walk(filePath) {
|
||||
const xlsxPaths = [];
|
||||
if(Array.isArray(filePath)) {
|
||||
@@ -82,18 +178,18 @@ async function main() {
|
||||
const filePaths = process.argv.slice(2);
|
||||
if(filePaths.length<0) process.exit(0);
|
||||
const xlsxs = await walk(filePaths);
|
||||
const sheets = {};
|
||||
for(const p of xlsxs) {
|
||||
const data = await transform(p);
|
||||
const data = await read(p);
|
||||
const d = dirname(p);
|
||||
for(const sheetName in data) {
|
||||
const savePath = join(d, `${sheetName}.json`);
|
||||
console.info(`[Transform] XLSX(${p}:${sheetName}) -> JSON(${savePath})`);
|
||||
await writeFile(
|
||||
savePath,
|
||||
JSON.stringify(data[sheetName], null, 4),
|
||||
);
|
||||
}
|
||||
sheets[p] = {
|
||||
dirname: d,
|
||||
data
|
||||
};
|
||||
}
|
||||
await write(
|
||||
transform(sheets)
|
||||
);
|
||||
console.info(`
|
||||
------------------------
|
||||
| Transform Complete |
|
||||
|
||||
@@ -0,0 +1,903 @@
|
||||
@media (min-width:640px){html{font-size:24px;}}
|
||||
@media (min-width:631px) and (max-width:639px){html{font-size:23.66px;}}
|
||||
@media (min-width:622px) and (max-width:630px){html{font-size:23.33px;}}
|
||||
@media (min-width:613px) and (max-width:621px){html{font-size:23px;}}
|
||||
@media (min-width:604px) and (max-width:612px){html{font-size:22.66px;}}
|
||||
@media (min-width:595px) and (max-width:603px){html{font-size:22.33px;}}
|
||||
@media (min-width:586px) and (max-width:594px){html{font-size:22px;}}
|
||||
@media (min-width:577px) and (max-width:585px){html{font-size:21.66px;}}
|
||||
@media (min-width:568px) and (max-width:576px){html{font-size:21.33px;}}
|
||||
@media (min-width:559px) and (max-width:567px){html{font-size:21px;}}
|
||||
@media (min-width:550px) and (max-width:558px){html{font-size:20.66px;}}
|
||||
@media (min-width:541px) and (max-width:549px){html{font-size:20.33px;}}
|
||||
@media (min-width:533px) and (max-width:540px){html{font-size:20px;}}
|
||||
@media (min-width:524px) and (max-width:532px){html{font-size:19.66px;}}
|
||||
@media (min-width:515px) and (max-width:523px){html{font-size:19.33px;}}
|
||||
@media (min-width:506px) and (max-width:514px){html{font-size:19px;}}
|
||||
@media (min-width:497px) and (max-width:505px){html{font-size:18.66px;}}
|
||||
@media (min-width:488px) and (max-width:496px){html{font-size:18.33px;}}
|
||||
@media (min-width:480px) and (max-width:487px){html{font-size:18px;}}
|
||||
@media (min-width:471px) and (max-width:479px){html{font-size:17.66px;}}
|
||||
@media (min-width:462px) and (max-width:470px){html{font-size:17.33px;}}
|
||||
@media (min-width:453px) and (max-width:461px){html{font-size:17px;}}
|
||||
@media (min-width:444px) and (max-width:452px){html{font-size:17.12px;}}
|
||||
@media (min-width:435px) and (max-width:443px){html{font-size:16.33px;}}
|
||||
@media (min-width:426px) and (max-width:434px){html{font-size:16px;}}
|
||||
@media (min-width:417px) and (max-width:425px){html{font-size:15.66px;}}
|
||||
@media (min-width:408px) and (max-width:416px){html{font-size:15.33px;}}
|
||||
@media (min-width:400px) and (max-width:407px){html{font-size:15px;}}
|
||||
@media (min-width:391px) and (max-width:399px){html{font-size:14.66px;}}
|
||||
@media (min-width:382px) and (max-width:390px){html{font-size:14.33px;}}
|
||||
@media (min-width:374px) and (max-width:381px){html{font-size:14px;}}
|
||||
@media (min-width:365px) and (max-width:373px){html{font-size:13.66px;}}
|
||||
@media (min-width:356px) and (max-width:364px){html{font-size:13.33px;}}
|
||||
@media (min-width:347px) and (max-width:355px){html{font-size:13px;}}
|
||||
@media (min-width:338px) and (max-width:346px){html{font-size:12.66px;}}
|
||||
@media (min-width:329px) and (max-width:337px){html{font-size:12.44px;}}
|
||||
@media (max-width:328px){html{font-size:12px;}}
|
||||
|
||||
@font-face {
|
||||
font-family: 'iconfont';
|
||||
src: url('iconfont.woff2?t=1628944689555') format('woff2'),
|
||||
url('iconfont.woff?t=1628944689555') format('woff'),
|
||||
url('iconfont.ttf?t=1628944689555') format('truetype');
|
||||
}
|
||||
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
input::-webkit-outer-spin-button,
|
||||
input::-webkit-inner-spin-button {
|
||||
-webkit-appearance: none;
|
||||
}
|
||||
input[type="number"]{
|
||||
-moz-appearance: textfield;
|
||||
}
|
||||
|
||||
html {
|
||||
background-color: #222831;
|
||||
font-family: PingFangSC, 'Noto Sans CJK SC', 'MS Yahei';
|
||||
}
|
||||
|
||||
body {
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
#main {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
width: 100%;
|
||||
max-width: 30rem;
|
||||
height: 100%;
|
||||
text-align: center;
|
||||
box-sizing: border-box;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
#title {
|
||||
position: fixed;
|
||||
font-size: 3rem;
|
||||
font-weight: 700;
|
||||
top: 35%;
|
||||
left: 50%;
|
||||
white-space: nowrap;
|
||||
transform: translate(-50%, -50%);
|
||||
color: #EEEEEE;
|
||||
}
|
||||
|
||||
#restart {
|
||||
position: fixed;
|
||||
top: 65%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
}
|
||||
|
||||
#restart .iconfont {
|
||||
margin-right: 0.5rem;
|
||||
}
|
||||
|
||||
#next {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#talentSelectedView {
|
||||
flex: 0 1 auto;
|
||||
}
|
||||
|
||||
.mainbtn {
|
||||
margin: 0.5rem 1rem 1rem;
|
||||
padding: 0.5rem 1.5rem;
|
||||
background-color: #393E46;
|
||||
border: 1px #EEEEEE solid;
|
||||
border-radius: 0.2rem;
|
||||
color: #EEEEEE;
|
||||
font-size: 1.6rem;
|
||||
white-space: nowrap;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.mainbtn:hover {
|
||||
background: #ff7878;
|
||||
color: #fff;
|
||||
transition: all .4s ease 0s;
|
||||
}
|
||||
|
||||
.btn-area {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.btn-area>.mainbtn {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.iconfont {
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
font-family: "iconfont" !important;
|
||||
font-style: normal;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
}
|
||||
|
||||
.sponsor,
|
||||
#rank,
|
||||
#specialthanks,
|
||||
#achievement {
|
||||
position: fixed;
|
||||
top: 4rem;
|
||||
right: 1rem;
|
||||
padding: 0.1rem;
|
||||
width: 6rem;
|
||||
border: none;
|
||||
border-radius: 0.2rem;
|
||||
background-color:lightsteelblue;
|
||||
font-size: 1.4rem;
|
||||
color: #EEEEEE;
|
||||
cursor: pointer;
|
||||
z-index:2;
|
||||
word-wrap: none;
|
||||
}
|
||||
|
||||
#specialthanks {
|
||||
background-color: #5865F2;
|
||||
top: 1rem;
|
||||
}
|
||||
|
||||
.sponsor {
|
||||
top: auto;
|
||||
bottom: 0;
|
||||
width: auto;
|
||||
padding: 0.5rem;
|
||||
}
|
||||
|
||||
#rank {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
right: 1.5rem;
|
||||
transform: translateY(-50%);
|
||||
}
|
||||
|
||||
#spthx {
|
||||
position: fixed;
|
||||
display: grid;
|
||||
top: 4rem;
|
||||
bottom: 5rem;
|
||||
left: 50%;
|
||||
width: 30rem;
|
||||
max-width: calc(100% - 2rem);
|
||||
transform: translateX(-50%);
|
||||
}
|
||||
|
||||
#spthx ul {
|
||||
list-style-type: none;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
#spthx ul li {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
#spthx ul.g1 {
|
||||
display: grid;
|
||||
max-block-size: 9rem;
|
||||
max-height: 9rem;
|
||||
overflow: scroll;
|
||||
}
|
||||
|
||||
#spthx ul.g1 li {
|
||||
display: inline-grid;
|
||||
background-color: orange;
|
||||
margin-bottom: 0.5rem;
|
||||
padding: 0.2rem 0;
|
||||
grid-template-columns: 7rem auto;
|
||||
}
|
||||
|
||||
#spthx ul.g1 li .name {
|
||||
padding: 0 0.5rem;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
#spthx ul.g1 li .comment {
|
||||
padding: 0 0.5rem;
|
||||
}
|
||||
|
||||
#spthx ul.g2 {
|
||||
color: white;
|
||||
display: grid;
|
||||
grid-template-columns: 50% 50%;
|
||||
overflow: scroll;
|
||||
}
|
||||
|
||||
#spthx ul.g2 li {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.title {
|
||||
color: white;
|
||||
position: relative;
|
||||
font-size: 1.5rem;
|
||||
font-weight: 700;
|
||||
padding: 1rem;
|
||||
}
|
||||
|
||||
ul#total,
|
||||
#achievements {
|
||||
list-style-type: none;
|
||||
display: grid;
|
||||
justify-items: center;
|
||||
grid-template-columns: 50% 50%;
|
||||
grid-auto-columns: max-content;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
ul#total li,
|
||||
#achievements li {
|
||||
position: relative;
|
||||
color: white;
|
||||
display: inline-grid;
|
||||
margin: 0.5rem;
|
||||
width: 12rem;
|
||||
height: 6rem;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
ul#total li .achievementtitle,
|
||||
#achievements li .achievementtitle{
|
||||
font-weight: 700;
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
|
||||
#achievements {
|
||||
overflow: scroll;
|
||||
}
|
||||
|
||||
#save,
|
||||
#load,
|
||||
#themeToggleBtn {
|
||||
padding: 0 0.7rem;
|
||||
width: 6.5rem;
|
||||
background-color:#EEEEEE;
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
font-size: 1.4rem;
|
||||
color: #222831;
|
||||
line-height: 2.5rem;
|
||||
text-align: center;
|
||||
vertical-align: middle;
|
||||
cursor: pointer;
|
||||
position: fixed;
|
||||
z-index:2;
|
||||
right: 0.5rem;
|
||||
bottom: 0.5rem;
|
||||
}
|
||||
|
||||
#save {
|
||||
background-color:#007046;
|
||||
color: white;
|
||||
bottom: 6.5rem;
|
||||
}
|
||||
#load {
|
||||
background-color: #fc5531;
|
||||
color: white;
|
||||
bottom: 3.5rem;
|
||||
}
|
||||
|
||||
.head {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
height: 5.2rem;
|
||||
font-size: 1.4rem;
|
||||
white-space: nowrap;
|
||||
color: #EEEEEE;
|
||||
}
|
||||
|
||||
.propinitial,
|
||||
.selectlist {
|
||||
list-style: none;
|
||||
flex: 1;
|
||||
padding: 1rem;
|
||||
}
|
||||
|
||||
.lifeProperty {
|
||||
list-style: none;
|
||||
padding: 2rem 1rem 0.5rem 1rem;
|
||||
display: flex;
|
||||
color: #FFFFFF;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.lifeProperty>li {
|
||||
flex: 1;
|
||||
margin: 0.1rem 2px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
border: 1px #ccc solid;
|
||||
border-radius: 0.2rem;
|
||||
font-size: 1rem;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.lifeProperty>li>span:last-child {
|
||||
background: #eee;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.selectlist>li {
|
||||
margin-bottom: 0.6rem;
|
||||
display: block;
|
||||
border: 1px #EEEEEE solid;
|
||||
border-radius: 0.2rem;
|
||||
color: #EEEEEE;
|
||||
font-size: 1.2rem;
|
||||
line-height: 1.6;
|
||||
user-select: none;
|
||||
position: relative;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.selectlist>li:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.achvg0,
|
||||
.grade0b {
|
||||
background-color: #464646;
|
||||
border: #f8f8f8 2px solid !important;
|
||||
}
|
||||
.achvg1,
|
||||
.grade1b {
|
||||
background-color: #6495ed;
|
||||
border: #f8f8f8 2px solid !important;
|
||||
}
|
||||
|
||||
.achvg2,
|
||||
.grade2b {
|
||||
background-color: #e2a7ff;
|
||||
border: #f8f8f8 2px solid !important;
|
||||
}
|
||||
|
||||
.achvg3,
|
||||
.grade3b {
|
||||
background-color: #ffa07a;
|
||||
border: #f8f8f8 2px solid !important;
|
||||
}
|
||||
|
||||
.mask::before {
|
||||
display: block;
|
||||
content: " ";
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-color: #000;
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
@media (min-width:1080px) {
|
||||
.grade0b:hover {
|
||||
background-color: #c0c0c0;
|
||||
color: #3b3b3b;
|
||||
transition: all .3s ease 0s;
|
||||
}
|
||||
|
||||
.grade1b:hover {
|
||||
background-color: #87cefa;
|
||||
color: #3b3b3b;
|
||||
transition: all .3s ease 0s;
|
||||
}
|
||||
|
||||
.grade2b:hover {
|
||||
background-color: #e7beff;
|
||||
color: #3b3b3b;
|
||||
transition: all .3s ease 0s;
|
||||
}
|
||||
|
||||
.grade3b:hover {
|
||||
background-color: #f7a989;
|
||||
color: #3b3b3b;
|
||||
transition: all .3s ease 0s;
|
||||
}
|
||||
}
|
||||
|
||||
.grade0b.selected,
|
||||
.grade1b.selected,
|
||||
.grade2b.selected,
|
||||
.grade3b.selected {
|
||||
box-shadow: #ccc 0px 0px 10px;
|
||||
color: #3b3b3b;
|
||||
overflow: hidden;
|
||||
}
|
||||
.grade0b.selected::after,
|
||||
.grade1b.selected::after,
|
||||
.grade2b.selected::after,
|
||||
.grade3b.selected::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
background-color:#000;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
box-shadow: 0 0 10px #000;
|
||||
opacity: 0;
|
||||
animation: blink 3s linear infinite;
|
||||
}
|
||||
|
||||
@keyframes blink {
|
||||
0% {
|
||||
opacity: 0;
|
||||
transform: translateX(-150%);
|
||||
}
|
||||
50% {
|
||||
opacity: .2;
|
||||
}
|
||||
100% {
|
||||
opacity: 0;
|
||||
transform: translateX(150%);
|
||||
}
|
||||
}
|
||||
|
||||
.grade0b.selected {
|
||||
background-color: #c0c0c0 !important;
|
||||
}
|
||||
|
||||
.grade1b.selected {
|
||||
background-color: #87cefa !important;
|
||||
}
|
||||
|
||||
.grade2b.selected {
|
||||
background-color: #e7beff !important;
|
||||
}
|
||||
|
||||
.grade3b.selected {
|
||||
background-color: #f1bfac !important;
|
||||
}
|
||||
|
||||
.propinitial {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.propbtn:hover {
|
||||
color: #5c5c5c;
|
||||
transition: all .2s ease 0s;
|
||||
}
|
||||
|
||||
.propinitial>li {
|
||||
position: relative;
|
||||
margin: 0.1rem auto;
|
||||
padding: 0.2rem;
|
||||
display: inline-block;
|
||||
border-radius: 0.2rem;
|
||||
color: #EEEEEE;
|
||||
font-size: 1.6rem;
|
||||
line-height: 2;
|
||||
}
|
||||
|
||||
.propinitial>li>input {
|
||||
height: 2.2rem;
|
||||
width: 2.2rem;
|
||||
margin: 0 0.5rem;
|
||||
padding: 0;
|
||||
font-size: 2rem;
|
||||
border: 0.1rem #EEEEEE solid;
|
||||
background-color: #393E46;
|
||||
color: #EEEEEE;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.propbtn {
|
||||
position: relative;
|
||||
cursor: pointer;
|
||||
font-size: 2rem;
|
||||
color: #EEEEEE;
|
||||
}
|
||||
|
||||
.judge>li>span:nth-child(1),
|
||||
.lifeTrajectory>li>span:nth-child(1) {
|
||||
width: 5rem;
|
||||
text-align: right;
|
||||
}
|
||||
.judge>li>span:nth-child(2),
|
||||
.lifeTrajectory>li>span:nth-child(2) {
|
||||
flex: 1;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.lifeTrajectory {
|
||||
flex: 1;
|
||||
margin: 0.5rem 1rem;
|
||||
padding: 0;
|
||||
border: 1px #9b9b9b solid;
|
||||
background-color: #393E46;
|
||||
border-radius: 4px;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.lifeTrajectory>li {
|
||||
margin: 10px 0;
|
||||
padding: 5px 10px;
|
||||
display: flex;
|
||||
background-color: #4a5361;
|
||||
box-shadow: #EEEEEE 0 0 0.4rem;
|
||||
color: #EEEEEE;
|
||||
font-size: 1rem;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
|
||||
.judge {
|
||||
list-style: none;
|
||||
flex: 1;
|
||||
margin: 1rem;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
border: 1px solid #EEEEEE;
|
||||
border-radius: 4px;
|
||||
overflow: scroll;
|
||||
}
|
||||
|
||||
.judge>li {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
background-color: #4a5361;
|
||||
border-bottom: 1px solid #EEEEEE;
|
||||
box-shadow: none;
|
||||
color: #EEEEEE;
|
||||
}
|
||||
|
||||
.judge>li:last-child {
|
||||
border-bottom: 0
|
||||
}
|
||||
|
||||
.judge>li.grade1 span,
|
||||
.judge>li.grade1 {
|
||||
background-color: #87cefa;
|
||||
color: #4a5361;
|
||||
}
|
||||
|
||||
.judge>li.grade2 span,
|
||||
.judge>li.grade2 {
|
||||
background-color: #e7beff;
|
||||
color: #4a5361;
|
||||
}
|
||||
|
||||
.judge>li.grade3 span,
|
||||
.judge>li.grade3 {
|
||||
background-color: #f7a989;
|
||||
color: #4a5361;
|
||||
}
|
||||
|
||||
|
||||
@import url("https://fonts.googleapis.com/css?family=Montserrat:400,400i,700");
|
||||
|
||||
:root {
|
||||
font-family: "Montserrat";
|
||||
}
|
||||
|
||||
html,
|
||||
body {
|
||||
margin: 0;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
body {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
i {
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
.banners-container {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
z-index: 9;
|
||||
}
|
||||
|
||||
.banner {
|
||||
color: white;
|
||||
font-weight: 700;
|
||||
padding: 2rem;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.banner .banner-message {
|
||||
flex: 1;
|
||||
padding: 0 2rem;
|
||||
word-break: break-word;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.banner .banner-close {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 0.1rem;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
transition: background 0.3s;
|
||||
}
|
||||
|
||||
.banner .iconfont {
|
||||
font-size: 2rem;
|
||||
}
|
||||
|
||||
.banner .banner-close:hover {
|
||||
background: rgba(0, 0, 0, 0.12);
|
||||
}
|
||||
|
||||
.banner.success {
|
||||
background: lightgreen;
|
||||
}
|
||||
|
||||
.banner.success::after {
|
||||
background: lightgreen;
|
||||
}
|
||||
|
||||
.banner.error {
|
||||
background: #ed1c24;
|
||||
}
|
||||
|
||||
.banner.error::after {
|
||||
background: #ed1c24;
|
||||
}
|
||||
|
||||
.banner.info {
|
||||
background: skyblue;
|
||||
}
|
||||
|
||||
.banner.info::after {
|
||||
background: skyblue;
|
||||
}
|
||||
|
||||
.banner::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
height: 10%;
|
||||
width: 100%;
|
||||
bottom: 100%;
|
||||
left: 0;
|
||||
}
|
||||
|
||||
.banner:not(.visible) {
|
||||
display: none;
|
||||
transform: translateY(-100%);
|
||||
}
|
||||
|
||||
.banner.visible {
|
||||
box-shadow: 0 2px 2px 2px rgba(0, 0, 0, 0.12);
|
||||
animation-name: banner-in;
|
||||
animation-direction: forwards;
|
||||
animation-duration: 0.6s;
|
||||
animation-timing-function: ease-in-out;
|
||||
animation-fill-mode: forwards;
|
||||
animation-iteration-count: 1;
|
||||
}
|
||||
|
||||
@keyframes banner-in {
|
||||
0% {
|
||||
transform: translateY(-100%);
|
||||
}
|
||||
|
||||
50% {
|
||||
transform: translateY(10%);
|
||||
}
|
||||
|
||||
100% {
|
||||
transform: translateY(0);
|
||||
}
|
||||
}
|
||||
|
||||
.show-banner {
|
||||
appearance: none;
|
||||
background: #ededed;
|
||||
border: 0;
|
||||
padding: 1rem 2rem;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
text-transform: uppercase;
|
||||
margin: 0.25rem;
|
||||
}
|
||||
|
||||
/**
|
||||
* @license
|
||||
* Copyright Akveo. All Rights Reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*/
|
||||
.eva-animation {
|
||||
animation-duration: 1s;
|
||||
animation-fill-mode: both;
|
||||
}
|
||||
|
||||
.eva-infinite {
|
||||
animation-iteration-count: infinite;
|
||||
}
|
||||
|
||||
.eva-icon-shake {
|
||||
animation-name: eva-shake;
|
||||
}
|
||||
|
||||
.eva-icon-zoom {
|
||||
animation-name: eva-zoomIn;
|
||||
}
|
||||
|
||||
.eva-icon-pulse {
|
||||
animation-name: eva-pulse;
|
||||
}
|
||||
|
||||
.eva-icon-flip {
|
||||
animation-name: eva-flipInY;
|
||||
}
|
||||
|
||||
.eva-hover {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.eva-hover:hover .eva-icon-hover-shake,
|
||||
.eva-parent-hover:hover .eva-icon-hover-shake {
|
||||
animation-name: eva-shake;
|
||||
}
|
||||
|
||||
.eva-hover:hover .eva-icon-hover-zoom,
|
||||
.eva-parent-hover:hover .eva-icon-hover-zoom {
|
||||
animation-name: eva-zoomIn;
|
||||
}
|
||||
|
||||
.eva-hover:hover .eva-icon-hover-pulse,
|
||||
.eva-parent-hover:hover .eva-icon-hover-pulse {
|
||||
animation-name: eva-pulse;
|
||||
}
|
||||
|
||||
.eva-hover:hover .eva-icon-hover-flip,
|
||||
.eva-parent-hover:hover .eva-icon-hover-flip {
|
||||
animation-name: eva-flipInY;
|
||||
}
|
||||
|
||||
@keyframes eva-flipInY {
|
||||
from {
|
||||
transform: perspective(400px) rotate3d(0, 1, 0, 90deg);
|
||||
animation-timing-function: ease-in;
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
40% {
|
||||
transform: perspective(400px) rotate3d(0, 1, 0, -20deg);
|
||||
animation-timing-function: ease-in;
|
||||
}
|
||||
|
||||
60% {
|
||||
transform: perspective(400px) rotate3d(0, 1, 0, 10deg);
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
80% {
|
||||
transform: perspective(400px) rotate3d(0, 1, 0, -5deg);
|
||||
}
|
||||
|
||||
to {
|
||||
transform: perspective(400px);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes eva-shake {
|
||||
|
||||
from,
|
||||
to {
|
||||
transform: translate3d(0, 0, 0);
|
||||
}
|
||||
|
||||
10%,
|
||||
30%,
|
||||
50%,
|
||||
70%,
|
||||
90% {
|
||||
transform: translate3d(-3px, 0, 0);
|
||||
}
|
||||
|
||||
20%,
|
||||
40%,
|
||||
60%,
|
||||
80% {
|
||||
transform: translate3d(3px, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes eva-pulse {
|
||||
from {
|
||||
transform: scale3d(1, 1, 1);
|
||||
}
|
||||
|
||||
50% {
|
||||
transform: scale3d(1.2, 1.2, 1.2);
|
||||
}
|
||||
|
||||
to {
|
||||
transform: scale3d(1, 1, 1);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes eva-zoomIn {
|
||||
from {
|
||||
opacity: 1;
|
||||
transform: scale3d(0.5, 0.5, 0.5);
|
||||
}
|
||||
|
||||
50% {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
::-webkit-scrollbar {
|
||||
width: 0 !important
|
||||
}
|
||||
|
||||
.deleteFixed {
|
||||
margin: 0;
|
||||
padding: 0.5rem 1rem;
|
||||
border: 0;
|
||||
border-radius: 0;
|
||||
overflow: visible;
|
||||
}
|
||||
|
||||
.operateBtn {
|
||||
padding: 0.5rem 1.5rem;
|
||||
border: 1px #EEEEEE solid;
|
||||
border-radius: 0.2rem;
|
||||
background-color:#393E46;
|
||||
font-size: 1.6rem;
|
||||
white-space: nowrap;
|
||||
transform: translate(-50%,-50%);
|
||||
cursor: pointer;
|
||||
z-index:2;
|
||||
color: #EEEEEE;
|
||||
}
|
||||
|
||||
.operateBtn:hover {
|
||||
background: #ff7878;
|
||||
color: #fff;
|
||||
transition: all .4s ease 0s;
|
||||
}
|
||||
|
||||
.domToImage2wx {
|
||||
position: fixed;
|
||||
z-index: 1111;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.domToImage2wx img {
|
||||
width: 100%;
|
||||
}
|
||||
@@ -0,0 +1,906 @@
|
||||
@media (min-width:640px){html{font-size:24px;}}
|
||||
@media (min-width:631px) and (max-width:639px){html{font-size:23.66px;}}
|
||||
@media (min-width:622px) and (max-width:630px){html{font-size:23.33px;}}
|
||||
@media (min-width:613px) and (max-width:621px){html{font-size:23px;}}
|
||||
@media (min-width:604px) and (max-width:612px){html{font-size:22.66px;}}
|
||||
@media (min-width:595px) and (max-width:603px){html{font-size:22.33px;}}
|
||||
@media (min-width:586px) and (max-width:594px){html{font-size:22px;}}
|
||||
@media (min-width:577px) and (max-width:585px){html{font-size:21.66px;}}
|
||||
@media (min-width:568px) and (max-width:576px){html{font-size:21.33px;}}
|
||||
@media (min-width:559px) and (max-width:567px){html{font-size:21px;}}
|
||||
@media (min-width:550px) and (max-width:558px){html{font-size:20.66px;}}
|
||||
@media (min-width:541px) and (max-width:549px){html{font-size:20.33px;}}
|
||||
@media (min-width:533px) and (max-width:540px){html{font-size:20px;}}
|
||||
@media (min-width:524px) and (max-width:532px){html{font-size:19.66px;}}
|
||||
@media (min-width:515px) and (max-width:523px){html{font-size:19.33px;}}
|
||||
@media (min-width:506px) and (max-width:514px){html{font-size:19px;}}
|
||||
@media (min-width:497px) and (max-width:505px){html{font-size:18.66px;}}
|
||||
@media (min-width:488px) and (max-width:496px){html{font-size:18.33px;}}
|
||||
@media (min-width:480px) and (max-width:487px){html{font-size:18px;}}
|
||||
@media (min-width:471px) and (max-width:479px){html{font-size:17.66px;}}
|
||||
@media (min-width:462px) and (max-width:470px){html{font-size:17.33px;}}
|
||||
@media (min-width:453px) and (max-width:461px){html{font-size:17px;}}
|
||||
@media (min-width:444px) and (max-width:452px){html{font-size:17.12px;}}
|
||||
@media (min-width:435px) and (max-width:443px){html{font-size:16.33px;}}
|
||||
@media (min-width:426px) and (max-width:434px){html{font-size:16px;}}
|
||||
@media (min-width:417px) and (max-width:425px){html{font-size:15.66px;}}
|
||||
@media (min-width:408px) and (max-width:416px){html{font-size:15.33px;}}
|
||||
@media (min-width:400px) and (max-width:407px){html{font-size:15px;}}
|
||||
@media (min-width:391px) and (max-width:399px){html{font-size:14.66px;}}
|
||||
@media (min-width:382px) and (max-width:390px){html{font-size:14.33px;}}
|
||||
@media (min-width:374px) and (max-width:381px){html{font-size:14px;}}
|
||||
@media (min-width:365px) and (max-width:373px){html{font-size:13.66px;}}
|
||||
@media (min-width:356px) and (max-width:364px){html{font-size:13.33px;}}
|
||||
@media (min-width:347px) and (max-width:355px){html{font-size:13px;}}
|
||||
@media (min-width:338px) and (max-width:346px){html{font-size:12.66px;}}
|
||||
@media (min-width:329px) and (max-width:337px){html{font-size:12.44px;}}
|
||||
@media (max-width:328px){html{font-size:12px;}}
|
||||
|
||||
@font-face {
|
||||
font-family: 'iconfont';
|
||||
src: url('iconfont.woff2?t=1628944689555') format('woff2'),
|
||||
url('iconfont.woff?t=1628944689555') format('woff'),
|
||||
url('iconfont.ttf?t=1628944689555') format('truetype');
|
||||
}
|
||||
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
input::-webkit-outer-spin-button,
|
||||
input::-webkit-inner-spin-button {
|
||||
-webkit-appearance: none;
|
||||
}
|
||||
input[type="number"]{
|
||||
-moz-appearance: textfield;
|
||||
}
|
||||
|
||||
html {
|
||||
background-color: #241619;
|
||||
font-family: PingFangSC, 'Noto Sans CJK SC', 'MS Yahei';
|
||||
}
|
||||
|
||||
body {
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
#main {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
width: 100%;
|
||||
max-width: 30rem;
|
||||
height: 100%;
|
||||
text-align: center;
|
||||
box-sizing: border-box;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
#title {
|
||||
position: fixed;
|
||||
font-size: 3rem;
|
||||
font-weight: 700;
|
||||
top: 35%;
|
||||
left: 50%;
|
||||
white-space: nowrap;
|
||||
transform: translate(-50%, -50%);
|
||||
color: #ff9f27;
|
||||
}
|
||||
|
||||
#restart {
|
||||
position: fixed;
|
||||
top: 65%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
}
|
||||
|
||||
#restart .iconfont {
|
||||
margin-right: 0.5rem;
|
||||
}
|
||||
|
||||
#next {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#talentSelectedView {
|
||||
flex: 0 1 auto;
|
||||
}
|
||||
|
||||
.mainbtn {
|
||||
margin: 0.5rem 1rem 1rem;
|
||||
padding: 0.5rem 1.5rem;
|
||||
background-color: #4a0388;
|
||||
border: 1px #4a0388 solid;
|
||||
border-radius: 0.2rem;
|
||||
color: #ff197b;
|
||||
font-size: 1.6rem;
|
||||
white-space: nowrap;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.mainbtn:hover {
|
||||
background: #fd373c;
|
||||
color: #4a0388;
|
||||
transition: all .4s ease 0s;
|
||||
}
|
||||
|
||||
.btn-area {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.btn-area>.mainbtn {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.iconfont {
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
font-family: "iconfont" !important;
|
||||
font-style: normal;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
}
|
||||
|
||||
.sponsor,
|
||||
#rank,
|
||||
#specialthanks,
|
||||
#achievement {
|
||||
position: fixed;
|
||||
top: 4rem;
|
||||
right: 1rem;
|
||||
padding: 0.1rem;
|
||||
width: 6rem;
|
||||
border: none;
|
||||
border-radius: 0.2rem;
|
||||
background-color: #1a0c18;
|
||||
font-size: 1.4rem;
|
||||
color: #ff9f27;
|
||||
cursor: pointer;
|
||||
z-index:2;
|
||||
word-wrap: none;
|
||||
}
|
||||
|
||||
#specialthanks {
|
||||
background-color: #1a0c18;
|
||||
top: 1rem;
|
||||
}
|
||||
|
||||
.sponsor {
|
||||
top: auto;
|
||||
bottom: 0;
|
||||
width: auto;
|
||||
padding: 0.5rem;
|
||||
}
|
||||
|
||||
#rank {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
right: 1.5rem;
|
||||
transform: translateY(-50%);
|
||||
}
|
||||
|
||||
#spthx {
|
||||
position: fixed;
|
||||
display: grid;
|
||||
top: 4rem;
|
||||
bottom: 5rem;
|
||||
left: 50%;
|
||||
width: 30rem;
|
||||
max-width: calc(100% - 2rem);
|
||||
transform: translateX(-50%);
|
||||
}
|
||||
|
||||
#spthx ul {
|
||||
list-style-type: none;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
#spthx ul li {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
#spthx ul.g1 {
|
||||
display: grid;
|
||||
max-block-size: 9rem;
|
||||
max-height: 9rem;
|
||||
overflow: scroll;
|
||||
}
|
||||
|
||||
#spthx ul.g1 li {
|
||||
display: inline-grid;
|
||||
background-color: orange;
|
||||
margin-bottom: 0.5rem;
|
||||
padding: 0.2rem 0;
|
||||
grid-template-columns: 7rem auto;
|
||||
}
|
||||
|
||||
#spthx ul.g1 li .name {
|
||||
padding: 0 0.5rem;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
#spthx ul.g1 li .comment {
|
||||
padding: 0 0.5rem;
|
||||
}
|
||||
|
||||
#spthx ul.g2 {
|
||||
color: white;
|
||||
display: grid;
|
||||
grid-template-columns: 50% 50%;
|
||||
overflow: scroll;
|
||||
}
|
||||
|
||||
#spthx ul.g2 li {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.title {
|
||||
color: #ff9f27;
|
||||
position: relative;
|
||||
font-size: 1.5rem;
|
||||
font-weight: 700;
|
||||
padding: 1rem;
|
||||
}
|
||||
|
||||
ul#total,
|
||||
#achievements {
|
||||
list-style-type: none;
|
||||
display: grid;
|
||||
justify-items: center;
|
||||
grid-template-columns: 50% 50%;
|
||||
grid-auto-columns: max-content;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
ul#total li,
|
||||
#achievements li {
|
||||
position: relative;
|
||||
color: #ff9f27;
|
||||
display: inline-grid;
|
||||
margin: 0.5rem;
|
||||
width: 12rem;
|
||||
height: 6rem;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
ul#total li .achievementtitle,
|
||||
#achievements li .achievementtitle{
|
||||
font-weight: 700;
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
|
||||
#achievements {
|
||||
overflow: scroll;
|
||||
}
|
||||
|
||||
#save,
|
||||
#load,
|
||||
#themeToggleBtn {
|
||||
padding: 0 0.7rem;
|
||||
width: 6.5rem;
|
||||
background-color: #1a0c18;
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
font-size: 1.4rem;
|
||||
color: #ff9f27;
|
||||
line-height: 2.5rem;
|
||||
text-align: center;
|
||||
vertical-align: middle;
|
||||
cursor: pointer;
|
||||
position: fixed;
|
||||
z-index:2;
|
||||
right: 0.5rem;
|
||||
bottom: 0.5rem;
|
||||
}
|
||||
|
||||
#themeToggleBtn {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#save {
|
||||
bottom: 3.5rem;
|
||||
}
|
||||
|
||||
.head {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
height: 5.2rem;
|
||||
font-size: 1.4rem;
|
||||
white-space: nowrap;
|
||||
color: #ff9f27;
|
||||
}
|
||||
|
||||
.propinitial,
|
||||
.selectlist {
|
||||
list-style: none;
|
||||
flex: 1;
|
||||
padding: 1rem;
|
||||
}
|
||||
|
||||
.lifeProperty {
|
||||
list-style: none;
|
||||
padding: 2rem 1rem 0.5rem 1rem;
|
||||
display: flex;
|
||||
color: #fd373c;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.lifeProperty>li {
|
||||
flex: 1;
|
||||
margin: 0.1rem 2px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
border: 1px #fd373c solid;
|
||||
border-radius: 0.2rem;
|
||||
font-size: 1rem;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.lifeProperty>li>span:last-child {
|
||||
background: #fd373c;
|
||||
color: #4a0388;
|
||||
}
|
||||
|
||||
.selectlist>li {
|
||||
margin-bottom: 0.6rem;
|
||||
display: block;
|
||||
border: 1px #ff9f27 solid;
|
||||
border-radius: 0.2rem;
|
||||
color: #ff9f27;
|
||||
font-size: 1.2rem;
|
||||
line-height: 1.6;
|
||||
user-select: none;
|
||||
position: relative;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.selectlist>li:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.achvg0,
|
||||
.grade0b {
|
||||
background-color: #231815;
|
||||
border: #ff9f27 2px solid !important;
|
||||
color: #ff9f27 !important;
|
||||
}
|
||||
.achvg1,
|
||||
.grade1b {
|
||||
background-color: #3b3894;
|
||||
border: #ff9f27 2px solid !important;
|
||||
}
|
||||
|
||||
.achvg2,
|
||||
.grade2b {
|
||||
background-color: #470063;
|
||||
border: #ff9f27 2px solid !important;
|
||||
}
|
||||
|
||||
.achvg3,
|
||||
.grade3b {
|
||||
background-color: #f73c47;
|
||||
border: #ff9f27 2px solid !important;
|
||||
color: #f8ea8b !important;
|
||||
}
|
||||
|
||||
.mask::before {
|
||||
display: block;
|
||||
content: " ";
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-color: #241619;
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
@media (min-width:1080px) {
|
||||
.grade0b:hover {
|
||||
background-color: #452915;
|
||||
transition: all .3s ease 0s;
|
||||
}
|
||||
|
||||
.grade1b:hover {
|
||||
background-color: #5553b3;
|
||||
transition: all .3s ease 0s;
|
||||
}
|
||||
|
||||
.grade2b:hover {
|
||||
background-color: #672183;
|
||||
transition: all .3s ease 0s;
|
||||
}
|
||||
|
||||
.grade3b:hover {
|
||||
background-color: #ff8561;
|
||||
transition: all .3s ease 0s;
|
||||
}
|
||||
}
|
||||
|
||||
.grade0b.selected,
|
||||
.grade1b.selected,
|
||||
.grade2b.selected,
|
||||
.grade3b.selected {
|
||||
box-shadow: #f74745 8px 4px 4px;
|
||||
overflow: hidden;
|
||||
}
|
||||
.grade0b.selected::after,
|
||||
.grade1b.selected::after,
|
||||
.grade2b.selected::after,
|
||||
.grade3b.selected::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
background-color: #fe028b;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
box-shadow: 0 0 10px #fe028b;
|
||||
opacity: 0;
|
||||
animation: blink 3s linear infinite;
|
||||
}
|
||||
|
||||
@keyframes blink {
|
||||
0% {
|
||||
opacity: 0;
|
||||
transform: translateX(-150%);
|
||||
}
|
||||
50% {
|
||||
opacity: .2;
|
||||
}
|
||||
100% {
|
||||
opacity: 0;
|
||||
transform: translateX(150%);
|
||||
}
|
||||
}
|
||||
|
||||
.grade0b.selected {
|
||||
background-color: #452915 !important;
|
||||
}
|
||||
|
||||
.grade1b.selected {
|
||||
background-color: #5553b3!important;
|
||||
}
|
||||
|
||||
.grade2b.selected {
|
||||
background-color: #672183 !important;
|
||||
}
|
||||
|
||||
.grade3b.selected {
|
||||
background-color: #ff8561 !important;
|
||||
}
|
||||
|
||||
.propinitial {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.propbtn:hover {
|
||||
color: #5c5c5c;
|
||||
transition: all .2s ease 0s;
|
||||
}
|
||||
|
||||
.propinitial>li {
|
||||
position: relative;
|
||||
margin: 0.1rem auto;
|
||||
padding: 0.2rem;
|
||||
display: inline-block;
|
||||
border-radius: 0.2rem;
|
||||
color: #ff9f27;
|
||||
font-size: 1.6rem;
|
||||
line-height: 2;
|
||||
}
|
||||
|
||||
.propinitial>li>input {
|
||||
height: 2.2rem;
|
||||
width: 2.2rem;
|
||||
margin: 0 0.5rem;
|
||||
padding: 0;
|
||||
font-size: 2rem;
|
||||
border: 0.1rem #ff9f27 solid;
|
||||
background-color: #393E46;
|
||||
color: #ff9f27;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.propbtn {
|
||||
position: relative;
|
||||
cursor: pointer;
|
||||
font-size: 2rem;
|
||||
color: #ff9f27;
|
||||
}
|
||||
|
||||
.judge>li>span:nth-child(1),
|
||||
.lifeTrajectory>li>span:nth-child(1) {
|
||||
width: 5rem;
|
||||
text-align: right;
|
||||
}
|
||||
.judge>li>span:nth-child(2),
|
||||
.lifeTrajectory>li>span:nth-child(2) {
|
||||
flex: 1;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.lifeTrajectory {
|
||||
flex: 1;
|
||||
margin: 0.5rem 1rem;
|
||||
padding: 0;
|
||||
border: 1px #ff9f27 solid;
|
||||
background-color: #241619;
|
||||
border-radius: 4px;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.lifeTrajectory>li {
|
||||
margin: 10px 0;
|
||||
padding: 5px 10px;
|
||||
display: flex;
|
||||
background-color: #231815;
|
||||
box-shadow: #ff9f27 0 0 0.4rem;
|
||||
color: #ff9f27;
|
||||
font-size: 1rem;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
|
||||
.judge {
|
||||
list-style: none;
|
||||
flex: 1;
|
||||
margin: 1rem;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
border: 1px solid #ff9f27;
|
||||
border-radius: 4px;
|
||||
overflow: scroll;
|
||||
}
|
||||
|
||||
.judge>li {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
background-color: #231815;
|
||||
border-bottom: 1px solid #ff9f27;
|
||||
box-shadow: none;
|
||||
color: #ff9f27;
|
||||
}
|
||||
|
||||
.judge>li:last-child {
|
||||
border-bottom: 0
|
||||
}
|
||||
|
||||
.judge>li.grade1 span,
|
||||
.judge>li.grade1 {
|
||||
background-color: #3b3894;
|
||||
}
|
||||
|
||||
.judge>li.grade2 span,
|
||||
.judge>li.grade2 {
|
||||
background-color: #470063;
|
||||
}
|
||||
|
||||
.judge>li.grade3 span,
|
||||
.judge>li.grade3 {
|
||||
background-color: #f73c47;
|
||||
color: #f8ea8b !important;
|
||||
}
|
||||
|
||||
|
||||
@import url("https://fonts.googleapis.com/css?family=Montserrat:400,400i,700");
|
||||
|
||||
:root {
|
||||
font-family: "Montserrat";
|
||||
}
|
||||
|
||||
html,
|
||||
body {
|
||||
margin: 0;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
body {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
i {
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
.banners-container {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
z-index: 9;
|
||||
}
|
||||
|
||||
.banner {
|
||||
color: white;
|
||||
font-weight: 700;
|
||||
padding: 2rem;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.banner .banner-message {
|
||||
flex: 1;
|
||||
padding: 0 2rem;
|
||||
word-break: break-word;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.banner .banner-close {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 0.1rem;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
transition: background 0.3s;
|
||||
}
|
||||
|
||||
.banner .iconfont {
|
||||
font-size: 2rem;
|
||||
}
|
||||
|
||||
.banner .banner-close:hover {
|
||||
background: rgba(0, 0, 0, 0.12);
|
||||
}
|
||||
|
||||
.banner.success {
|
||||
background: #c101f9;
|
||||
}
|
||||
|
||||
.banner.success::after {
|
||||
background: #c101f9;
|
||||
}
|
||||
|
||||
.banner.error {
|
||||
background: #ff3a3f;
|
||||
}
|
||||
|
||||
.banner.error::after {
|
||||
background: #ff3a3f;
|
||||
}
|
||||
|
||||
.banner.info {
|
||||
background: #282366;
|
||||
}
|
||||
|
||||
.banner.info::after {
|
||||
background: #282366;
|
||||
}
|
||||
|
||||
.banner::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
height: 10%;
|
||||
width: 100%;
|
||||
bottom: 100%;
|
||||
left: 0;
|
||||
}
|
||||
|
||||
.banner:not(.visible) {
|
||||
display: none;
|
||||
transform: translateY(-100%);
|
||||
}
|
||||
|
||||
.banner.visible {
|
||||
box-shadow: 0 2px 2px 2px rgba(0, 0, 0, 0.12);
|
||||
animation-name: banner-in;
|
||||
animation-direction: forwards;
|
||||
animation-duration: 0.6s;
|
||||
animation-timing-function: ease-in-out;
|
||||
animation-fill-mode: forwards;
|
||||
animation-iteration-count: 1;
|
||||
}
|
||||
|
||||
@keyframes banner-in {
|
||||
0% {
|
||||
transform: translateY(-100%);
|
||||
}
|
||||
|
||||
50% {
|
||||
transform: translateY(10%);
|
||||
}
|
||||
|
||||
100% {
|
||||
transform: translateY(0);
|
||||
}
|
||||
}
|
||||
|
||||
.show-banner {
|
||||
appearance: none;
|
||||
background: #ededed;
|
||||
border: 0;
|
||||
padding: 1rem 2rem;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
text-transform: uppercase;
|
||||
margin: 0.25rem;
|
||||
}
|
||||
|
||||
/**
|
||||
* @license
|
||||
* Copyright Akveo. All Rights Reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*/
|
||||
.eva-animation {
|
||||
animation-duration: 1s;
|
||||
animation-fill-mode: both;
|
||||
}
|
||||
|
||||
.eva-infinite {
|
||||
animation-iteration-count: infinite;
|
||||
}
|
||||
|
||||
.eva-icon-shake {
|
||||
animation-name: eva-shake;
|
||||
}
|
||||
|
||||
.eva-icon-zoom {
|
||||
animation-name: eva-zoomIn;
|
||||
}
|
||||
|
||||
.eva-icon-pulse {
|
||||
animation-name: eva-pulse;
|
||||
}
|
||||
|
||||
.eva-icon-flip {
|
||||
animation-name: eva-flipInY;
|
||||
}
|
||||
|
||||
.eva-hover {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.eva-hover:hover .eva-icon-hover-shake,
|
||||
.eva-parent-hover:hover .eva-icon-hover-shake {
|
||||
animation-name: eva-shake;
|
||||
}
|
||||
|
||||
.eva-hover:hover .eva-icon-hover-zoom,
|
||||
.eva-parent-hover:hover .eva-icon-hover-zoom {
|
||||
animation-name: eva-zoomIn;
|
||||
}
|
||||
|
||||
.eva-hover:hover .eva-icon-hover-pulse,
|
||||
.eva-parent-hover:hover .eva-icon-hover-pulse {
|
||||
animation-name: eva-pulse;
|
||||
}
|
||||
|
||||
.eva-hover:hover .eva-icon-hover-flip,
|
||||
.eva-parent-hover:hover .eva-icon-hover-flip {
|
||||
animation-name: eva-flipInY;
|
||||
}
|
||||
|
||||
@keyframes eva-flipInY {
|
||||
from {
|
||||
transform: perspective(400px) rotate3d(0, 1, 0, 90deg);
|
||||
animation-timing-function: ease-in;
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
40% {
|
||||
transform: perspective(400px) rotate3d(0, 1, 0, -20deg);
|
||||
animation-timing-function: ease-in;
|
||||
}
|
||||
|
||||
60% {
|
||||
transform: perspective(400px) rotate3d(0, 1, 0, 10deg);
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
80% {
|
||||
transform: perspective(400px) rotate3d(0, 1, 0, -5deg);
|
||||
}
|
||||
|
||||
to {
|
||||
transform: perspective(400px);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes eva-shake {
|
||||
|
||||
from,
|
||||
to {
|
||||
transform: translate3d(0, 0, 0);
|
||||
}
|
||||
|
||||
10%,
|
||||
30%,
|
||||
50%,
|
||||
70%,
|
||||
90% {
|
||||
transform: translate3d(-3px, 0, 0);
|
||||
}
|
||||
|
||||
20%,
|
||||
40%,
|
||||
60%,
|
||||
80% {
|
||||
transform: translate3d(3px, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes eva-pulse {
|
||||
from {
|
||||
transform: scale3d(1, 1, 1);
|
||||
}
|
||||
|
||||
50% {
|
||||
transform: scale3d(1.2, 1.2, 1.2);
|
||||
}
|
||||
|
||||
to {
|
||||
transform: scale3d(1, 1, 1);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes eva-zoomIn {
|
||||
from {
|
||||
opacity: 1;
|
||||
transform: scale3d(0.5, 0.5, 0.5);
|
||||
}
|
||||
|
||||
50% {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
::-webkit-scrollbar {
|
||||
width: 0 !important
|
||||
}
|
||||
|
||||
.deleteFixed {
|
||||
margin: 0;
|
||||
padding: 0.5rem 1rem;
|
||||
border: 0;
|
||||
border-radius: 0;
|
||||
overflow: visible;
|
||||
}
|
||||
|
||||
.operateBtn {
|
||||
padding: 0.5rem 1.5rem;
|
||||
border: 1px #EEEEEE solid;
|
||||
border-radius: 0.2rem;
|
||||
background-color:#393E46;
|
||||
font-size: 1.6rem;
|
||||
white-space: nowrap;
|
||||
transform: translate(-50%,-50%);
|
||||
cursor: pointer;
|
||||
z-index:2;
|
||||
color: #EEEEEE;
|
||||
}
|
||||
|
||||
.operateBtn:hover {
|
||||
background: #ff7878;
|
||||
color: #fff;
|
||||
transition: all .4s ease 0s;
|
||||
}
|
||||
|
||||
.domToImage2wx {
|
||||
position: fixed;
|
||||
z-index: 1111;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.domToImage2wx img {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.github-corner,
|
||||
.discord-btn {
|
||||
background-color: #1a0c18 !important;
|
||||
color: #ff9f27 !important;
|
||||
}
|
||||
.github-corner > svg path.octo-arm,
|
||||
.github-corner > svg path.octo-body,
|
||||
.discord-btn > svg > g > path {
|
||||
fill: #ff9f27 !important;
|
||||
}
|
||||
|
After Width: | Height: | Size: 11 KiB |
|
After Width: | Height: | Size: 14 KiB |
|
After Width: | Height: | Size: 15 KiB |
|
After Width: | Height: | Size: 22 KiB |
|
After Width: | Height: | Size: 71 KiB |
|
After Width: | Height: | Size: 114 KiB |
|
After Width: | Height: | Size: 5.4 KiB |
|
After Width: | Height: | Size: 8.1 KiB |
@@ -4,13 +4,13 @@
|
||||
<meta charset="UTF-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<link rel="stylesheet" href="style.css">
|
||||
<script src="https://cdn.jsdelivr.net/npm/jquery@3.6.0/dist/jquery.min.js"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
|
||||
<script>window.json = async fileName=>(await axios(`../data/${fileName}.json`)).data;</script>
|
||||
<title>Document</title>
|
||||
<meta name="description" content="やり直すんだ。そして、次はうまくやる。"/>
|
||||
<meta name="keywords" content="人生重开模拟器 liferestart life restart remake 人生重来"/>
|
||||
<link id="themeLink" rel="stylesheet" href="light.css">
|
||||
<link rel="manifest" href="./manifest.json">
|
||||
<title>Life Restart</title>
|
||||
</head>
|
||||
<body style="margin: 0; height: 100%">
|
||||
<body>
|
||||
<div class="banners-container">
|
||||
<div class="banners">
|
||||
<div class="banner error">
|
||||
@@ -30,18 +30,23 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<a href="https://github.com/VickScarlet/lifeRestart" class="github-corner" style="z-index: 9999;" aria-label="View source on GitHub"><svg width="80" height="80" viewBox="0 0 250 250" style="fill:#151513; color:#fff; position: absolute; top: 0; border: 0; left: 0; transform: scale(-1, 1);" aria-hidden="true"><path d="M0,0 L115,115 L130,115 L142,142 L250,250 L250,0 Z"></path><path d="M128.3,109.0 C113.8,99.7 119.0,89.6 119.0,89.6 C122.0,82.7 120.5,78.6 120.5,78.6 C119.2,72.0 123.4,76.3 123.4,76.3 C127.3,80.9 125.5,87.3 125.5,87.3 C122.9,97.6 130.6,101.9 134.4,103.2" fill="currentColor" style="transform-origin: 130px 106px;" class="octo-arm"></path><path d="M115.0,115.0 C114.9,115.1 118.7,116.5 119.8,115.4 L133.7,101.6 C136.9,99.2 139.9,98.4 142.2,98.6 C133.8,88.0 127.5,74.4 143.8,58.0 C148.5,53.4 154.0,51.2 159.7,51.0 C160.3,49.4 163.2,43.6 171.4,40.1 C171.4,40.1 176.1,42.5 178.8,56.2 C183.1,58.6 187.2,61.8 190.9,65.4 C194.5,69.0 197.7,73.2 200.1,77.6 C213.8,80.2 216.3,84.9 216.3,84.9 C212.7,93.1 206.9,96.0 205.4,96.6 C205.1,102.4 203.0,107.8 198.3,112.5 C181.9,128.9 168.3,122.5 157.7,114.1 C157.9,116.9 156.7,120.9 152.7,124.9 L141.0,136.5 C139.8,137.7 141.6,141.9 141.8,141.8 Z" fill="currentColor" class="octo-body"></path></svg><style>.github-corner:hover .octo-arm{animation:octocat-wave 560ms ease-in-out}@keyframes octocat-wave{0%,100%{transform:rotate(0)}20%,60%{transform:rotate(-25deg)}40%,80%{transform:rotate(10deg)}}@media (max-width:500px){.github-corner:hover .octo-arm{animation:none}.github-corner .octo-arm{animation:octocat-wave 560ms ease-in-out}}</style></a>
|
||||
|
||||
<script src="../lib/jquery-3.6.0.min.js"></script>
|
||||
<script src="../lib/dom-to-image.min.js"></script>
|
||||
<script src="../public/bundle.js"></script>
|
||||
<script>
|
||||
if ('serviceWorker' in navigator) {
|
||||
window.addEventListener('load', function () {
|
||||
navigator.serviceWorker.register('./sw.js', {scope: '.'})
|
||||
.then(function (registration) {
|
||||
console.log('ServiceWorker registration successful');
|
||||
})
|
||||
.catch(function (err) {
|
||||
console.log('ServiceWorker registration failed');
|
||||
});
|
||||
});
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
<script>
|
||||
// Pssst, I've created a github package - https://github.com/brookesb91/dismissible
|
||||
const hideBanners = (e) => {
|
||||
document
|
||||
.querySelectorAll(".banner.visible")
|
||||
.forEach((b) => b.classList.remove("visible"));
|
||||
};
|
||||
</script>
|
||||
<script type="module">
|
||||
import App from '../src/app.js';
|
||||
const app = new App();
|
||||
app.initial();
|
||||
</script>
|
||||
</html>
|
||||
@@ -0,0 +1,900 @@
|
||||
@media (min-width:640px){html{font-size:24px;}}
|
||||
@media (min-width:631px) and (max-width:639px){html{font-size:23.66px;}}
|
||||
@media (min-width:622px) and (max-width:630px){html{font-size:23.33px;}}
|
||||
@media (min-width:613px) and (max-width:621px){html{font-size:23px;}}
|
||||
@media (min-width:604px) and (max-width:612px){html{font-size:22.66px;}}
|
||||
@media (min-width:595px) and (max-width:603px){html{font-size:22.33px;}}
|
||||
@media (min-width:586px) and (max-width:594px){html{font-size:22px;}}
|
||||
@media (min-width:577px) and (max-width:585px){html{font-size:21.66px;}}
|
||||
@media (min-width:568px) and (max-width:576px){html{font-size:21.33px;}}
|
||||
@media (min-width:559px) and (max-width:567px){html{font-size:21px;}}
|
||||
@media (min-width:550px) and (max-width:558px){html{font-size:20.66px;}}
|
||||
@media (min-width:541px) and (max-width:549px){html{font-size:20.33px;}}
|
||||
@media (min-width:533px) and (max-width:540px){html{font-size:20px;}}
|
||||
@media (min-width:524px) and (max-width:532px){html{font-size:19.66px;}}
|
||||
@media (min-width:515px) and (max-width:523px){html{font-size:19.33px;}}
|
||||
@media (min-width:506px) and (max-width:514px){html{font-size:19px;}}
|
||||
@media (min-width:497px) and (max-width:505px){html{font-size:18.66px;}}
|
||||
@media (min-width:488px) and (max-width:496px){html{font-size:18.33px;}}
|
||||
@media (min-width:480px) and (max-width:487px){html{font-size:18px;}}
|
||||
@media (min-width:471px) and (max-width:479px){html{font-size:17.66px;}}
|
||||
@media (min-width:462px) and (max-width:470px){html{font-size:17.33px;}}
|
||||
@media (min-width:453px) and (max-width:461px){html{font-size:17px;}}
|
||||
@media (min-width:444px) and (max-width:452px){html{font-size:17.12px;}}
|
||||
@media (min-width:435px) and (max-width:443px){html{font-size:16.33px;}}
|
||||
@media (min-width:426px) and (max-width:434px){html{font-size:16px;}}
|
||||
@media (min-width:417px) and (max-width:425px){html{font-size:15.66px;}}
|
||||
@media (min-width:408px) and (max-width:416px){html{font-size:15.33px;}}
|
||||
@media (min-width:400px) and (max-width:407px){html{font-size:15px;}}
|
||||
@media (min-width:391px) and (max-width:399px){html{font-size:14.66px;}}
|
||||
@media (min-width:382px) and (max-width:390px){html{font-size:14.33px;}}
|
||||
@media (min-width:374px) and (max-width:381px){html{font-size:14px;}}
|
||||
@media (min-width:365px) and (max-width:373px){html{font-size:13.66px;}}
|
||||
@media (min-width:356px) and (max-width:364px){html{font-size:13.33px;}}
|
||||
@media (min-width:347px) and (max-width:355px){html{font-size:13px;}}
|
||||
@media (min-width:338px) and (max-width:346px){html{font-size:12.66px;}}
|
||||
@media (min-width:329px) and (max-width:337px){html{font-size:12.44px;}}
|
||||
@media (max-width:328px){html{font-size:12px;}}
|
||||
|
||||
@font-face {
|
||||
font-family: 'iconfont';
|
||||
src: url('iconfont.woff2?t=1628944689555') format('woff2'),
|
||||
url('iconfont.woff?t=1628944689555') format('woff'),
|
||||
url('iconfont.ttf?t=1628944689555') format('truetype');
|
||||
}
|
||||
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
input::-webkit-outer-spin-button,
|
||||
input::-webkit-inner-spin-button {
|
||||
-webkit-appearance: none;
|
||||
}
|
||||
input[type="number"]{
|
||||
-moz-appearance: textfield;
|
||||
}
|
||||
|
||||
html {
|
||||
font-family: PingFangSC, 'Noto Sans CJK SC', 'MS Yahei';
|
||||
}
|
||||
|
||||
body {
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
#main {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
width: 100%;
|
||||
max-width: 30rem;
|
||||
height: 100%;
|
||||
text-align: center;
|
||||
box-sizing: border-box;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
#title {
|
||||
position: fixed;
|
||||
font-size: 3rem;
|
||||
font-weight: 700;
|
||||
top: 35%;
|
||||
left: 50%;
|
||||
white-space: nowrap;
|
||||
transform: translate(-50%, -50%);
|
||||
color: #000;
|
||||
}
|
||||
|
||||
#restart {
|
||||
position: fixed;
|
||||
top: 65%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
}
|
||||
|
||||
#restart .iconfont {
|
||||
margin-right: 0.5rem;
|
||||
}
|
||||
|
||||
#next {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#talentSelectedView {
|
||||
flex: 0 1 auto;
|
||||
}
|
||||
|
||||
.mainbtn {
|
||||
margin: 0.5rem 1rem 1rem;
|
||||
padding: 0.5rem 1.5rem;
|
||||
background-color: #FFFFFF;
|
||||
border: 1px #CCCCCC solid;
|
||||
border-radius: 0.2rem;
|
||||
color: #000000;
|
||||
font-size: 1.6rem;
|
||||
white-space: nowrap;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.mainbtn:hover {
|
||||
background: #ff7878;
|
||||
color: #FFFFFF;
|
||||
transition: all .4s ease 0s;
|
||||
}
|
||||
|
||||
.btn-area {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.btn-area>.mainbtn {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.iconfont {
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
font-family: "iconfont" !important;
|
||||
font-style: normal;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
}
|
||||
|
||||
.sponsor,
|
||||
#rank,
|
||||
#specialthanks,
|
||||
#achievement {
|
||||
position: fixed;
|
||||
top: 4rem;
|
||||
right: 1rem;
|
||||
padding: 0.1rem;
|
||||
width: 6rem;
|
||||
border: none;
|
||||
border-radius: 0.2rem;
|
||||
background-color:lightsteelblue;
|
||||
font-size: 1.4rem;
|
||||
color: #EEEEEE;
|
||||
cursor: pointer;
|
||||
z-index:2;
|
||||
word-wrap: none;
|
||||
}
|
||||
|
||||
#specialthanks {
|
||||
background-color: #5865F2;
|
||||
top: 1rem;
|
||||
}
|
||||
|
||||
.sponsor {
|
||||
top: auto;
|
||||
bottom: 0;
|
||||
width: auto;
|
||||
padding: 0.5rem;
|
||||
}
|
||||
|
||||
#rank {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
right: 1.5rem;
|
||||
transform: translateY(-50%);
|
||||
}
|
||||
|
||||
#spthx {
|
||||
position: fixed;
|
||||
display: grid;
|
||||
top: 4rem;
|
||||
bottom: 5rem;
|
||||
left: 50%;
|
||||
width: 30rem;
|
||||
max-width: calc(100% - 2rem);
|
||||
transform: translateX(-50%);
|
||||
}
|
||||
|
||||
#spthx ul {
|
||||
list-style-type: none;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
#spthx ul li {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
#spthx ul.g1 {
|
||||
display: grid;
|
||||
max-block-size: 9rem;
|
||||
max-height: 9rem;
|
||||
overflow: scroll;
|
||||
}
|
||||
|
||||
#spthx ul.g1 li {
|
||||
display: inline-grid;
|
||||
background-color: orange;
|
||||
margin-bottom: 0.5rem;
|
||||
padding: 0.2rem 0;
|
||||
grid-template-columns: 7rem auto;
|
||||
}
|
||||
|
||||
#spthx ul.g1 li .name {
|
||||
padding: 0 0.5rem;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
#spthx ul.g1 li .comment {
|
||||
padding: 0 0.5rem;
|
||||
}
|
||||
|
||||
#spthx ul.g2 {
|
||||
display: grid;
|
||||
grid-template-columns: 50% 50%;
|
||||
overflow: scroll;
|
||||
}
|
||||
|
||||
#spthx ul.g2 li {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.title {
|
||||
position: relative;
|
||||
font-size: 1.5rem;
|
||||
font-weight: 700;
|
||||
padding: 1rem;
|
||||
}
|
||||
|
||||
ul#total,
|
||||
#achievements {
|
||||
list-style-type: none;
|
||||
display: grid;
|
||||
justify-items: center;
|
||||
grid-template-columns: 50% 50%;
|
||||
grid-auto-columns: max-content;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
ul#total li,
|
||||
#achievements li {
|
||||
position: relative;
|
||||
display: inline-grid;
|
||||
margin: 0.5rem;
|
||||
width: 12rem;
|
||||
height: 6rem;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
ul#total li .achievementtitle,
|
||||
#achievements li .achievementtitle{
|
||||
font-weight: 700;
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
|
||||
#achievements {
|
||||
overflow: scroll;
|
||||
}
|
||||
|
||||
#save,
|
||||
#load,
|
||||
#themeToggleBtn {
|
||||
padding: 0 0.7rem;
|
||||
width: 6.5rem;
|
||||
background-color:#222831;
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
font-size: 1.4rem;
|
||||
color: #EEEEEE;
|
||||
line-height: 2.5rem;
|
||||
text-align: center;
|
||||
vertical-align: middle;
|
||||
cursor: pointer;
|
||||
position: fixed;
|
||||
z-index:2;
|
||||
right: 0.5rem;
|
||||
bottom: 0.5rem;
|
||||
}
|
||||
|
||||
#save {
|
||||
background-color:#007046;
|
||||
color: white;
|
||||
bottom: 6.5rem;
|
||||
}
|
||||
#load {
|
||||
background-color: #fc5531;
|
||||
color: white;
|
||||
bottom: 3.5rem;
|
||||
}
|
||||
|
||||
.head {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
height: 5.2rem;
|
||||
font-size: 1.4rem;
|
||||
white-space: nowrap;
|
||||
color: #000;
|
||||
}
|
||||
|
||||
.propinitial,
|
||||
.selectlist {
|
||||
list-style: none;
|
||||
flex: 1;
|
||||
padding: 1rem;
|
||||
}
|
||||
|
||||
.lifeProperty {
|
||||
list-style: none;
|
||||
padding: 2rem 1rem 0.5rem 1rem;
|
||||
display: flex;
|
||||
color: #FFFFFF;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.lifeProperty>li {
|
||||
flex: 1;
|
||||
margin: 0.1rem 2px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
background-color: #8d8d8d;
|
||||
border: 1px #ccc solid;
|
||||
border-radius: 0.2rem;
|
||||
font-size: 1rem;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.lifeProperty>li>span:last-child {
|
||||
background: #fff;
|
||||
color: #000;
|
||||
}
|
||||
|
||||
.selectlist>li {
|
||||
margin-bottom: 0.6rem;
|
||||
display: block;
|
||||
border: 1px #EEEEEE solid;
|
||||
border-radius: 0.2rem;
|
||||
color: #666;
|
||||
font-size: 1.2rem;
|
||||
line-height: 1.6;
|
||||
user-select: none;
|
||||
position: relative;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.selectlist>li:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.propinitial {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.propbtn:hover {
|
||||
color: #5c5c5c;
|
||||
transition: all .2s ease 0s;
|
||||
}
|
||||
|
||||
.propinitial>li {
|
||||
position: relative;
|
||||
margin: 0.1rem auto;
|
||||
padding: 0.2rem;
|
||||
display: inline-block;
|
||||
border-radius: 0.2rem;
|
||||
color: #000;
|
||||
font-size: 1.6rem;
|
||||
line-height: 2;
|
||||
}
|
||||
|
||||
.propinitial>li>input {
|
||||
height: 2.2rem;
|
||||
width: 2.2rem;
|
||||
margin: 0 0.5rem;
|
||||
padding: 0;
|
||||
font-size: 2rem;
|
||||
border: 0.1rem #000 solid;
|
||||
background-color: #fff;
|
||||
color: #000;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.propbtn {
|
||||
position: relative;
|
||||
cursor: pointer;
|
||||
font-size: 2rem;
|
||||
color: #000;
|
||||
}
|
||||
|
||||
.judge>li>span:nth-child(1),
|
||||
.lifeTrajectory>li>span:nth-child(1) {
|
||||
width: 5rem;
|
||||
text-align: right;
|
||||
}
|
||||
.judge>li>span:nth-child(2),
|
||||
.lifeTrajectory>li>span:nth-child(2) {
|
||||
flex: 1;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.lifeTrajectory {
|
||||
flex: 1;
|
||||
margin: 0.5rem 1rem;
|
||||
padding: 0;
|
||||
border: 1px #9b9b9b solid;
|
||||
background-color: #fff;
|
||||
border-radius: 4px;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.lifeTrajectory>li {
|
||||
margin: 10px 0;
|
||||
padding: 5px 10px;
|
||||
display: flex;
|
||||
background-color: #fff;
|
||||
box-shadow: #b1b1b1 0 0 0.4rem;
|
||||
color: #1a1a1a;
|
||||
font-size: 1rem;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
|
||||
.judge {
|
||||
list-style: none;
|
||||
flex: 1;
|
||||
margin: 1rem;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
border: 1px solid #EEEEEE;
|
||||
border-radius: 4px;
|
||||
overflow: scroll;
|
||||
}
|
||||
|
||||
.judge>li {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
background-color: #6f6f6f;
|
||||
border-bottom: 1px solid #EEEEEE;
|
||||
box-shadow: none;
|
||||
color: #EEEEEE;
|
||||
}
|
||||
|
||||
.judge>li:last-child {
|
||||
border-bottom: 0
|
||||
}
|
||||
|
||||
.judge>li.grade1 span,
|
||||
.judge>li.grade1 {
|
||||
background-color: #87cefa;
|
||||
color: #4a5361;
|
||||
}
|
||||
|
||||
.judge>li.grade2 span,
|
||||
.judge>li.grade2 {
|
||||
background-color: #e7beff;
|
||||
color: #4a5361;
|
||||
}
|
||||
|
||||
.judge>li.grade3 span,
|
||||
.judge>li.grade3 {
|
||||
background-color: #f7a989;
|
||||
color: #4a5361;
|
||||
}
|
||||
|
||||
|
||||
@import url("https://fonts.googleapis.com/css?family=Montserrat:400,400i,700");
|
||||
|
||||
:root {
|
||||
font-family: "Montserrat";
|
||||
}
|
||||
|
||||
html,
|
||||
body {
|
||||
margin: 0;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
body {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
i {
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
.banners-container {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
z-index: 9;
|
||||
}
|
||||
|
||||
.banner {
|
||||
color: white;
|
||||
font-weight: 700;
|
||||
padding: 2rem;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.banner .banner-message {
|
||||
flex: 1;
|
||||
padding: 0 2rem;
|
||||
word-break: break-word;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.banner .banner-close {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 0.1rem;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
transition: background 0.3s;
|
||||
}
|
||||
|
||||
.banner .iconfont {
|
||||
font-size: 2rem;
|
||||
}
|
||||
|
||||
.banner .banner-close:hover {
|
||||
background: rgba(0, 0, 0, 0.12);
|
||||
}
|
||||
|
||||
.banner.success {
|
||||
background: lightgreen;
|
||||
}
|
||||
|
||||
.banner.success::after {
|
||||
background: lightgreen;
|
||||
}
|
||||
|
||||
.banner.error {
|
||||
background: #ed1c24;
|
||||
}
|
||||
|
||||
.banner.error::after {
|
||||
background: #ed1c24;
|
||||
}
|
||||
|
||||
.banner.info {
|
||||
background: skyblue;
|
||||
}
|
||||
|
||||
.banner.info::after {
|
||||
background: skyblue;
|
||||
}
|
||||
|
||||
.banner::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
height: 10%;
|
||||
width: 100%;
|
||||
bottom: 100%;
|
||||
left: 0;
|
||||
}
|
||||
|
||||
.banner:not(.visible) {
|
||||
display: none;
|
||||
transform: translateY(-100%);
|
||||
}
|
||||
|
||||
.banner.visible {
|
||||
box-shadow: 0 2px 2px 2px rgba(0, 0, 0, 0.12);
|
||||
animation-name: banner-in;
|
||||
animation-direction: forwards;
|
||||
animation-duration: 0.6s;
|
||||
animation-timing-function: ease-in-out;
|
||||
animation-fill-mode: forwards;
|
||||
animation-iteration-count: 1;
|
||||
}
|
||||
|
||||
.achvg0,
|
||||
.grade0b {
|
||||
background-color: #ededed;
|
||||
border: #c5c5c5 2px solid !important;
|
||||
}
|
||||
|
||||
.achvg1,
|
||||
.grade1b {
|
||||
background-color: #7ea5ec;
|
||||
border: #c5c5c5 2px solid !important;
|
||||
}
|
||||
|
||||
.achvg2,
|
||||
.grade2b {
|
||||
background-color: #e2a7ff;
|
||||
border: #c5c5c5 2px solid !important;
|
||||
}
|
||||
|
||||
.achvg3,
|
||||
.grade3b {
|
||||
background-color: #ffa07a;
|
||||
border: #c5c5c5 2px solid !important;
|
||||
}
|
||||
|
||||
.mask::before {
|
||||
display: block;
|
||||
content: " ";
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-color: #000;
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
@media (min-width:1080px) {
|
||||
.grade0b:hover {
|
||||
background-color: #868686;
|
||||
transition: all .3s ease 0s;
|
||||
}
|
||||
|
||||
.grade1b:hover {
|
||||
background-color: #5d90ff;
|
||||
color: #3b3b3b;
|
||||
transition: all .3s ease 0s;
|
||||
}
|
||||
|
||||
.grade2b:hover {
|
||||
background-color: #bc72ec;
|
||||
color: #3b3b3b;
|
||||
transition: all .3s ease 0s;
|
||||
}
|
||||
|
||||
.grade3b:hover {
|
||||
background-color: #e09074;
|
||||
color: #3b3b3b;
|
||||
transition: all .3s ease 0s;
|
||||
}
|
||||
}
|
||||
|
||||
.grade0b.selected,
|
||||
.grade1b.selected,
|
||||
.grade2b.selected,
|
||||
.grade3b.selected {
|
||||
box-shadow: #bbb 0px 0px 10px;
|
||||
color: #fff;
|
||||
overflow: hidden;
|
||||
}
|
||||
.grade0b.selected::after,
|
||||
.grade1b.selected::after,
|
||||
.grade2b.selected::after,
|
||||
.grade3b.selected::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
background-color:#000;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
box-shadow: 0 0 10px #000;
|
||||
opacity: 0;
|
||||
animation: blink 3s linear infinite;
|
||||
}
|
||||
|
||||
@keyframes blink {
|
||||
0% {
|
||||
opacity: 0;
|
||||
transform: translateX(-150%);
|
||||
}
|
||||
50% {
|
||||
opacity: .2;
|
||||
}
|
||||
100% {
|
||||
opacity: 0;
|
||||
transform: translateX(150%);
|
||||
}
|
||||
}
|
||||
|
||||
.grade0b.selected {
|
||||
background-color: #444 !important;
|
||||
}
|
||||
|
||||
.grade1b.selected {
|
||||
background-color: #407dec !important;
|
||||
}
|
||||
|
||||
.grade2b.selected {
|
||||
background-color: #b362e7 !important;
|
||||
}
|
||||
|
||||
.grade3b.selected {
|
||||
background-color: #ff7f4d !important;
|
||||
}
|
||||
|
||||
@keyframes banner-in {
|
||||
0% {
|
||||
transform: translateY(-100%);
|
||||
}
|
||||
|
||||
50% {
|
||||
transform: translateY(10%);
|
||||
}
|
||||
|
||||
100% {
|
||||
transform: translateY(0);
|
||||
}
|
||||
}
|
||||
|
||||
.show-banner {
|
||||
appearance: none;
|
||||
background: #ededed;
|
||||
border: 0;
|
||||
padding: 1rem 2rem;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
text-transform: uppercase;
|
||||
margin: 0.25rem;
|
||||
}
|
||||
|
||||
/**
|
||||
* @license
|
||||
* Copyright Akveo. All Rights Reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*/
|
||||
.eva-animation {
|
||||
animation-duration: 1s;
|
||||
animation-fill-mode: both;
|
||||
}
|
||||
|
||||
.eva-infinite {
|
||||
animation-iteration-count: infinite;
|
||||
}
|
||||
|
||||
.eva-icon-shake {
|
||||
animation-name: eva-shake;
|
||||
}
|
||||
|
||||
.eva-icon-zoom {
|
||||
animation-name: eva-zoomIn;
|
||||
}
|
||||
|
||||
.eva-icon-pulse {
|
||||
animation-name: eva-pulse;
|
||||
}
|
||||
|
||||
.eva-icon-flip {
|
||||
animation-name: eva-flipInY;
|
||||
}
|
||||
|
||||
.eva-hover {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.eva-hover:hover .eva-icon-hover-shake,
|
||||
.eva-parent-hover:hover .eva-icon-hover-shake {
|
||||
animation-name: eva-shake;
|
||||
}
|
||||
|
||||
.eva-hover:hover .eva-icon-hover-zoom,
|
||||
.eva-parent-hover:hover .eva-icon-hover-zoom {
|
||||
animation-name: eva-zoomIn;
|
||||
}
|
||||
|
||||
.eva-hover:hover .eva-icon-hover-pulse,
|
||||
.eva-parent-hover:hover .eva-icon-hover-pulse {
|
||||
animation-name: eva-pulse;
|
||||
}
|
||||
|
||||
.eva-hover:hover .eva-icon-hover-flip,
|
||||
.eva-parent-hover:hover .eva-icon-hover-flip {
|
||||
animation-name: eva-flipInY;
|
||||
}
|
||||
|
||||
@keyframes eva-flipInY {
|
||||
from {
|
||||
transform: perspective(400px) rotate3d(0, 1, 0, 90deg);
|
||||
animation-timing-function: ease-in;
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
40% {
|
||||
transform: perspective(400px) rotate3d(0, 1, 0, -20deg);
|
||||
animation-timing-function: ease-in;
|
||||
}
|
||||
|
||||
60% {
|
||||
transform: perspective(400px) rotate3d(0, 1, 0, 10deg);
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
80% {
|
||||
transform: perspective(400px) rotate3d(0, 1, 0, -5deg);
|
||||
}
|
||||
|
||||
to {
|
||||
transform: perspective(400px);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes eva-shake {
|
||||
|
||||
from,
|
||||
to {
|
||||
transform: translate3d(0, 0, 0);
|
||||
}
|
||||
|
||||
10%,
|
||||
30%,
|
||||
50%,
|
||||
70%,
|
||||
90% {
|
||||
transform: translate3d(-3px, 0, 0);
|
||||
}
|
||||
|
||||
20%,
|
||||
40%,
|
||||
60%,
|
||||
80% {
|
||||
transform: translate3d(3px, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes eva-pulse {
|
||||
from {
|
||||
transform: scale3d(1, 1, 1);
|
||||
}
|
||||
|
||||
50% {
|
||||
transform: scale3d(1.2, 1.2, 1.2);
|
||||
}
|
||||
|
||||
to {
|
||||
transform: scale3d(1, 1, 1);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes eva-zoomIn {
|
||||
from {
|
||||
opacity: 1;
|
||||
transform: scale3d(0.5, 0.5, 0.5);
|
||||
}
|
||||
|
||||
50% {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
::-webkit-scrollbar {
|
||||
width: 0 !important
|
||||
}
|
||||
|
||||
.deleteFixed {
|
||||
margin: 0;
|
||||
padding: 0.5rem 1rem;
|
||||
border: 0;
|
||||
border-radius: 0;
|
||||
overflow: visible;
|
||||
}
|
||||
|
||||
.operateBtn {
|
||||
padding: 0.5rem 1.5rem;
|
||||
border: 1px #EEEEEE solid;
|
||||
border-radius: 0.2rem;
|
||||
background-color:#393E46;
|
||||
font-size: 1.6rem;
|
||||
white-space: nowrap;
|
||||
transform: translate(-50%,-50%);
|
||||
cursor: pointer;
|
||||
z-index:2;
|
||||
color: #EEEEEE;
|
||||
}
|
||||
|
||||
.operateBtn:hover {
|
||||
background: #ff7878;
|
||||
color: #fff;
|
||||
transition: all .4s ease 0s;
|
||||
}
|
||||
|
||||
.domToImage2wx {
|
||||
position: fixed;
|
||||
z-index: 1111;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.domToImage2wx img {
|
||||
width: 100%;
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
{
|
||||
"icons": [
|
||||
{
|
||||
"src": "./images/icons/icon-72x72.png",
|
||||
"sizes": "72x72",
|
||||
"type": "image/png"
|
||||
},
|
||||
{
|
||||
"src": "./images/icons/icon-96x96.png",
|
||||
"sizes": "96x96",
|
||||
"type": "image/png"
|
||||
},
|
||||
{
|
||||
"src": "./images/icons/icon-128x128.png",
|
||||
"sizes": "128x128",
|
||||
"type": "image/png"
|
||||
},
|
||||
{
|
||||
"src": "./images/icons/icon-144x144.png",
|
||||
"sizes": "144x144",
|
||||
"type": "image/png"
|
||||
},
|
||||
{
|
||||
"src": "./images/icons/icon-152x152.png",
|
||||
"sizes": "152x152",
|
||||
"type": "image/png"
|
||||
},
|
||||
{
|
||||
"src": "./images/icons/icon-192x192.png",
|
||||
"sizes": "192x192",
|
||||
"type": "image/png"
|
||||
},
|
||||
{
|
||||
"src": "./images/icons/icon-384x384.png",
|
||||
"sizes": "384x384",
|
||||
"type": "image/png"
|
||||
},
|
||||
{
|
||||
"src": "./images/icons/icon-512x512.png",
|
||||
"sizes": "512x512",
|
||||
"type": "image/png"
|
||||
}
|
||||
],
|
||||
"name": "人生重开模拟器",
|
||||
"short_name": "LifeRestart",
|
||||
"orientation": "portrait",
|
||||
"display": "standalone",
|
||||
"start_url": "/view/index.html",
|
||||
"description": "人生重开模拟器",
|
||||
"background_color": "#ffffff"
|
||||
}
|
||||
@@ -1,457 +0,0 @@
|
||||
@media (min-width:640px){html{font-size:24px;}}
|
||||
@media (min-width:631px) and (max-width:639px){html{font-size:23.66px;}}
|
||||
@media (min-width:622px) and (max-width:630px){html{font-size:23.33px;}}
|
||||
@media (min-width:613px) and (max-width:621px){html{font-size:23px;}}
|
||||
@media (min-width:604px) and (max-width:612px){html{font-size:22.66px;}}
|
||||
@media (min-width:595px) and (max-width:603px){html{font-size:22.33px;}}
|
||||
@media (min-width:586px) and (max-width:594px){html{font-size:22px;}}
|
||||
@media (min-width:577px) and (max-width:585px){html{font-size:21.66px;}}
|
||||
@media (min-width:568px) and (max-width:576px){html{font-size:21.33px;}}
|
||||
@media (min-width:559px) and (max-width:567px){html{font-size:21px;}}
|
||||
@media (min-width:550px) and (max-width:558px){html{font-size:20.66px;}}
|
||||
@media (min-width:541px) and (max-width:549px){html{font-size:20.33px;}}
|
||||
@media (min-width:533px) and (max-width:540px){html{font-size:20px;}}
|
||||
@media (min-width:524px) and (max-width:532px){html{font-size:19.66px;}}
|
||||
@media (min-width:515px) and (max-width:523px){html{font-size:19.33px;}}
|
||||
@media (min-width:506px) and (max-width:514px){html{font-size:19px;}}
|
||||
@media (min-width:497px) and (max-width:505px){html{font-size:18.66px;}}
|
||||
@media (min-width:488px) and (max-width:496px){html{font-size:18.33px;}}
|
||||
@media (min-width:480px) and (max-width:487px){html{font-size:18px;}}
|
||||
@media (min-width:471px) and (max-width:479px){html{font-size:17.66px;}}
|
||||
@media (min-width:462px) and (max-width:470px){html{font-size:17.33px;}}
|
||||
@media (min-width:453px) and (max-width:461px){html{font-size:17px;}}
|
||||
@media (min-width:444px) and (max-width:452px){html{font-size:17.12px;}}
|
||||
@media (min-width:435px) and (max-width:443px){html{font-size:16.33px;}}
|
||||
@media (min-width:426px) and (max-width:434px){html{font-size:16px;}}
|
||||
@media (min-width:417px) and (max-width:425px){html{font-size:15.66px;}}
|
||||
@media (min-width:408px) and (max-width:416px){html{font-size:15.33px;}}
|
||||
@media (min-width:400px) and (max-width:407px){html{font-size:15px;}}
|
||||
@media (min-width:391px) and (max-width:399px){html{font-size:14.66px;}}
|
||||
@media (min-width:382px) and (max-width:390px){html{font-size:14.33px;}}
|
||||
@media (min-width:374px) and (max-width:381px){html{font-size:14px;}}
|
||||
@media (min-width:365px) and (max-width:373px){html{font-size:13.66px;}}
|
||||
@media (min-width:356px) and (max-width:364px){html{font-size:13.33px;}}
|
||||
@media (min-width:347px) and (max-width:355px){html{font-size:13px;}}
|
||||
@media (min-width:338px) and (max-width:346px){html{font-size:12.66px;}}
|
||||
@media (min-width:329px) and (max-width:337px){html{font-size:12.44px;}}
|
||||
@media (max-width:328px){html{font-size:12px;}}
|
||||
|
||||
@font-face {
|
||||
font-family: 'iconfont';
|
||||
src: url('iconfont.woff2?t=1628944689555') format('woff2'),
|
||||
url('iconfont.woff?t=1628944689555') format('woff'),
|
||||
url('iconfont.ttf?t=1628944689555') format('truetype');
|
||||
}
|
||||
|
||||
html {
|
||||
font-family: PingFangSC, 'Noto Sans CJK SC', 'MS Yahei';
|
||||
}
|
||||
|
||||
#main {
|
||||
align-content: center;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
#title {
|
||||
position: fixed;
|
||||
font-size: 3rem;
|
||||
font-weight: 700;
|
||||
top: 35%;
|
||||
left: 50%;
|
||||
white-space: nowrap;
|
||||
transform: translate(-50%,-50%);
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.mainbtn {
|
||||
position: fixed;
|
||||
top: 65%;
|
||||
left: 50%;
|
||||
padding: 0.8rem 1rem;
|
||||
border: 1px #ccc solid;
|
||||
border-radius: 0.2rem;
|
||||
background-color:white;
|
||||
font-size: 1.6rem;
|
||||
white-space: nowrap;
|
||||
transform: translate(-50%,-50%);
|
||||
cursor: pointer;
|
||||
z-index:2;
|
||||
}
|
||||
|
||||
.iconfont {
|
||||
font-family: "iconfont" !important;
|
||||
font-style: normal;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
}
|
||||
|
||||
#rank {
|
||||
position: fixed;
|
||||
top: 1rem;
|
||||
right: 1rem;
|
||||
padding: 0.1rem 1rem;
|
||||
border: none;
|
||||
border-radius: 0.2rem;
|
||||
background-color:lightsteelblue;
|
||||
font-size: 1.4rem;
|
||||
color: white;
|
||||
cursor: pointer;
|
||||
z-index:2;
|
||||
}
|
||||
|
||||
.head {
|
||||
position: fixed;
|
||||
font-size: 1.4rem;
|
||||
top: 1.1rem;
|
||||
left: 50%;
|
||||
white-space: nowrap;
|
||||
transform: translateX(-50%);
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.judge,
|
||||
.lifeTrajectory,
|
||||
.propinitial,
|
||||
.selectlist {
|
||||
position: fixed;
|
||||
list-style-type: none;
|
||||
left: 50%;
|
||||
top: 5rem;
|
||||
bottom: 8.5rem;
|
||||
width: 30rem;
|
||||
max-width: calc(100% - 2rem);
|
||||
margin: auto;
|
||||
padding: 0;
|
||||
overflow: auto;
|
||||
transform: translateX(-50%);
|
||||
}
|
||||
|
||||
.selectlist > li {
|
||||
position: relative;
|
||||
border: 1px #ccc solid;
|
||||
display: inline-block;
|
||||
width: 95%;
|
||||
margin: 0.1rem auto;
|
||||
font-size: 1.4rem;
|
||||
text-align: center;
|
||||
border-radius: 0.2rem;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.selectlist > li::before {
|
||||
position: absolute;
|
||||
display: inline-block;
|
||||
left: 0;
|
||||
top: 0;
|
||||
border-radius: 0.2rem 0 0 0.2rem;
|
||||
margin: -1px;
|
||||
padding: 1px;
|
||||
height: 100%;
|
||||
width: 1.5rem;
|
||||
content: " ";
|
||||
}
|
||||
|
||||
.grade1,
|
||||
.grade1b::before {
|
||||
background-color: rgb(116, 191, 255) !important;
|
||||
}
|
||||
|
||||
.grade2,
|
||||
.grade2b::before {
|
||||
background-color: rgb(226, 167, 255) !important;
|
||||
}
|
||||
|
||||
.grade3,
|
||||
.grade3b::before {
|
||||
background-color: lightsalmon !important;
|
||||
}
|
||||
|
||||
.selected {
|
||||
background-color: gray;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.propinitial {
|
||||
top: 6rem;
|
||||
bottom: 14rem;
|
||||
}
|
||||
|
||||
.propinitial > li {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
width: 95%;
|
||||
margin: 0.1rem auto;
|
||||
font-size: 1.4rem;
|
||||
text-align: center;
|
||||
border-radius: 0.2rem;
|
||||
padding: 0.2rem;
|
||||
}
|
||||
|
||||
.propinitial > li > input {
|
||||
height: 2.2rem;
|
||||
width: 2.2rem;
|
||||
margin: 0 0.5rem;
|
||||
padding: 0;
|
||||
text-align: center;
|
||||
font-size: 2rem;
|
||||
border: 0.1rem #ccc solid;
|
||||
}
|
||||
|
||||
.propbtn {
|
||||
position: relative;
|
||||
cursor: pointer;
|
||||
font-size: 2rem;
|
||||
}
|
||||
|
||||
.lifeTrajectory {
|
||||
border: 1px lightblue solid;
|
||||
background-color: aliceblue;
|
||||
}
|
||||
|
||||
.judge > li,
|
||||
.lifeTrajectory > li {
|
||||
position: relative;
|
||||
width: calc(100% - 7rem);
|
||||
margin: 0.5rem 0;
|
||||
padding: 0.5rem 1rem 0.5rem 6rem;
|
||||
font-size: 1.4rem;
|
||||
background-color: white;
|
||||
box-shadow: lightblue 0 0 0.4rem;
|
||||
}
|
||||
|
||||
.judge > li > span,
|
||||
.lifeTrajectory > li > span {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
width: 6rem;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.judge > li {
|
||||
box-shadow: lightgray 0 0 0.4rem;
|
||||
width: calc(100% - 9rem);
|
||||
margin: 0.5rem;
|
||||
padding: 0.5rem 1rem 0.5rem 7rem;
|
||||
}
|
||||
|
||||
.judge > li > span {
|
||||
background-color: white;
|
||||
height: calc(100% - 1rem);
|
||||
padding: 0.5rem 0;
|
||||
top: 0;
|
||||
}
|
||||
|
||||
|
||||
@import url("https://fonts.googleapis.com/css?family=Montserrat:400,400i,700");
|
||||
:root {
|
||||
font-family: "Montserrat";
|
||||
}
|
||||
|
||||
html,
|
||||
body {
|
||||
margin: 0;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
body {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
i {
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
.banners-container {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
z-index: 9;
|
||||
}
|
||||
|
||||
.banner {
|
||||
color: white;
|
||||
font-weight: 700;
|
||||
padding: 2rem;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
}
|
||||
.banner .banner-message {
|
||||
flex: 1;
|
||||
padding: 0 2rem;
|
||||
word-break: break-word;
|
||||
overflow: auto;
|
||||
}
|
||||
.banner .banner-close {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 0.1rem;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
transition: background 0.3s;
|
||||
}
|
||||
|
||||
.banner .iconfont {
|
||||
font-size: 2rem;
|
||||
}
|
||||
|
||||
.banner .banner-close:hover {
|
||||
background: rgba(0, 0, 0, 0.12);
|
||||
}
|
||||
|
||||
.banner.success {
|
||||
background: lightgreen;
|
||||
}
|
||||
.banner.success::after {
|
||||
background: lightgreen;
|
||||
}
|
||||
.banner.error {
|
||||
background: #ed1c24;
|
||||
}
|
||||
.banner.error::after {
|
||||
background: #ed1c24;
|
||||
}
|
||||
.banner.info {
|
||||
background: skyblue;
|
||||
}
|
||||
.banner.info::after {
|
||||
background: skyblue;
|
||||
}
|
||||
|
||||
.banner::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
height: 10%;
|
||||
width: 100%;
|
||||
bottom: 100%;
|
||||
left: 0;
|
||||
}
|
||||
|
||||
.banner:not(.visible) {
|
||||
display: none;
|
||||
transform: translateY(-100%);
|
||||
}
|
||||
|
||||
.banner.visible {
|
||||
box-shadow: 0 2px 2px 2px rgba(0, 0, 0, 0.12);
|
||||
animation-name: banner-in;
|
||||
animation-direction: forwards;
|
||||
animation-duration: 0.6s;
|
||||
animation-timing-function: ease-in-out;
|
||||
animation-fill-mode: forwards;
|
||||
animation-iteration-count: 1;
|
||||
}
|
||||
|
||||
@keyframes banner-in {
|
||||
0% {
|
||||
transform: translateY(-100%);
|
||||
}
|
||||
50% {
|
||||
transform: translateY(10%);
|
||||
}
|
||||
100% {
|
||||
transform: translateY(0);
|
||||
}
|
||||
}
|
||||
.show-banner {
|
||||
appearance: none;
|
||||
background: #ededed;
|
||||
border: 0;
|
||||
padding: 1rem 2rem;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
text-transform: uppercase;
|
||||
margin: 0.25rem;
|
||||
}
|
||||
|
||||
/**
|
||||
* @license
|
||||
* Copyright Akveo. All Rights Reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*/
|
||||
.eva-animation {
|
||||
animation-duration: 1s;
|
||||
animation-fill-mode: both; }
|
||||
|
||||
.eva-infinite {
|
||||
animation-iteration-count: infinite; }
|
||||
|
||||
.eva-icon-shake {
|
||||
animation-name: eva-shake; }
|
||||
|
||||
.eva-icon-zoom {
|
||||
animation-name: eva-zoomIn; }
|
||||
|
||||
.eva-icon-pulse {
|
||||
animation-name: eva-pulse; }
|
||||
|
||||
.eva-icon-flip {
|
||||
animation-name: eva-flipInY; }
|
||||
|
||||
.eva-hover {
|
||||
display: inline-block; }
|
||||
|
||||
.eva-hover:hover .eva-icon-hover-shake, .eva-parent-hover:hover .eva-icon-hover-shake {
|
||||
animation-name: eva-shake; }
|
||||
|
||||
.eva-hover:hover .eva-icon-hover-zoom, .eva-parent-hover:hover .eva-icon-hover-zoom {
|
||||
animation-name: eva-zoomIn; }
|
||||
|
||||
.eva-hover:hover .eva-icon-hover-pulse, .eva-parent-hover:hover .eva-icon-hover-pulse {
|
||||
animation-name: eva-pulse; }
|
||||
|
||||
.eva-hover:hover .eva-icon-hover-flip, .eva-parent-hover:hover .eva-icon-hover-flip {
|
||||
animation-name: eva-flipInY; }
|
||||
|
||||
@keyframes eva-flipInY {
|
||||
from {
|
||||
transform: perspective(400px) rotate3d(0, 1, 0, 90deg);
|
||||
animation-timing-function: ease-in;
|
||||
opacity: 0; }
|
||||
40% {
|
||||
transform: perspective(400px) rotate3d(0, 1, 0, -20deg);
|
||||
animation-timing-function: ease-in; }
|
||||
60% {
|
||||
transform: perspective(400px) rotate3d(0, 1, 0, 10deg);
|
||||
opacity: 1; }
|
||||
80% {
|
||||
transform: perspective(400px) rotate3d(0, 1, 0, -5deg); }
|
||||
to {
|
||||
transform: perspective(400px); } }
|
||||
|
||||
@keyframes eva-shake {
|
||||
from,
|
||||
to {
|
||||
transform: translate3d(0, 0, 0); }
|
||||
10%,
|
||||
30%,
|
||||
50%,
|
||||
70%,
|
||||
90% {
|
||||
transform: translate3d(-3px, 0, 0); }
|
||||
20%,
|
||||
40%,
|
||||
60%,
|
||||
80% {
|
||||
transform: translate3d(3px, 0, 0); } }
|
||||
|
||||
@keyframes eva-pulse {
|
||||
from {
|
||||
transform: scale3d(1, 1, 1); }
|
||||
50% {
|
||||
transform: scale3d(1.2, 1.2, 1.2); }
|
||||
to {
|
||||
transform: scale3d(1, 1, 1); } }
|
||||
|
||||
@keyframes eva-zoomIn {
|
||||
from {
|
||||
opacity: 1;
|
||||
transform: scale3d(0.5, 0.5, 0.5); }
|
||||
50% {
|
||||
opacity: 1; } }
|
||||
@@ -0,0 +1,27 @@
|
||||
var CACHE_VERSION = 'sw_v1';
|
||||
|
||||
var CACHE_FILES = [
|
||||
'/',
|
||||
];
|
||||
|
||||
self.addEventListener('install', function (event) {
|
||||
event.waitUntil(
|
||||
caches.open(CACHE_VERSION)
|
||||
.then(cache => cache.addAll(CACHE_FILES)
|
||||
.then(() => self.skipWaiting())
|
||||
));
|
||||
});
|
||||
|
||||
self.addEventListener('activate', function (event) {
|
||||
event.waitUntil(
|
||||
caches.keys().then(function (keys) {
|
||||
return Promise.all(keys.map(function (key, i) {
|
||||
if (key !== CACHE_VERSION) {
|
||||
return caches.delete(keys[i]);
|
||||
}
|
||||
}));
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
self.addEventListener('fetch', function(event) {});
|
||||
@@ -4,36 +4,34 @@
|
||||
<meta charset="UTF-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<link rel="stylesheet" href="style.css">
|
||||
<script src="https://cdn.jsdelivr.net/npm/jquery@3.6.0/dist/jquery.min.js"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
|
||||
<script>window.json = async fileName=>(await axios(`../data/${fileName}.json`)).data;</script>
|
||||
<title>Document</title>
|
||||
<meta name="description" content="やり直すんだ。そして、次はうまくやる。"/>
|
||||
<meta name="keywords" content="人生重开模拟器 liferestart life restart remake 人生重来"/>
|
||||
<link id="themeLink" rel="stylesheet" href="light.css">
|
||||
<script src="../lib/jquery-3.6.0.min.js"></script>
|
||||
<script src="../lib/dom-to-image.min.js"></script>
|
||||
<script type="module" src="../src/index.js"></script>
|
||||
<title>Life Restart</title>
|
||||
</head>
|
||||
<body style="margin: 0; height: 100%">
|
||||
<div id="main">
|
||||
<div class="head">人生总结</div>
|
||||
<ul id="judge" class="judge" style="bottom: calc(35% + 2.5rem)">
|
||||
<li class="grade2"><span>颜值:</span>9级 美若天仙</li>
|
||||
<li><span>智力:</span>4级 智力一般</li>
|
||||
<li><span>体质:</span>1级 极度虚弱</li>
|
||||
<li><span>家境:</span>6级 小康之家</li>
|
||||
<li><span>享年:</span>3岁 早夭</li>
|
||||
<li><span>快乐:</span>3级 不太幸福的人生</li>
|
||||
<li><span>快乐:</span>3级 不太幸福的人生</li>
|
||||
<li><span>快乐:</span>3级 不太幸福的人生</li>
|
||||
<li><span>快乐:</span>3级 不太幸福的人生</li>
|
||||
<li><span>快乐:</span>3级 不太幸福的人生</li>
|
||||
<li><span>快乐:</span>3级 不太幸福的人生</li>
|
||||
<li><span>快乐:</span>3级 不太幸福的人生</li>
|
||||
<li><span>快乐:</span>3级 不太幸福的人生</li>
|
||||
<li><span>快乐:</span>3级 不太幸福的人生</li>
|
||||
</ul>
|
||||
<div class="head" style="top:auto; bottom:35%">天赋,你可以选一个,下辈子还能抽到</div>
|
||||
<ul id="talents" class="selectlist" style="top:calc(65% + 0.5rem); bottom:8rem">
|
||||
<li class="grade2b">黑幕(面试一定成功)</li>
|
||||
</ul>
|
||||
<button id="again" class="mainbtn" style="top:auto; bottom:0.1em"><span class="iconfont"></span>再次重开</button>
|
||||
<div class="banners-container">
|
||||
<div class="banners">
|
||||
<div class="banner error">
|
||||
<div class="banner-icon"><span class="iconfont"></span></div>
|
||||
<pre class="banner-message">Oops! Something went wrong!</pre>
|
||||
<div class="banner-close" onclick="hideBanners()"><span class="iconfont"></span></div>
|
||||
</div>
|
||||
<div class="banner success">
|
||||
<div class="banner-icon"><span class="iconfont"></span></div>
|
||||
<pre class="banner-message">Everything was fine!</pre>
|
||||
<div class="banner-close" onclick="hideBanners()"><span class="iconfont"></span></div>
|
||||
</div>
|
||||
<div class="banner info">
|
||||
<div class="banner-icon"><span class="iconfont"></span></div>
|
||||
<pre class="banner-message">Here is some useful information</pre>
|
||||
<div class="banner-close" onclick="hideBanners()"><span class="iconfont"></span></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<a href="https://github.com/VickScarlet/lifeRestart" class="github-corner" style="z-index: 9999;" aria-label="View source on GitHub"><svg width="80" height="80" viewBox="0 0 250 250" style="fill:#151513; color:#fff; position: absolute; top: 0; border: 0; left: 0; transform: scale(-1, 1);" aria-hidden="true"><path d="M0,0 L115,115 L130,115 L142,142 L250,250 L250,0 Z"></path><path d="M128.3,109.0 C113.8,99.7 119.0,89.6 119.0,89.6 C122.0,82.7 120.5,78.6 120.5,78.6 C119.2,72.0 123.4,76.3 123.4,76.3 C127.3,80.9 125.5,87.3 125.5,87.3 C122.9,97.6 130.6,101.9 134.4,103.2" fill="currentColor" style="transform-origin: 130px 106px;" class="octo-arm"></path><path d="M115.0,115.0 C114.9,115.1 118.7,116.5 119.8,115.4 L133.7,101.6 C136.9,99.2 139.9,98.4 142.2,98.6 C133.8,88.0 127.5,74.4 143.8,58.0 C148.5,53.4 154.0,51.2 159.7,51.0 C160.3,49.4 163.2,43.6 171.4,40.1 C171.4,40.1 176.1,42.5 178.8,56.2 C183.1,58.6 187.2,61.8 190.9,65.4 C194.5,69.0 197.7,73.2 200.1,77.6 C213.8,80.2 216.3,84.9 216.3,84.9 C212.7,93.1 206.9,96.0 205.4,96.6 C205.1,102.4 203.0,107.8 198.3,112.5 C181.9,128.9 168.3,122.5 157.7,114.1 C157.9,116.9 156.7,120.9 152.7,124.9 L141.0,136.5 C139.8,137.7 141.6,141.9 141.8,141.8 Z" fill="currentColor" class="octo-body"></path></svg><style>.github-corner:hover .octo-arm{animation:octocat-wave 560ms ease-in-out}@keyframes octocat-wave{0%,100%{transform:rotate(0)}20%,60%{transform:rotate(-25deg)}40%,80%{transform:rotate(10deg)}}@media (max-width:500px){.github-corner:hover .octo-arm{animation:none}.github-corner .octo-arm{animation:octocat-wave 560ms ease-in-out}}</style></a>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,60 @@
|
||||
const path = require('path');
|
||||
|
||||
module.exports = {
|
||||
mode: 'production',
|
||||
entry: './src/index.js',
|
||||
devtool: 'eval-cheap-module-source-map',
|
||||
devServer: {
|
||||
static: [
|
||||
{
|
||||
directory: path.join(__dirname, 'data'),
|
||||
publicPath: '/data',
|
||||
},
|
||||
{
|
||||
directory: path.join(__dirname, 'public'),
|
||||
publicPath: '/public',
|
||||
},
|
||||
{
|
||||
directory: path.join(__dirname, 'view'),
|
||||
publicPath: '/view',
|
||||
},
|
||||
{
|
||||
directory: path.join(__dirname, 'src'),
|
||||
publicPath: '/src',
|
||||
},
|
||||
{
|
||||
directory: path.join(__dirname, 'lib'),
|
||||
publicPath: '/lib',
|
||||
}
|
||||
],
|
||||
},
|
||||
output: {
|
||||
path: path.resolve(__dirname, 'public'),
|
||||
filename: 'bundle.js',
|
||||
clean: true,
|
||||
},
|
||||
// resolve: {
|
||||
// extensions: ['.js'],
|
||||
// },
|
||||
module: {
|
||||
rules: [{
|
||||
test: /\.js$/,
|
||||
exclude: /node_modules/,
|
||||
use: {
|
||||
loader: 'babel-loader',
|
||||
options: {
|
||||
presets: [
|
||||
[
|
||||
'@babel/preset-env',
|
||||
{
|
||||
"targets": "> 0.25%, not dead",
|
||||
"useBuiltIns": "usage",
|
||||
"corejs": "3.8.3",
|
||||
}
|
||||
]
|
||||
]
|
||||
}
|
||||
}
|
||||
}]
|
||||
}
|
||||
};
|
||||