steamsheep-ts-game-engine 1.0.0
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/README.md +1087 -0
- package/dist/core/index.d.mts +328 -0
- package/dist/core/index.d.ts +328 -0
- package/dist/core/index.js +220 -0
- package/dist/core/index.js.map +1 -0
- package/dist/core/index.mjs +195 -0
- package/dist/core/index.mjs.map +1 -0
- package/dist/index.d.mts +10 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.js +1196 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +1160 -0
- package/dist/index.mjs.map +1 -0
- package/dist/state/index.d.mts +110 -0
- package/dist/state/index.d.ts +110 -0
- package/dist/state/index.js +479 -0
- package/dist/state/index.js.map +1 -0
- package/dist/state/index.mjs +476 -0
- package/dist/state/index.mjs.map +1 -0
- package/dist/store-BP5bpjRr.d.ts +327 -0
- package/dist/store-BeEHel1o.d.mts +327 -0
- package/dist/systems/index.d.mts +318 -0
- package/dist/systems/index.d.ts +318 -0
- package/dist/systems/index.js +347 -0
- package/dist/systems/index.js.map +1 -0
- package/dist/systems/index.mjs +341 -0
- package/dist/systems/index.mjs.map +1 -0
- package/dist/types-CZueoTHl.d.mts +464 -0
- package/dist/types-CZueoTHl.d.ts +464 -0
- package/dist/ui/index.d.mts +56 -0
- package/dist/ui/index.d.ts +56 -0
- package/dist/ui/index.js +412 -0
- package/dist/ui/index.js.map +1 -0
- package/dist/ui/index.mjs +407 -0
- package/dist/ui/index.mjs.map +1 -0
- package/package.json +76 -0
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
// core/messages.ts
|
|
4
|
+
var SystemMessages = {
|
|
5
|
+
/** 资源不足提示 */
|
|
6
|
+
NOT_ENOUGH_RESOURCES: "sys:not_enough_resources",
|
|
7
|
+
/** 条件不满足提示 */
|
|
8
|
+
REQUIREMENT_NOT_MET: "sys:requirement_not_met",
|
|
9
|
+
/** 操作成功提示 */
|
|
10
|
+
ACTION_SUCCESS: "sys:action_success",
|
|
11
|
+
/** 时间回溯成功提示 */
|
|
12
|
+
UNDO_SUCCESS: "sys:undo_success"
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
// core/constants.ts
|
|
16
|
+
var ENGINE_VERSION = "1.0.0";
|
|
17
|
+
var DEFAULT_CONFIG = {
|
|
18
|
+
/** 默认存档键名 */
|
|
19
|
+
DEFAULT_SAVE_KEY: "game-save",
|
|
20
|
+
/** 最大日志条数 */
|
|
21
|
+
MAX_LOG_ENTRIES: 50,
|
|
22
|
+
/** 最大历史快照数 */
|
|
23
|
+
MAX_HISTORY_SNAPSHOTS: 20,
|
|
24
|
+
/** 飘字显示时长(毫秒) */
|
|
25
|
+
TOAST_DURATION: 3e3
|
|
26
|
+
};
|
|
27
|
+
var LOG_TYPE_COLORS = {
|
|
28
|
+
info: "#3b82f6",
|
|
29
|
+
success: "#10b981",
|
|
30
|
+
warn: "#f59e0b",
|
|
31
|
+
error: "#ef4444",
|
|
32
|
+
result: "#6366f1"
|
|
33
|
+
};
|
|
34
|
+
var DEFAULT_STATS = {
|
|
35
|
+
/** 默认生命值 */
|
|
36
|
+
DEFAULT_HP: 100,
|
|
37
|
+
/** 默认金币 */
|
|
38
|
+
DEFAULT_GOLD: 0
|
|
39
|
+
};
|
|
40
|
+
var TIME_CONSTANTS = {
|
|
41
|
+
/** 一天的小时数 */
|
|
42
|
+
HOURS_PER_DAY: 24,
|
|
43
|
+
/** 早晨开始时间 */
|
|
44
|
+
MORNING_START: 6,
|
|
45
|
+
/** 中午开始时间 */
|
|
46
|
+
NOON_START: 12,
|
|
47
|
+
/** 傍晚开始时间 */
|
|
48
|
+
EVENING_START: 18,
|
|
49
|
+
/** 夜晚开始时间 */
|
|
50
|
+
NIGHT_START: 22
|
|
51
|
+
};
|
|
52
|
+
var UI_CONSTANTS = {
|
|
53
|
+
/** 侧边栏宽度 */
|
|
54
|
+
SIDEBAR_WIDTH: 288,
|
|
55
|
+
// 72 * 4 = 288px (w-72)
|
|
56
|
+
/** 日志栏宽度 */
|
|
57
|
+
LOG_WIDTH: 320,
|
|
58
|
+
// 80 * 4 = 320px (w-80)
|
|
59
|
+
/** Toast 容器 z-index */
|
|
60
|
+
TOAST_Z_INDEX: 1e3,
|
|
61
|
+
/** Modal 容器 z-index */
|
|
62
|
+
MODAL_Z_INDEX: 2e3
|
|
63
|
+
};
|
|
64
|
+
var VALIDATION = {
|
|
65
|
+
/** 最小属性值 */
|
|
66
|
+
MIN_STAT_VALUE: 0,
|
|
67
|
+
/** 最大属性值 */
|
|
68
|
+
MAX_STAT_VALUE: 9999,
|
|
69
|
+
/** 最大背包容量 */
|
|
70
|
+
MAX_INVENTORY_SIZE: 100,
|
|
71
|
+
/** 最小动作 ID 长度 */
|
|
72
|
+
MIN_ACTION_ID_LENGTH: 1,
|
|
73
|
+
/** 最大动作 ID 长度 */
|
|
74
|
+
MAX_ACTION_ID_LENGTH: 50
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
// core/utils.ts
|
|
78
|
+
function generateId() {
|
|
79
|
+
return `${Date.now()}-${Math.random().toString(36).slice(2, 11)}`;
|
|
80
|
+
}
|
|
81
|
+
function deepClone(obj) {
|
|
82
|
+
return JSON.parse(JSON.stringify(obj));
|
|
83
|
+
}
|
|
84
|
+
function clamp(value, min, max) {
|
|
85
|
+
return Math.min(Math.max(value, min), max);
|
|
86
|
+
}
|
|
87
|
+
function formatNumber(num) {
|
|
88
|
+
return num.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
|
|
89
|
+
}
|
|
90
|
+
function getTimeOfDay(hour) {
|
|
91
|
+
if (hour >= TIME_CONSTANTS.MORNING_START && hour < TIME_CONSTANTS.NOON_START) {
|
|
92
|
+
return "\u65E9\u6668";
|
|
93
|
+
} else if (hour >= TIME_CONSTANTS.NOON_START && hour < TIME_CONSTANTS.EVENING_START) {
|
|
94
|
+
return "\u4E0B\u5348";
|
|
95
|
+
} else if (hour >= TIME_CONSTANTS.EVENING_START && hour < TIME_CONSTANTS.NIGHT_START) {
|
|
96
|
+
return "\u508D\u665A";
|
|
97
|
+
} else {
|
|
98
|
+
return "\u591C\u665A";
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
function getPercentage(current, max) {
|
|
102
|
+
if (max === 0) return 0;
|
|
103
|
+
return Math.round(current / max * 100);
|
|
104
|
+
}
|
|
105
|
+
function randomInt(min, max) {
|
|
106
|
+
return Math.floor(Math.random() * (max - min + 1)) + min;
|
|
107
|
+
}
|
|
108
|
+
function randomChoice(array) {
|
|
109
|
+
if (array.length === 0) return void 0;
|
|
110
|
+
return array[Math.floor(Math.random() * array.length)];
|
|
111
|
+
}
|
|
112
|
+
function shuffle(array) {
|
|
113
|
+
const result = [...array];
|
|
114
|
+
for (let i = result.length - 1; i > 0; i--) {
|
|
115
|
+
const j = Math.floor(Math.random() * (i + 1));
|
|
116
|
+
[result[i], result[j]] = [result[j], result[i]];
|
|
117
|
+
}
|
|
118
|
+
return result;
|
|
119
|
+
}
|
|
120
|
+
function delay(ms) {
|
|
121
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
122
|
+
}
|
|
123
|
+
function isEmpty(obj) {
|
|
124
|
+
return Object.keys(obj).length === 0;
|
|
125
|
+
}
|
|
126
|
+
function get(obj, path, defaultValue) {
|
|
127
|
+
const keys = path.split(".");
|
|
128
|
+
let result = obj;
|
|
129
|
+
for (const key of keys) {
|
|
130
|
+
if (result && typeof result === "object" && key in result) {
|
|
131
|
+
result = result[key];
|
|
132
|
+
} else {
|
|
133
|
+
return defaultValue;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
return result;
|
|
137
|
+
}
|
|
138
|
+
function debounce(fn, wait) {
|
|
139
|
+
let timeout = null;
|
|
140
|
+
return function(...args) {
|
|
141
|
+
if (timeout) clearTimeout(timeout);
|
|
142
|
+
timeout = setTimeout(() => fn.apply(this, args), wait);
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
function throttle(fn, wait) {
|
|
146
|
+
let lastTime = 0;
|
|
147
|
+
return function(...args) {
|
|
148
|
+
const now = Date.now();
|
|
149
|
+
if (now - lastTime >= wait) {
|
|
150
|
+
lastTime = now;
|
|
151
|
+
fn.apply(this, args);
|
|
152
|
+
}
|
|
153
|
+
};
|
|
154
|
+
}
|
|
155
|
+
function formatGameTime(day, time) {
|
|
156
|
+
const hour = time % TIME_CONSTANTS.HOURS_PER_DAY;
|
|
157
|
+
const period = getTimeOfDay(hour);
|
|
158
|
+
const displayHour = hour === 0 ? 12 : hour > 12 ? hour - 12 : hour;
|
|
159
|
+
return `\u7B2C ${day} \u5929 ${period} ${displayHour}:00`;
|
|
160
|
+
}
|
|
161
|
+
function getStateDiff(oldState, newState) {
|
|
162
|
+
const diff = {
|
|
163
|
+
stats: {},
|
|
164
|
+
itemsAdded: [],
|
|
165
|
+
itemsRemoved: [],
|
|
166
|
+
flagsChanged: {}
|
|
167
|
+
};
|
|
168
|
+
for (const key in newState.stats) {
|
|
169
|
+
const oldValue = oldState.stats[key] || 0;
|
|
170
|
+
const newValue = newState.stats[key] || 0;
|
|
171
|
+
if (oldValue !== newValue) {
|
|
172
|
+
diff.stats[key] = newValue - oldValue;
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
const oldItems = new Set(oldState.inventory);
|
|
176
|
+
const newItems = new Set(newState.inventory);
|
|
177
|
+
for (const item of newState.inventory) {
|
|
178
|
+
if (!oldItems.has(item)) {
|
|
179
|
+
diff.itemsAdded.push(item);
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
for (const item of oldState.inventory) {
|
|
183
|
+
if (!newItems.has(item)) {
|
|
184
|
+
diff.itemsRemoved.push(item);
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
for (const key in newState.flags) {
|
|
188
|
+
if (oldState.flags[key] !== newState.flags[key]) {
|
|
189
|
+
diff.flagsChanged[key] = newState.flags[key];
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
return diff;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
exports.DEFAULT_CONFIG = DEFAULT_CONFIG;
|
|
196
|
+
exports.DEFAULT_STATS = DEFAULT_STATS;
|
|
197
|
+
exports.ENGINE_VERSION = ENGINE_VERSION;
|
|
198
|
+
exports.LOG_TYPE_COLORS = LOG_TYPE_COLORS;
|
|
199
|
+
exports.SystemMessages = SystemMessages;
|
|
200
|
+
exports.TIME_CONSTANTS = TIME_CONSTANTS;
|
|
201
|
+
exports.UI_CONSTANTS = UI_CONSTANTS;
|
|
202
|
+
exports.VALIDATION = VALIDATION;
|
|
203
|
+
exports.clamp = clamp;
|
|
204
|
+
exports.debounce = debounce;
|
|
205
|
+
exports.deepClone = deepClone;
|
|
206
|
+
exports.delay = delay;
|
|
207
|
+
exports.formatGameTime = formatGameTime;
|
|
208
|
+
exports.formatNumber = formatNumber;
|
|
209
|
+
exports.generateId = generateId;
|
|
210
|
+
exports.get = get;
|
|
211
|
+
exports.getPercentage = getPercentage;
|
|
212
|
+
exports.getStateDiff = getStateDiff;
|
|
213
|
+
exports.getTimeOfDay = getTimeOfDay;
|
|
214
|
+
exports.isEmpty = isEmpty;
|
|
215
|
+
exports.randomChoice = randomChoice;
|
|
216
|
+
exports.randomInt = randomInt;
|
|
217
|
+
exports.shuffle = shuffle;
|
|
218
|
+
exports.throttle = throttle;
|
|
219
|
+
//# sourceMappingURL=index.js.map
|
|
220
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../core/messages.ts","../../core/constants.ts","../../core/utils.ts"],"names":[],"mappings":";;;AAQO,IAAM,cAAA,GAAiB;AAAA;AAAA,EAE5B,oBAAA,EAAsB,0BAAA;AAAA;AAAA,EAEtB,mBAAA,EAAqB,yBAAA;AAAA;AAAA,EAErB,cAAA,EAAgB,oBAAA;AAAA;AAAA,EAEhB,YAAA,EAAc;AAChB;;;ACTO,IAAM,cAAA,GAAiB;AAKvB,IAAM,cAAA,GAAiB;AAAA;AAAA,EAE5B,gBAAA,EAAkB,WAAA;AAAA;AAAA,EAElB,eAAA,EAAiB,EAAA;AAAA;AAAA,EAEjB,qBAAA,EAAuB,EAAA;AAAA;AAAA,EAEvB,cAAA,EAAgB;AAClB;AAKO,IAAM,eAAA,GAAkB;AAAA,EAC7B,IAAA,EAAM,SAAA;AAAA,EACN,OAAA,EAAS,SAAA;AAAA,EACT,IAAA,EAAM,SAAA;AAAA,EACN,KAAA,EAAO,SAAA;AAAA,EACP,MAAA,EAAQ;AACV;AAKO,IAAM,aAAA,GAAgB;AAAA;AAAA,EAE3B,UAAA,EAAY,GAAA;AAAA;AAAA,EAEZ,YAAA,EAAc;AAChB;AAKO,IAAM,cAAA,GAAiB;AAAA;AAAA,EAE5B,aAAA,EAAe,EAAA;AAAA;AAAA,EAEf,aAAA,EAAe,CAAA;AAAA;AAAA,EAEf,UAAA,EAAY,EAAA;AAAA;AAAA,EAEZ,aAAA,EAAe,EAAA;AAAA;AAAA,EAEf,WAAA,EAAa;AACf;AAKO,IAAM,YAAA,GAAe;AAAA;AAAA,EAE1B,aAAA,EAAe,GAAA;AAAA;AAAA;AAAA,EAEf,SAAA,EAAW,GAAA;AAAA;AAAA;AAAA,EAEX,aAAA,EAAe,GAAA;AAAA;AAAA,EAEf,aAAA,EAAe;AACjB;AAKO,IAAM,UAAA,GAAa;AAAA;AAAA,EAExB,cAAA,EAAgB,CAAA;AAAA;AAAA,EAEhB,cAAA,EAAgB,IAAA;AAAA;AAAA,EAEhB,kBAAA,EAAoB,GAAA;AAAA;AAAA,EAEpB,oBAAA,EAAsB,CAAA;AAAA;AAAA,EAEtB,oBAAA,EAAsB;AACxB;;;ACvEO,SAAS,UAAA,GAAqB;AACnC,EAAA,OAAO,CAAA,EAAG,IAAA,CAAK,GAAA,EAAK,IAAI,IAAA,CAAK,MAAA,EAAO,CAAE,QAAA,CAAS,EAAE,CAAA,CAAE,KAAA,CAAM,CAAA,EAAG,EAAE,CAAC,CAAA,CAAA;AACjE;AAeO,SAAS,UAAa,GAAA,EAAW;AACtC,EAAA,OAAO,IAAA,CAAK,KAAA,CAAM,IAAA,CAAK,SAAA,CAAU,GAAG,CAAC,CAAA;AACvC;AAiBO,SAAS,KAAA,CAAM,KAAA,EAAe,GAAA,EAAa,GAAA,EAAqB;AACrE,EAAA,OAAO,KAAK,GAAA,CAAI,IAAA,CAAK,IAAI,KAAA,EAAO,GAAG,GAAG,GAAG,CAAA;AAC3C;AAaO,SAAS,aAAa,GAAA,EAAqB;AAChD,EAAA,OAAO,GAAA,CAAI,QAAA,EAAS,CAAE,OAAA,CAAQ,yBAAyB,GAAG,CAAA;AAC5D;AAeO,SAAS,aAAa,IAAA,EAAsB;AACjD,EAAA,IAAI,IAAA,IAAQ,cAAA,CAAe,aAAA,IAAiB,IAAA,GAAO,eAAe,UAAA,EAAY;AAC5E,IAAA,OAAO,cAAA;AAAA,EACT,WAAW,IAAA,IAAQ,cAAA,CAAe,UAAA,IAAc,IAAA,GAAO,eAAe,aAAA,EAAe;AACnF,IAAA,OAAO,cAAA;AAAA,EACT,WAAW,IAAA,IAAQ,cAAA,CAAe,aAAA,IAAiB,IAAA,GAAO,eAAe,WAAA,EAAa;AACpF,IAAA,OAAO,cAAA;AAAA,EACT,CAAA,MAAO;AACL,IAAA,OAAO,cAAA;AAAA,EACT;AACF;AAeO,SAAS,aAAA,CAAc,SAAiB,GAAA,EAAqB;AAClE,EAAA,IAAI,GAAA,KAAQ,GAAG,OAAO,CAAA;AACtB,EAAA,OAAO,IAAA,CAAK,KAAA,CAAO,OAAA,GAAU,GAAA,GAAO,GAAG,CAAA;AACzC;AAcO,SAAS,SAAA,CAAU,KAAa,GAAA,EAAqB;AAC1D,EAAA,OAAO,IAAA,CAAK,MAAM,IAAA,CAAK,MAAA,MAAY,GAAA,GAAM,GAAA,GAAM,EAAE,CAAA,GAAI,GAAA;AACvD;AAaO,SAAS,aAAgB,KAAA,EAA2B;AACzD,EAAA,IAAI,KAAA,CAAM,MAAA,KAAW,CAAA,EAAG,OAAO,MAAA;AAC/B,EAAA,OAAO,KAAA,CAAM,KAAK,KAAA,CAAM,IAAA,CAAK,QAAO,GAAI,KAAA,CAAM,MAAM,CAAC,CAAA;AACvD;AAaO,SAAS,QAAW,KAAA,EAAiB;AAC1C,EAAA,MAAM,MAAA,GAAS,CAAC,GAAG,KAAK,CAAA;AACxB,EAAA,KAAA,IAAS,IAAI,MAAA,CAAO,MAAA,GAAS,CAAA,EAAG,CAAA,GAAI,GAAG,CAAA,EAAA,EAAK;AAC1C,IAAA,MAAM,IAAI,IAAA,CAAK,KAAA,CAAM,KAAK,MAAA,EAAO,IAAK,IAAI,CAAA,CAAE,CAAA;AAC5C,IAAA,CAAC,MAAA,CAAO,CAAC,CAAA,EAAG,MAAA,CAAO,CAAC,CAAC,CAAA,GAAI,CAAC,MAAA,CAAO,CAAC,CAAA,EAAG,MAAA,CAAO,CAAC,CAAC,CAAA;AAAA,EAChD;AACA,EAAA,OAAO,MAAA;AACT;AAaO,SAAS,MAAM,EAAA,EAA2B;AAC/C,EAAA,OAAO,IAAI,OAAA,CAAQ,CAAC,YAAY,UAAA,CAAW,OAAA,EAAS,EAAE,CAAC,CAAA;AACzD;AAcO,SAAS,QAAQ,GAAA,EAAsB;AAC5C,EAAA,OAAO,MAAA,CAAO,IAAA,CAAK,GAAG,CAAA,CAAE,MAAA,KAAW,CAAA;AACrC;AAiBO,SAAS,GAAA,CAAO,GAAA,EAAc,IAAA,EAAc,YAAA,EAAqB;AACtE,EAAA,MAAM,IAAA,GAAO,IAAA,CAAK,KAAA,CAAM,GAAG,CAAA;AAC3B,EAAA,IAAI,MAAA,GAAkB,GAAA;AAEtB,EAAA,KAAA,MAAW,OAAO,IAAA,EAAM;AACtB,IAAA,IAAI,MAAA,IAAU,OAAO,MAAA,KAAW,QAAA,IAAY,OAAO,MAAA,EAAQ;AACzD,MAAA,MAAA,GAAU,OAAmC,GAAG,CAAA;AAAA,IAClD,CAAA,MAAO;AACL,MAAA,OAAO,YAAA;AAAA,IACT;AAAA,EACF;AAEA,EAAA,OAAO,MAAA;AACT;AAeO,SAAS,QAAA,CACd,IACA,IAAA,EACkC;AAClC,EAAA,IAAI,OAAA,GAAgD,IAAA;AAEpD,EAAA,OAAO,YAA4B,IAAA,EAAqB;AACtD,IAAA,IAAI,OAAA,eAAsB,OAAO,CAAA;AACjC,IAAA,OAAA,GAAU,WAAW,MAAM,EAAA,CAAG,MAAM,IAAA,EAAM,IAAI,GAAG,IAAI,CAAA;AAAA,EACvD,CAAA;AACF;AAeO,SAAS,QAAA,CACd,IACA,IAAA,EACkC;AAClC,EAAA,IAAI,QAAA,GAAW,CAAA;AAEf,EAAA,OAAO,YAA4B,IAAA,EAAqB;AACtD,IAAA,MAAM,GAAA,GAAM,KAAK,GAAA,EAAI;AACrB,IAAA,IAAI,GAAA,GAAM,YAAY,IAAA,EAAM;AAC1B,MAAA,QAAA,GAAW,GAAA;AACX,MAAA,EAAA,CAAG,KAAA,CAAM,MAAM,IAAI,CAAA;AAAA,IACrB;AAAA,EACF,CAAA;AACF;AAcO,SAAS,cAAA,CAAe,KAAa,IAAA,EAAsB;AAChE,EAAA,MAAM,IAAA,GAAO,OAAO,cAAA,CAAe,aAAA;AACnC,EAAA,MAAM,MAAA,GAAS,aAAa,IAAI,CAAA;AAChC,EAAA,MAAM,cAAc,IAAA,KAAS,CAAA,GAAI,KAAK,IAAA,GAAO,EAAA,GAAK,OAAO,EAAA,GAAK,IAAA;AAC9D,EAAA,OAAO,CAAA,OAAA,EAAK,GAAG,CAAA,QAAA,EAAM,MAAM,IAAI,WAAW,CAAA,GAAA,CAAA;AAC5C;AAeO,SAAS,YAAA,CACd,UACA,QAAA,EAMA;AACA,EAAA,MAAM,IAAA,GAAO;AAAA,IACX,OAAO,EAAC;AAAA,IACR,YAAY,EAAC;AAAA,IACb,cAAc,EAAC;AAAA,IACf,cAAc;AAAC,GACjB;AAGA,EAAA,KAAA,MAAW,GAAA,IAAO,SAAS,KAAA,EAAO;AAChC,IAAA,MAAM,QAAA,GAAW,QAAA,CAAS,KAAA,CAAM,GAAG,CAAA,IAAK,CAAA;AACxC,IAAA,MAAM,QAAA,GAAW,QAAA,CAAS,KAAA,CAAM,GAAG,CAAA,IAAK,CAAA;AACxC,IAAA,IAAI,aAAa,QAAA,EAAU;AACzB,MAAA,IAAA,CAAK,KAAA,CAAM,GAAG,CAAA,GAAI,QAAA,GAAW,QAAA;AAAA,IAC/B;AAAA,EACF;AAGA,EAAA,MAAM,QAAA,GAAW,IAAI,GAAA,CAAI,QAAA,CAAS,SAAS,CAAA;AAC3C,EAAA,MAAM,QAAA,GAAW,IAAI,GAAA,CAAI,QAAA,CAAS,SAAS,CAAA;AAE3C,EAAA,KAAA,MAAW,IAAA,IAAQ,SAAS,SAAA,EAAW;AACrC,IAAA,IAAI,CAAC,QAAA,CAAS,GAAA,CAAI,IAAI,CAAA,EAAG;AACvB,MAAA,IAAA,CAAK,UAAA,CAAW,KAAK,IAAI,CAAA;AAAA,IAC3B;AAAA,EACF;AAEA,EAAA,KAAA,MAAW,IAAA,IAAQ,SAAS,SAAA,EAAW;AACrC,IAAA,IAAI,CAAC,QAAA,CAAS,GAAA,CAAI,IAAI,CAAA,EAAG;AACvB,MAAA,IAAA,CAAK,YAAA,CAAa,KAAK,IAAI,CAAA;AAAA,IAC7B;AAAA,EACF;AAGA,EAAA,KAAA,MAAW,GAAA,IAAO,SAAS,KAAA,EAAO;AAChC,IAAA,IAAI,SAAS,KAAA,CAAM,GAAG,MAAM,QAAA,CAAS,KAAA,CAAM,GAAG,CAAA,EAAG;AAC/C,MAAA,IAAA,CAAK,YAAA,CAAa,GAAG,CAAA,GAAI,QAAA,CAAS,MAAM,GAAG,CAAA;AAAA,IAC7C;AAAA,EACF;AAEA,EAAA,OAAO,IAAA;AACT","file":"index.js","sourcesContent":["// src/engine/core/messages.ts\n\n/**\n * 系统消息常量\n * \n * 使用特殊的标识符(sys: 前缀),让 UI 层知道这需要翻译。\n * 这些常量用于系统级别的提示消息,应该在 UI 层进行本地化处理。\n */\nexport const SystemMessages = {\n /** 资源不足提示 */\n NOT_ENOUGH_RESOURCES: 'sys:not_enough_resources',\n /** 条件不满足提示 */\n REQUIREMENT_NOT_MET: 'sys:requirement_not_met',\n /** 操作成功提示 */\n ACTION_SUCCESS: 'sys:action_success',\n /** 时间回溯成功提示 */\n UNDO_SUCCESS: 'sys:undo_success',\n} as const;","// src/engine/core/constants.ts\n/**\n * 全局常量定义\n */\n\n/**\n * 引擎版本\n */\nexport const ENGINE_VERSION = '1.0.0';\n\n/**\n * 默认配置\n */\nexport const DEFAULT_CONFIG = {\n /** 默认存档键名 */\n DEFAULT_SAVE_KEY: 'game-save',\n /** 最大日志条数 */\n MAX_LOG_ENTRIES: 50,\n /** 最大历史快照数 */\n MAX_HISTORY_SNAPSHOTS: 20,\n /** 飘字显示时长(毫秒) */\n TOAST_DURATION: 3000,\n} as const;\n\n/**\n * 日志类型颜色映射\n */\nexport const LOG_TYPE_COLORS = {\n info: '#3b82f6',\n success: '#10b981',\n warn: '#f59e0b',\n error: '#ef4444',\n result: '#6366f1',\n} as const;\n\n/**\n * 默认属性值\n */\nexport const DEFAULT_STATS = {\n /** 默认生命值 */\n DEFAULT_HP: 100,\n /** 默认金币 */\n DEFAULT_GOLD: 0,\n} as const;\n\n/**\n * 游戏时间常量\n */\nexport const TIME_CONSTANTS = {\n /** 一天的小时数 */\n HOURS_PER_DAY: 24,\n /** 早晨开始时间 */\n MORNING_START: 6,\n /** 中午开始时间 */\n NOON_START: 12,\n /** 傍晚开始时间 */\n EVENING_START: 18,\n /** 夜晚开始时间 */\n NIGHT_START: 22,\n} as const;\n\n/**\n * UI 常量\n */\nexport const UI_CONSTANTS = {\n /** 侧边栏宽度 */\n SIDEBAR_WIDTH: 288, // 72 * 4 = 288px (w-72)\n /** 日志栏宽度 */\n LOG_WIDTH: 320, // 80 * 4 = 320px (w-80)\n /** Toast 容器 z-index */\n TOAST_Z_INDEX: 1000,\n /** Modal 容器 z-index */\n MODAL_Z_INDEX: 2000,\n} as const;\n\n/**\n * 验证常量\n */\nexport const VALIDATION = {\n /** 最小属性值 */\n MIN_STAT_VALUE: 0,\n /** 最大属性值 */\n MAX_STAT_VALUE: 9999,\n /** 最大背包容量 */\n MAX_INVENTORY_SIZE: 100,\n /** 最小动作 ID 长度 */\n MIN_ACTION_ID_LENGTH: 1,\n /** 最大动作 ID 长度 */\n MAX_ACTION_ID_LENGTH: 50,\n} as const;","// src/engine/core/utils.ts\n/**\n * 工具函数集合\n */\n\nimport type { GameState } from './types';\nimport { TIME_CONSTANTS } from './constants';\n\n/**\n * 生成唯一 ID\n * \n * @returns 唯一标识符字符串\n * \n * @example\n * ```typescript\n * const id = generateId(); // \"1234567890-abc123\"\n * ```\n */\nexport function generateId(): string {\n return `${Date.now()}-${Math.random().toString(36).slice(2, 11)}`;\n}\n\n/**\n * 深拷贝对象\n * \n * 使用 JSON 序列化实现深拷贝,注意会丢失函数、Symbol 等特殊类型\n * \n * @param obj - 要拷贝的对象\n * @returns 深拷贝后的对象\n * \n * @example\n * ```typescript\n * const copy = deepClone(originalObject);\n * ```\n */\nexport function deepClone<T>(obj: T): T {\n return JSON.parse(JSON.stringify(obj));\n}\n\n/**\n * 限制数值在指定范围内\n * \n * @param value - 要限制的值\n * @param min - 最小值\n * @param max - 最大值\n * @returns 限制后的值\n * \n * @example\n * ```typescript\n * clamp(150, 0, 100); // 100\n * clamp(-10, 0, 100); // 0\n * clamp(50, 0, 100); // 50\n * ```\n */\nexport function clamp(value: number, min: number, max: number): number {\n return Math.min(Math.max(value, min), max);\n}\n\n/**\n * 格式化数字,添加千位分隔符\n * \n * @param num - 要格式化的数字\n * @returns 格式化后的字符串\n * \n * @example\n * ```typescript\n * formatNumber(1234567); // \"1,234,567\"\n * ```\n */\nexport function formatNumber(num: number): string {\n return num.toString().replace(/\\B(?=(\\d{3})+(?!\\d))/g, ',');\n}\n\n/**\n * 获取时间段描述\n * \n * @param hour - 小时数 (0-23)\n * @returns 时间段描述\n * \n * @example\n * ```typescript\n * getTimeOfDay(8); // \"早晨\"\n * getTimeOfDay(14); // \"下午\"\n * getTimeOfDay(20); // \"傍晚\"\n * ```\n */\nexport function getTimeOfDay(hour: number): string {\n if (hour >= TIME_CONSTANTS.MORNING_START && hour < TIME_CONSTANTS.NOON_START) {\n return '早晨';\n } else if (hour >= TIME_CONSTANTS.NOON_START && hour < TIME_CONSTANTS.EVENING_START) {\n return '下午';\n } else if (hour >= TIME_CONSTANTS.EVENING_START && hour < TIME_CONSTANTS.NIGHT_START) {\n return '傍晚';\n } else {\n return '夜晚';\n }\n}\n\n/**\n * 计算百分比\n * \n * @param current - 当前值\n * @param max - 最大值\n * @returns 百分比 (0-100)\n * \n * @example\n * ```typescript\n * getPercentage(75, 100); // 75\n * getPercentage(0, 100); // 0\n * ```\n */\nexport function getPercentage(current: number, max: number): number {\n if (max === 0) return 0;\n return Math.round((current / max) * 100);\n}\n\n/**\n * 随机整数\n * \n * @param min - 最小值(包含)\n * @param max - 最大值(包含)\n * @returns 随机整数\n * \n * @example\n * ```typescript\n * randomInt(1, 6); // 1-6 之间的随机整数(模拟骰子)\n * ```\n */\nexport function randomInt(min: number, max: number): number {\n return Math.floor(Math.random() * (max - min + 1)) + min;\n}\n\n/**\n * 从数组中随机选择一个元素\n * \n * @param array - 数组\n * @returns 随机选择的元素,如果数组为空则返回 undefined\n * \n * @example\n * ```typescript\n * randomChoice(['剑', '盾', '药水']); // 随机返回一个\n * ```\n */\nexport function randomChoice<T>(array: T[]): T | undefined {\n if (array.length === 0) return undefined;\n return array[Math.floor(Math.random() * array.length)];\n}\n\n/**\n * 打乱数组顺序(Fisher-Yates 算法)\n * \n * @param array - 要打乱的数组\n * @returns 打乱后的新数组\n * \n * @example\n * ```typescript\n * shuffle([1, 2, 3, 4, 5]); // [3, 1, 5, 2, 4]\n * ```\n */\nexport function shuffle<T>(array: T[]): T[] {\n const result = [...array];\n for (let i = result.length - 1; i > 0; i--) {\n const j = Math.floor(Math.random() * (i + 1));\n [result[i], result[j]] = [result[j], result[i]];\n }\n return result;\n}\n\n/**\n * 延迟执行\n * \n * @param ms - 延迟毫秒数\n * @returns Promise\n * \n * @example\n * ```typescript\n * await delay(1000); // 延迟 1 秒\n * ```\n */\nexport function delay(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\n/**\n * 检查对象是否为空\n * \n * @param obj - 要检查的对象\n * @returns 是否为空\n * \n * @example\n * ```typescript\n * isEmpty({}); // true\n * isEmpty({ a: 1 }); // false\n * ```\n */\nexport function isEmpty(obj: object): boolean {\n return Object.keys(obj).length === 0;\n}\n\n/**\n * 安全地获取嵌套属性\n * \n * @param obj - 对象\n * @param path - 属性路径,用点分隔\n * @param defaultValue - 默认值\n * @returns 属性值或默认值\n * \n * @example\n * ```typescript\n * const obj = { a: { b: { c: 123 } } };\n * get(obj, 'a.b.c', 0); // 123\n * get(obj, 'a.x.y', 0); // 0\n * ```\n */\nexport function get<T>(obj: unknown, path: string, defaultValue?: T): T {\n const keys = path.split('.');\n let result: unknown = obj;\n\n for (const key of keys) {\n if (result && typeof result === 'object' && key in result) {\n result = (result as Record<string, unknown>)[key];\n } else {\n return defaultValue as T;\n }\n }\n\n return result as T;\n}\n\n/**\n * 防抖函数\n * \n * @param fn - 要防抖的函数\n * @param wait - 等待时间(毫秒)\n * @returns 防抖后的函数\n * \n * @example\n * ```typescript\n * const debouncedSave = debounce(() => saveGame(), 1000);\n * debouncedSave(); // 1秒内多次调用只执行最后一次\n * ```\n */\nexport function debounce<T extends (...args: never[]) => unknown>(\n fn: T,\n wait: number\n): (...args: Parameters<T>) => void {\n let timeout: ReturnType<typeof setTimeout> | null = null;\n\n return function (this: unknown, ...args: Parameters<T>) {\n if (timeout) clearTimeout(timeout);\n timeout = setTimeout(() => fn.apply(this, args), wait);\n };\n}\n\n/**\n * 节流函数\n * \n * @param fn - 要节流的函数\n * @param wait - 等待时间(毫秒)\n * @returns 节流后的函数\n * \n * @example\n * ```typescript\n * const throttledUpdate = throttle(() => updateUI(), 100);\n * throttledUpdate(); // 100ms 内只执行一次\n * ```\n */\nexport function throttle<T extends (...args: never[]) => unknown>(\n fn: T,\n wait: number\n): (...args: Parameters<T>) => void {\n let lastTime = 0;\n\n return function (this: unknown, ...args: Parameters<T>) {\n const now = Date.now();\n if (now - lastTime >= wait) {\n lastTime = now;\n fn.apply(this, args);\n }\n };\n}\n\n/**\n * 格式化游戏时间\n * \n * @param day - 天数\n * @param time - 小时数\n * @returns 格式化的时间字符串\n * \n * @example\n * ```typescript\n * formatGameTime(5, 14); // \"第 5 天 下午 2:00\"\n * ```\n */\nexport function formatGameTime(day: number, time: number): string {\n const hour = time % TIME_CONSTANTS.HOURS_PER_DAY;\n const period = getTimeOfDay(hour);\n const displayHour = hour === 0 ? 12 : hour > 12 ? hour - 12 : hour;\n return `第 ${day} 天 ${period} ${displayHour}:00`;\n}\n\n/**\n * 计算两个状态之间的差异\n * \n * @param oldState - 旧状态\n * @param newState - 新状态\n * @returns 差异对象\n * \n * @example\n * ```typescript\n * const diff = getStateDiff(oldState, newState);\n * console.log(diff.stats); // { hp: -10, gold: 5 }\n * ```\n */\nexport function getStateDiff<S extends string, I extends string, F extends string, X>(\n oldState: GameState<S, I, F, X>,\n newState: GameState<S, I, F, X>\n): {\n stats: Partial<Record<S, number>>;\n itemsAdded: I[];\n itemsRemoved: I[];\n flagsChanged: Partial<Record<F, boolean>>;\n} {\n const diff = {\n stats: {} as Partial<Record<S, number>>,\n itemsAdded: [] as I[],\n itemsRemoved: [] as I[],\n flagsChanged: {} as Partial<Record<F, boolean>>,\n };\n\n // 计算属性差异\n for (const key in newState.stats) {\n const oldValue = oldState.stats[key] || 0;\n const newValue = newState.stats[key] || 0;\n if (oldValue !== newValue) {\n diff.stats[key] = newValue - oldValue;\n }\n }\n\n // 计算物品差异\n const oldItems = new Set(oldState.inventory);\n const newItems = new Set(newState.inventory);\n\n for (const item of newState.inventory) {\n if (!oldItems.has(item)) {\n diff.itemsAdded.push(item);\n }\n }\n\n for (const item of oldState.inventory) {\n if (!newItems.has(item)) {\n diff.itemsRemoved.push(item);\n }\n }\n\n // 计算标记差异\n for (const key in newState.flags) {\n if (oldState.flags[key] !== newState.flags[key]) {\n diff.flagsChanged[key] = newState.flags[key];\n }\n }\n\n return diff;\n}"]}
|
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
// core/messages.ts
|
|
2
|
+
var SystemMessages = {
|
|
3
|
+
/** 资源不足提示 */
|
|
4
|
+
NOT_ENOUGH_RESOURCES: "sys:not_enough_resources",
|
|
5
|
+
/** 条件不满足提示 */
|
|
6
|
+
REQUIREMENT_NOT_MET: "sys:requirement_not_met",
|
|
7
|
+
/** 操作成功提示 */
|
|
8
|
+
ACTION_SUCCESS: "sys:action_success",
|
|
9
|
+
/** 时间回溯成功提示 */
|
|
10
|
+
UNDO_SUCCESS: "sys:undo_success"
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
// core/constants.ts
|
|
14
|
+
var ENGINE_VERSION = "1.0.0";
|
|
15
|
+
var DEFAULT_CONFIG = {
|
|
16
|
+
/** 默认存档键名 */
|
|
17
|
+
DEFAULT_SAVE_KEY: "game-save",
|
|
18
|
+
/** 最大日志条数 */
|
|
19
|
+
MAX_LOG_ENTRIES: 50,
|
|
20
|
+
/** 最大历史快照数 */
|
|
21
|
+
MAX_HISTORY_SNAPSHOTS: 20,
|
|
22
|
+
/** 飘字显示时长(毫秒) */
|
|
23
|
+
TOAST_DURATION: 3e3
|
|
24
|
+
};
|
|
25
|
+
var LOG_TYPE_COLORS = {
|
|
26
|
+
info: "#3b82f6",
|
|
27
|
+
success: "#10b981",
|
|
28
|
+
warn: "#f59e0b",
|
|
29
|
+
error: "#ef4444",
|
|
30
|
+
result: "#6366f1"
|
|
31
|
+
};
|
|
32
|
+
var DEFAULT_STATS = {
|
|
33
|
+
/** 默认生命值 */
|
|
34
|
+
DEFAULT_HP: 100,
|
|
35
|
+
/** 默认金币 */
|
|
36
|
+
DEFAULT_GOLD: 0
|
|
37
|
+
};
|
|
38
|
+
var TIME_CONSTANTS = {
|
|
39
|
+
/** 一天的小时数 */
|
|
40
|
+
HOURS_PER_DAY: 24,
|
|
41
|
+
/** 早晨开始时间 */
|
|
42
|
+
MORNING_START: 6,
|
|
43
|
+
/** 中午开始时间 */
|
|
44
|
+
NOON_START: 12,
|
|
45
|
+
/** 傍晚开始时间 */
|
|
46
|
+
EVENING_START: 18,
|
|
47
|
+
/** 夜晚开始时间 */
|
|
48
|
+
NIGHT_START: 22
|
|
49
|
+
};
|
|
50
|
+
var UI_CONSTANTS = {
|
|
51
|
+
/** 侧边栏宽度 */
|
|
52
|
+
SIDEBAR_WIDTH: 288,
|
|
53
|
+
// 72 * 4 = 288px (w-72)
|
|
54
|
+
/** 日志栏宽度 */
|
|
55
|
+
LOG_WIDTH: 320,
|
|
56
|
+
// 80 * 4 = 320px (w-80)
|
|
57
|
+
/** Toast 容器 z-index */
|
|
58
|
+
TOAST_Z_INDEX: 1e3,
|
|
59
|
+
/** Modal 容器 z-index */
|
|
60
|
+
MODAL_Z_INDEX: 2e3
|
|
61
|
+
};
|
|
62
|
+
var VALIDATION = {
|
|
63
|
+
/** 最小属性值 */
|
|
64
|
+
MIN_STAT_VALUE: 0,
|
|
65
|
+
/** 最大属性值 */
|
|
66
|
+
MAX_STAT_VALUE: 9999,
|
|
67
|
+
/** 最大背包容量 */
|
|
68
|
+
MAX_INVENTORY_SIZE: 100,
|
|
69
|
+
/** 最小动作 ID 长度 */
|
|
70
|
+
MIN_ACTION_ID_LENGTH: 1,
|
|
71
|
+
/** 最大动作 ID 长度 */
|
|
72
|
+
MAX_ACTION_ID_LENGTH: 50
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
// core/utils.ts
|
|
76
|
+
function generateId() {
|
|
77
|
+
return `${Date.now()}-${Math.random().toString(36).slice(2, 11)}`;
|
|
78
|
+
}
|
|
79
|
+
function deepClone(obj) {
|
|
80
|
+
return JSON.parse(JSON.stringify(obj));
|
|
81
|
+
}
|
|
82
|
+
function clamp(value, min, max) {
|
|
83
|
+
return Math.min(Math.max(value, min), max);
|
|
84
|
+
}
|
|
85
|
+
function formatNumber(num) {
|
|
86
|
+
return num.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
|
|
87
|
+
}
|
|
88
|
+
function getTimeOfDay(hour) {
|
|
89
|
+
if (hour >= TIME_CONSTANTS.MORNING_START && hour < TIME_CONSTANTS.NOON_START) {
|
|
90
|
+
return "\u65E9\u6668";
|
|
91
|
+
} else if (hour >= TIME_CONSTANTS.NOON_START && hour < TIME_CONSTANTS.EVENING_START) {
|
|
92
|
+
return "\u4E0B\u5348";
|
|
93
|
+
} else if (hour >= TIME_CONSTANTS.EVENING_START && hour < TIME_CONSTANTS.NIGHT_START) {
|
|
94
|
+
return "\u508D\u665A";
|
|
95
|
+
} else {
|
|
96
|
+
return "\u591C\u665A";
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
function getPercentage(current, max) {
|
|
100
|
+
if (max === 0) return 0;
|
|
101
|
+
return Math.round(current / max * 100);
|
|
102
|
+
}
|
|
103
|
+
function randomInt(min, max) {
|
|
104
|
+
return Math.floor(Math.random() * (max - min + 1)) + min;
|
|
105
|
+
}
|
|
106
|
+
function randomChoice(array) {
|
|
107
|
+
if (array.length === 0) return void 0;
|
|
108
|
+
return array[Math.floor(Math.random() * array.length)];
|
|
109
|
+
}
|
|
110
|
+
function shuffle(array) {
|
|
111
|
+
const result = [...array];
|
|
112
|
+
for (let i = result.length - 1; i > 0; i--) {
|
|
113
|
+
const j = Math.floor(Math.random() * (i + 1));
|
|
114
|
+
[result[i], result[j]] = [result[j], result[i]];
|
|
115
|
+
}
|
|
116
|
+
return result;
|
|
117
|
+
}
|
|
118
|
+
function delay(ms) {
|
|
119
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
120
|
+
}
|
|
121
|
+
function isEmpty(obj) {
|
|
122
|
+
return Object.keys(obj).length === 0;
|
|
123
|
+
}
|
|
124
|
+
function get(obj, path, defaultValue) {
|
|
125
|
+
const keys = path.split(".");
|
|
126
|
+
let result = obj;
|
|
127
|
+
for (const key of keys) {
|
|
128
|
+
if (result && typeof result === "object" && key in result) {
|
|
129
|
+
result = result[key];
|
|
130
|
+
} else {
|
|
131
|
+
return defaultValue;
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
return result;
|
|
135
|
+
}
|
|
136
|
+
function debounce(fn, wait) {
|
|
137
|
+
let timeout = null;
|
|
138
|
+
return function(...args) {
|
|
139
|
+
if (timeout) clearTimeout(timeout);
|
|
140
|
+
timeout = setTimeout(() => fn.apply(this, args), wait);
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
function throttle(fn, wait) {
|
|
144
|
+
let lastTime = 0;
|
|
145
|
+
return function(...args) {
|
|
146
|
+
const now = Date.now();
|
|
147
|
+
if (now - lastTime >= wait) {
|
|
148
|
+
lastTime = now;
|
|
149
|
+
fn.apply(this, args);
|
|
150
|
+
}
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
function formatGameTime(day, time) {
|
|
154
|
+
const hour = time % TIME_CONSTANTS.HOURS_PER_DAY;
|
|
155
|
+
const period = getTimeOfDay(hour);
|
|
156
|
+
const displayHour = hour === 0 ? 12 : hour > 12 ? hour - 12 : hour;
|
|
157
|
+
return `\u7B2C ${day} \u5929 ${period} ${displayHour}:00`;
|
|
158
|
+
}
|
|
159
|
+
function getStateDiff(oldState, newState) {
|
|
160
|
+
const diff = {
|
|
161
|
+
stats: {},
|
|
162
|
+
itemsAdded: [],
|
|
163
|
+
itemsRemoved: [],
|
|
164
|
+
flagsChanged: {}
|
|
165
|
+
};
|
|
166
|
+
for (const key in newState.stats) {
|
|
167
|
+
const oldValue = oldState.stats[key] || 0;
|
|
168
|
+
const newValue = newState.stats[key] || 0;
|
|
169
|
+
if (oldValue !== newValue) {
|
|
170
|
+
diff.stats[key] = newValue - oldValue;
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
const oldItems = new Set(oldState.inventory);
|
|
174
|
+
const newItems = new Set(newState.inventory);
|
|
175
|
+
for (const item of newState.inventory) {
|
|
176
|
+
if (!oldItems.has(item)) {
|
|
177
|
+
diff.itemsAdded.push(item);
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
for (const item of oldState.inventory) {
|
|
181
|
+
if (!newItems.has(item)) {
|
|
182
|
+
diff.itemsRemoved.push(item);
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
for (const key in newState.flags) {
|
|
186
|
+
if (oldState.flags[key] !== newState.flags[key]) {
|
|
187
|
+
diff.flagsChanged[key] = newState.flags[key];
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
return diff;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
export { DEFAULT_CONFIG, DEFAULT_STATS, ENGINE_VERSION, LOG_TYPE_COLORS, SystemMessages, TIME_CONSTANTS, UI_CONSTANTS, VALIDATION, clamp, debounce, deepClone, delay, formatGameTime, formatNumber, generateId, get, getPercentage, getStateDiff, getTimeOfDay, isEmpty, randomChoice, randomInt, shuffle, throttle };
|
|
194
|
+
//# sourceMappingURL=index.mjs.map
|
|
195
|
+
//# sourceMappingURL=index.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../core/messages.ts","../../core/constants.ts","../../core/utils.ts"],"names":[],"mappings":";AAQO,IAAM,cAAA,GAAiB;AAAA;AAAA,EAE5B,oBAAA,EAAsB,0BAAA;AAAA;AAAA,EAEtB,mBAAA,EAAqB,yBAAA;AAAA;AAAA,EAErB,cAAA,EAAgB,oBAAA;AAAA;AAAA,EAEhB,YAAA,EAAc;AAChB;;;ACTO,IAAM,cAAA,GAAiB;AAKvB,IAAM,cAAA,GAAiB;AAAA;AAAA,EAE5B,gBAAA,EAAkB,WAAA;AAAA;AAAA,EAElB,eAAA,EAAiB,EAAA;AAAA;AAAA,EAEjB,qBAAA,EAAuB,EAAA;AAAA;AAAA,EAEvB,cAAA,EAAgB;AAClB;AAKO,IAAM,eAAA,GAAkB;AAAA,EAC7B,IAAA,EAAM,SAAA;AAAA,EACN,OAAA,EAAS,SAAA;AAAA,EACT,IAAA,EAAM,SAAA;AAAA,EACN,KAAA,EAAO,SAAA;AAAA,EACP,MAAA,EAAQ;AACV;AAKO,IAAM,aAAA,GAAgB;AAAA;AAAA,EAE3B,UAAA,EAAY,GAAA;AAAA;AAAA,EAEZ,YAAA,EAAc;AAChB;AAKO,IAAM,cAAA,GAAiB;AAAA;AAAA,EAE5B,aAAA,EAAe,EAAA;AAAA;AAAA,EAEf,aAAA,EAAe,CAAA;AAAA;AAAA,EAEf,UAAA,EAAY,EAAA;AAAA;AAAA,EAEZ,aAAA,EAAe,EAAA;AAAA;AAAA,EAEf,WAAA,EAAa;AACf;AAKO,IAAM,YAAA,GAAe;AAAA;AAAA,EAE1B,aAAA,EAAe,GAAA;AAAA;AAAA;AAAA,EAEf,SAAA,EAAW,GAAA;AAAA;AAAA;AAAA,EAEX,aAAA,EAAe,GAAA;AAAA;AAAA,EAEf,aAAA,EAAe;AACjB;AAKO,IAAM,UAAA,GAAa;AAAA;AAAA,EAExB,cAAA,EAAgB,CAAA;AAAA;AAAA,EAEhB,cAAA,EAAgB,IAAA;AAAA;AAAA,EAEhB,kBAAA,EAAoB,GAAA;AAAA;AAAA,EAEpB,oBAAA,EAAsB,CAAA;AAAA;AAAA,EAEtB,oBAAA,EAAsB;AACxB;;;ACvEO,SAAS,UAAA,GAAqB;AACnC,EAAA,OAAO,CAAA,EAAG,IAAA,CAAK,GAAA,EAAK,IAAI,IAAA,CAAK,MAAA,EAAO,CAAE,QAAA,CAAS,EAAE,CAAA,CAAE,KAAA,CAAM,CAAA,EAAG,EAAE,CAAC,CAAA,CAAA;AACjE;AAeO,SAAS,UAAa,GAAA,EAAW;AACtC,EAAA,OAAO,IAAA,CAAK,KAAA,CAAM,IAAA,CAAK,SAAA,CAAU,GAAG,CAAC,CAAA;AACvC;AAiBO,SAAS,KAAA,CAAM,KAAA,EAAe,GAAA,EAAa,GAAA,EAAqB;AACrE,EAAA,OAAO,KAAK,GAAA,CAAI,IAAA,CAAK,IAAI,KAAA,EAAO,GAAG,GAAG,GAAG,CAAA;AAC3C;AAaO,SAAS,aAAa,GAAA,EAAqB;AAChD,EAAA,OAAO,GAAA,CAAI,QAAA,EAAS,CAAE,OAAA,CAAQ,yBAAyB,GAAG,CAAA;AAC5D;AAeO,SAAS,aAAa,IAAA,EAAsB;AACjD,EAAA,IAAI,IAAA,IAAQ,cAAA,CAAe,aAAA,IAAiB,IAAA,GAAO,eAAe,UAAA,EAAY;AAC5E,IAAA,OAAO,cAAA;AAAA,EACT,WAAW,IAAA,IAAQ,cAAA,CAAe,UAAA,IAAc,IAAA,GAAO,eAAe,aAAA,EAAe;AACnF,IAAA,OAAO,cAAA;AAAA,EACT,WAAW,IAAA,IAAQ,cAAA,CAAe,aAAA,IAAiB,IAAA,GAAO,eAAe,WAAA,EAAa;AACpF,IAAA,OAAO,cAAA;AAAA,EACT,CAAA,MAAO;AACL,IAAA,OAAO,cAAA;AAAA,EACT;AACF;AAeO,SAAS,aAAA,CAAc,SAAiB,GAAA,EAAqB;AAClE,EAAA,IAAI,GAAA,KAAQ,GAAG,OAAO,CAAA;AACtB,EAAA,OAAO,IAAA,CAAK,KAAA,CAAO,OAAA,GAAU,GAAA,GAAO,GAAG,CAAA;AACzC;AAcO,SAAS,SAAA,CAAU,KAAa,GAAA,EAAqB;AAC1D,EAAA,OAAO,IAAA,CAAK,MAAM,IAAA,CAAK,MAAA,MAAY,GAAA,GAAM,GAAA,GAAM,EAAE,CAAA,GAAI,GAAA;AACvD;AAaO,SAAS,aAAgB,KAAA,EAA2B;AACzD,EAAA,IAAI,KAAA,CAAM,MAAA,KAAW,CAAA,EAAG,OAAO,MAAA;AAC/B,EAAA,OAAO,KAAA,CAAM,KAAK,KAAA,CAAM,IAAA,CAAK,QAAO,GAAI,KAAA,CAAM,MAAM,CAAC,CAAA;AACvD;AAaO,SAAS,QAAW,KAAA,EAAiB;AAC1C,EAAA,MAAM,MAAA,GAAS,CAAC,GAAG,KAAK,CAAA;AACxB,EAAA,KAAA,IAAS,IAAI,MAAA,CAAO,MAAA,GAAS,CAAA,EAAG,CAAA,GAAI,GAAG,CAAA,EAAA,EAAK;AAC1C,IAAA,MAAM,IAAI,IAAA,CAAK,KAAA,CAAM,KAAK,MAAA,EAAO,IAAK,IAAI,CAAA,CAAE,CAAA;AAC5C,IAAA,CAAC,MAAA,CAAO,CAAC,CAAA,EAAG,MAAA,CAAO,CAAC,CAAC,CAAA,GAAI,CAAC,MAAA,CAAO,CAAC,CAAA,EAAG,MAAA,CAAO,CAAC,CAAC,CAAA;AAAA,EAChD;AACA,EAAA,OAAO,MAAA;AACT;AAaO,SAAS,MAAM,EAAA,EAA2B;AAC/C,EAAA,OAAO,IAAI,OAAA,CAAQ,CAAC,YAAY,UAAA,CAAW,OAAA,EAAS,EAAE,CAAC,CAAA;AACzD;AAcO,SAAS,QAAQ,GAAA,EAAsB;AAC5C,EAAA,OAAO,MAAA,CAAO,IAAA,CAAK,GAAG,CAAA,CAAE,MAAA,KAAW,CAAA;AACrC;AAiBO,SAAS,GAAA,CAAO,GAAA,EAAc,IAAA,EAAc,YAAA,EAAqB;AACtE,EAAA,MAAM,IAAA,GAAO,IAAA,CAAK,KAAA,CAAM,GAAG,CAAA;AAC3B,EAAA,IAAI,MAAA,GAAkB,GAAA;AAEtB,EAAA,KAAA,MAAW,OAAO,IAAA,EAAM;AACtB,IAAA,IAAI,MAAA,IAAU,OAAO,MAAA,KAAW,QAAA,IAAY,OAAO,MAAA,EAAQ;AACzD,MAAA,MAAA,GAAU,OAAmC,GAAG,CAAA;AAAA,IAClD,CAAA,MAAO;AACL,MAAA,OAAO,YAAA;AAAA,IACT;AAAA,EACF;AAEA,EAAA,OAAO,MAAA;AACT;AAeO,SAAS,QAAA,CACd,IACA,IAAA,EACkC;AAClC,EAAA,IAAI,OAAA,GAAgD,IAAA;AAEpD,EAAA,OAAO,YAA4B,IAAA,EAAqB;AACtD,IAAA,IAAI,OAAA,eAAsB,OAAO,CAAA;AACjC,IAAA,OAAA,GAAU,WAAW,MAAM,EAAA,CAAG,MAAM,IAAA,EAAM,IAAI,GAAG,IAAI,CAAA;AAAA,EACvD,CAAA;AACF;AAeO,SAAS,QAAA,CACd,IACA,IAAA,EACkC;AAClC,EAAA,IAAI,QAAA,GAAW,CAAA;AAEf,EAAA,OAAO,YAA4B,IAAA,EAAqB;AACtD,IAAA,MAAM,GAAA,GAAM,KAAK,GAAA,EAAI;AACrB,IAAA,IAAI,GAAA,GAAM,YAAY,IAAA,EAAM;AAC1B,MAAA,QAAA,GAAW,GAAA;AACX,MAAA,EAAA,CAAG,KAAA,CAAM,MAAM,IAAI,CAAA;AAAA,IACrB;AAAA,EACF,CAAA;AACF;AAcO,SAAS,cAAA,CAAe,KAAa,IAAA,EAAsB;AAChE,EAAA,MAAM,IAAA,GAAO,OAAO,cAAA,CAAe,aAAA;AACnC,EAAA,MAAM,MAAA,GAAS,aAAa,IAAI,CAAA;AAChC,EAAA,MAAM,cAAc,IAAA,KAAS,CAAA,GAAI,KAAK,IAAA,GAAO,EAAA,GAAK,OAAO,EAAA,GAAK,IAAA;AAC9D,EAAA,OAAO,CAAA,OAAA,EAAK,GAAG,CAAA,QAAA,EAAM,MAAM,IAAI,WAAW,CAAA,GAAA,CAAA;AAC5C;AAeO,SAAS,YAAA,CACd,UACA,QAAA,EAMA;AACA,EAAA,MAAM,IAAA,GAAO;AAAA,IACX,OAAO,EAAC;AAAA,IACR,YAAY,EAAC;AAAA,IACb,cAAc,EAAC;AAAA,IACf,cAAc;AAAC,GACjB;AAGA,EAAA,KAAA,MAAW,GAAA,IAAO,SAAS,KAAA,EAAO;AAChC,IAAA,MAAM,QAAA,GAAW,QAAA,CAAS,KAAA,CAAM,GAAG,CAAA,IAAK,CAAA;AACxC,IAAA,MAAM,QAAA,GAAW,QAAA,CAAS,KAAA,CAAM,GAAG,CAAA,IAAK,CAAA;AACxC,IAAA,IAAI,aAAa,QAAA,EAAU;AACzB,MAAA,IAAA,CAAK,KAAA,CAAM,GAAG,CAAA,GAAI,QAAA,GAAW,QAAA;AAAA,IAC/B;AAAA,EACF;AAGA,EAAA,MAAM,QAAA,GAAW,IAAI,GAAA,CAAI,QAAA,CAAS,SAAS,CAAA;AAC3C,EAAA,MAAM,QAAA,GAAW,IAAI,GAAA,CAAI,QAAA,CAAS,SAAS,CAAA;AAE3C,EAAA,KAAA,MAAW,IAAA,IAAQ,SAAS,SAAA,EAAW;AACrC,IAAA,IAAI,CAAC,QAAA,CAAS,GAAA,CAAI,IAAI,CAAA,EAAG;AACvB,MAAA,IAAA,CAAK,UAAA,CAAW,KAAK,IAAI,CAAA;AAAA,IAC3B;AAAA,EACF;AAEA,EAAA,KAAA,MAAW,IAAA,IAAQ,SAAS,SAAA,EAAW;AACrC,IAAA,IAAI,CAAC,QAAA,CAAS,GAAA,CAAI,IAAI,CAAA,EAAG;AACvB,MAAA,IAAA,CAAK,YAAA,CAAa,KAAK,IAAI,CAAA;AAAA,IAC7B;AAAA,EACF;AAGA,EAAA,KAAA,MAAW,GAAA,IAAO,SAAS,KAAA,EAAO;AAChC,IAAA,IAAI,SAAS,KAAA,CAAM,GAAG,MAAM,QAAA,CAAS,KAAA,CAAM,GAAG,CAAA,EAAG;AAC/C,MAAA,IAAA,CAAK,YAAA,CAAa,GAAG,CAAA,GAAI,QAAA,CAAS,MAAM,GAAG,CAAA;AAAA,IAC7C;AAAA,EACF;AAEA,EAAA,OAAO,IAAA;AACT","file":"index.mjs","sourcesContent":["// src/engine/core/messages.ts\n\n/**\n * 系统消息常量\n * \n * 使用特殊的标识符(sys: 前缀),让 UI 层知道这需要翻译。\n * 这些常量用于系统级别的提示消息,应该在 UI 层进行本地化处理。\n */\nexport const SystemMessages = {\n /** 资源不足提示 */\n NOT_ENOUGH_RESOURCES: 'sys:not_enough_resources',\n /** 条件不满足提示 */\n REQUIREMENT_NOT_MET: 'sys:requirement_not_met',\n /** 操作成功提示 */\n ACTION_SUCCESS: 'sys:action_success',\n /** 时间回溯成功提示 */\n UNDO_SUCCESS: 'sys:undo_success',\n} as const;","// src/engine/core/constants.ts\n/**\n * 全局常量定义\n */\n\n/**\n * 引擎版本\n */\nexport const ENGINE_VERSION = '1.0.0';\n\n/**\n * 默认配置\n */\nexport const DEFAULT_CONFIG = {\n /** 默认存档键名 */\n DEFAULT_SAVE_KEY: 'game-save',\n /** 最大日志条数 */\n MAX_LOG_ENTRIES: 50,\n /** 最大历史快照数 */\n MAX_HISTORY_SNAPSHOTS: 20,\n /** 飘字显示时长(毫秒) */\n TOAST_DURATION: 3000,\n} as const;\n\n/**\n * 日志类型颜色映射\n */\nexport const LOG_TYPE_COLORS = {\n info: '#3b82f6',\n success: '#10b981',\n warn: '#f59e0b',\n error: '#ef4444',\n result: '#6366f1',\n} as const;\n\n/**\n * 默认属性值\n */\nexport const DEFAULT_STATS = {\n /** 默认生命值 */\n DEFAULT_HP: 100,\n /** 默认金币 */\n DEFAULT_GOLD: 0,\n} as const;\n\n/**\n * 游戏时间常量\n */\nexport const TIME_CONSTANTS = {\n /** 一天的小时数 */\n HOURS_PER_DAY: 24,\n /** 早晨开始时间 */\n MORNING_START: 6,\n /** 中午开始时间 */\n NOON_START: 12,\n /** 傍晚开始时间 */\n EVENING_START: 18,\n /** 夜晚开始时间 */\n NIGHT_START: 22,\n} as const;\n\n/**\n * UI 常量\n */\nexport const UI_CONSTANTS = {\n /** 侧边栏宽度 */\n SIDEBAR_WIDTH: 288, // 72 * 4 = 288px (w-72)\n /** 日志栏宽度 */\n LOG_WIDTH: 320, // 80 * 4 = 320px (w-80)\n /** Toast 容器 z-index */\n TOAST_Z_INDEX: 1000,\n /** Modal 容器 z-index */\n MODAL_Z_INDEX: 2000,\n} as const;\n\n/**\n * 验证常量\n */\nexport const VALIDATION = {\n /** 最小属性值 */\n MIN_STAT_VALUE: 0,\n /** 最大属性值 */\n MAX_STAT_VALUE: 9999,\n /** 最大背包容量 */\n MAX_INVENTORY_SIZE: 100,\n /** 最小动作 ID 长度 */\n MIN_ACTION_ID_LENGTH: 1,\n /** 最大动作 ID 长度 */\n MAX_ACTION_ID_LENGTH: 50,\n} as const;","// src/engine/core/utils.ts\n/**\n * 工具函数集合\n */\n\nimport type { GameState } from './types';\nimport { TIME_CONSTANTS } from './constants';\n\n/**\n * 生成唯一 ID\n * \n * @returns 唯一标识符字符串\n * \n * @example\n * ```typescript\n * const id = generateId(); // \"1234567890-abc123\"\n * ```\n */\nexport function generateId(): string {\n return `${Date.now()}-${Math.random().toString(36).slice(2, 11)}`;\n}\n\n/**\n * 深拷贝对象\n * \n * 使用 JSON 序列化实现深拷贝,注意会丢失函数、Symbol 等特殊类型\n * \n * @param obj - 要拷贝的对象\n * @returns 深拷贝后的对象\n * \n * @example\n * ```typescript\n * const copy = deepClone(originalObject);\n * ```\n */\nexport function deepClone<T>(obj: T): T {\n return JSON.parse(JSON.stringify(obj));\n}\n\n/**\n * 限制数值在指定范围内\n * \n * @param value - 要限制的值\n * @param min - 最小值\n * @param max - 最大值\n * @returns 限制后的值\n * \n * @example\n * ```typescript\n * clamp(150, 0, 100); // 100\n * clamp(-10, 0, 100); // 0\n * clamp(50, 0, 100); // 50\n * ```\n */\nexport function clamp(value: number, min: number, max: number): number {\n return Math.min(Math.max(value, min), max);\n}\n\n/**\n * 格式化数字,添加千位分隔符\n * \n * @param num - 要格式化的数字\n * @returns 格式化后的字符串\n * \n * @example\n * ```typescript\n * formatNumber(1234567); // \"1,234,567\"\n * ```\n */\nexport function formatNumber(num: number): string {\n return num.toString().replace(/\\B(?=(\\d{3})+(?!\\d))/g, ',');\n}\n\n/**\n * 获取时间段描述\n * \n * @param hour - 小时数 (0-23)\n * @returns 时间段描述\n * \n * @example\n * ```typescript\n * getTimeOfDay(8); // \"早晨\"\n * getTimeOfDay(14); // \"下午\"\n * getTimeOfDay(20); // \"傍晚\"\n * ```\n */\nexport function getTimeOfDay(hour: number): string {\n if (hour >= TIME_CONSTANTS.MORNING_START && hour < TIME_CONSTANTS.NOON_START) {\n return '早晨';\n } else if (hour >= TIME_CONSTANTS.NOON_START && hour < TIME_CONSTANTS.EVENING_START) {\n return '下午';\n } else if (hour >= TIME_CONSTANTS.EVENING_START && hour < TIME_CONSTANTS.NIGHT_START) {\n return '傍晚';\n } else {\n return '夜晚';\n }\n}\n\n/**\n * 计算百分比\n * \n * @param current - 当前值\n * @param max - 最大值\n * @returns 百分比 (0-100)\n * \n * @example\n * ```typescript\n * getPercentage(75, 100); // 75\n * getPercentage(0, 100); // 0\n * ```\n */\nexport function getPercentage(current: number, max: number): number {\n if (max === 0) return 0;\n return Math.round((current / max) * 100);\n}\n\n/**\n * 随机整数\n * \n * @param min - 最小值(包含)\n * @param max - 最大值(包含)\n * @returns 随机整数\n * \n * @example\n * ```typescript\n * randomInt(1, 6); // 1-6 之间的随机整数(模拟骰子)\n * ```\n */\nexport function randomInt(min: number, max: number): number {\n return Math.floor(Math.random() * (max - min + 1)) + min;\n}\n\n/**\n * 从数组中随机选择一个元素\n * \n * @param array - 数组\n * @returns 随机选择的元素,如果数组为空则返回 undefined\n * \n * @example\n * ```typescript\n * randomChoice(['剑', '盾', '药水']); // 随机返回一个\n * ```\n */\nexport function randomChoice<T>(array: T[]): T | undefined {\n if (array.length === 0) return undefined;\n return array[Math.floor(Math.random() * array.length)];\n}\n\n/**\n * 打乱数组顺序(Fisher-Yates 算法)\n * \n * @param array - 要打乱的数组\n * @returns 打乱后的新数组\n * \n * @example\n * ```typescript\n * shuffle([1, 2, 3, 4, 5]); // [3, 1, 5, 2, 4]\n * ```\n */\nexport function shuffle<T>(array: T[]): T[] {\n const result = [...array];\n for (let i = result.length - 1; i > 0; i--) {\n const j = Math.floor(Math.random() * (i + 1));\n [result[i], result[j]] = [result[j], result[i]];\n }\n return result;\n}\n\n/**\n * 延迟执行\n * \n * @param ms - 延迟毫秒数\n * @returns Promise\n * \n * @example\n * ```typescript\n * await delay(1000); // 延迟 1 秒\n * ```\n */\nexport function delay(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\n/**\n * 检查对象是否为空\n * \n * @param obj - 要检查的对象\n * @returns 是否为空\n * \n * @example\n * ```typescript\n * isEmpty({}); // true\n * isEmpty({ a: 1 }); // false\n * ```\n */\nexport function isEmpty(obj: object): boolean {\n return Object.keys(obj).length === 0;\n}\n\n/**\n * 安全地获取嵌套属性\n * \n * @param obj - 对象\n * @param path - 属性路径,用点分隔\n * @param defaultValue - 默认值\n * @returns 属性值或默认值\n * \n * @example\n * ```typescript\n * const obj = { a: { b: { c: 123 } } };\n * get(obj, 'a.b.c', 0); // 123\n * get(obj, 'a.x.y', 0); // 0\n * ```\n */\nexport function get<T>(obj: unknown, path: string, defaultValue?: T): T {\n const keys = path.split('.');\n let result: unknown = obj;\n\n for (const key of keys) {\n if (result && typeof result === 'object' && key in result) {\n result = (result as Record<string, unknown>)[key];\n } else {\n return defaultValue as T;\n }\n }\n\n return result as T;\n}\n\n/**\n * 防抖函数\n * \n * @param fn - 要防抖的函数\n * @param wait - 等待时间(毫秒)\n * @returns 防抖后的函数\n * \n * @example\n * ```typescript\n * const debouncedSave = debounce(() => saveGame(), 1000);\n * debouncedSave(); // 1秒内多次调用只执行最后一次\n * ```\n */\nexport function debounce<T extends (...args: never[]) => unknown>(\n fn: T,\n wait: number\n): (...args: Parameters<T>) => void {\n let timeout: ReturnType<typeof setTimeout> | null = null;\n\n return function (this: unknown, ...args: Parameters<T>) {\n if (timeout) clearTimeout(timeout);\n timeout = setTimeout(() => fn.apply(this, args), wait);\n };\n}\n\n/**\n * 节流函数\n * \n * @param fn - 要节流的函数\n * @param wait - 等待时间(毫秒)\n * @returns 节流后的函数\n * \n * @example\n * ```typescript\n * const throttledUpdate = throttle(() => updateUI(), 100);\n * throttledUpdate(); // 100ms 内只执行一次\n * ```\n */\nexport function throttle<T extends (...args: never[]) => unknown>(\n fn: T,\n wait: number\n): (...args: Parameters<T>) => void {\n let lastTime = 0;\n\n return function (this: unknown, ...args: Parameters<T>) {\n const now = Date.now();\n if (now - lastTime >= wait) {\n lastTime = now;\n fn.apply(this, args);\n }\n };\n}\n\n/**\n * 格式化游戏时间\n * \n * @param day - 天数\n * @param time - 小时数\n * @returns 格式化的时间字符串\n * \n * @example\n * ```typescript\n * formatGameTime(5, 14); // \"第 5 天 下午 2:00\"\n * ```\n */\nexport function formatGameTime(day: number, time: number): string {\n const hour = time % TIME_CONSTANTS.HOURS_PER_DAY;\n const period = getTimeOfDay(hour);\n const displayHour = hour === 0 ? 12 : hour > 12 ? hour - 12 : hour;\n return `第 ${day} 天 ${period} ${displayHour}:00`;\n}\n\n/**\n * 计算两个状态之间的差异\n * \n * @param oldState - 旧状态\n * @param newState - 新状态\n * @returns 差异对象\n * \n * @example\n * ```typescript\n * const diff = getStateDiff(oldState, newState);\n * console.log(diff.stats); // { hp: -10, gold: 5 }\n * ```\n */\nexport function getStateDiff<S extends string, I extends string, F extends string, X>(\n oldState: GameState<S, I, F, X>,\n newState: GameState<S, I, F, X>\n): {\n stats: Partial<Record<S, number>>;\n itemsAdded: I[];\n itemsRemoved: I[];\n flagsChanged: Partial<Record<F, boolean>>;\n} {\n const diff = {\n stats: {} as Partial<Record<S, number>>,\n itemsAdded: [] as I[],\n itemsRemoved: [] as I[],\n flagsChanged: {} as Partial<Record<F, boolean>>,\n };\n\n // 计算属性差异\n for (const key in newState.stats) {\n const oldValue = oldState.stats[key] || 0;\n const newValue = newState.stats[key] || 0;\n if (oldValue !== newValue) {\n diff.stats[key] = newValue - oldValue;\n }\n }\n\n // 计算物品差异\n const oldItems = new Set(oldState.inventory);\n const newItems = new Set(newState.inventory);\n\n for (const item of newState.inventory) {\n if (!oldItems.has(item)) {\n diff.itemsAdded.push(item);\n }\n }\n\n for (const item of oldState.inventory) {\n if (!newItems.has(item)) {\n diff.itemsRemoved.push(item);\n }\n }\n\n // 计算标记差异\n for (const key in newState.flags) {\n if (oldState.flags[key] !== newState.flags[key]) {\n diff.flagsChanged[key] = newState.flags[key];\n }\n }\n\n return diff;\n}"]}
|
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export { A as ActionDef, E as EffectDef, G as GameState, b as LocationDef, L as LogEntry, a as NotificationPayload, N as NotificationType, R as RequirementDef, S as StatRequirement, W as WorldState } from './types-CZueoTHl.mjs';
|
|
2
|
+
export { DEFAULT_CONFIG, DEFAULT_STATS, ENGINE_VERSION, LOG_TYPE_COLORS, SystemMessages, TIME_CONSTANTS, UI_CONSTANTS, VALIDATION, clamp, debounce, deepClone, delay, formatGameTime, formatNumber, generateId, get, getPercentage, getStateDiff, getTimeOfDay, isEmpty, randomChoice, randomInt, shuffle, throttle } from './core/index.mjs';
|
|
3
|
+
export { a as GameStore, G as GameStoreActions, c as createGameEngineStore } from './store-BeEHel1o.mjs';
|
|
4
|
+
export { HistoryManager } from './state/index.mjs';
|
|
5
|
+
export { EngineEvents, EventBus, FlowSystem, QuerySystem, gameEvents } from './systems/index.mjs';
|
|
6
|
+
export { Layout, LogStream, MainContent, OverlaySystem } from './ui/index.mjs';
|
|
7
|
+
import 'zustand/middleware';
|
|
8
|
+
import 'zustand';
|
|
9
|
+
import 'react';
|
|
10
|
+
import 'react/jsx-runtime';
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export { A as ActionDef, E as EffectDef, G as GameState, b as LocationDef, L as LogEntry, a as NotificationPayload, N as NotificationType, R as RequirementDef, S as StatRequirement, W as WorldState } from './types-CZueoTHl.js';
|
|
2
|
+
export { DEFAULT_CONFIG, DEFAULT_STATS, ENGINE_VERSION, LOG_TYPE_COLORS, SystemMessages, TIME_CONSTANTS, UI_CONSTANTS, VALIDATION, clamp, debounce, deepClone, delay, formatGameTime, formatNumber, generateId, get, getPercentage, getStateDiff, getTimeOfDay, isEmpty, randomChoice, randomInt, shuffle, throttle } from './core/index.js';
|
|
3
|
+
export { a as GameStore, G as GameStoreActions, c as createGameEngineStore } from './store-BP5bpjRr.js';
|
|
4
|
+
export { HistoryManager } from './state/index.js';
|
|
5
|
+
export { EngineEvents, EventBus, FlowSystem, QuerySystem, gameEvents } from './systems/index.js';
|
|
6
|
+
export { Layout, LogStream, MainContent, OverlaySystem } from './ui/index.js';
|
|
7
|
+
import 'zustand/middleware';
|
|
8
|
+
import 'zustand';
|
|
9
|
+
import 'react';
|
|
10
|
+
import 'react/jsx-runtime';
|