@jeik/dingtalk-connector 0.8.21-fix1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +686 -0
- package/LICENSE +21 -0
- package/README.en.md +181 -0
- package/README.md +221 -0
- package/bin/dingtalk-connector.js +858 -0
- package/bin/wizard-config.mjs +110 -0
- package/dist/accounts-BAzdqkAV.mjs +268 -0
- package/dist/accounts-BQptOmgB.mjs +2 -0
- package/dist/chunk-upload-BBQgGtcZ.mjs +193 -0
- package/dist/chunk-upload-DaLXXZH3.mjs +2 -0
- package/dist/common-C8pYKU_y.mjs +2 -0
- package/dist/common-Dt9n6fQN.mjs +101 -0
- package/dist/connection-DHHFFNQJ.mjs +423 -0
- package/dist/entry-bundled.d.mts +16 -0
- package/dist/entry-bundled.mjs +31 -0
- package/dist/game-xiyou-CqHt-6Q1.mjs +4271 -0
- package/dist/gateway-methods-C4tcgI7P.mjs +771 -0
- package/dist/gateway-methods-Ci31A3vg.mjs +2 -0
- package/dist/http-client-CpnJHB89.mjs +2 -0
- package/dist/http-client-DFWZgO1n.mjs +33 -0
- package/dist/index.d.mts +193 -0
- package/dist/index.mjs +45 -0
- package/dist/logger-BmJkQkm1.mjs +2 -0
- package/dist/logger-mZ9OSbmD.mjs +58 -0
- package/dist/media-C_SVin7s.mjs +2 -0
- package/dist/media-cz72EVS3.mjs +509 -0
- package/dist/message-handler-DESzFFDc.mjs +1971 -0
- package/dist/messaging-B6l1sRvX.mjs +1044 -0
- package/dist/runtime-DUgpo5zC.mjs +1422 -0
- package/dist/session-DJ4jYqPv.mjs +114 -0
- package/dist/utils-Bjh4r_qS.mjs +4 -0
- package/dist/utils-CIfI_3Jh.mjs +63 -0
- package/dist/utils-legacy-CALCPP1t.mjs +230 -0
- package/dist/utils-legacy-CFYDBM4r.mjs +3 -0
- package/docs/DEAP_AGENT_GUIDE.en.md +115 -0
- package/docs/DEAP_AGENT_GUIDE.md +115 -0
- package/docs/DINGTALK_MANUAL_SETUP.md +50 -0
- package/docs/MULTI_AGENT_SETUP.md +306 -0
- package/docs/RELEASE_NOTES_V0.7.10.md +40 -0
- package/docs/RELEASE_NOTES_V0.7.2.md +143 -0
- package/docs/RELEASE_NOTES_V0.7.3.md +149 -0
- package/docs/RELEASE_NOTES_V0.7.4.md +206 -0
- package/docs/RELEASE_NOTES_V0.7.5.md +267 -0
- package/docs/RELEASE_NOTES_V0.7.6.md +219 -0
- package/docs/RELEASE_NOTES_V0.7.7.md +122 -0
- package/docs/RELEASE_NOTES_V0.7.8.md +101 -0
- package/docs/RELEASE_NOTES_V0.7.9.md +65 -0
- package/docs/RELEASE_NOTES_V0.8.0.md +53 -0
- package/docs/RELEASE_NOTES_V0.8.1.md +47 -0
- package/docs/RELEASE_NOTES_V0.8.10.md +49 -0
- package/docs/RELEASE_NOTES_V0.8.11.md +51 -0
- package/docs/RELEASE_NOTES_V0.8.12.md +63 -0
- package/docs/RELEASE_NOTES_V0.8.13-beta.0.md +69 -0
- package/docs/RELEASE_NOTES_V0.8.13.md +62 -0
- package/docs/RELEASE_NOTES_V0.8.14.md +86 -0
- package/docs/RELEASE_NOTES_V0.8.16.md +40 -0
- package/docs/RELEASE_NOTES_V0.8.17.md +87 -0
- package/docs/RELEASE_NOTES_V0.8.18.md +64 -0
- package/docs/RELEASE_NOTES_V0.8.19.md +62 -0
- package/docs/RELEASE_NOTES_V0.8.2.md +55 -0
- package/docs/RELEASE_NOTES_V0.8.20.md +49 -0
- package/docs/RELEASE_NOTES_V0.8.3.md +63 -0
- package/docs/RELEASE_NOTES_V0.8.4.md +45 -0
- package/docs/RELEASE_NOTES_V0.8.7.md +49 -0
- package/docs/RELEASE_NOTES_V0.8.8.md +63 -0
- package/docs/RELEASE_NOTES_V0.8.9.md +81 -0
- package/docs/RELEASE_NOTES_v0.7.0.md +142 -0
- package/docs/RELEASE_NOTES_v0.7.1.md +74 -0
- package/docs/TROUBLESHOOTING.md +122 -0
- package/index.ts +77 -0
- package/openclaw.plugin.json +551 -0
- package/package.json +147 -0
- package/skills/dingtalk-channel-rules/SKILL.md +91 -0
- package/skills/dingtalk-troubleshoot/SKILL.md +93 -0
- package/skills/dws-cli/SKILL.md +129 -0
- package/skills/dws-cli/references/error-codes.md +95 -0
- package/skills/dws-cli/references/field-rules.md +105 -0
- package/skills/dws-cli/references/global-reference.md +104 -0
- package/skills/dws-cli/references/intent-guide.md +114 -0
- package/skills/dws-cli/references/products/aitable.md +452 -0
- package/skills/dws-cli/references/products/attendance.md +93 -0
- package/skills/dws-cli/references/products/calendar.md +217 -0
- package/skills/dws-cli/references/products/chat.md +292 -0
- package/skills/dws-cli/references/products/contact.md +108 -0
- package/skills/dws-cli/references/products/ding.md +57 -0
- package/skills/dws-cli/references/products/report.md +162 -0
- package/skills/dws-cli/references/products/simple.md +128 -0
- package/skills/dws-cli/references/products/todo.md +138 -0
- package/skills/dws-cli/references/products/workbench.md +39 -0
- package/skills/dws-cli/references/recovery-guide.md +94 -0
- package/src/channel.ts +588 -0
- package/src/config/accounts.ts +242 -0
- package/src/config/schema.ts +180 -0
- package/src/core/connection.ts +741 -0
- package/src/core/message-handler.ts +1788 -0
- package/src/core/provider.ts +111 -0
- package/src/core/state.ts +54 -0
- package/src/device-auth-config.ts +14 -0
- package/src/device-auth.ts +197 -0
- package/src/directory.ts +95 -0
- package/src/docs.ts +293 -0
- package/src/game-xiyou/achievement-engine.ts +252 -0
- package/src/game-xiyou/bounty-system.ts +315 -0
- package/src/game-xiyou/commands.ts +223 -0
- package/src/game-xiyou/drop-engine.ts +241 -0
- package/src/game-xiyou/encounter-system.ts +135 -0
- package/src/game-xiyou/escape-engine.ts +164 -0
- package/src/game-xiyou/exp-calculator.ts +139 -0
- package/src/game-xiyou/index.ts +479 -0
- package/src/game-xiyou/level-system.ts +91 -0
- package/src/game-xiyou/monster-pool.ts +180 -0
- package/src/game-xiyou/pity-counter.ts +114 -0
- package/src/game-xiyou/random-event-engine.ts +648 -0
- package/src/game-xiyou/renderer.ts +679 -0
- package/src/game-xiyou/storage.ts +218 -0
- package/src/game-xiyou/treasure-system.ts +105 -0
- package/src/game-xiyou/types.ts +582 -0
- package/src/game-xiyou/uid-resolver.ts +49 -0
- package/src/gateway-methods.ts +740 -0
- package/src/onboarding.ts +553 -0
- package/src/policy.ts +32 -0
- package/src/probe.ts +210 -0
- package/src/reply-dispatcher.ts +874 -0
- package/src/runtime.ts +32 -0
- package/src/sdk/helpers.ts +322 -0
- package/src/sdk/types.ts +519 -0
- package/src/secret-input.ts +19 -0
- package/src/services/media/audio.ts +54 -0
- package/src/services/media/chunk-upload.ts +296 -0
- package/src/services/media/common.ts +155 -0
- package/src/services/media/file.ts +75 -0
- package/src/services/media/image.ts +81 -0
- package/src/services/media/index.ts +10 -0
- package/src/services/media/video.ts +162 -0
- package/src/services/media.ts +1143 -0
- package/src/services/messaging/card.ts +604 -0
- package/src/services/messaging/index.ts +18 -0
- package/src/services/messaging/mentions.ts +267 -0
- package/src/services/messaging/send.ts +141 -0
- package/src/services/messaging.ts +1191 -0
- package/src/services/reply-markers.ts +55 -0
- package/src/targets.ts +45 -0
- package/src/types/index.ts +59 -0
- package/src/types/pdf-parse.d.ts +3 -0
- package/src/utils/agent.ts +63 -0
- package/src/utils/async.ts +51 -0
- package/src/utils/constants.ts +27 -0
- package/src/utils/http-client.ts +38 -0
- package/src/utils/index.ts +8 -0
- package/src/utils/logger.ts +78 -0
- package/src/utils/session.ts +147 -0
- package/src/utils/token.ts +93 -0
- package/src/utils/utils-legacy.ts +454 -0
- package/tsconfig.json +20 -0
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* JSON 持久化层
|
|
3
|
+
*
|
|
4
|
+
* 所有养成数据存储在 ~/.dingtalk-connector/gamification/ 目录下,
|
|
5
|
+
* 按 UID 哈希分文件存储,支持 profile / collection / history 三类数据。
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import * as fs from 'fs';
|
|
9
|
+
import * as path from 'path';
|
|
10
|
+
import * as os from 'os';
|
|
11
|
+
import { createHmac } from 'crypto';
|
|
12
|
+
import type {
|
|
13
|
+
UserProfile, UserCollection, UserHistory, GamificationSettings, PityCounters,
|
|
14
|
+
BountyHistory, ActiveEventState, EventStats,
|
|
15
|
+
} from './types.ts';
|
|
16
|
+
import { createDefaultBountyHistory } from './bounty-system.ts';
|
|
17
|
+
import { createDefaultActiveEventState, createDefaultEventStats } from './random-event-engine.ts';
|
|
18
|
+
|
|
19
|
+
const STORAGE_DIR = path.join(os.homedir(), '.dingtalk-connector', 'gamification');
|
|
20
|
+
const CHECKSUM_SECRET = 'xiyou-hmac-secret-2026';
|
|
21
|
+
|
|
22
|
+
function ensureStorageDir(): void {
|
|
23
|
+
if (!fs.existsSync(STORAGE_DIR)) {
|
|
24
|
+
fs.mkdirSync(STORAGE_DIR, { recursive: true });
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function getProfilePath(uidHash: string): string {
|
|
29
|
+
return path.join(STORAGE_DIR, `profile-${uidHash}.json`);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function getCollectionPath(uidHash: string): string {
|
|
33
|
+
return path.join(STORAGE_DIR, `collection-${uidHash}.json`);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function getHistoryPath(uidHash: string): string {
|
|
37
|
+
return path.join(STORAGE_DIR, `history-${uidHash}.json`);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// ============ Checksum ============
|
|
41
|
+
|
|
42
|
+
function computeChecksum(profile: Omit<UserProfile, 'checksum'>): string {
|
|
43
|
+
const payload = `${profile.uidHash}:${profile.totalExp}:${profile.level}:${profile.totalOperations}`;
|
|
44
|
+
return createHmac('sha256', CHECKSUM_SECRET).update(payload).digest('hex').slice(0, 32);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export function verifyChecksum(profile: UserProfile): boolean {
|
|
48
|
+
const expected = computeChecksum(profile);
|
|
49
|
+
return profile.checksum === expected;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// ============ Profile ============
|
|
53
|
+
|
|
54
|
+
function createDefaultProfile(uidHash: string): UserProfile {
|
|
55
|
+
const defaultSettings: GamificationSettings = {
|
|
56
|
+
enabled: false,
|
|
57
|
+
showDropAnimation: true,
|
|
58
|
+
muteNormalDrops: false,
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
const defaultPity: PityCounters = {
|
|
62
|
+
sinceLastRare: 0,
|
|
63
|
+
sinceLastEpic: 0,
|
|
64
|
+
sinceLastLegendary: 0,
|
|
65
|
+
totalDropsWithoutShiny: 0,
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
const profile: Omit<UserProfile, 'checksum'> = {
|
|
69
|
+
uidHash,
|
|
70
|
+
level: 1,
|
|
71
|
+
title: '凡人',
|
|
72
|
+
totalExp: 0,
|
|
73
|
+
totalOperations: 0,
|
|
74
|
+
currentCombo: 0,
|
|
75
|
+
maxCombo: 0,
|
|
76
|
+
consecutiveSignInDays: 0,
|
|
77
|
+
lastSignInDate: '',
|
|
78
|
+
totalRecoveries: 0,
|
|
79
|
+
consecutiveFailures: 0,
|
|
80
|
+
productUsage: {},
|
|
81
|
+
pityCounters: defaultPity,
|
|
82
|
+
buffs: [],
|
|
83
|
+
settings: defaultSettings,
|
|
84
|
+
encounters: [],
|
|
85
|
+
unlockedAchievements: [],
|
|
86
|
+
treasures: [],
|
|
87
|
+
consumedTreasures: [],
|
|
88
|
+
createdAt: Date.now(),
|
|
89
|
+
// v2 字段
|
|
90
|
+
escapeHistory: {},
|
|
91
|
+
totalEscapes: 0,
|
|
92
|
+
dailyBounty: null,
|
|
93
|
+
bountyHistory: createDefaultBountyHistory(),
|
|
94
|
+
activeEvents: createDefaultActiveEventState(),
|
|
95
|
+
eventStats: createDefaultEventStats(),
|
|
96
|
+
eventHistory: [],
|
|
97
|
+
};
|
|
98
|
+
|
|
99
|
+
return { ...profile, checksum: computeChecksum(profile) };
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
export function loadProfile(uidHash: string): UserProfile {
|
|
103
|
+
ensureStorageDir();
|
|
104
|
+
const filePath = getProfilePath(uidHash);
|
|
105
|
+
|
|
106
|
+
if (!fs.existsSync(filePath)) {
|
|
107
|
+
const profile = createDefaultProfile(uidHash);
|
|
108
|
+
saveProfile(profile);
|
|
109
|
+
return profile;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
try {
|
|
113
|
+
const raw = fs.readFileSync(filePath, 'utf-8');
|
|
114
|
+
const profile = JSON.parse(raw) as UserProfile;
|
|
115
|
+
return migrateProfile(profile);
|
|
116
|
+
} catch {
|
|
117
|
+
const profile = createDefaultProfile(uidHash);
|
|
118
|
+
saveProfile(profile);
|
|
119
|
+
return profile;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* 补全旧版本 profile 中缺失的 v2 字段,确保向后兼容
|
|
125
|
+
*/
|
|
126
|
+
function migrateProfile(profile: UserProfile): UserProfile {
|
|
127
|
+
let migrated = false;
|
|
128
|
+
|
|
129
|
+
if (!profile.escapeHistory) { profile.escapeHistory = {}; migrated = true; }
|
|
130
|
+
if (profile.totalEscapes == null) { profile.totalEscapes = 0; migrated = true; }
|
|
131
|
+
if (profile.dailyBounty === undefined) { profile.dailyBounty = null; migrated = true; }
|
|
132
|
+
if (!profile.bountyHistory) { profile.bountyHistory = createDefaultBountyHistory(); migrated = true; }
|
|
133
|
+
if (!profile.activeEvents) { profile.activeEvents = createDefaultActiveEventState(); migrated = true; }
|
|
134
|
+
if (!profile.eventStats) { profile.eventStats = createDefaultEventStats(); migrated = true; }
|
|
135
|
+
if (!profile.eventHistory) { profile.eventHistory = []; migrated = true; }
|
|
136
|
+
|
|
137
|
+
if (migrated) {
|
|
138
|
+
saveProfile(profile);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
return profile;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
export function saveProfile(profile: UserProfile): void {
|
|
145
|
+
ensureStorageDir();
|
|
146
|
+
const withChecksum: UserProfile = {
|
|
147
|
+
...profile,
|
|
148
|
+
checksum: computeChecksum(profile),
|
|
149
|
+
};
|
|
150
|
+
const filePath = getProfilePath(profile.uidHash);
|
|
151
|
+
fs.writeFileSync(filePath, JSON.stringify(withChecksum, null, 2), 'utf-8');
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// ============ Collection ============
|
|
155
|
+
|
|
156
|
+
function createDefaultCollection(uidHash: string): UserCollection {
|
|
157
|
+
return { uidHash, entries: [] };
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
export function loadCollection(uidHash: string): UserCollection {
|
|
161
|
+
ensureStorageDir();
|
|
162
|
+
const filePath = getCollectionPath(uidHash);
|
|
163
|
+
|
|
164
|
+
if (!fs.existsSync(filePath)) {
|
|
165
|
+
const collection = createDefaultCollection(uidHash);
|
|
166
|
+
saveCollection(collection);
|
|
167
|
+
return collection;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
try {
|
|
171
|
+
const raw = fs.readFileSync(filePath, 'utf-8');
|
|
172
|
+
return JSON.parse(raw) as UserCollection;
|
|
173
|
+
} catch {
|
|
174
|
+
const collection = createDefaultCollection(uidHash);
|
|
175
|
+
saveCollection(collection);
|
|
176
|
+
return collection;
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
export function saveCollection(collection: UserCollection): void {
|
|
181
|
+
ensureStorageDir();
|
|
182
|
+
const filePath = getCollectionPath(collection.uidHash);
|
|
183
|
+
fs.writeFileSync(filePath, JSON.stringify(collection, null, 2), 'utf-8');
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
// ============ History ============
|
|
187
|
+
|
|
188
|
+
const MAX_HISTORY_RECORDS = 500;
|
|
189
|
+
|
|
190
|
+
function createDefaultHistory(uidHash: string): UserHistory {
|
|
191
|
+
return { uidHash, records: [] };
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
export function loadHistory(uidHash: string): UserHistory {
|
|
195
|
+
ensureStorageDir();
|
|
196
|
+
const filePath = getHistoryPath(uidHash);
|
|
197
|
+
|
|
198
|
+
if (!fs.existsSync(filePath)) {
|
|
199
|
+
return createDefaultHistory(uidHash);
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
try {
|
|
203
|
+
const raw = fs.readFileSync(filePath, 'utf-8');
|
|
204
|
+
return JSON.parse(raw) as UserHistory;
|
|
205
|
+
} catch {
|
|
206
|
+
return createDefaultHistory(uidHash);
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
export function saveHistory(history: UserHistory): void {
|
|
211
|
+
ensureStorageDir();
|
|
212
|
+
// 只保留最近 500 条
|
|
213
|
+
if (history.records.length > MAX_HISTORY_RECORDS) {
|
|
214
|
+
history.records = history.records.slice(-MAX_HISTORY_RECORDS);
|
|
215
|
+
}
|
|
216
|
+
const filePath = getHistoryPath(history.uidHash);
|
|
217
|
+
fs.writeFileSync(filePath, JSON.stringify(history, null, 2), 'utf-8');
|
|
218
|
+
}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 法宝系统
|
|
3
|
+
*
|
|
4
|
+
* 等级 ≥ 5(天兵)后解锁。法宝来源于神仙赐宝和特殊成就奖励。
|
|
5
|
+
* 一次性法宝通过命令使用,永久法宝自动生效。
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import type { UserProfile, Treasure, Buff } from './types.ts';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* 法宝数据(内联,导出供 encounter-system 引用)
|
|
12
|
+
*/
|
|
13
|
+
export const TREASURES_DATA: Treasure[] = [
|
|
14
|
+
{ id: "jintouyun", name: "筋斗云", source: "菩提祖师赐宝", description: "连击加成额外 +0.5", effect: "comboBonus", value: 0.5, consumable: false },
|
|
15
|
+
{ id: "jingping", name: "净瓶", source: "观音菩萨赐宝", description: "recovery 成功时额外 +5 修行值", effect: "expMultiplier", value: 1.1, consumable: false },
|
|
16
|
+
{ id: "zijinhulu", name: "紫金葫芦", source: "太上老君赐宝", description: "每日额外 1 次掉落机会", effect: "extraDrop", value: 1, consumable: false },
|
|
17
|
+
{ id: "pantao", name: "蟠桃", source: "太白金星赐宝", description: "使用后立即 +50 修行值", effect: "instantExp", value: 50, consumable: true },
|
|
18
|
+
{ id: "qiankunquan", name: "乾坤圈", source: "哪吒赐宝", description: "闪光概率 +0.05%", effect: "shinyRateBonus", value: 0.0005, consumable: false },
|
|
19
|
+
{ id: "sanjiandao", name: "三尖两刃刀", source: "二郎真君赐宝", description: "CLI 错误自动重试 +1 次", effect: "cliRetry", value: 1, consumable: false },
|
|
20
|
+
{ id: "linglongta", name: "玲珑宝塔", source: "托塔天王赐宝", description: "普通掉落 20% 概率升级为精良", effect: "normalUpgrade", value: 0.2, consumable: false },
|
|
21
|
+
{ id: "renshenguo", name: "人参果", source: "镇元大仙赐宝", description: "使用后立即 +200 修行值", effect: "instantExp", value: 200, consumable: true },
|
|
22
|
+
{ id: "dinghaishenzhen", name: "定海神针", source: "成就「齐天大圣」解锁", description: "所有掉落率 +1%", effect: "allRateBonus", value: 0.01, consumable: false },
|
|
23
|
+
{ id: "jingguzhou", name: "紧箍咒", source: "成就「西天取经」解锁", description: "保底计数器速度 ×1.5", effect: "pitySpeed", value: 1.5, consumable: false },
|
|
24
|
+
{ id: "bashanshan", name: "芭蕉扇", source: "收服铁扇公主后概率获得", description: "连续签到奖励 ×2", effect: "signInMultiplier", value: 2, consumable: false },
|
|
25
|
+
{ id: "zhaoyaojing", name: "照妖镜", source: "收服全部精良妖怪后解锁", description: "掉落时预览下一次的品质", effect: "previewNextQuality", value: 1, consumable: false },
|
|
26
|
+
];
|
|
27
|
+
|
|
28
|
+
const allTreasures: Treasure[] = TREASURES_DATA;
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* 根据 ID 查找法宝
|
|
32
|
+
*/
|
|
33
|
+
export function getTreasureById(treasureId: string): Treasure | undefined {
|
|
34
|
+
return allTreasures.find(t => t.id === treasureId);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* 获取用户拥有的法宝列表(含详情)
|
|
39
|
+
*/
|
|
40
|
+
export function getUserTreasures(profile: UserProfile): Treasure[] {
|
|
41
|
+
return profile.treasures
|
|
42
|
+
.map(id => getTreasureById(id))
|
|
43
|
+
.filter((t): t is Treasure => t !== undefined);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* 获取用户可使用的一次性法宝
|
|
48
|
+
*/
|
|
49
|
+
export function getConsumableTreasures(profile: UserProfile): Treasure[] {
|
|
50
|
+
return getUserTreasures(profile).filter(
|
|
51
|
+
t => t.consumable && !profile.consumedTreasures.includes(t.id)
|
|
52
|
+
);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* 使用一次性法宝
|
|
57
|
+
*
|
|
58
|
+
* @returns 使用结果描述,或 null(法宝不存在/已使用/不可消耗)
|
|
59
|
+
*/
|
|
60
|
+
export function consumeTreasure(
|
|
61
|
+
profile: UserProfile,
|
|
62
|
+
treasureName: string
|
|
63
|
+
): { treasure: Treasure; expGained: number; message: string } | null {
|
|
64
|
+
// 按名称查找法宝
|
|
65
|
+
const treasure = allTreasures.find(t => t.name === treasureName);
|
|
66
|
+
if (!treasure) return null;
|
|
67
|
+
|
|
68
|
+
// 检查用户是否拥有
|
|
69
|
+
if (!profile.treasures.includes(treasure.id)) return null;
|
|
70
|
+
|
|
71
|
+
// 检查是否可消耗
|
|
72
|
+
if (!treasure.consumable) return null;
|
|
73
|
+
|
|
74
|
+
// 检查是否已使用
|
|
75
|
+
if (profile.consumedTreasures.includes(treasure.id)) return null;
|
|
76
|
+
|
|
77
|
+
// 标记为已使用
|
|
78
|
+
profile.consumedTreasures.push(treasure.id);
|
|
79
|
+
|
|
80
|
+
// 应用效果
|
|
81
|
+
let expGained = 0;
|
|
82
|
+
let message = '';
|
|
83
|
+
|
|
84
|
+
if (treasure.effect === 'instantExp') {
|
|
85
|
+
expGained = treasure.value;
|
|
86
|
+
profile.totalExp += expGained;
|
|
87
|
+
message = `修行值 +${expGained}`;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
return { treasure, expGained, message };
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* 检查是否有额外掉落机会(紫金葫芦效果)
|
|
95
|
+
*/
|
|
96
|
+
export function hasExtraDropChance(profile: UserProfile): boolean {
|
|
97
|
+
return profile.buffs.some(b => b.effect === 'extraDrop');
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* 检查是否有品质预览能力(照妖镜效果)
|
|
102
|
+
*/
|
|
103
|
+
export function hasQualityPreview(profile: UserProfile): boolean {
|
|
104
|
+
return profile.buffs.some(b => b.effect === 'previewNextQuality');
|
|
105
|
+
}
|