├── .github ├── ISSUE_TEMPLATE │ ├── bug反馈.md │ ├── 功能请求.md │ ├── 反馈建议.md │ └── 文档改进.md └── workflows │ └── xiuxian-game.yml ├── .gitignore ├── Dockerfile ├── LICENSE ├── README.md ├── dev-dist ├── registerSW.js ├── sw.js ├── workbox-5199072c.js ├── workbox-86c9b217.js └── workbox-b5f7729d.js ├── docs ├── CNAME ├── assets │ ├── css │ │ ├── index-BZBS9mDs.css │ │ ├── index-PRxJplS_.css │ │ └── vendor-modules-D2BJWH85.css │ ├── js │ │ ├── index-BuMI15Hl.js │ │ ├── index-FRf3Tfz5.js │ │ └── vendor-modules-BL2bTueU.js │ └── svg │ │ ├── cloth-ChmXEApe.svg │ │ ├── fist-CaMjbPZE.svg │ │ └── scissors-BKSjQyjM.svg ├── favicon.ico ├── icons │ ├── icon-192x192.png │ └── icon-512x512.png ├── index.html ├── manifest.webmanifest ├── registerSW.js ├── sw.js └── workbox-3e8df8c8.js ├── index.html ├── package-lock.json ├── package.json ├── public ├── CNAME ├── favicon.ico └── icons │ ├── icon-192x192.png │ └── icon-512x512.png ├── src ├── App.vue ├── assets │ ├── CaretTop.svg │ ├── caretBottom.svg │ ├── cloth.svg │ ├── dice1.svg │ ├── dice2.svg │ ├── dice3.svg │ ├── dice4.svg │ ├── dice5.svg │ ├── dice6.svg │ ├── fist.svg │ ├── scissors.svg │ ├── wm_bg_1.png │ └── wm_bg_2.png ├── auto-imports.d.ts ├── components.d.ts ├── components │ ├── equipTooltip.vue │ └── tag.vue ├── main.js ├── plugins │ ├── achievement.js │ ├── achievementChecker.js │ ├── boss.js │ ├── combat.js │ ├── crypto.js │ ├── equip.js │ ├── equipAll.js │ ├── game.js │ ├── minheap.js │ ├── monster.js │ ├── npc.js │ ├── router.js │ ├── shop.js │ └── store.js └── views │ ├── bossPage.vue │ ├── cultivatePage.vue │ ├── endlessPage.vue │ ├── explorePage.vue │ ├── game │ ├── Dicegame.vue │ ├── SecretRealm.vue │ ├── checkin.vue │ ├── fortunetelling.vue │ ├── game.vue │ ├── rock.vue │ └── toe.vue │ ├── homePage.vue │ ├── indexPage.vue │ └── mapExploration.vue └── vite.config.js /.github/ISSUE_TEMPLATE/bug反馈.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: BUG反馈 3 | about: 报告项目中发现的缺陷或问题 4 | title: "[BUG] 简要描述问题" 5 | labels: 'bug' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **问题描述** 11 | 清晰准确地描述遇到的问题 12 | 13 | **重现步骤** 14 | 1. 第一步操作 15 | 2. 第二步操作 16 | 3. 出现问题的操作 17 | 18 | **期望行为** 19 | 描述您认为正确的行为应该是怎样的 20 | 21 | **实际行为** 22 | 描述实际发生的错误行为 23 | 24 | **环境信息** 25 | - 操作系统: 26 | - 浏览器(如适用): 27 | - 项目版本: 28 | 29 | **截图或日志(可选)** 30 | 如果有错误截图或日志,请提供 -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/功能请求.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: 功能请求 3 | about: 请求添加新功能或改进现有功能 4 | title: "[功能] 简要描述功能" 5 | labels: 'enhancement' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **功能描述** 11 | 清晰描述您希望添加的功能 12 | 13 | **功能背景** 14 | 说明为什么需要这个功能,它能解决什么问题 15 | 16 | **建议实现方案(可选)** 17 | 如果有具体的实现想法,可以在这里描述 18 | 19 | **附加信息** 20 | 任何其他有助于理解这个功能的信息 -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/反馈建议.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: 反馈建议 3 | about: 为这个项目提出功能建议或改进意见 4 | title: "[建议] 简要描述您的建议" 5 | labels: 'enhancement' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **您的建议是什么?** 11 | 请清晰描述您希望添加的功能或改进点 12 | 13 | **为什么需要这个功能/改进?** 14 | 说明这个建议会解决什么问题或带来什么价值 15 | 16 | **您期望的实现方式(可选)** 17 | 如果有具体的实现想法,可以在这里描述 18 | 19 | **附加信息(可选)** 20 | 任何其他有助于理解这个建议的信息 21 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/文档改进.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: 文档改进 3 | about: 报告文档问题或建议改进 4 | title: "[文档] 简要描述问题" 5 | labels: 'documentation' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **文档位置** 11 | 指出需要改进的文档路径或URL 12 | 13 | **当前问题** 14 | 描述当前文档存在的问题或不清晰的地方 15 | 16 | **改进建议** 17 | 提出具体的改进建议 18 | 19 | **附加信息(可选)** 20 | 任何其他有助于改进文档的信息 -------------------------------------------------------------------------------- /.github/workflows/xiuxian-game.yml: -------------------------------------------------------------------------------- 1 | name: 自动化创建Docker镜像 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | 8 | jobs: 9 | build-amd64: 10 | runs-on: ubuntu-latest 11 | permissions: 12 | contents: read 13 | packages: write 14 | steps: 15 | - name: 检查代码 16 | uses: actions/checkout@v2 17 | 18 | - name: 登录 GitHub Container Registry 19 | uses: docker/login-action@v2 20 | with: 21 | registry: ghcr.io 22 | username: ${{ github.actor }} 23 | password: ${{ secrets.GHCR_TOKEN }} 24 | 25 | - name: 构建并推送 amd64 Docker镜像 26 | uses: docker/build-push-action@v3 27 | with: 28 | context: . 29 | platforms: linux/amd64 30 | push: true 31 | tags: ghcr.io/${{ github.repository_owner }}/vue-xiuxiangame:amd64 32 | 33 | build-arm64: 34 | runs-on: ubuntu-22.04-arm 35 | permissions: 36 | contents: read 37 | packages: write 38 | steps: 39 | - name: 检查代码 40 | uses: actions/checkout@v2 41 | 42 | - name: 登录 GitHub Container Registry 43 | uses: docker/login-action@v2 44 | with: 45 | registry: ghcr.io 46 | username: ${{ github.actor }} 47 | password: ${{ secrets.GHCR_TOKEN }} 48 | 49 | - name: 构建并推送 arm64 Docker镜像 50 | uses: docker/build-push-action@v3 51 | with: 52 | context: . 53 | platforms: linux/arm64 54 | push: true 55 | tags: ghcr.io/${{ github.repository_owner }}/vue-xiuxiangame:arm64 56 | 57 | create-manifest: 58 | needs: [build-amd64, build-arm64] 59 | runs-on: ubuntu-latest 60 | permissions: 61 | contents: read 62 | packages: write 63 | steps: 64 | - name: 登录 GitHub Container Registry 65 | uses: docker/login-action@v2 66 | with: 67 | registry: ghcr.io 68 | username: ${{ github.actor }} 69 | password: ${{ secrets.GHCR_TOKEN }} 70 | 71 | - name: 创建并推送多架构清单 72 | run: | 73 | docker manifest create ghcr.io/${{ github.repository_owner }}/vue-xiuxiangame:latest \ 74 | ghcr.io/${{ github.repository_owner }}/vue-xiuxiangame:amd64 \ 75 | ghcr.io/${{ github.repository_owner }}/vue-xiuxiangame:arm64 76 | docker manifest push ghcr.io/${{ github.repository_owner }}/vue-xiuxiangame:latest -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | pnpm-lock.yaml 3 | node_modules 4 | /dist 5 | 6 | 7 | # local env files 8 | .env.local 9 | .env.*.local 10 | 11 | # Log files 12 | npm-debug.log* 13 | yarn-debug.log* 14 | yarn-error.log* 15 | pnpm-debug.log* 16 | 17 | # Editor directories and files 18 | .idea 19 | .vscode 20 | *.suo 21 | *.ntvs* 22 | *.njsproj 23 | *.sln 24 | *.sw? 25 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | # 构建阶段 2 | FROM node:lts AS build 3 | WORKDIR /app 4 | COPY . . 5 | RUN npm install && \ 6 | npm run build 7 | 8 | # 运行阶段 9 | FROM node:lts AS runtime 10 | WORKDIR /app 11 | COPY --from=build /app/dist /app 12 | RUN npm install -g http-server 13 | 14 | EXPOSE 8080 15 | 16 | CMD ["http-server", "/app", "-p", "8080"] -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Creative Commons Attribution-NonCommercial 4.0 International Public License 2 | 3 | This work is licensed under the Creative Commons Attribution-NonCommercial 4.0 4 | International Public License. To view a copy of this license, visit 5 | https://creativecommons.org/licenses/by-nc/4.0/legalcode. 6 | 7 | You are free to: 8 | Share — copy and redistribute the material in any medium or format 9 | Adapt — remix, transform, and build upon the material 10 | 11 | Under the following terms: 12 | Attribution — You must give appropriate credit, provide a link to the license, 13 | and indicate if changes were made. You may do so in any reasonable manner, 14 | but not in any way that suggests the licensor endorses you or your use. 15 | 16 | NonCommercial — You may not use the material for commercial purposes. 17 | 18 | No additional restrictions — You may not apply legal terms or technological 19 | measures that legally restrict others from doing anything the license permits. 20 | 21 | Notice: 22 | This work is the original creation of Jun Qian (谦君). Source code available at: 23 | https://github.com/setube/vue-xiuxiangame 24 | This license does not constitute a waiver of any copyright or related rights. 25 | 26 | When you share adaptations of this work, you must: 27 | - Provide prominent attribution to the original author 28 | - Retain this license document 29 | - Clearly indicate modifications made and dates 30 | - Distribute under the same CC BY-NC 4.0 license 31 | 32 | © 2025 Jun Qian - All rights reserved (except those granted by this license) -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 | 3 |

4 |

5 | license MIT 6 | QQ群:920930589 7 | TapTap 8 | Featured|HelloGitHub 9 |

10 | 11 | ## 我的文字修仙全靠刷 12 | 13 | - 项目框架 [Vue.js](https://cn.vuejs.org) 14 | - 项目UI [Element Plus](https://element-plus.org/zh-CN) 15 | - 状态管理库 [Pinia](https://pinia.vuejs.org/zh) 16 | 17 | Docker贡献者: 18 | 19 | - wuchenchina [无尘](https://github.com/wuchenchina) 20 | - CoolXiTech [酷曦科技](https://github.com/CoolXiTech) 21 | - Firfr [Firfe](https://github.com/Firfr) 22 | 23 | 鸣谢以上开源项目及贡献者,排名不分先后. 24 | 25 | ## 快速开始 26 | - [本地安装指南](https://github.com/setube/vue-xiuxiangame/wiki/%E6%9C%AC%E5%9C%B0%E5%AE%89%E8%A3%85%E6%8C%87%E5%8D%97) 27 | - [Docker 部署指南](https://github.com/setube/vue-xiuxiangame/wiki/Docker%E9%83%A8%E7%BD%B2%E6%8C%87%E5%8D%97) 28 | 29 | ## 版权声明 30 | 知识共享署名-非商业性使用 4.0 国际许可协议 31 | 32 | 本作品采用知识共享署名-非商业性使用 4.0 国际许可协议进行许可。 33 | 要查看此许可协议的副本,请访问 http://creativecommons.org/licenses/by-nc/4.0/。 34 | 35 | 您自由地: 36 | 共享 — 在任何媒介以任何形式复制、发行本作品 37 | 改编 — 修改、转换或以本作品为基础进行创作 38 | 39 | 惟须遵守以下条件: 40 | 署名 — 您必须给出适当的署名,提供指向本许可协议的链接,同时标明是否(对原始作品)作了修改。您可以用任何合理的方式来署名,但不得以任何方式暗示许可人为您或您的使用背书。 41 | 42 | 非商业性使用 — 您不得将本作品用于商业目的。 43 | 44 | 没有附加限制 — 您不得适用法律术语或者技术措施从而限制其他人做许可协议允许的事情。 45 | 46 | 声明: 47 | 本作品是作者(谦君)的原创作品,项目源码地址:https://github.com/setube/vue-xiuxiangame 48 | 本授权条款不得被视为或解释为对任何版权的放弃或其他限制。 49 | 50 | 当您分享本作品的改编版本时,您必须: 51 | - 在显著位置标注原作者的署名 52 | - 保留本许可协议文档 53 | - 明确说明修改内容及修改日期 54 | - 使用相同的 CC BY-NC 4.0 协议进行分发 55 | 56 | © 2025 谦君 - 保留所有权利(根据本许可协议授予的权限除外) -------------------------------------------------------------------------------- /dev-dist/registerSW.js: -------------------------------------------------------------------------------- 1 | if('serviceWorker' in navigator) navigator.serviceWorker.register('/dev-sw.js?dev-sw', { scope: '/', type: 'classic' }) -------------------------------------------------------------------------------- /dev-dist/sw.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2018 Google Inc. All Rights Reserved. 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * http://www.apache.org/licenses/LICENSE-2.0 7 | * Unless required by applicable law or agreed to in writing, software 8 | * distributed under the License is distributed on an "AS IS" BASIS, 9 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 10 | * See the License for the specific language governing permissions and 11 | * limitations under the License. 12 | */ 13 | 14 | // If the loader is already loaded, just stop. 15 | if (!self.define) { 16 | let registry = {}; 17 | 18 | // Used for `eval` and `importScripts` where we can't get script URL by other means. 19 | // In both cases, it's safe to use a global var because those functions are synchronous. 20 | let nextDefineUri; 21 | 22 | const singleRequire = (uri, parentUri) => { 23 | uri = new URL(uri + ".js", parentUri).href; 24 | return registry[uri] || ( 25 | 26 | new Promise(resolve => { 27 | if ("document" in self) { 28 | const script = document.createElement("script"); 29 | script.src = uri; 30 | script.onload = resolve; 31 | document.head.appendChild(script); 32 | } else { 33 | nextDefineUri = uri; 34 | importScripts(uri); 35 | resolve(); 36 | } 37 | }) 38 | 39 | .then(() => { 40 | let promise = registry[uri]; 41 | if (!promise) { 42 | throw new Error(`Module ${uri} didn’t register its module`); 43 | } 44 | return promise; 45 | }) 46 | ); 47 | }; 48 | 49 | self.define = (depsNames, factory) => { 50 | const uri = nextDefineUri || ("document" in self ? document.currentScript.src : "") || location.href; 51 | if (registry[uri]) { 52 | // Module is already loading or loaded. 53 | return; 54 | } 55 | let exports = {}; 56 | const require = depUri => singleRequire(depUri, uri); 57 | const specialDeps = { 58 | module: { uri }, 59 | exports, 60 | require 61 | }; 62 | registry[uri] = Promise.all(depsNames.map( 63 | depName => specialDeps[depName] || require(depName) 64 | )).then(deps => { 65 | factory(...deps); 66 | return exports; 67 | }); 68 | }; 69 | } 70 | define(['./workbox-86c9b217'], (function (workbox) { 'use strict'; 71 | 72 | self.skipWaiting(); 73 | workbox.clientsClaim(); 74 | 75 | /** 76 | * The precacheAndRoute() method efficiently caches and responds to 77 | * requests for URLs in the manifest. 78 | * See https://goo.gl/S9QRab 79 | */ 80 | workbox.precacheAndRoute([{ 81 | "url": "registerSW.js", 82 | "revision": "3ca0b8505b4bec776b69afdba2768812" 83 | }, { 84 | "url": "index.html", 85 | "revision": "0.1v5f36uibdg" 86 | }], {}); 87 | workbox.cleanupOutdatedCaches(); 88 | workbox.registerRoute(new workbox.NavigationRoute(workbox.createHandlerBoundToURL("index.html"), { 89 | allowlist: [/^\/$/] 90 | })); 91 | 92 | })); 93 | -------------------------------------------------------------------------------- /docs/CNAME: -------------------------------------------------------------------------------- 1 | xiuxian.wenzi.games -------------------------------------------------------------------------------- /docs/assets/svg/cloth-ChmXEApe.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /docs/assets/svg/fist-CaMjbPZE.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /docs/assets/svg/scissors-BKSjQyjM.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /docs/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/setube/vue-XiuXianGame/4f20756a30b5fdafd32be8aa8cf895ab95279157/docs/favicon.ico -------------------------------------------------------------------------------- /docs/icons/icon-192x192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/setube/vue-XiuXianGame/4f20756a30b5fdafd32be8aa8cf895ab95279157/docs/icons/icon-192x192.png -------------------------------------------------------------------------------- /docs/icons/icon-512x512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/setube/vue-XiuXianGame/4f20756a30b5fdafd32be8aa8cf895ab95279157/docs/icons/icon-512x512.png -------------------------------------------------------------------------------- /docs/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 9 | 10 | 我的文字修仙全靠刷 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /docs/manifest.webmanifest: -------------------------------------------------------------------------------- 1 | {"name":"我的文字修仙全靠刷","short_name":"文字修仙","description":"文字游戏: 我的文字修仙全靠刷","start_url":"./","display":"standalone","background_color":"#ffffff","theme_color":"#4d4d4d","lang":"en","scope":"./","icons":[{"src":"/icons/icon-192x192.png","sizes":"192x192","type":"image/png"},{"src":"/icons/icon-512x512.png","sizes":"512x512","type":"image/png"}]} 2 | -------------------------------------------------------------------------------- /docs/registerSW.js: -------------------------------------------------------------------------------- 1 | if('serviceWorker' in navigator) {window.addEventListener('load', () => {navigator.serviceWorker.register('./sw.js', { scope: './' })})} -------------------------------------------------------------------------------- /docs/sw.js: -------------------------------------------------------------------------------- 1 | if(!self.define){let e,s={};const i=(i,n)=>(i=new URL(i+".js",n).href,s[i]||new Promise((s=>{if("document"in self){const e=document.createElement("script");e.src=i,e.onload=s,document.head.appendChild(e)}else e=i,importScripts(i),s()})).then((()=>{let e=s[i];if(!e)throw new Error(`Module ${i} didn’t register its module`);return e})));self.define=(n,r)=>{const o=e||("document"in self?document.currentScript.src:"")||location.href;if(s[o])return;let c={};const l=e=>i(e,o),t={module:{uri:o},exports:c,require:l};s[o]=Promise.all(n.map((e=>t[e]||l(e)))).then((e=>(r(...e),c)))}}define(["./workbox-3e8df8c8"],(function(e){"use strict";self.skipWaiting(),e.clientsClaim(),e.precacheAndRoute([{url:"assets/css/index-BZBS9mDs.css",revision:null},{url:"assets/css/vendor-modules-D2BJWH85.css",revision:null},{url:"assets/js/index-BuMI15Hl.js",revision:null},{url:"assets/js/vendor-modules-BL2bTueU.js",revision:null},{url:"index.html",revision:"8c49adc2dfc4c4c0129e4f1605df92af"},{url:"registerSW.js",revision:"402b66900e731ca748771b6fc5e7a068"},{url:"icons/icon-192x192.png",revision:"49fd62a1e8f83c24ec63b3e49b974165"},{url:"icons/icon-512x512.png",revision:"cee5a3cc5bf5966f9afda748e7c5942d"},{url:"manifest.webmanifest",revision:"97ef209e8e37a541821a1b549f0b882e"}],{}),e.cleanupOutdatedCaches(),e.registerRoute(new e.NavigationRoute(e.createHandlerBoundToURL("index.html")))})); 2 | -------------------------------------------------------------------------------- /docs/workbox-3e8df8c8.js: -------------------------------------------------------------------------------- 1 | define(["exports"],(function(t){"use strict";try{self["workbox:core:7.2.0"]&&_()}catch(t){}const e=(t,...e)=>{let s=t;return e.length>0&&(s+=` :: ${JSON.stringify(e)}`),s};class s extends Error{constructor(t,s){super(e(t,s)),this.name=t,this.details=s}}try{self["workbox:routing:7.2.0"]&&_()}catch(t){}const n=t=>t&&"object"==typeof t?t:{handle:t};class i{constructor(t,e,s="GET"){this.handler=n(e),this.match=t,this.method=s}setCatchHandler(t){this.catchHandler=n(t)}}class r extends i{constructor(t,e,s){super((({url:e})=>{const s=t.exec(e.href);if(s&&(e.origin===location.origin||0===s.index))return s.slice(1)}),e,s)}}class o{constructor(){this.t=new Map,this.i=new Map}get routes(){return this.t}addFetchListener(){self.addEventListener("fetch",(t=>{const{request:e}=t,s=this.handleRequest({request:e,event:t});s&&t.respondWith(s)}))}addCacheListener(){self.addEventListener("message",(t=>{if(t.data&&"CACHE_URLS"===t.data.type){const{payload:e}=t.data,s=Promise.all(e.urlsToCache.map((e=>{"string"==typeof e&&(e=[e]);const s=new Request(...e);return this.handleRequest({request:s,event:t})})));t.waitUntil(s),t.ports&&t.ports[0]&&s.then((()=>t.ports[0].postMessage(!0)))}}))}handleRequest({request:t,event:e}){const s=new URL(t.url,location.href);if(!s.protocol.startsWith("http"))return;const n=s.origin===location.origin,{params:i,route:r}=this.findMatchingRoute({event:e,request:t,sameOrigin:n,url:s});let o=r&&r.handler;const c=t.method;if(!o&&this.i.has(c)&&(o=this.i.get(c)),!o)return;let a;try{a=o.handle({url:s,request:t,event:e,params:i})}catch(t){a=Promise.reject(t)}const h=r&&r.catchHandler;return a instanceof Promise&&(this.o||h)&&(a=a.catch((async n=>{if(h)try{return await h.handle({url:s,request:t,event:e,params:i})}catch(t){t instanceof Error&&(n=t)}if(this.o)return this.o.handle({url:s,request:t,event:e});throw n}))),a}findMatchingRoute({url:t,sameOrigin:e,request:s,event:n}){const i=this.t.get(s.method)||[];for(const r of i){let i;const o=r.match({url:t,sameOrigin:e,request:s,event:n});if(o)return i=o,(Array.isArray(i)&&0===i.length||o.constructor===Object&&0===Object.keys(o).length||"boolean"==typeof o)&&(i=void 0),{route:r,params:i}}return{}}setDefaultHandler(t,e="GET"){this.i.set(e,n(t))}setCatchHandler(t){this.o=n(t)}registerRoute(t){this.t.has(t.method)||this.t.set(t.method,[]),this.t.get(t.method).push(t)}unregisterRoute(t){if(!this.t.has(t.method))throw new s("unregister-route-but-not-found-with-method",{method:t.method});const e=this.t.get(t.method).indexOf(t);if(!(e>-1))throw new s("unregister-route-route-not-registered");this.t.get(t.method).splice(e,1)}}let c;const a=()=>(c||(c=new o,c.addFetchListener(),c.addCacheListener()),c);function h(t,e,n){let o;if("string"==typeof t){const s=new URL(t,location.href);o=new i((({url:t})=>t.href===s.href),e,n)}else if(t instanceof RegExp)o=new r(t,e,n);else if("function"==typeof t)o=new i(t,e,n);else{if(!(t instanceof i))throw new s("unsupported-route-type",{moduleName:"workbox-routing",funcName:"registerRoute",paramName:"capture"});o=t}return a().registerRoute(o),o}const u={googleAnalytics:"googleAnalytics",precache:"precache-v2",prefix:"workbox",runtime:"runtime",suffix:"undefined"!=typeof registration?registration.scope:""},l=t=>[u.prefix,t,u.suffix].filter((t=>t&&t.length>0)).join("-"),f=t=>t||l(u.precache),w=t=>t||l(u.runtime);function d(t,e){const s=e();return t.waitUntil(s),s}try{self["workbox:precaching:7.2.0"]&&_()}catch(t){}function p(t){if(!t)throw new s("add-to-cache-list-unexpected-type",{entry:t});if("string"==typeof t){const e=new URL(t,location.href);return{cacheKey:e.href,url:e.href}}const{revision:e,url:n}=t;if(!n)throw new s("add-to-cache-list-unexpected-type",{entry:t});if(!e){const t=new URL(n,location.href);return{cacheKey:t.href,url:t.href}}const i=new URL(n,location.href),r=new URL(n,location.href);return i.searchParams.set("__WB_REVISION__",e),{cacheKey:i.href,url:r.href}}class y{constructor(){this.updatedURLs=[],this.notUpdatedURLs=[],this.handlerWillStart=async({request:t,state:e})=>{e&&(e.originalRequest=t)},this.cachedResponseWillBeUsed=async({event:t,state:e,cachedResponse:s})=>{if("install"===t.type&&e&&e.originalRequest&&e.originalRequest instanceof Request){const t=e.originalRequest.url;s?this.notUpdatedURLs.push(t):this.updatedURLs.push(t)}return s}}}class g{constructor({precacheController:t}){this.cacheKeyWillBeUsed=async({request:t,params:e})=>{const s=(null==e?void 0:e.cacheKey)||this.h.getCacheKeyForURL(t.url);return s?new Request(s,{headers:t.headers}):t},this.h=t}}let R;async function m(t,e){let n=null;if(t.url){n=new URL(t.url).origin}if(n!==self.location.origin)throw new s("cross-origin-copy-response",{origin:n});const i=t.clone(),r={headers:new Headers(i.headers),status:i.status,statusText:i.statusText},o=e?e(r):r,c=function(){if(void 0===R){const t=new Response("");if("body"in t)try{new Response(t.body),R=!0}catch(t){R=!1}R=!1}return R}()?i.body:await i.blob();return new Response(c,o)}function v(t,e){const s=new URL(t);for(const t of e)s.searchParams.delete(t);return s.href}class q{constructor(){this.promise=new Promise(((t,e)=>{this.resolve=t,this.reject=e}))}}const U=new Set;try{self["workbox:strategies:7.2.0"]&&_()}catch(t){}function L(t){return"string"==typeof t?new Request(t):t}class b{constructor(t,e){this.u={},Object.assign(this,e),this.event=e.event,this.l=t,this.p=new q,this.R=[],this.m=[...t.plugins],this.v=new Map;for(const t of this.m)this.v.set(t,{});this.event.waitUntil(this.p.promise)}async fetch(t){const{event:e}=this;let n=L(t);if("navigate"===n.mode&&e instanceof FetchEvent&&e.preloadResponse){const t=await e.preloadResponse;if(t)return t}const i=this.hasCallback("fetchDidFail")?n.clone():null;try{for(const t of this.iterateCallbacks("requestWillFetch"))n=await t({request:n.clone(),event:e})}catch(t){if(t instanceof Error)throw new s("plugin-error-request-will-fetch",{thrownErrorMessage:t.message})}const r=n.clone();try{let t;t=await fetch(n,"navigate"===n.mode?void 0:this.l.fetchOptions);for(const s of this.iterateCallbacks("fetchDidSucceed"))t=await s({event:e,request:r,response:t});return t}catch(t){throw i&&await this.runCallbacks("fetchDidFail",{error:t,event:e,originalRequest:i.clone(),request:r.clone()}),t}}async fetchAndCachePut(t){const e=await this.fetch(t),s=e.clone();return this.waitUntil(this.cachePut(t,s)),e}async cacheMatch(t){const e=L(t);let s;const{cacheName:n,matchOptions:i}=this.l,r=await this.getCacheKey(e,"read"),o=Object.assign(Object.assign({},i),{cacheName:n});s=await caches.match(r,o);for(const t of this.iterateCallbacks("cachedResponseWillBeUsed"))s=await t({cacheName:n,matchOptions:i,cachedResponse:s,request:r,event:this.event})||void 0;return s}async cachePut(t,e){const n=L(t);var i;await(i=0,new Promise((t=>setTimeout(t,i))));const r=await this.getCacheKey(n,"write");if(!e)throw new s("cache-put-with-no-response",{url:(o=r.url,new URL(String(o),location.href).href.replace(new RegExp(`^${location.origin}`),""))});var o;const c=await this.q(e);if(!c)return!1;const{cacheName:a,matchOptions:h}=this.l,u=await self.caches.open(a),l=this.hasCallback("cacheDidUpdate"),f=l?await async function(t,e,s,n){const i=v(e.url,s);if(e.url===i)return t.match(e,n);const r=Object.assign(Object.assign({},n),{ignoreSearch:!0}),o=await t.keys(e,r);for(const e of o)if(i===v(e.url,s))return t.match(e,n)}(u,r.clone(),["__WB_REVISION__"],h):null;try{await u.put(r,l?c.clone():c)}catch(t){if(t instanceof Error)throw"QuotaExceededError"===t.name&&await async function(){for(const t of U)await t()}(),t}for(const t of this.iterateCallbacks("cacheDidUpdate"))await t({cacheName:a,oldResponse:f,newResponse:c.clone(),request:r,event:this.event});return!0}async getCacheKey(t,e){const s=`${t.url} | ${e}`;if(!this.u[s]){let n=t;for(const t of this.iterateCallbacks("cacheKeyWillBeUsed"))n=L(await t({mode:e,request:n,event:this.event,params:this.params}));this.u[s]=n}return this.u[s]}hasCallback(t){for(const e of this.l.plugins)if(t in e)return!0;return!1}async runCallbacks(t,e){for(const s of this.iterateCallbacks(t))await s(e)}*iterateCallbacks(t){for(const e of this.l.plugins)if("function"==typeof e[t]){const s=this.v.get(e),n=n=>{const i=Object.assign(Object.assign({},n),{state:s});return e[t](i)};yield n}}waitUntil(t){return this.R.push(t),t}async doneWaiting(){let t;for(;t=this.R.shift();)await t}destroy(){this.p.resolve(null)}async q(t){let e=t,s=!1;for(const t of this.iterateCallbacks("cacheWillUpdate"))if(e=await t({request:this.request,response:e,event:this.event})||void 0,s=!0,!e)break;return s||e&&200!==e.status&&(e=void 0),e}}class C{constructor(t={}){this.cacheName=w(t.cacheName),this.plugins=t.plugins||[],this.fetchOptions=t.fetchOptions,this.matchOptions=t.matchOptions}handle(t){const[e]=this.handleAll(t);return e}handleAll(t){t instanceof FetchEvent&&(t={event:t,request:t.request});const e=t.event,s="string"==typeof t.request?new Request(t.request):t.request,n="params"in t?t.params:void 0,i=new b(this,{event:e,request:s,params:n}),r=this.U(i,s,e);return[r,this.L(r,i,s,e)]}async U(t,e,n){let i;await t.runCallbacks("handlerWillStart",{event:n,request:e});try{if(i=await this._(e,t),!i||"error"===i.type)throw new s("no-response",{url:e.url})}catch(s){if(s instanceof Error)for(const r of t.iterateCallbacks("handlerDidError"))if(i=await r({error:s,event:n,request:e}),i)break;if(!i)throw s}for(const s of t.iterateCallbacks("handlerWillRespond"))i=await s({event:n,request:e,response:i});return i}async L(t,e,s,n){let i,r;try{i=await t}catch(r){}try{await e.runCallbacks("handlerDidRespond",{event:n,request:s,response:i}),await e.doneWaiting()}catch(t){t instanceof Error&&(r=t)}if(await e.runCallbacks("handlerDidComplete",{event:n,request:s,response:i,error:r}),e.destroy(),r)throw r}}class E extends C{constructor(t={}){t.cacheName=f(t.cacheName),super(t),this.C=!1!==t.fallbackToNetwork,this.plugins.push(E.copyRedirectedCacheableResponsesPlugin)}async _(t,e){const s=await e.cacheMatch(t);return s||(e.event&&"install"===e.event.type?await this.O(t,e):await this.N(t,e))}async N(t,e){let n;const i=e.params||{};if(!this.C)throw new s("missing-precache-entry",{cacheName:this.cacheName,url:t.url});{const s=i.integrity,r=t.integrity,o=!r||r===s;n=await e.fetch(new Request(t,{integrity:"no-cors"!==t.mode?r||s:void 0})),s&&o&&"no-cors"!==t.mode&&(this.k(),await e.cachePut(t,n.clone()))}return n}async O(t,e){this.k();const n=await e.fetch(t);if(!await e.cachePut(t,n.clone()))throw new s("bad-precaching-response",{url:t.url,status:n.status});return n}k(){let t=null,e=0;for(const[s,n]of this.plugins.entries())n!==E.copyRedirectedCacheableResponsesPlugin&&(n===E.defaultPrecacheCacheabilityPlugin&&(t=s),n.cacheWillUpdate&&e++);0===e?this.plugins.push(E.defaultPrecacheCacheabilityPlugin):e>1&&null!==t&&this.plugins.splice(t,1)}}E.defaultPrecacheCacheabilityPlugin={cacheWillUpdate:async({response:t})=>!t||t.status>=400?null:t},E.copyRedirectedCacheableResponsesPlugin={cacheWillUpdate:async({response:t})=>t.redirected?await m(t):t};class O{constructor({cacheName:t,plugins:e=[],fallbackToNetwork:s=!0}={}){this.K=new Map,this.P=new Map,this.T=new Map,this.l=new E({cacheName:f(t),plugins:[...e,new g({precacheController:this})],fallbackToNetwork:s}),this.install=this.install.bind(this),this.activate=this.activate.bind(this)}get strategy(){return this.l}precache(t){this.addToCacheList(t),this.W||(self.addEventListener("install",this.install),self.addEventListener("activate",this.activate),this.W=!0)}addToCacheList(t){const e=[];for(const n of t){"string"==typeof n?e.push(n):n&&void 0===n.revision&&e.push(n.url);const{cacheKey:t,url:i}=p(n),r="string"!=typeof n&&n.revision?"reload":"default";if(this.K.has(i)&&this.K.get(i)!==t)throw new s("add-to-cache-list-conflicting-entries",{firstEntry:this.K.get(i),secondEntry:t});if("string"!=typeof n&&n.integrity){if(this.T.has(t)&&this.T.get(t)!==n.integrity)throw new s("add-to-cache-list-conflicting-integrities",{url:i});this.T.set(t,n.integrity)}if(this.K.set(i,t),this.P.set(i,r),e.length>0){const t=`Workbox is precaching URLs without revision info: ${e.join(", ")}\nThis is generally NOT safe. Learn more at https://bit.ly/wb-precache`;console.warn(t)}}}install(t){return d(t,(async()=>{const e=new y;this.strategy.plugins.push(e);for(const[e,s]of this.K){const n=this.T.get(s),i=this.P.get(e),r=new Request(e,{integrity:n,cache:i,credentials:"same-origin"});await Promise.all(this.strategy.handleAll({params:{cacheKey:s},request:r,event:t}))}const{updatedURLs:s,notUpdatedURLs:n}=e;return{updatedURLs:s,notUpdatedURLs:n}}))}activate(t){return d(t,(async()=>{const t=await self.caches.open(this.strategy.cacheName),e=await t.keys(),s=new Set(this.K.values()),n=[];for(const i of e)s.has(i.url)||(await t.delete(i),n.push(i.url));return{deletedURLs:n}}))}getURLsToCacheKeys(){return this.K}getCachedURLs(){return[...this.K.keys()]}getCacheKeyForURL(t){const e=new URL(t,location.href);return this.K.get(e.href)}getIntegrityForCacheKey(t){return this.T.get(t)}async matchPrecache(t){const e=t instanceof Request?t.url:t,s=this.getCacheKeyForURL(e);if(s){return(await self.caches.open(this.strategy.cacheName)).match(s)}}createHandlerBoundToURL(t){const e=this.getCacheKeyForURL(t);if(!e)throw new s("non-precached-url",{url:t});return s=>(s.request=new Request(t),s.params=Object.assign({cacheKey:e},s.params),this.strategy.handle(s))}}let x;const N=()=>(x||(x=new O),x);class k extends i{constructor(t,e){super((({request:s})=>{const n=t.getURLsToCacheKeys();for(const i of function*(t,{ignoreURLParametersMatching:e=[/^utm_/,/^fbclid$/],directoryIndex:s="index.html",cleanURLs:n=!0,urlManipulation:i}={}){const r=new URL(t,location.href);r.hash="",yield r.href;const o=function(t,e=[]){for(const s of[...t.searchParams.keys()])e.some((t=>t.test(s)))&&t.searchParams.delete(s);return t}(r,e);if(yield o.href,s&&o.pathname.endsWith("/")){const t=new URL(o.href);t.pathname+=s,yield t.href}if(n){const t=new URL(o.href);t.pathname+=".html",yield t.href}if(i){const t=i({url:r});for(const e of t)yield e.href}}(s.url,e)){const e=n.get(i);if(e){return{cacheKey:e,integrity:t.getIntegrityForCacheKey(e)}}}}),t.strategy)}}t.NavigationRoute=class extends i{constructor(t,{allowlist:e=[/./],denylist:s=[]}={}){super((t=>this.j(t)),t),this.M=e,this.S=s}j({url:t,request:e}){if(e&&"navigate"!==e.mode)return!1;const s=t.pathname+t.search;for(const t of this.S)if(t.test(s))return!1;return!!this.M.some((t=>t.test(s)))}},t.cleanupOutdatedCaches=function(){self.addEventListener("activate",(t=>{const e=f();t.waitUntil((async(t,e="-precache-")=>{const s=(await self.caches.keys()).filter((s=>s.includes(e)&&s.includes(self.registration.scope)&&s!==t));return await Promise.all(s.map((t=>self.caches.delete(t)))),s})(e).then((t=>{})))}))},t.clientsClaim=function(){self.addEventListener("activate",(()=>self.clients.claim()))},t.createHandlerBoundToURL=function(t){return N().createHandlerBoundToURL(t)},t.precacheAndRoute=function(t,e){!function(t){N().precache(t)}(t),function(t){const e=N();h(new k(e,t))}(e)},t.registerRoute=h})); 2 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 9 | 10 | 我的文字修仙全靠刷 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "xiuxian-game", 3 | "private": true, 4 | "version": "1.0.0", 5 | "type": "module", 6 | "scripts": { 7 | "dev": "vite --open", 8 | "build": "vite build", 9 | "preview": "vite preview --port 8080" 10 | }, 11 | "dependencies": { 12 | "@element-plus/icons-vue": "^2.3.1", 13 | "crypto-js": "^4.2.0", 14 | "element-plus": "^2.8.1", 15 | "file-saver": "^2.0.5", 16 | "pinia": "^3.0.2", 17 | "pinia-plugin-persistedstate": "^4.0.0", 18 | "terser": "^5.31.6", 19 | "unplugin-vue-components": "^28.5.0", 20 | "vue": "^3.4.37", 21 | "vue-router": "^4.4.3" 22 | }, 23 | "devDependencies": { 24 | "@vitejs/plugin-vue": "^5.1.3", 25 | "javascript-obfuscator": "^4.1.1", 26 | "terser": "^5.31.6", 27 | "unplugin-auto-import": "^19.2.0", 28 | "unplugin-icons": "^22.1.0", 29 | "vite": "^6.3.5", 30 | "vite-plugin-bundle-obfuscator": "^1.0.9", 31 | "vite-plugin-pwa": "^1.0.0" 32 | }, 33 | "pnpm": { 34 | "ignoredBuiltDependencies": [ 35 | "esbuild" 36 | ] 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /public/CNAME: -------------------------------------------------------------------------------- 1 | xiuxian.wenzi.games -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/setube/vue-XiuXianGame/4f20756a30b5fdafd32be8aa8cf895ab95279157/public/favicon.ico -------------------------------------------------------------------------------- /public/icons/icon-192x192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/setube/vue-XiuXianGame/4f20756a30b5fdafd32be8aa8cf895ab95279157/public/icons/icon-192x192.png -------------------------------------------------------------------------------- /public/icons/icon-512x512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/setube/vue-XiuXianGame/4f20756a30b5fdafd32be8aa8cf895ab95279157/public/icons/icon-512x512.png -------------------------------------------------------------------------------- /src/App.vue: -------------------------------------------------------------------------------- 1 | 37 | 38 | 64 | 65 | 149 | 150 | 467 | -------------------------------------------------------------------------------- /src/assets/CaretTop.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/caretBottom.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/cloth.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/dice1.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/dice2.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/dice3.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/dice4.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/dice5.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/dice6.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/fist.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/scissors.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/wm_bg_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/setube/vue-XiuXianGame/4f20756a30b5fdafd32be8aa8cf895ab95279157/src/assets/wm_bg_1.png -------------------------------------------------------------------------------- /src/assets/wm_bg_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/setube/vue-XiuXianGame/4f20756a30b5fdafd32be8aa8cf895ab95279157/src/assets/wm_bg_2.png -------------------------------------------------------------------------------- /src/auto-imports.d.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | /* prettier-ignore */ 3 | // @ts-nocheck 4 | // noinspection JSUnusedGlobalSymbols 5 | // Generated by unplugin-auto-import 6 | export { } 7 | declare global { 8 | 9 | } 10 | -------------------------------------------------------------------------------- /src/components.d.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | // @ts-nocheck 3 | // Generated by unplugin-vue-components 4 | // Read more: https://github.com/vuejs/core/pull/3399 5 | export { } 6 | 7 | /* prettier-ignore */ 8 | declare module 'vue' { 9 | export interface GlobalComponents { 10 | ElButton: typeof import('element-plus/es')['ElButton'] 11 | ElCheckbox: typeof import('element-plus/es')['ElCheckbox'] 12 | ElCheckboxGroup: typeof import('element-plus/es')['ElCheckboxGroup'] 13 | ElCollapse: typeof import('element-plus/es')['ElCollapse'] 14 | ElCollapseItem: typeof import('element-plus/es')['ElCollapseItem'] 15 | ElDialog: typeof import('element-plus/es')['ElDialog'] 16 | ElDivider: typeof import('element-plus/es')['ElDivider'] 17 | ElDrawer: typeof import('element-plus/es')['ElDrawer'] 18 | ElDropdown: typeof import('element-plus/es')['ElDropdown'] 19 | ElDropdownItem: typeof import('element-plus/es')['ElDropdownItem'] 20 | ElDropdownMenu: typeof import('element-plus/es')['ElDropdownMenu'] 21 | ElIcon: typeof import('element-plus/es')['ElIcon'] 22 | ElTabPane: typeof import('element-plus/es')['ElTabPane'] 23 | ElTabs: typeof import('element-plus/es')['ElTabs'] 24 | ElTag: typeof import('element-plus/es')['ElTag'] 25 | ElUpload: typeof import('element-plus/es')['ElUpload'] 26 | RouterLink: typeof import('vue-router')['RouterLink'] 27 | RouterView: typeof import('vue-router')['RouterView'] 28 | Tag: typeof import('./components/tag.vue')['default'] 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/components/equipTooltip.vue: -------------------------------------------------------------------------------- 1 | 46 | 47 | 64 | 102 | 109 | -------------------------------------------------------------------------------- /src/components/tag.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 23 | -------------------------------------------------------------------------------- /src/main.js: -------------------------------------------------------------------------------- 1 | import App from './App.vue' 2 | import { createApp } from 'vue' 3 | import { createPinia } from 'pinia' 4 | import 'element-plus/dist/index.css' 5 | import router from '@/plugins/router' 6 | import * as ElementPlusIconsVue from '@element-plus/icons-vue' 7 | import piniaPluginPersistedstate from 'pinia-plugin-persistedstate' 8 | import ElementPlus from 'element-plus' 9 | 10 | const app = createApp(App) 11 | 12 | const pinia = createPinia() 13 | pinia.use(piniaPluginPersistedstate) 14 | app.use(pinia) 15 | 16 | for (const [key, component] of Object.entries(ElementPlusIconsVue)) { 17 | app.component(key, component) 18 | } 19 | 20 | app.use(router) 21 | app.use(ElementPlus) 22 | app.mount('#app') 23 | -------------------------------------------------------------------------------- /src/plugins/achievement.js: -------------------------------------------------------------------------------- 1 | const achievement = { 2 | // 所有成就 3 | all() { 4 | return [ 5 | { 6 | name: '灵宠成就', 7 | type: 'pet', 8 | data: this.pet() 9 | }, 10 | { 11 | name: '探索成就', 12 | type: 'monster', 13 | data: this.monster() 14 | }, 15 | { 16 | name: '装备成就', 17 | type: 'equipment', 18 | data: this.equipment() 19 | } 20 | ] 21 | }, 22 | // 灵宠相关成就 23 | pet() { 24 | return [ 25 | { 26 | // 成就ID 27 | id: 1, 28 | // 成就名称 29 | name: '气血神宠', 30 | // 成就奖励 31 | award: 1000, 32 | //佩戴奖励 33 | titleBonus: { 34 | health: 5000 35 | }, 36 | //达成条件 37 | condition: { 38 | dodge: 0, 39 | health: 23500, 40 | attack: 0, 41 | defense: 0, 42 | critical: 0 43 | } 44 | }, 45 | { 46 | id: 2, 47 | name: '攻击神宠', 48 | award: 1000, 49 | titleBonus: { 50 | attack: 1000 51 | }, 52 | condition: { 53 | dodge: 0, 54 | health: 0, 55 | attack: 7050, 56 | defense: 0, 57 | critical: 0 58 | } 59 | }, 60 | { 61 | id: 3, 62 | name: '防御神宠', 63 | award: 1000, 64 | titleBonus: { 65 | defense: 100 66 | }, 67 | condition: { 68 | dodge: 0, 69 | health: 0, 70 | attack: 0, 71 | defense: 705, 72 | critical: 0 73 | } 74 | }, 75 | { 76 | id: 4, 77 | name: '闪避神宠', 78 | award: 1000, 79 | titleBonus: { 80 | dodge: 0.1 81 | }, 82 | condition: { 83 | dodge: 0.47, 84 | health: 0, 85 | attack: 0, 86 | defense: 0, 87 | critical: 0 88 | } 89 | }, 90 | { 91 | id: 5, 92 | name: '暴击神宠', 93 | award: 1000, 94 | titleBonus: { 95 | critical: 0.1 96 | }, 97 | condition: { 98 | dodge: 0, 99 | health: 0, 100 | attack: 0, 101 | defense: 0, 102 | critical: 0.47 103 | } 104 | }, 105 | { 106 | id: 6, 107 | name: '灵宠天花板', 108 | titleBonus: { 109 | attack: 2500 110 | }, 111 | award: 10000, 112 | condition: { 113 | dodge: 0.47, 114 | health: 23500, 115 | attack: 7050, 116 | defense: 705, 117 | critical: 0.47 118 | } 119 | } 120 | ] 121 | }, 122 | // 装备相关成就 123 | equipment() { 124 | return [] 125 | }, 126 | // 打怪相关成就 127 | monster() { 128 | return [ 129 | { 130 | id: 7, 131 | name: '挑战者', 132 | desc: '通关无尽塔100层', 133 | titleBonus: { 134 | critical: 0.05 135 | }, 136 | award: 10000, 137 | condition: { 138 | highestTowerFloor: 100 139 | }, 140 | }, 141 | { 142 | id: 8, 143 | name: '征服者', 144 | desc: '通关无尽塔1000层', 145 | titleBonus: { 146 | critical: 0.1 147 | }, 148 | award: 10000, 149 | condition: { 150 | highestTowerFloor: 1000 151 | } 152 | }, 153 | { 154 | id: 8, 155 | name: '长生者', 156 | desc: '寿元达到1000岁', 157 | titleBonus: { 158 | health: 10000 159 | }, 160 | award: 10000, 161 | condition: { 162 | age: 1000 163 | } 164 | }, 165 | { 166 | id: 9, 167 | name: '幸运之星', 168 | desc: '小游戏胜利超过10次', 169 | titleBonus: { 170 | defense: 0.01 171 | }, 172 | award: 10000, 173 | condition: { 174 | gameWins: 10 175 | } 176 | }, 177 | { 178 | id: 10, 179 | name: '天选之子', 180 | desc: '小游戏胜利超过100次', 181 | titleBonus: { 182 | defense: 0.1 183 | }, 184 | award: 10000, 185 | condition: { 186 | gameWins: 100 187 | } 188 | } 189 | ] 190 | } 191 | } 192 | export default achievement -------------------------------------------------------------------------------- /src/plugins/achievementChecker.js: -------------------------------------------------------------------------------- 1 | import achievement from '@/plugins/achievement' 2 | 3 | export const checkAchievements = (player, type, data) => { 4 | const newAchievements = [] 5 | switch (type) { 6 | case 'pet': 7 | checkPetAchievements(player, data, newAchievements) 8 | break 9 | case 'monster': 10 | checkMonsterAchievements(player, data, newAchievements) 11 | break 12 | case 'equipment': 13 | checkEquipmentAchievements(player, data, newAchievements) 14 | break 15 | } 16 | return newAchievements 17 | } 18 | 19 | const checkPetAchievements = (player, pet, newAchievements) => { 20 | const petAchievements = achievement.pet() 21 | petAchievements.forEach(item => { 22 | if (!player.achievement.pet.find(i => i.id === item.id) && checkCondition(item.condition, pet)) { 23 | newAchievements.push(item) 24 | player.achievement.pet.push({ id: item.id }) 25 | player.props.cultivateDan += item.award 26 | } 27 | }) 28 | } 29 | 30 | const checkMonsterAchievements = (player) => { 31 | const monsterAchievements = achievement.monster() 32 | monsterAchievements.forEach(item => { 33 | if (!player.achievement.monster.find(i => i.id === item.id) && checkCondition(item.condition, player)) { 34 | player.achievement.monster.push({ id: item.id }) 35 | player.props.cultivateDan += item.award 36 | } 37 | }) 38 | } 39 | 40 | const checkEquipmentAchievements = (player, equipmentData, newAchievements) => { 41 | const equipmentAchievements = achievement.equipment() 42 | equipmentAchievements.forEach(item => { 43 | if (!player.achievement.equipment.find(i => i.id === item.id) && checkCondition(item.condition, equipmentData)) { 44 | newAchievements.push(item) 45 | player.achievement.equipment.push({ id: item.id }) 46 | player.props.cultivateDan += item.award 47 | } 48 | }) 49 | } 50 | 51 | const checkCondition = (condition, data) => { 52 | for (const [key, value] of Object.entries(condition)) { 53 | if (data[key] === undefined || data[key] < value) { 54 | return false 55 | } 56 | } 57 | return true 58 | } -------------------------------------------------------------------------------- /src/plugins/boss.js: -------------------------------------------------------------------------------- 1 | const boss = { 2 | drawPrize(lv) { 3 | const bossInfo = this.boss_Names() 4 | // 血量 5 | const health = this.getRandomInt(50000, 100000) * lv 6 | // 攻击 7 | const attack = this.getRandomInt(5000, 10000) * lv 8 | // 防御 9 | const defense = this.getRandomInt(1000, 10000) * lv 10 | // 闪避 11 | const dodge = this.getRandomFloatInRange(0.1, 0.8) 12 | // 暴击 13 | const critical = this.getRandomFloatInRange(0.1, 1) 14 | return { 15 | name: bossInfo.name, 16 | text: this.boss_Text(), 17 | time: Math.floor(Date.now() / 1000), 18 | desc: bossInfo.description, 19 | level: 144, 20 | dodge, 21 | attack, 22 | health, 23 | defense, 24 | conquer: false, 25 | critical, 26 | maxhealth: health 27 | } 28 | }, 29 | // boss掉落 30 | boss_Equip(lv) { 31 | const weapon = [ 32 | '赤焰凤凰剑', '血玉红莲枪', '烈焰焚天弓', '赤霄神火戟', '火舞流云扇', 33 | '朱雀炎翼鞭', '赤龙焚世刃', '炎狱魔瞳镰', '炽血星辰杖', '红莲业火轮' 34 | ] 35 | const armor = [ 36 | '烈焰红莲战甲', '赤霄火凤云裳', '朱雀焚天织锦', '赤焰龙鳞宝衣', '血色蔷薇华服', 37 | '丹霞流光长袍', '炎阳炽烈战袍', '炽火红莲披风', '火舞凤凰羽衣', '红莲业火锦衣' 38 | ] 39 | const accessory = [ 40 | '赤焰凤凰翎', '血珀琉璃坠', '烈焰红宝石链', '朱雀之翼耳环', '红莲业火镯', 41 | '丹霄火凤戒', '玛瑙赤焰项链', '炽天使之泪珮', '绯红织锦手环', '火凤涅槃珠链' 42 | ] 43 | const sutra = [ 44 | '炽焰灵珠阵图', '火凤涅槃炉鼎', '红莲业火净世碑', '血玉轮回盘', '朱雀翔天翼', 45 | '烈焰焚天炉', '丹霄火域图', '赤龙炼魂珠', '火灵炽心镜', '九转炎灵祭坛' 46 | ] 47 | const weaponTypes = { 48 | weapon: { names: weapon, probability: 25 }, 49 | armor: { names: armor, probability: 25 }, 50 | accessory: { names: accessory, probability: 25 }, 51 | sutra: { names: sutra, probability: 25 } 52 | } 53 | const totalProbability = Object.values(weaponTypes).reduce((acc, { probability }) => acc + probability, 0) 54 | const random = Math.floor(Math.random() * totalProbability) 55 | let cumulativeProbability = 0 56 | for (const [quality, { names, probability }] of Object.entries(weaponTypes)) { 57 | cumulativeProbability += probability 58 | if (random < cumulativeProbability) { 59 | const dodge = this.getRandomFloatInRange(0.05, 0.1) 60 | const Attack = this.getRandomInt(500, 1000) * lv * 10 61 | const Health = this.getRandomInt(5000, 10000) * lv * 10 62 | const defense = this.getRandomInt(500, 1000) * lv * 10 63 | const Criticalhitrate = this.getRandomFloatInRange(0.05, 0.1) 64 | return { 65 | id: Date.now(), // 装备ID 66 | name: names[Math.floor(Math.random() * names.length)], //装备名字 67 | type: quality, // 装备类型 68 | level: lv, // 装备等级 69 | score: this.calculateEquipmentScore(dodge, Attack, Health, Criticalhitrate, defense), // 装备评分 70 | dodge: ['accessory', 'sutra'].includes(quality) ? dodge : 0, // 闪避率 71 | attack: ['weapon', 'accessory', 'sutra'].includes(quality) ? Attack : 0, // 攻击力 72 | health: ['armor', 'accessory', 'sutra'].includes(quality) ? Health : 0, // 血量 73 | quality: 'danger', // 装备品质 74 | // 初始数据 75 | initial: { 76 | dodge: ['accessory', 'sutra'].includes(quality) ? dodge : 0, // 闪避率 77 | attack: ['weapon', 'accessory', 'sutra'].includes(quality) ? Attack : 0, // 攻击力 78 | health: ['armor', 'accessory', 'sutra'].includes(quality) ? Health : 0, // 血量 79 | defense: ['accessory', 'sutra'].includes(quality) ? defense : 0, // 装备防御 80 | critical: ['weapon', 'accessory', 'sutra'].includes(quality) ? Criticalhitrate : 0, // 暴击率 81 | }, 82 | defense: ['armor', 'accessory', 'sutra'].includes(quality) ? defense : 0, // 装备防御 83 | critical: ['weapon', 'accessory', 'sutra'].includes(quality) ? Criticalhitrate : 0 // 暴击率 84 | } 85 | } 86 | } 87 | }, 88 | // boss语录 89 | boss_Text() { 90 | const text = [ 91 | '你的时代已经结束,现在,是我主宰一切的时候了。', 92 | '你的努力,终究只是为我铺就了通往胜利的道路。', 93 | '战胜你,对我来说不过是举手之劳,你的实力,不过如此。', 94 | '你的生命,在我的手中如蝼蚁般脆弱,你的死亡,只是我计划中的一环。', 95 | '你的失败,证明了我的智慧与力量无可匹敌,而你,只是我的垫脚石。', 96 | '你的存在,曾让我感到一丝威胁,但现在,你已成为我脚下的尘埃。', 97 | '你的勇气可嘉,但可惜,勇气并不能改变结果,你最终还是败在了我的脚下。', 98 | '你的死,将是我传奇中的一笔,而你,将永远被我踩在脚下。', 99 | '你的挣扎与反抗,不过是徒劳无功,你的命运,早已注定。', 100 | '你的终结,是我迈向更高峰的开始,你的存在,对我来说已无任何意义。', 101 | '你的死亡,将证明我的强大与不可战胜,而你,将永远成为我的手下败将。', 102 | '你的遗言,对我来说毫无意义,因为你已经无法再影响我的计划。', 103 | '你的逝去,只是宇宙间的一次微小波动,而我,将继续书写我的传奇。', 104 | '你的失败,是我成功路上的一个注脚,而你,将永远无法摆脱这个污点。', 105 | '你的生命之火已经熄灭,而我,将继续燃烧,照亮整个世界。', 106 | '你的死亡,让我更加坚信自己的道路是正确的,而你,只是我路上的一个过客。', 107 | '你的存在,曾让我有过一丝犹豫,但现在,我已经没有任何顾虑,因为我已经彻底战胜了你。', 108 | '你的终结,是我力量的证明,而你,将永远无法逃脱这个宿命。', 109 | '你的死亡,将是我成就伟大事业的基石,而你,将永远被世人遗忘。', 110 | '你的挑战,虽然激烈,但终究无法撼动我的地位,你的死亡,只是我辉煌人生中的一个注脚。' 111 | ] 112 | return text[Math.floor(Math.random() * text.length)] 113 | }, 114 | boss_Names() { 115 | const boss = [ 116 | { name: '烛龙神尊', description: '乃钟山之神,睁眼为昼,闭眼为夜,呼吸间风云变幻,掌控着时间的流转。' }, 117 | { name: '幽冥鬼帝', description: '传说中幽冥界的至高统治者,掌管生死轮回,其力量深不可测,能召唤万千亡灵为其所用。' }, 118 | { name: '苍穹魔尊', description: '诞生于九天之上,因贪恋凡间情感而堕入魔道,拥有操控天地元素、撕裂虚空的能力。' }, 119 | { name: '龙皇傲天', description: '龙族中的至尊,身披璀璨龙鳞,掌握着古老龙族的所有秘辛与力量,其威严令万兽臣服。' }, 120 | { name: '凤舞九天', description: '凤凰一族的女王,拥有不死之身与涅槃重生的能力,其羽翼轻挥,即可掀起滔天火焰,焚尽一切。' }, 121 | { name: '雷神天尊', description: '天界雷神转世,手持雷神锤,能召唤九天神雷,一击之下,山河破碎,万物寂灭。' }, 122 | { name: '幽冥血皇', description: '幽冥界中的古老存在,以鲜血为食,其力量源自于无尽的杀戮与怨念,令人闻风丧胆。' }, 123 | { name: '玄冰龙神', description: '来自极北之地的神秘生物,融合了龙与冰元素的力量,其身躯坚不可摧,能冻结世间万物。' }, 124 | { name: '金翅大鹏王', description: '大鹏一族中的王者,拥有遮天蔽日的双翼,速度之快,可瞬息万里,其利爪足以撕裂空间。' }, 125 | { name: '混沌魔君', description: '诞生于混沌之初的古老魔物,其力量源自于宇宙的本源,能够扭曲现实,吞噬万物,是天地间最可怕的存在之一。' } 126 | ] 127 | return boss[Math.floor(Math.random() * boss.length)] 128 | }, 129 | getRandomInt(min, max) { 130 | min = Math.ceil(min) 131 | max = Math.floor(max) 132 | return Math.floor(Math.random() * (max - min + 1)) + min 133 | }, 134 | getRandomFloatInRange(min, max) { 135 | return Math.random() * (max - min) + min 136 | }, 137 | // 计算装备评分 138 | calculateEquipmentScore(dodge = 0, attack = 0, health = 0, critical = 0, defense = 0) { 139 | // 评分权重 140 | const weights = { 141 | attack: 1.5, // 攻击 142 | health: 1.0, // 气血 143 | defense: 1.2, // 防御 144 | critRate: 1.8, // 暴击 145 | dodgeRate: 1.6 //闪避 146 | } 147 | // 计算评分 148 | const score = ( 149 | dodge * weights.dodgeRate + 150 | attack * weights.attack + 151 | (health / 100) * weights.health + 152 | defense * weights.defense + 153 | critical * weights.critRate 154 | ) 155 | return Math.floor(score) 156 | } 157 | } 158 | export default boss -------------------------------------------------------------------------------- /src/plugins/combat.js: -------------------------------------------------------------------------------- 1 | export default { 2 | calculateDamage(attacker, defender) { 3 | // 基础伤害计算 4 | let damage = Math.max(0, Math.floor(attacker.attack - defender.defense)) 5 | damage = damage <= 1 ? 1 : damage // 伤害最小为1 6 | // 闪避判定 7 | const isHit = Math.random() > defender.dodge 8 | if (!isHit) return { damage: 0, isCritical: false, isHit: false } 9 | // 暴击判定 10 | let isCritical = false 11 | if (Math.random() < attacker.critical) { 12 | damage *= 1.5 13 | isCritical = true 14 | } 15 | // 返回计算结果,包括伤害值,暴击状态和命中状态 16 | return { damage, isCritical, isHit: true } 17 | }, 18 | executeCombatRound(attacker, defender) { 19 | const attackResult = this.calculateDamage(attacker, defender) 20 | if (attackResult.isHit) defender.health = Math.max(0, defender.health - attackResult.damage) 21 | // 返回本轮攻击的结果,包括伤害值,暴击状态,命中状态及防御者剩余生命值 22 | return { 23 | damage: attackResult.damage, 24 | isCritical: attackResult.isCritical, 25 | isHit: attackResult.isHit, 26 | remainingHealth: defender.health 27 | } 28 | } 29 | } -------------------------------------------------------------------------------- /src/plugins/crypto.js: -------------------------------------------------------------------------------- 1 | import CryptoJS from 'crypto-js' 2 | 3 | const crypto = { 4 | iv() { 5 | return ['Y', 'o', 'u', 'r', 'E', 'n', 'c', 'r', 'y', 'p', 't', 'i', 'o', 'n', 'K', 'e'] 6 | }, 7 | encryption(val) { 8 | const iv = this.iv().join('') 9 | return CryptoJS.AES.encrypt(JSON.stringify(val), iv, { 10 | iv, 11 | mode: CryptoJS.mode.CBC, 12 | padding: CryptoJS.pad.Pkcs7 13 | }).toString() 14 | }, 15 | decryption(data) { 16 | const iv = this.iv().join('') 17 | const player = CryptoJS.AES.decrypt(data, iv, { 18 | iv, 19 | mode: CryptoJS.mode.CBC, 20 | padding: CryptoJS.pad.Pkcs7 21 | }).toString(CryptoJS.enc.Utf8) 22 | return JSON.parse(player) 23 | }, 24 | } 25 | 26 | export default crypto -------------------------------------------------------------------------------- /src/plugins/equip.js: -------------------------------------------------------------------------------- 1 | const equips = { 2 | drawPrize(lv, type, names_a, names_b, names_c, names_d, names_e, names_f, isNewbie) { 3 | // 如果玩家等级为0 生成的装备等级最低为1, 如果玩家等级低于40级的话就随机生成当前等级和低于当前等级的装备 4 | lv = lv == 0 ? 1 : lv 5 | // 如果已领取新手礼包 6 | if (isNewbie) lv = this.getRandomInt(1, lv) 7 | // 装备的抽中概率 8 | const weaponTypes = { 9 | info: { names: names_a, probability: 50 }, // 白装 10 | success: { names: names_b, probability: 20 }, // 绿装 11 | primary: { names: names_c, probability: 15 }, // 蓝装 12 | purple: { names: names_d, probability: 9 }, // 紫装 13 | warning: { names: names_e, probability: 5 }, // 金装 14 | danger: { names: names_f, probability: 1 } // 红装 15 | } 16 | const totalProbability = Object.values(weaponTypes).reduce((acc, { probability }) => acc + probability, 0) 17 | const random = Math.floor(Math.random() * totalProbability) 18 | let cumulativeProbability = 0 19 | for (const [quality, { names, probability }] of Object.entries(weaponTypes)) { 20 | cumulativeProbability += probability 21 | if (random < cumulativeProbability) { 22 | // 根据装备品质调整装备属性值 23 | const qualityMultiplier = { info: 1.2, success: 2, primary: 3, purple: 5, warning: 7, danger: 10 } 24 | const multiplier = qualityMultiplier[quality] 25 | const dodge = ['accessory', 'sutra'].includes(type) ? this.equip_Criticalhitrate(lv) : 0 26 | const attack = ['weapon', 'accessory', 'sutra'].includes(type) ? Math.floor(this.equip_Attack(lv) * multiplier) : 0 27 | const health = ['armor', 'accessory', 'sutra'].includes(type) ? Math.floor(this.equip_Health(lv) * multiplier) : 0 28 | const defense = ['armor', 'accessory', 'sutra'].includes(type) ? Math.floor(this.equip_Attack(lv) * multiplier) : 0 29 | const critical = ['weapon', 'accessory', 'sutra'].includes(type) ? this.equip_Criticalhitrate(lv) : 0 30 | const baseEquip = { 31 | id: Date.now(), // 装备ID 32 | name: names[Math.floor(Math.random() * names.length)], //装备名字 33 | type, // 装备类型 34 | lock: false, 35 | level: lv, // 装备等级 36 | score: this.calculateEquipmentScore(dodge, attack, health, critical, defense), // 装备评分 37 | dodge, // 闪避率 38 | attack, // 攻击力 39 | health, // 血量 40 | defense, // 防御 41 | critical, // 暴击率 42 | // 初始数据 43 | initial: { 44 | dodge, // 闪避率 45 | attack, // 攻击力 46 | health, // 血量 47 | defense, // 装备防御 48 | critical // 暴击率 49 | }, 50 | quality, 51 | strengthen: 0 // 炼器等级 52 | } 53 | return baseEquip 54 | } 55 | } 56 | }, 57 | equip_Weapons(lv, isNewbie = false) { 58 | const names_a = [ 59 | '白玉净尘剑', '雪魄寒冰枪', '白龙吟风弓', '月华流光扇', '白玉玄灵笛', 60 | '霜雪无痕鞭', '云隐白凰刃', '净世白莲杖', '冰魄寒光轮', '白玉玲珑塔' 61 | ] 62 | const names_b = [ 63 | '翠玉青藤剑', '碧影灵蛇鞭', '绿叶风暴弓', '青木长生杖', '翡翠灵犀刃', 64 | '藤蔓缠绕索', '翠竹清风扇', '生命之泉壶', '绿野仙踪笛', '森罗万象轮' 65 | ] 66 | const names_c = [ 67 | '寒冰破晓剑', '碧海潮生笛', '蓝玉冰魄弓', '苍穹蓝龙枪', '冰魄寒光剑', 68 | '鲛人织梦扇', '深海之怒戟', '碧波凌霄杖', '幽蓝蝶舞鞭', '银河落霜刃' 69 | ] 70 | const names_d = [ 71 | '紫霄龙吟剑', '幽冥紫蝶刃', '星河紫电枪', '紫玉寒冰弓', '紫焰凤凰琴', 72 | '苍穹紫雷锤', '紫莲幽光扇', '紫晶破晓戟', '幽冥紫影鞭', '紫霄凌虚杖' 73 | ] 74 | const names_e = [ 75 | '金煌剑', '炽焰长枪', '琥珀流光弓', '龙鳞金斧', '破晓黄玉锤', 76 | '炎阳鞭', '流光扇', '战神金戟', '黄芒闪电刃', '日曜乾坤轮' 77 | ] 78 | const names_f = [ 79 | '赤焰凤凰剑', '血玉红莲枪', '烈焰焚天弓', '赤霄神火戟', '火舞流云扇', 80 | '朱雀炎翼鞭', '赤龙焚世刃', '炎狱魔瞳镰', '炽血星辰杖', '红莲业火轮' 81 | ] 82 | return this.drawPrize(lv, 'weapon', names_a, names_b, names_c, names_d, names_e, names_f, isNewbie) 83 | }, 84 | equip_Armors(lv, isNewbie = false) { 85 | const names_a = [ 86 | '瑶池仙绡羽衣', '广寒玉兔霜甲', '昆仑玉璧战袍', '白龙吐珠云裳', '九天玄女素绫', 87 | '瑶光星辰织锦', '冰魄银丝战衣', '凌霄琼华宝衣', '雪域神女雪绒', '云隐龙鳞轻铠' 88 | ] 89 | const names_b = [ 90 | '翠竹幽兰轻衫', '碧落青藤云裳', '碧眼麒麟战衣', '青鸾翔翼织锦', '苍梧古木灵袍', 91 | '绿野仙踪羽衣', '灵蛇翠蔓软甲', '翡翠琉璃长裙', '松风竹影轻裘', '春水碧于天衣' 92 | ] 93 | const names_c = [ 94 | '寒冰护甲衣', '碧波守护铠', '蓝玉冰心链甲', '苍穹蓝灵披风', '深海蛟龙鳞甲', 95 | '冰魄幽光战铠', '蓝蝶轻舞护腕', '银河之盾胸甲', '鲛人织梦护腿', '碧波凌波靴' 96 | ] 97 | const names_d = [ 98 | '紫云织锦袍', '幽冥紫霜甲', '星河紫霞衣', '紫玉冰心链甲', '紫焰凤凰披风', 99 | '苍穹紫雷战铠', '紫莲幽光护腕', '紫晶凌霄战裙', '幽冥紫影护腿', '紫霄逐风靴' 100 | ] 101 | const names_e = [ 102 | '金辉流光锦袍', '琥珀流光战衣', '黄土龙纹长袍', '日炎金鳞铠甲', '秋菊金缎华服', 103 | '蜜蜡黄绸云裳', '凤凰涅槃黄衫', '黄沙漫天披风', '金穗流光纱裙', '辉煌金羽战袍' 104 | ] 105 | const names_f = [ 106 | '烈焰红莲战甲', '赤霄火凤云裳', '朱雀焚天织锦', '赤焰龙鳞宝衣', '血色蔷薇华服', 107 | '丹霞流光长袍', '炎阳炽烈战袍', '炽火红莲披风', '火舞凤凰羽衣', '红莲业火锦衣' 108 | ] 109 | return this.drawPrize(lv, 'armor', names_a, names_b, names_c, names_d, names_e, names_f, isNewbie) 110 | }, 111 | equip_Accessorys(lv, isNewbie = false) { 112 | const names_a = [ 113 | '瑶池白玉簪', '月华流光坠', '寒霜凝露链', '九天玄女玉佩', '云锦织梦镯', 114 | '龙涎润雪环', '白鹤衔珠珮', '仙山雪莲花链', '瑶台仙露耳环', '银河织梦项链' 115 | ] 116 | const names_b = [ 117 | '翠竹凝露簪', '碧泉幽兰链', '青藤绕梦镯', '翡翠灵叶耳环', '灵山仙草玉佩', 118 | '松柏长青戒', '翠影轻舞项链', '绿野仙踪手环', '碧波荡漾珠链', '春回大地玉珮' 119 | ] 120 | const names_c = [ 121 | '碧海珊瑚簪', '冰魄幽蓝链', '深海珍珠耳环', '蓝田玉髓镯', '苍穹蓝宝坠', 122 | '鲛人泪滴珠', '碧波荡漾戒', '银河之心项链', '蓝蝶飞舞手环', '深海龙鳞珮' 123 | ] 124 | const names_d = [ 125 | '紫霄流光戒', '幽冥紫蝶项链', '星河紫玉耳环', '紫玉冰心手链', '紫焰凤凰簪', 126 | '苍穹紫雷吊坠', '紫莲幽光发带', '紫晶破晓护符', '幽冥紫影指环', '紫霄凌虚玉佩' 127 | ] 128 | const names_e = [ 129 | '金辉日冕簪', '琥珀流光链', '黄粱一梦镯', '皇天后土玉佩', '蜜蜡福瑞戒', 130 | '秋收万颗项链', '暖阳照耀耳环', '炎黄子孙玉珮', '金色麦田手环', '盛世繁华珠链' 131 | ] 132 | const names_f = [ 133 | '赤焰凤凰翎', '血珀琉璃坠', '烈焰红宝石链', '朱雀之翼耳环', '红莲业火镯', 134 | '丹霄火凤戒', '玛瑙赤焰项链', '炽天使之泪珮', '绯红织锦手环', '火凤涅槃珠链' 135 | ] 136 | return this.drawPrize(lv, 'accessory', names_a, names_b, names_c, names_d, names_e, names_f, isNewbie) 137 | }, 138 | equip_Sutras(lv, isNewbie = false) { 139 | const names_a = [ 140 | '白玉净瓶', '寒霜琉璃镜', '瑶池雪莲珠', '九天玄冰尺', '月华宝莲灯', 141 | '白云隐龙笛', '玉清昆仑扇', '净世白莲座', '银河落雪琴', '碧落瑶光盘' 142 | ] 143 | const names_b = [ 144 | '翠玉葫芦', '青木长生杖', '碧落灵珠', '幽冥鬼藤鞭', '万木回春图', 145 | '绿绮琴音笛', '青鸾火凤羽扇', '翠影追魂剑', '草木皆兵符', '碧泉灵泉壶' 146 | ] 147 | const names_c = [ 148 | '碧波神珠', '冰魄寒玉葫', '深海龙息珠', '苍穹蓝灵珠', '鲛人织梦灯', 149 | '银河落霜瓶', '蓝玉冰心镜', '寒冰净世莲', '碧波幽兰笛', '深海龙吟佩' 150 | ] 151 | const names_d = [ 152 | '紫霄神雷珠', '幽冥紫蝶翼', '星河紫玉壶', '紫玉冰心镜', '紫焰凤凰翎', 153 | '苍穹紫雷鼎', '紫莲幽光轮', '紫晶破晓琴', '幽冥紫影幡', '紫霄凌虚印' 154 | ] 155 | const names_e = [ 156 | '金蛟剪', '乾坤圈', '黄金玲珑塔', '戊己杏黄旗', '轩辕黄帝鼎', 157 | '镇妖伏魔镜', '落日熔金轮', '万寿无疆葫芦', '金翅大鹏羽扇', '地黄玄玉珠' 158 | ] 159 | const names_f = [ 160 | '炽焰灵珠阵图', '火凤涅槃炉鼎', '红莲业火净世碑', '血玉轮回盘', '朱雀翔天翼', 161 | '烈焰焚天炉', '丹霄火域图', '赤龙炼魂珠', '火灵炽心镜', '九转炎灵祭坛' 162 | ] 163 | return this.drawPrize(lv, 'sutra', names_a, names_b, names_c, names_d, names_e, names_f, isNewbie) 164 | }, 165 | equip_Attack(lv) { 166 | return this.getRandomInt(10, 50) * lv 167 | }, 168 | equip_Health(lv) { 169 | return this.getRandomInt(100, 500) * lv 170 | }, 171 | equip_Criticalhitrate() { 172 | return this.getRandomFloatInRange(0.01, 0.05) 173 | }, 174 | // equip_Defense (lv, isNewbie = true) { 175 | // if (lv >= 1 && lv <= 5) { 176 | // return this.getRandomInt(15, 150) * lv 177 | // } else if (lv >= 6 && lv <= 10) { 178 | // return this.getRandomInt(150, 300) * lv 179 | // } else { 180 | // return this.getRandomInt(300, 500) * lv 181 | // } 182 | // }, 183 | getRandomInt(min, max) { 184 | min = Math.ceil(min) 185 | max = Math.floor(max) 186 | return Math.floor(Math.random() * (max - min + 1)) + min 187 | }, 188 | getRandomFloatInRange(min, max) { 189 | return Math.random() * (max - min) + min 190 | }, 191 | // 计算装备评分 192 | calculateEquipmentScore(dodge = 0, attack = 0, health = 0, critical = 0, defense = 0) { 193 | // 评分权重 194 | const weights = { 195 | attack: 1.5, // 攻击 196 | health: 1.0, // 气血 197 | defense: 1.2, // 防御 198 | critRate: 1.8, // 暴击 199 | dodgeRate: 1.6 //闪避 200 | } 201 | // 计算评分 202 | const score = ( 203 | dodge * weights.dodgeRate * 100 + 204 | attack * weights.attack + 205 | (health / 100) * weights.health + 206 | defense * weights.defense + 207 | critical * weights.critRate * 100 208 | ) 209 | return Math.floor(score) 210 | } 211 | } 212 | export default equips -------------------------------------------------------------------------------- /src/plugins/equipAll.js: -------------------------------------------------------------------------------- 1 | const All = { 2 | drawPrize(lv) { 3 | const types = [ 4 | { type: 'weapon', data: this.equipWeapons() }, 5 | { type: 'armor', data: this.equipArmors() }, 6 | { type: 'accessory', data: this.equipAccessories() }, 7 | { type: 'sutra', data: this.equipSutras() } 8 | ] 9 | const prize = { info: 50, success: 20, primary: 15, purple: 9, warning: 5, danger: 1, pink: 0 } 10 | const genre = { sutra: '法器', armor: '护甲', weapon: '兵器', accessory: '灵宝' } 11 | const quality = Object.keys(prize) 12 | const getAttribute = (type, lv, attribute, quality) => { 13 | // 根据装备品质调整装备属性值 14 | const qualityMultiplier = { info: 1.2, success: 2, primary: 3, purple: 5, warning: 7, danger: 10, pink: 15 } 15 | const multiplier = qualityMultiplier[quality] 16 | const Attack = 1000 * lv 17 | const Health = 10000 * lv 18 | const CriticalHitrate = quality == 'pink' ? 0.25 : 0.1 19 | const attrs = { 20 | score: this.calculateEquipmentScore(CriticalHitrate, Attack, Health, CriticalHitrate, CriticalHitrate), 21 | dodge: ['accessory', 'sutra'].includes(type) ? CriticalHitrate * multiplier : 0, 22 | attack: ['weapon', 'accessory', 'sutra'].includes(type) ? Math.floor(Attack * multiplier) : 0, 23 | health: ['armor', 'accessory', 'sutra'].includes(type) ? Math.floor(Health * multiplier) : 0, 24 | defense: ['armor', 'accessory', 'sutra'].includes(type) ? Math.floor(Attack * multiplier) : 0, 25 | critical: ['weapon', 'accessory', 'sutra'].includes(type) ? CriticalHitrate * multiplier : 0 26 | } 27 | return attrs[attribute] 28 | } 29 | return types.map(({ type, data }) => ({ 30 | type, 31 | name: genre[type], 32 | data: data.flatMap((subtype, kk) => 33 | subtype.map(name => ({ 34 | name, 35 | type, 36 | level: lv, 37 | score: getAttribute(type, lv, 'score', quality[kk]), 38 | prize: prize[quality[kk]], 39 | dodge: getAttribute(type, lv, 'dodge', quality[kk]), 40 | attack: getAttribute(type, lv, 'attack', quality[kk]), 41 | health: getAttribute(type, lv, 'health', quality[kk]), 42 | defense: getAttribute(type, lv, 'defense', quality[kk]), 43 | critical: getAttribute(type, lv, 'critical', quality[kk]), 44 | quality: quality[kk] 45 | })) 46 | ) 47 | })) 48 | }, 49 | equipWeapons() { 50 | return [ 51 | ['白玉净尘剑', '雪魄寒冰枪', '白龙吟风弓', '月华流光扇', '白玉玄灵笛', '霜雪无痕鞭', '云隐白凰刃', '净世白莲杖', '冰魄寒光轮', '白玉玲珑塔'], 52 | ['翠玉青藤剑', '碧影灵蛇鞭', '绿叶风暴弓', '青木长生杖', '翡翠灵犀刃', '藤蔓缠绕索', '翠竹清风扇', '生命之泉壶', '绿野仙踪笛', '森罗万象轮'], 53 | ['寒冰破晓剑', '碧海潮生笛', '蓝玉冰魄弓', '苍穹蓝龙枪', '冰魄寒光剑', '鲛人织梦扇', '深海之怒戟', '碧波凌霄杖', '幽蓝蝶舞鞭', '银河落霜刃'], 54 | ['紫霄龙吟剑', '幽冥紫蝶刃', '星河紫电枪', '紫玉寒冰弓', '紫焰凤凰琴', '苍穹紫雷锤', '紫莲幽光扇', '紫晶破晓戟', '幽冥紫影鞭', '紫霄凌虚杖'], 55 | ['金煌剑', '炽焰长枪', '琥珀流光弓', '龙鳞金斧', '破晓黄玉锤', '炎阳鞭', '流光扇', '战神金戟', '黄芒闪电刃', '日曜乾坤轮'], 56 | ['赤焰凤凰剑', '血玉红莲枪', '烈焰焚天弓', '赤霄神火戟', '火舞流云扇', '朱雀炎翼鞭', '赤龙焚世刃', '炎狱魔瞳镰', '炽血星辰杖', '红莲业火轮'], 57 | ['粉晶月刃剑', '樱花吹雪弓', '蔷薇缠绕鞭', '蜜桃梦境杖', '粉蝶幻光刃', '粉晶流光扇', '甜梦水晶枪', '粉樱魔法杖', '粉钻心语弩', '柔粉蔷薇盾'] 58 | ] 59 | }, 60 | equipArmors() { 61 | return [ 62 | ['瑶池仙绡羽衣', '广寒玉兔霜甲', '昆仑玉璧战袍', '白龙吐珠云裳', '九天玄女素绫', '瑶光星辰织锦', '冰魄银丝战衣', '凌霄琼华宝衣', '雪域神女雪绒', '云隐龙鳞轻铠'], 63 | ['翠竹幽兰轻衫', '碧落青藤云裳', '碧眼麒麟战衣', '青鸾翔翼织锦', '苍梧古木灵袍', '绿野仙踪羽衣', '灵蛇翠蔓软甲', '翡翠琉璃长裙', '松风竹影轻裘', '春水碧于天衣'], 64 | ['寒冰护甲衣', '碧波守护铠', '蓝玉冰心链甲', '苍穹蓝灵披风', '深海蛟龙鳞甲', '冰魄幽光战铠', '蓝蝶轻舞护腕', '银河之盾胸甲', '鲛人织梦护腿', '碧波凌波靴'], 65 | ['紫云织锦袍', '幽冥紫霜甲', '星河紫霞衣', '紫玉冰心链甲', '紫焰凤凰披风', '苍穹紫雷战铠', '紫莲幽光护腕', '紫晶凌霄战裙', '幽冥紫影护腿', '紫霄逐风靴'], 66 | ['金辉流光锦袍', '琥珀流光战衣', '黄土龙纹长袍', '日炎金鳞铠甲', '秋菊金缎华服', '蜜蜡黄绸云裳', '凤凰涅槃黄衫', '黄沙漫天披风', '金穗流光纱裙', '辉煌金羽战袍'], 67 | ['烈焰红莲战甲', '赤霄火凤云裳', '朱雀焚天织锦', '赤焰龙鳞宝衣', '血色蔷薇华服', '丹霞流光长袍', '炎阳炽烈战袍', '炽火红莲披风', '火舞凤凰羽衣', '红莲业火锦衣'], 68 | ['粉樱绮梦裳', '甜梦粉蝶衣', '蜜桃恋曲裙', '粉晶流光铠', '樱花恋歌袍', '柔粉蔷薇甲', '粉蝶翩翩袖', '甜梦羽织衣', '粉晶幻彩裙', '蜜桃梦境袍'] 69 | ] 70 | }, 71 | equipAccessories() { 72 | return [ 73 | ['瑶池白玉簪', '月华流光坠', '寒霜凝露链', '九天玄女玉佩', '云锦织梦镯', '龙涎润雪环', '白鹤衔珠珮', '昆仑雪莲花链', '瑶台仙露耳环', '银河织梦项链'], 74 | ['翠竹凝露簪', '碧泉幽兰链', '青藤绕梦镯', '翡翠灵叶耳环', '灵山仙草玉佩', '松柏长青戒', '翠影轻舞项链', '绿野仙踪手环', '碧波荡漾珠链', '春回大地玉珮'], 75 | ['碧海珊瑚簪', '冰魄幽蓝链', '深海珍珠耳环', '蓝田玉髓镯', '苍穹蓝宝坠', '鲛人泪滴珠', '碧波荡漾戒', '银河之心项链', '蓝蝶飞舞手环', '深海龙鳞珮'], 76 | ['紫霄流光戒', '幽冥紫蝶项链', '星河紫玉耳环', '紫玉冰心手链', '紫焰凤凰簪', '苍穹紫雷吊坠', '紫莲幽光发带', '紫晶破晓护符', '幽冥紫影指环', '紫霄凌虚玉佩'], 77 | ['金辉日冕簪', '琥珀流光链', '黄粱一梦镯', '皇天后土玉佩', '蜜蜡福瑞戒', '秋收万颗项链', '暖阳照耀耳环', '炎黄子孙玉珮', '金色麦田手环', '盛世繁华珠链'], 78 | ['赤焰凤凰翎', '血珀琉璃坠', '烈焰红宝石链', '朱雀之翼耳环', '红莲业火镯', '丹霄火凤戒', '玛瑙赤焰项链', '炽天使之泪珮', '绯红织锦手环', '火凤涅槃珠链'], 79 | ['粉晶梦蝶链', '樱花恋曲簪', '甜梦蔷薇戒', '蜜桃绮梦环', '粉蝶轻舞坠', '粉晶甜蜜链', '柔粉心语珥', '樱花绮梦镯', '蜜桃梦境簪', '粉蝶幻彩带'] 80 | ] 81 | }, 82 | equipSutras() { 83 | return [ 84 | ['白玉净瓶', '寒霜琉璃镜', '瑶池雪莲珠', '九天玄冰尺', '月华宝莲灯', '白云隐龙笛', '玉清昆仑扇', '净世白莲座', '银河落雪琴', '碧落瑶光盘'], 85 | ['翠玉葫芦', '青木长生杖', '碧落灵珠', '幽冥鬼藤鞭', '万木回春图', '绿绮琴音笛', '青鸾火凤羽扇', '翠影追魂剑', '草木皆兵符', '碧泉灵泉壶'], 86 | ['碧波神珠', '冰魄寒玉葫', '深海龙息珠', '苍穹蓝灵珠', '鲛人织梦灯', '银河落霜瓶', '蓝玉冰心镜', '寒冰净世莲', '碧波幽兰笛', '深海龙吟佩'], 87 | ['紫霄神雷珠', '幽冥紫蝶翼', '星河紫玉壶', '紫玉冰心镜', '紫焰凤凰翎', '苍穹紫雷鼎', '紫莲幽光轮', '紫晶破晓琴', '幽冥紫影幡', '紫霄凌虚印'], 88 | ['金蛟剪', '乾坤圈', '黄金玲珑塔', '戊己杏黄旗', '轩辕黄帝鼎', '镇妖伏魔镜', '落日熔金轮', '万寿无疆葫芦', '金翅大鹏羽扇', '地黄玄玉珠'], 89 | ['炽焰灵珠阵图', '火凤涅槃炉鼎', '红莲业火净世碑', '血玉轮回盘', '朱雀翔天翼', '烈焰焚天炉', '丹霄火域图', '赤龙炼魂珠', '火灵炽心镜', '九转炎灵祭坛'], 90 | ['粉樱梦幻笛', '甜心粉蝶壶', '蜜桃恋语镜', '粉晶流光珠', '柔粉绮梦石', '樱花纷飞扇', '甜梦绮罗盘', '蜜桃幻影灯', '粉蝶织梦琴', '粉樱守护符'] 91 | ] 92 | }, 93 | // 计算装备评分 94 | calculateEquipmentScore(dodge = 0, attack = 0, health = 0, critical = 0, defense = 0) { 95 | // 评分权重 96 | const weights = { 97 | attack: 1.5, // 攻击 98 | health: 1.0, // 气血 99 | defense: 1.2, // 防御 100 | critRate: 1.8, // 暴击 101 | dodgeRate: 1.6 //闪避 102 | } 103 | // 计算评分 104 | const score = ( 105 | dodge * weights.dodgeRate * 100 + 106 | attack * weights.attack + 107 | (health / 100) * weights.health + 108 | defense * weights.defense + 109 | critical * weights.critRate * 100 110 | ) 111 | return Math.floor(score) 112 | } 113 | } 114 | export default All -------------------------------------------------------------------------------- /src/plugins/game.js: -------------------------------------------------------------------------------- 1 | import { ElNotification } from 'element-plus' 2 | 3 | export const maxLv = 144 4 | 5 | export const gameNotifys = (data) => { 6 | ElNotification.closeAll() 7 | ElNotification(data) 8 | } 9 | 10 | export const levelNames = (level) => { 11 | const levelsPerStage = 9 12 | const stageIndex = Math.floor((level - 1) / levelsPerStage) 13 | const stageLevel = ((level - 1) % levelsPerStage) + 1 14 | const numberName = { 15 | 1: '一', 2: '二', 3: '三', 4: '四', 16 | 5: '五', 6: '六', 7: '七', 8: '八', 9: '九' 17 | } 18 | const stageNames = [ 19 | '筑基', '开光', '胎息', '辟谷', 20 | '金丹', '元婴', '出窍', '分神', 21 | '合体', '大乘', '渡劫', '地仙', 22 | '天仙', '金仙', '大罗金仙', '九天玄仙' 23 | ] 24 | if (level === 0) return '凡人' 25 | else if (level >= maxLv) return '九天玄仙九层' 26 | else return `${stageNames[stageIndex]}${numberName[stageLevel]}层` 27 | } 28 | 29 | export const dropdownTypeObject = { 30 | id: '时间', 31 | level: '境界', 32 | score: '评分', 33 | health: '气血', 34 | attack: '攻击', 35 | defense: '防御', 36 | critical: '暴击', 37 | dodge: '闪避', 38 | } 39 | export const dropdownType = Object.entries(dropdownTypeObject).map( 40 | ([type, name]) => ({ type, name }) 41 | ) 42 | 43 | export const genre = { 44 | sutra: '法器', 45 | armor: '护甲', 46 | weapon: '神兵', 47 | accessory: '灵宝', 48 | } 49 | 50 | export const isAPP = location.host == 'appassets.androidplatform.net' 51 | 52 | export const levels = { 53 | info: '黄阶', 54 | pink: '仙阶', 55 | danger: '神阶', 56 | purple: '天阶', 57 | primary: '地阶', 58 | success: '玄阶', 59 | warning: '帝阶', 60 | } 61 | 62 | export const propItemNames = { 63 | money: { name: '灵石', desc: '可以通过分解获得装备获得' }, 64 | flying: { name: '传送符', desc: '可以通过赠送礼物给NPC获得' }, 65 | rootBone: { name: '悟性丹', desc: '可以通过击败世界BOSS获得' }, 66 | qingyuan: { name: '情缘', desc: '可以通过赠送礼物给NPC获得' }, 67 | currency: { name: '鸿蒙石', desc: '可以通过击败世界BOSS获得' }, 68 | cultivateDan: { name: '培养丹', desc: '可以通过探索获得' }, 69 | strengtheningStone: { name: '炼器石', desc: '可以通过分解装备获得' }, 70 | } 71 | 72 | export const formatNumberToChineseUnit = (number) => { 73 | number = number > 0 ? Math.floor(number) : 0 74 | const units = [ 75 | '', 76 | '万', 77 | '亿', 78 | '兆', 79 | '京', 80 | '垓', 81 | '秭', 82 | '穰', 83 | '沟', 84 | '涧', 85 | '正', 86 | '载', 87 | '极', 88 | ] 89 | const bigTenThousand = window.BigInt(10000) 90 | let num = window.BigInt(number) 91 | let unitIndex = 0 92 | let additionalUnits = '' 93 | while (num >= bigTenThousand) { 94 | num /= bigTenThousand 95 | unitIndex++ 96 | if (unitIndex >= units.length - 1) { 97 | additionalUnits += '极' 98 | unitIndex = 0 99 | } 100 | } 101 | return num.toString() + units[unitIndex] + additionalUnits 102 | } 103 | 104 | export const smoothScrollToBottom = (element) => { 105 | const start = element.scrollTop 106 | const end = element.scrollHeight 107 | const duration = 300 108 | const startTime = performance.now() 109 | const scroll = () => { 110 | const currentTime = performance.now() 111 | const timeElapsed = currentTime - startTime 112 | const progress = Math.min(timeElapsed / duration, 1) 113 | element.scrollTop = start + (end - start) * easeInOutCubic(progress) 114 | if (progress < 1) window.requestAnimationFrame(scroll) 115 | } 116 | const easeInOutCubic = (t) => 117 | t < 0.5 ? 4 * t * t * t : 1 - Math.pow(-2 * t + 2, 3) / 2 118 | window.requestAnimationFrame(scroll) 119 | } 120 | -------------------------------------------------------------------------------- /src/plugins/minheap.js: -------------------------------------------------------------------------------- 1 | // 基于最小堆的优先队列实现 2 | class MinHeap { 3 | constructor() { 4 | // 初始化堆为空数组 5 | this.heap = [] 6 | } 7 | // 向堆中添加一个新节点 8 | add(node, priority) { 9 | // 将新节点和优先级添加到堆的末尾 10 | this.heap.push({ node, priority }) 11 | // 将新节点上浮到正确的位置以维护堆的性质 12 | this.bubbleUp(this.heap.length - 1) 13 | } 14 | // 上浮操作,将节点移动到正确的位置以维护堆的性质 15 | bubbleUp(index) { 16 | // 当前节点的父节点索引 17 | while (index > 0) { 18 | const parentIndex = Math.floor((index - 1) / 2) 19 | // 如果父节点的优先级小于等于当前节点的优先级,则堆的性质已经满足 20 | if (this.heap[parentIndex].priority <= this.heap[index].priority) break 21 | // 交换当前节点与父节点的位置 22 | [this.heap[parentIndex], this.heap[index]] = [this.heap[index], this.heap[parentIndex]] 23 | // 更新当前节点的索引为其父节点的索引 24 | index = parentIndex 25 | } 26 | } 27 | // 移除并返回堆中的最小节点(即优先级最高的节点) 28 | poll() { 29 | // 堆顶的最小节点 30 | const min = this.heap[0] 31 | // 从堆中移除最后一个节点并保存 32 | const end = this.heap.pop() 33 | // 如果堆中还有其他节点,则将最后一个节点移动到堆顶并进行下沉操作 34 | if (this.heap.length > 0) { 35 | this.heap[0] = end 36 | this.bubbleDown(0) 37 | } 38 | // 返回最小节点 39 | return min.node 40 | } 41 | // 下沉操作,将节点移动到正确的位置以维护堆的性质 42 | bubbleDown(index) { 43 | const length = this.heap.length 44 | const element = this.heap[index] 45 | while (true) { 46 | // 当前节点的左子节点和右子节点的索引 47 | let leftChildIndex = 2 * index + 1 48 | let rightChildIndex = 2 * index + 2 49 | let swapIndex = null 50 | // 如果左子节点存在且其优先级小于当前节点的优先级,则选择左子节点进行交换 51 | if (leftChildIndex < length) { 52 | if (this.heap[leftChildIndex].priority < element.priority) { 53 | swapIndex = leftChildIndex 54 | } 55 | } 56 | // 如果右子节点存在且其优先级小于当前节点或左子节点的优先级,则选择右子节点进行交换 57 | if (rightChildIndex < length) { 58 | if ( 59 | (swapIndex === null && this.heap[rightChildIndex].priority < element.priority) || 60 | (swapIndex !== null && this.heap[rightChildIndex].priority < this.heap[leftChildIndex].priority) 61 | ) swapIndex = rightChildIndex 62 | } 63 | // 如果没有需要交换的子节点,退出循环 64 | if (swapIndex === null) break 65 | // 交换当前节点与选择的子节点的位置 66 | [this.heap[index], this.heap[swapIndex]] = [this.heap[swapIndex], this.heap[index]] 67 | // 更新当前节点的索引为交换后子节点的索引 68 | index = swapIndex 69 | } 70 | } 71 | // 检查堆是否为空 72 | isEmpty() { 73 | return this.heap.length === 0 74 | } 75 | } 76 | 77 | export default MinHeap -------------------------------------------------------------------------------- /src/plugins/monster.js: -------------------------------------------------------------------------------- 1 | const monsters = { 2 | monster_Names(lv) { 3 | const names_a = [ 4 | '影魅狸奴', '幽谷灵蛇', '雾隐狐仙', '松间灵猴', '月影蝠妖', 5 | '山涧蛟童', '林涧鹿灵', '岩隙石精', '风鸣鹤怪', '翠竹蛙仙' 6 | ] 7 | const names_b = [ 8 | '青龙啸天', '白虎破晓', '朱雀焚翼', '玄武镇海', '麒麟踏瑞', 9 | '凤凰涅槃', '毕方炽焰', '貔貅吞金', '白泽知世', '狻猊御火' 10 | ] 11 | const names_c = [ 12 | '伏羲天帝', '女娲圣母', '昊天玉皇', '太上老君', '东华帝君', 13 | '西王母后', '神农炎帝', '轩辕黄帝', '瑶姬仙子', '真武大帝' 14 | ] 15 | const names_d = [ 16 | '混沌始元尊', '乾坤造物主', '宇宙创生神', '万灵始祖皇', '鸿蒙创世者', 17 | '无极造化君', '太虚衍化神', '元始天尊祖', '虚空造物圣', '界域开辟者' 18 | ] 19 | if (lv >= 1 && lv <= 19) { 20 | return names_a[Math.floor(Math.random() * names_a.length)] 21 | } else if (lv >= 20 && lv <= 49) { 22 | return names_b[Math.floor(Math.random() * names_b.length)] 23 | } else if (lv >= 50 && lv <= 100) { 24 | return names_c[Math.floor(Math.random() * names_c.length)] 25 | } else { 26 | return names_d[Math.floor(Math.random() * names_c.length)] 27 | } 28 | }, 29 | monster_Attack(lv) { 30 | if (lv <= 144) { 31 | return this.getRandomInt(50, 150) * lv 32 | } else { 33 | return this.getRandomInt(10000, 50000) * lv 34 | } 35 | }, 36 | monster_Health(lv) { 37 | if (lv <= 144) { 38 | return this.getRandomInt(100, 500) * lv 39 | } else { 40 | return this.getRandomInt(10000, 50000) * lv 41 | } 42 | }, 43 | monster_Defense(lv) { 44 | if (lv <= 144) { 45 | return this.getRandomInt(1, 15) * lv 46 | } else { 47 | return this.getRandomInt(500, 1000) * lv 48 | } 49 | }, 50 | monster_Criticalhitrate(lv) { 51 | if (lv <= 144) { 52 | return this.getRandomFloatInRange(0.001, 0.01) 53 | } else { 54 | return this.getRandomFloatInRange(0.1, 0.75) 55 | } 56 | }, 57 | getRandomInt(min, max) { 58 | min = Math.ceil(min) 59 | max = Math.floor(max) 60 | return Math.floor(Math.random() * (max - min + 1)) + min 61 | }, 62 | getRandomFloatInRange(min, max) { 63 | return Math.random() * (max - min) + min 64 | } 65 | } 66 | export default monsters -------------------------------------------------------------------------------- /src/plugins/npc.js: -------------------------------------------------------------------------------- 1 | const npc = { 2 | npcNames() { 3 | const names = [ 4 | '云渺仙子', 5 | '琉光幽姬', 6 | '烟霞仙子', 7 | '清韵灵姬', 8 | '碧落灵仙', 9 | '绮霞灵女', 10 | '瑶光雪姬', 11 | '琉璃雪姬', 12 | '幽篁雪姬', 13 | '雪舞灵姬', 14 | ] 15 | return names 16 | }, 17 | // 随机输出数组中的10个对象 18 | // getRandomObjects () { 19 | // const names = [ 20 | // '张雅琪', '李欣怡', '王芷若', '赵思涵', '刘梦琪', '陈语嫣', '周婧琪', '吴婉儿', '黄雨婷', '徐雪莹', 21 | // '孙诗涵', '高静琪', '何晓萱', '郑心怡', '梁梓萱', '谢梦瑶', '罗雨萱', '许芷萱', '冯可馨', '程芷若', 22 | // '蔡欣妍', '邓婉婷', '郭慧妍', '叶思敏', '马婧雯', '林雨欣', '苏若馨', '卢悦琳', '丁雅婷', '唐梦婷', 23 | // '萧语彤', '宋诗雅', '许晓蕾', '韩芷涵', '章欣悦', '沈静茹', '魏婉君', '姜雨薇', '秦梓涵', '陶思琪', 24 | // '袁婧涵', '蒋语嫣', '胡婉清', '余怡然', '陆梦洁', '钱芷若', '严雅静', '曹思颖', '江晓燕', '方雨欣' 25 | // ]; 26 | // const randomObjects = []; 27 | 28 | // for (let i = 0; i < 10; i++) { 29 | // const randomIndex = Math.floor(Math.random() * names.length); 30 | // randomObjects.push(names[randomIndex]); 31 | // } 32 | 33 | // return randomObjects; 34 | // } 35 | } 36 | 37 | export default npc 38 | -------------------------------------------------------------------------------- /src/plugins/router.js: -------------------------------------------------------------------------------- 1 | import map from '../views/mapExploration.vue' 2 | import boss from '../views/bossPage.vue' 3 | import home from '../views/homePage.vue' 4 | import index from '../views/indexPage.vue' 5 | import explore from '../views/explorePage.vue' 6 | import cultivate from '../views/cultivatePage.vue' 7 | import endlesstower from '../views/endlessPage.vue' 8 | import game from '../views/game/game.vue' 9 | import { createRouter, createWebHashHistory } from 'vue-router' 10 | 11 | const routes = [ 12 | { 13 | path: '/', 14 | name: 'index', 15 | meta: { 16 | keepAlive: false, 17 | }, 18 | component: index, 19 | }, 20 | { 21 | path: '/home', 22 | name: 'home', 23 | meta: { 24 | keepAlive: false, 25 | }, 26 | component: home, 27 | }, 28 | { 29 | path: '/cultivate', 30 | name: 'cultivate', 31 | meta: { 32 | keepAlive: false, 33 | }, 34 | component: cultivate, 35 | }, 36 | { 37 | path: '/map', 38 | name: 'map', 39 | meta: { 40 | keepAlive: false, 41 | }, 42 | component: map, 43 | }, 44 | { 45 | path: '/explore', 46 | name: 'explore', 47 | meta: { 48 | keepAlive: false, 49 | }, 50 | component: explore, 51 | }, 52 | { 53 | path: '/boss', 54 | name: 'boss', 55 | meta: { 56 | keepAlive: false, 57 | }, 58 | component: boss, 59 | }, 60 | { 61 | path: '/endlesstower', 62 | name: 'endlesstower', 63 | meta: { 64 | keepAlive: false, 65 | }, 66 | component: endlesstower, 67 | }, 68 | { 69 | path: '/game', 70 | name: 'game', 71 | meta: { 72 | keepAlive: false, 73 | }, 74 | component: game, 75 | }, 76 | ] 77 | const router = createRouter({ 78 | history: createWebHashHistory(), 79 | routes, 80 | }) 81 | 82 | export default router 83 | -------------------------------------------------------------------------------- /src/plugins/shop.js: -------------------------------------------------------------------------------- 1 | const shop = { 2 | drawPrize(lv) { 3 | const types = [ 4 | { type: 'weapon', data: this.equipWeapons() }, 5 | { type: 'armor', data: this.equipArmors() }, 6 | { type: 'accessory', data: this.equipAccessories() }, 7 | { type: 'sutra', data: this.equipSutras() } 8 | ] 9 | const genre = { sutra: '法器', armor: '护甲', weapon: '兵器', accessory: '灵宝' } 10 | const getAttribute = (type, lv, attribute) => { 11 | // 根据装备品质调整装备属性值 12 | const multiplier = 15 13 | const dodge = this.getRandomFloatInRange(0.02, 0.25) 14 | const Attack = this.getRandomInt(200, 1000) * lv 15 | const Health = this.getRandomInt(2000, 10000) * lv 16 | const defense = this.getRandomInt(200, 1000) * lv 17 | const CriticalHitrate = this.getRandomFloatInRange(0.02, 0.25) 18 | const attrs = { 19 | score: this.calculateEquipmentScore(dodge, Attack, Health, CriticalHitrate, defense), // 装备评分 20 | dodge: ['accessory', 'sutra'].includes(type) ? dodge : 0, 21 | attack: ['weapon', 'accessory', 'sutra'].includes(type) ? Attack * multiplier : 0, 22 | health: ['armor', 'accessory', 'sutra'].includes(type) ? Health * multiplier : 0, 23 | defense: ['armor', 'accessory', 'sutra'].includes(type) ? defense * multiplier : 0, 24 | critical: ['weapon', 'accessory', 'sutra'].includes(type) ? CriticalHitrate : 0 25 | } 26 | return attrs[attribute] 27 | } 28 | return types.map(({ type, data }) => ({ 29 | type, 30 | name: genre[type], 31 | data: data.flatMap((name) => ({ 32 | id: Date.now(), 33 | name, 34 | type, 35 | lock: true, 36 | level: lv, 37 | score: getAttribute(type, lv, 'score'), 38 | dodge: getAttribute(type, lv, 'dodge'), 39 | attack: getAttribute(type, lv, 'attack'), 40 | health: getAttribute(type, lv, 'health'), 41 | defense: getAttribute(type, lv, 'defense'), 42 | critical: getAttribute(type, lv, 'critical'), 43 | // 初始数据 44 | initial: { 45 | dodge: getAttribute(type, lv, 'dodge'), // 闪避率 46 | attack: getAttribute(type, lv, 'attack'), // 攻击力 47 | health: getAttribute(type, lv, 'health'), // 血量 48 | defense: getAttribute(type, lv, 'defense'), // 装备防御 49 | critical: getAttribute(type, lv, 'critical') // 暴击率 50 | }, 51 | quality: 'pink' 52 | })) 53 | })) 54 | }, 55 | equipWeapons() { 56 | return ['粉晶月刃剑', '樱花吹雪弓', '蔷薇缠绕鞭', '蜜桃梦境杖', '粉蝶幻光刃', '粉晶流光扇', '甜梦水晶枪', '粉樱魔法杖', '粉钻心语弩', '柔粉蔷薇盾'] 57 | }, 58 | equipArmors() { 59 | return ['粉樱绮梦裳', '甜梦粉蝶衣', '蜜桃恋曲裙', '粉晶流光铠', '樱花恋歌袍', '柔粉蔷薇甲', '粉蝶翩翩袖', '甜梦羽织衣', '粉晶幻彩裙', '蜜桃梦境袍'] 60 | }, 61 | equipAccessories() { 62 | return ['粉晶梦蝶链', '樱花恋曲簪', '甜梦蔷薇戒', '蜜桃绮梦环', '粉蝶轻舞坠', '粉晶甜蜜链', '柔粉心语珥', '樱花绮梦镯', '蜜桃梦境簪', '粉蝶幻彩带'] 63 | }, 64 | equipSutras() { 65 | return ['粉樱梦幻笛', '甜心粉蝶壶', '蜜桃恋语镜', '粉晶流光珠', '柔粉绮梦石', '樱花纷飞扇', '甜梦绮罗盘', '蜜桃幻影灯', '粉蝶织梦琴', '粉樱守护符'] 66 | }, 67 | getRandomInt(min, max) { 68 | min = Math.ceil(min) 69 | max = Math.floor(max) 70 | return Math.floor(Math.random() * (max - min + 1)) + min 71 | }, 72 | getRandomFloatInRange(min, max) { 73 | return Math.random() * (max - min) + min 74 | }, 75 | // 计算装备评分 76 | calculateEquipmentScore(dodge = 0, attack = 0, health = 0, critical = 0, defense = 0) { 77 | // 评分权重 78 | const weights = { 79 | attack: 1.5, // 攻击 80 | health: 1.0, // 气血 81 | defense: 1.2, // 防御 82 | critRate: 1.8, // 暴击 83 | dodgeRate: 1.6 //闪避 84 | } 85 | // 计算评分 86 | const score = ( 87 | dodge * weights.dodgeRate + 88 | attack * weights.attack + 89 | (health / 100) * weights.health + 90 | defense * weights.defense + 91 | critical * weights.critRate 92 | ) 93 | return Math.floor(score) 94 | } 95 | } 96 | 97 | export default shop -------------------------------------------------------------------------------- /src/plugins/store.js: -------------------------------------------------------------------------------- 1 | import { defineStore } from 'pinia' 2 | import crypto from '@/plugins/crypto' 3 | 4 | export const useMainStore = defineStore('main', { 5 | state: () => ({ 6 | // boss属性 7 | boss: { 8 | name: '', 9 | text: '', 10 | time: 0, 11 | desc: '', 12 | level: 0, 13 | dodge: 0, 14 | attack: 0, 15 | health: 0, 16 | conquer: false, 17 | defense: 0, 18 | critical: 0, 19 | maxhealth: 0, 20 | }, 21 | // 玩家属性 22 | player: { 23 | zc: false, 24 | age: 1, 25 | pet: {}, 26 | time: 0, 27 | name: '玩家', 28 | dark: false, 29 | npcs: [], 30 | wife: {}, 31 | pets: [], 32 | wifes: [], 33 | props: { 34 | money: 0, 35 | flying: 0, 36 | qingyuan: 0, 37 | rootBone: 0, 38 | currency: 0, 39 | cultivateDan: 0, 40 | strengtheningStone: 0, 41 | }, 42 | score: 0, 43 | level: 0, 44 | dodge: 0, 45 | points: 0, 46 | attack: 10, 47 | health: 100, 48 | critical: 0, 49 | defense: 10, 50 | taskNum: 0, 51 | version: 0.8, 52 | currency: 0, 53 | maxHealth: 100, 54 | inventory: [], 55 | isNewbie: false, 56 | shopData: [], 57 | equipment: { 58 | sutra: {}, 59 | armor: {}, 60 | weapon: {}, 61 | accessory: {}, 62 | }, 63 | achievement: { 64 | pet: [], 65 | monster: [], 66 | equipment: [], 67 | }, 68 | script: '', 69 | cultivation: 0, 70 | currentTitle: null, 71 | reincarnation: 0, 72 | maxCultivation: 100, 73 | backpackCapacity: 50, 74 | sellingEquipmentData: [], 75 | highestTowerFloor: 1, 76 | rewardedTowerFloors: [], 77 | nextGameTimes: { 78 | rps: null, 79 | dice: null, 80 | fortune: null, 81 | secretrealm: 0, 82 | gamblingStone: null, 83 | }, 84 | gameWins: 0, 85 | gameLosses: 0, 86 | checkinDays: 0, 87 | checkinStreak: 0, 88 | lastCheckinDate: null, 89 | fortuneTellingDate: null, 90 | checkedInToday: false, 91 | }, 92 | // 怪物信息 93 | monster: { 94 | name: '', 95 | // 气血 96 | health: 0, 97 | // 攻击 98 | attack: 0, 99 | // 防御 100 | defense: 0, 101 | // 闪避率 102 | dodge: 0, 103 | // 暴击 104 | critical: 0, 105 | }, 106 | mapData: { 107 | y: 0, 108 | x: 0, 109 | map: [], 110 | }, 111 | mapScroll: 0, 112 | fishingMap: [], 113 | }), 114 | persist: { 115 | key: 'vuex', 116 | paths: ['boss', 'player'], 117 | storage: localStorage, 118 | serializer: { 119 | serialize: (state) => { 120 | return JSON.stringify({ 121 | boss: crypto.encryption(state.boss), 122 | player: crypto.encryption(state.player), 123 | }) 124 | }, 125 | deserialize: (value) => { 126 | const state = JSON.parse(value) 127 | return { 128 | boss: crypto.decryption(state.boss), 129 | player: crypto.decryption(state.player), 130 | } 131 | }, 132 | }, 133 | }, 134 | }) 135 | -------------------------------------------------------------------------------- /src/views/bossPage.vue: -------------------------------------------------------------------------------- 1 | 27 | 28 | 275 | 276 | -------------------------------------------------------------------------------- /src/views/cultivatePage.vue: -------------------------------------------------------------------------------- 1 | 24 | 25 | 215 | 216 | -------------------------------------------------------------------------------- /src/views/game/Dicegame.vue: -------------------------------------------------------------------------------- 1 | 17 | 18 | 102 | 103 | -------------------------------------------------------------------------------- /src/views/game/SecretRealm.vue: -------------------------------------------------------------------------------- 1 | 29 | 30 | 159 | 160 | 246 | -------------------------------------------------------------------------------- /src/views/game/checkin.vue: -------------------------------------------------------------------------------- 1 | 17 | 18 | 70 | 71 | -------------------------------------------------------------------------------- /src/views/game/fortunetelling.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 41 | 42 | 76 | -------------------------------------------------------------------------------- /src/views/game/game.vue: -------------------------------------------------------------------------------- 1 | 40 | 41 | 105 | 106 | -------------------------------------------------------------------------------- /src/views/game/rock.vue: -------------------------------------------------------------------------------- 1 | 32 | 33 | 97 | 98 | 162 | -------------------------------------------------------------------------------- /src/views/game/toe.vue: -------------------------------------------------------------------------------- 1 | 18 | 19 | 150 | 151 | 210 | -------------------------------------------------------------------------------- /src/views/indexPage.vue: -------------------------------------------------------------------------------- 1 | 70 | 71 | 107 | 129 | -------------------------------------------------------------------------------- /vite.config.js: -------------------------------------------------------------------------------- 1 | import path from 'path' 2 | import vue from '@vitejs/plugin-vue' 3 | import Icons from 'unplugin-icons/vite' 4 | import { VitePWA } from 'vite-plugin-pwa' 5 | import AutoImport from 'unplugin-auto-import/vite' 6 | import Components from 'unplugin-vue-components/vite' 7 | import IconsResolver from 'unplugin-icons/resolver' 8 | import { defineConfig } from 'vite' 9 | import { ElementPlusResolver } from 'unplugin-vue-components/resolvers' 10 | import vitePluginBundleObfuscator from 'vite-plugin-bundle-obfuscator' 11 | 12 | export default defineConfig({ 13 | base: './', 14 | build: { 15 | minify: 'terser', 16 | rollupOptions: { 17 | output: { 18 | manualChunks: (id) => { 19 | if (id.includes('node_modules')) return 'vendor' 20 | }, 21 | chunkFileNames: 'assets/js/[name]-[hash].js', 22 | entryFileNames: 'assets/js/[name]-[hash].js', 23 | assetFileNames: (assetInfo) => { 24 | if (assetInfo.name && assetInfo.name.endsWith('.ico')) return '[name].[ext]' 25 | return 'assets/[ext]/[name]-[hash].[ext]' 26 | } 27 | } 28 | }, 29 | terserOptions: { 30 | compress: { 31 | drop_console: false, 32 | drop_debugger: true 33 | } 34 | } 35 | }, 36 | plugins: [ 37 | vue(), 38 | Icons({ 39 | autoInstall: true 40 | }), 41 | VitePWA({ 42 | manifest: { 43 | name: '我的文字修仙全靠刷', 44 | icons: [ 45 | { 46 | src: '/icons/icon-192x192.png', 47 | sizes: '192x192', 48 | type: 'image/png' 49 | }, 50 | { 51 | src: '/icons/icon-512x512.png', 52 | sizes: '512x512', 53 | type: 'image/png' 54 | } 55 | ], 56 | short_name: '文字修仙', 57 | description: '文字游戏: 我的文字修仙全靠刷', 58 | theme_color: '#4d4d4d' 59 | }, 60 | devOptions: { 61 | enabled: true 62 | }, 63 | registerType: 'autoUpdate' 64 | }), 65 | AutoImport({ 66 | resolvers: [ 67 | IconsResolver({ 68 | prefix: 'Icon' 69 | }), 70 | ElementPlusResolver() 71 | ] 72 | }), 73 | Components({ 74 | resolvers: [ 75 | IconsResolver({ 76 | enabledCollections: ['ep'] 77 | }), 78 | ElementPlusResolver() 79 | ] 80 | }), 81 | vitePluginBundleObfuscator({ 82 | log: false, 83 | enable: true, 84 | options: { 85 | log: false, 86 | compact: true, 87 | stringArray: true, 88 | renameGlobals: false, 89 | selfDefending: false, 90 | debugProtection: false, 91 | rotateStringArray: true, 92 | deadCodeInjection: false, 93 | stringArrayEncoding: ['none'], 94 | disableConsoleOutput: true, 95 | stringArrayThreshold: 0.75, 96 | controlFlowFlattening: false, 97 | unicodeEscapeSequence: true, 98 | identifierNamesGenerator: 'hexadecimal' 99 | }, 100 | excludes: ['router.js'], 101 | autoExcludeNodeModules: true 102 | }) 103 | ], 104 | resolve: { 105 | alias: { 106 | '@': path.resolve(__dirname, 'src') 107 | } 108 | }, 109 | logLevel: 'error' 110 | }) 111 | --------------------------------------------------------------------------------