jihaitang commited on
Commit
c421b53
·
verified ·
1 Parent(s): e4e2b2f

Upload 3 files

Browse files
Files changed (3) hide show
  1. index.html +111 -0
  2. script.js +915 -0
  3. style.css +575 -0
index.html ADDED
@@ -0,0 +1,111 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="zh-CN">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>对战系统</title>
7
+ <link rel="stylesheet" href="style.css">
8
+ <link rel="preconnect" href="https://fonts.googleapis.com">
9
+ <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
10
+ <link href="https://fonts.googleapis.com/css2?family=Ma+Shan+Zheng&family=ZCOOL+XiaoWei&display=swap" rel="stylesheet">
11
+ </head>
12
+ <body>
13
+ <div class="game-container">
14
+ <div class="npc-portrait-layer"></div>
15
+ <div class="screen-flash"></div>
16
+ <!-- 战斗场景 -->
17
+ <div class="battle-scene">
18
+ <!-- 回合指示器 -->
19
+ <div class="turn-indicator">
20
+ <div id="turn-text">我方行动</div>
21
+ </div>
22
+
23
+ <!-- 玩家状态区 -->
24
+ <div class="player-status-area">
25
+ <div class="health-container">
26
+ <div class="health-bar">
27
+ <div class="health-fill" id="player-health"></div>
28
+ </div>
29
+ <div class="health-text">
30
+ <span id="player-health-value">50</span>/<span id="player-max-health">50</span>
31
+ </div>
32
+ </div>
33
+ <div class="energy-display">
34
+ <div class="energy-value"><span id="player-energy">0</span>/10</div>
35
+ <div class="energy-icon">⚡</div>
36
+ </div>
37
+ </div>
38
+
39
+ <!-- 敌人状态区 -->
40
+ <div class="enemy-status-area">
41
+ <div class="health-container">
42
+ <div class="health-bar">
43
+ <div class="health-fill" id="enemy-health"></div>
44
+ </div>
45
+ <div class="health-text">
46
+ <span id="enemy-health-value">50</span>/<span id="enemy-max-health">50</span>
47
+ </div>
48
+ </div>
49
+ <div class="energy-display">
50
+ <div class="energy-value"><span id="enemy-energy">0</span>/10</div>
51
+ <div class="energy-icon">⚡</div>
52
+ </div>
53
+ </div>
54
+
55
+ <!-- 左侧玩家角色 -->
56
+ <div class="character player-character"></div>
57
+
58
+ <!-- 右侧敌方角色 -->
59
+ <div class="character enemy-character"></div>
60
+
61
+ <!-- 战斗命令区域 -->
62
+ <div class="command-buttons-floating">
63
+ <div class="command-btn" id="gather" data-key="Q">
64
+ <div class="key-hint">Q</div>
65
+ <div class="btn-name">集气</div>
66
+ </div>
67
+ <div class="command-btn" id="defend" data-key="W">
68
+ <div class="key-hint">W</div>
69
+ <div class="btn-name">防御</div>
70
+ </div>
71
+ <div class="command-btn" id="light-attack" data-key="E">
72
+ <div class="key-hint">E</div>
73
+ <div class="btn-name">轻攻击</div>
74
+ </div>
75
+ <div class="command-btn" id="heavy-attack" data-key="R">
76
+ <div class="key-hint">R</div>
77
+ <div class="btn-name">重攻击</div>
78
+ </div>
79
+ <div class="command-btn" id="special" data-key="F">
80
+ <div class="key-hint">T</div>
81
+ <div class="btn-name">绝招</div>
82
+ </div>
83
+ <div class="command-btn" id="taunt" data-key="C">
84
+ <div class="key-hint">Y</div>
85
+ <div class="btn-name">嘴炮</div>
86
+ </div>
87
+ </div>
88
+ </div>
89
+
90
+ <!-- 战斗日志 -->
91
+ <div class="battle-log" id="battle-log">
92
+ <p>战斗开始,请选择行动...</p>
93
+ </div>
94
+
95
+ <!-- 确认弹窗 -->
96
+ <div id="confirm-modal" class="modal">
97
+ <div class="modal-content">
98
+ <div class="modal-header">确认行动</div>
99
+ <div class="modal-body">
100
+ 已选择: <span id="selected-action">无</span>
101
+ </div>
102
+ <div class="modal-footer">
103
+ <button id="confirm-action">确认</button>
104
+ <button id="cancel-action">取消</button>
105
+ </div>
106
+ </div>
107
+ </div>
108
+ </div>
109
+ <script src="script.js"></script>
110
+ </body>
111
+ </html>
script.js ADDED
@@ -0,0 +1,915 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // 敌方信息原始文本
2
+ const enemyInfoText = `
3
+ 发起战斗,敌方信息如下
4
+ name: 杂鱼
5
+ maxHealth: 低
6
+ basicDamage: 低
7
+ `;
8
+
9
+ // 游戏主背景和弹窗背景图片链接
10
+ const GAME_BG_URL = 'https://files.catbox.moe/4qg2k3.png';
11
+ const MODAL_BG_URL = 'https://img.freepik.com/free-photo/brown-concrete-wall-with-scratches_45130-1491.jpg?size=626&ext=jpg';
12
+
13
+ // 玩家信息
14
+ const PLAYER_INFO = {
15
+ name: 'user',
16
+ maxHealth: 50,
17
+ currentHealth: 50,
18
+ energy: 0,
19
+ maxEnergy: 10,
20
+ selectedAction: null,
21
+ basicDamage: 20 // 轻攻击基础伤害
22
+ };
23
+
24
+ // 生命值和伤害等级映射
25
+ const healthMap = { '低': 50, '中': 80, '高': 100 };
26
+ const damageMap = { '低': 20, '中': 30, '高': 40 };
27
+ const styles = ['风', '火', '林', '山'];
28
+
29
+ // 常见NPC信息
30
+ const commonNPCs = {
31
+ '姬姒': {
32
+ name: '姬姒',
33
+ maxHealth: 100,
34
+ basicDamage: 30,
35
+ style: '风',
36
+ portrait: 'https://files.catbox.moe/3sfu4i.png'
37
+ },
38
+ '北条': {
39
+ name: '北条',
40
+ maxHealth: 80,
41
+ basicDamage: 50,
42
+ style: '火',
43
+ portrait: 'https://files.catbox.moe/07djrh.png'
44
+ },
45
+ '神宫寺': {
46
+ name: '神宫寺',
47
+ maxHealth: 120,
48
+ basicDamage: 20,
49
+ style: '山',
50
+ portrait: 'https://files.catbox.moe/3sfu4i.png'
51
+ },
52
+ // 可继续添加更多NPC
53
+ };
54
+
55
+ // 解析敌方信息的函数
56
+ function parseEnemyInfo(text) {
57
+ // 提取
58
+ const nameMatch = text.match(/name:\s*([^\n]+)/);
59
+ const npcName = nameMatch ? nameMatch[1].trim() : '';
60
+ clearEnemyPortrait();
61
+ // 优先查找常见NPC
62
+ if (npcName && commonNPCs[npcName]) {
63
+ const npc = commonNPCs[npcName];
64
+ // 更新敌人立绘
65
+ updateEnemyPortrait(npc.portrait);
66
+ return {
67
+ name: npc.name,
68
+ maxHealth: npc.maxHealth,
69
+ currentHealth: npc.maxHealth,
70
+ energy: 0,
71
+ maxEnergy: 10,
72
+ selectedAction: null,
73
+ basicDamage: npc.basicDamage,
74
+ style: npc.style
75
+ };
76
+ }
77
+
78
+ // 没有匹配到常见NPC,走原有解析逻辑,风格随机
79
+ const maxHealthMatch = text.match(/maxHealth:\s*([^\n]+)/);
80
+ const basicDamageMatch = text.match(/basicDamage:\s*([^\n]+)/);
81
+ // 清除敌人立绘
82
+ clearEnemyPortrait();
83
+ return {
84
+ name: npcName,
85
+ maxHealth: maxHealthMatch ? healthMap[maxHealthMatch[1].trim()] || 80 : 80,
86
+ currentHealth: maxHealthMatch ? healthMap[maxHealthMatch[1].trim()] || 80 : 80,
87
+ energy: 0,
88
+ maxEnergy: 10,
89
+ selectedAction: null,
90
+ basicDamage: basicDamageMatch ? damageMap[basicDamageMatch[1].trim()] || 30 : 30,
91
+ style: styles[Math.floor(Math.random() * styles.length)]
92
+ };
93
+ }
94
+
95
+ // 更新敌人立绘
96
+ function updateEnemyPortrait(portraitUrl) {
97
+ const npcPortraitLayer = document.querySelector('.npc-portrait-layer');
98
+ npcPortraitLayer.style.backgroundImage = `url('${portraitUrl}')`;
99
+ }
100
+
101
+ // 清除敌人立绘
102
+ function clearEnemyPortrait() {
103
+ const npcPortraitLayer = document.querySelector('.npc-portrait-layer');
104
+ npcPortraitLayer.style.backgroundImage = '';
105
+ }
106
+
107
+ // 游戏状态对象
108
+ const gameState = {
109
+ currentTurn: 'player', // 'player' or 'enemy'
110
+ waitingForConfirmation: false,
111
+ player: { ...PLAYER_INFO },
112
+ enemy: parseEnemyInfo(enemyInfoText)
113
+ };
114
+
115
+ // 获取DOM元素
116
+ const playerHealthBar = document.getElementById('player-health');
117
+ const enemyHealthBar = document.getElementById('enemy-health');
118
+ const playerHealthValue = document.getElementById('player-health-value');
119
+ const enemyHealthValue = document.getElementById('enemy-health-value');
120
+ const playerMaxHealth = document.getElementById('player-max-health'); // 新增
121
+ const enemyMaxHealth = document.getElementById('enemy-max-health'); // 新增
122
+ const playerEnergyDisplay = document.getElementById('player-energy');
123
+ const enemyEnergyDisplay = document.getElementById('enemy-energy');
124
+ const battleLog = document.getElementById('battle-log');
125
+ const turnText = document.getElementById('turn-text');
126
+ const selectedActionText = document.getElementById('selected-action');
127
+ const confirmActionButton = document.getElementById('confirm-action');
128
+ const cancelActionButton = document.getElementById('cancel-action');
129
+ const commandButtons = document.querySelectorAll('.command-btn');
130
+ const confirmModal = document.getElementById('confirm-modal');
131
+
132
+ // 角色元素
133
+ const playerCharacter = document.querySelector('.player-character');
134
+ const enemyCharacter = document.querySelector('.enemy-character');
135
+
136
+ // 初始化游戏
137
+ function initGame() {
138
+ updateDisplay();
139
+ addLog('战斗开始,请选择行动...');
140
+
141
+ // 添加按钮点击事件 - 支持触屏和鼠标
142
+ setupButtonEvents();
143
+
144
+ // 键盘控制
145
+ document.addEventListener('keydown', handleKeyPress);
146
+ }
147
+
148
+ // 设置按钮事件
149
+ function setupButtonEvents() {
150
+ document.getElementById('gather').addEventListener('click', () => selectAction('gather'));
151
+ document.getElementById('defend').addEventListener('click', () => selectAction('defend'));
152
+ document.getElementById('light-attack').addEventListener('click', () => selectAction('light-attack'));
153
+ document.getElementById('heavy-attack').addEventListener('click', () => selectAction('heavy-attack'));
154
+ document.getElementById('special').addEventListener('click', () => selectAction('special'));
155
+ document.getElementById('taunt').addEventListener('click', () => selectAction('taunt'));
156
+
157
+ // 确认按钮事件
158
+ confirmActionButton.addEventListener('click', () => {
159
+ confirmModal.style.display = 'none';
160
+ confirmAction();
161
+ });
162
+
163
+ // 取消按钮事件
164
+ cancelActionButton.addEventListener('click', () => {
165
+ confirmModal.style.display = 'none';
166
+ gameState.player.selectedAction = null;
167
+ updateDisplay();
168
+ });
169
+ }
170
+
171
+ // 更新显示
172
+ function updateDisplay() {
173
+ // 更新生命值显示
174
+ playerHealthBar.style.width = `${(gameState.player.currentHealth / gameState.player.maxHealth) * 100}%`;
175
+ enemyHealthBar.style.width = `${(gameState.enemy.currentHealth / gameState.enemy.maxHealth) * 100}%`;
176
+
177
+ // 更新生命值文本
178
+ playerHealthValue.textContent = gameState.player.currentHealth;
179
+ enemyHealthValue.textContent = gameState.enemy.currentHealth;
180
+
181
+ // 更新最大生命值文本
182
+ playerMaxHealth.textContent = gameState.player.maxHealth;
183
+ enemyMaxHealth.textContent = gameState.enemy.maxHealth;
184
+
185
+ // 更新能量值
186
+ playerEnergyDisplay.textContent = gameState.player.energy;
187
+ enemyEnergyDisplay.textContent = gameState.enemy.energy;
188
+
189
+ // 更新回合指示
190
+ turnText.textContent = gameState.currentTurn === 'player' ? '我方行动' : '敌方行动';
191
+
192
+ // 根据能量值启用/禁用按钮
193
+ checkButtonAvailability();
194
+ }
195
+
196
+ // 检查按钮可用性
197
+ function checkButtonAvailability() {
198
+ // 如果不是玩家回合或正在等待确认,禁用所有按钮
199
+ if (gameState.currentTurn !== 'player' || gameState.waitingForConfirmation) {
200
+ commandButtons.forEach(btn => {
201
+ btn.classList.add('disabled');
202
+ });
203
+ return;
204
+ }
205
+
206
+ // 重置按钮状态
207
+ commandButtons.forEach(btn => {
208
+ btn.classList.remove('disabled');
209
+ btn.classList.remove('selected');
210
+ });
211
+
212
+ // 根据能量值启用/禁用按钮
213
+ if (gameState.player.energy < 1) {
214
+ document.getElementById('light-attack').classList.add('disabled');
215
+ }
216
+
217
+ if (gameState.player.energy < 2) {
218
+ document.getElementById('heavy-attack').classList.add('disabled');
219
+ }
220
+
221
+ if (gameState.player.energy < 5) {
222
+ document.getElementById('special').classList.add('disabled');
223
+ }
224
+
225
+ // 如果有选中的动作,高亮显示
226
+ if (gameState.player.selectedAction) {
227
+ document.getElementById(gameState.player.selectedAction).classList.add('selected');
228
+ }
229
+ }
230
+
231
+ // 添加战斗日志
232
+ function addLog(message) {
233
+ const logEntry = document.createElement('p');
234
+ logEntry.textContent = message;
235
+ battleLog.appendChild(logEntry);
236
+ battleLog.scrollTop = battleLog.scrollHeight;
237
+ }
238
+
239
+ // 选择动作
240
+ function selectAction(action) {
241
+ // 如果不是玩家回合或正在等待确认,返回
242
+ if (gameState.currentTurn !== 'player' || gameState.waitingForConfirmation) return;
243
+
244
+ // 检查按钮是否被禁用
245
+ if (document.getElementById(action).classList.contains('disabled')) {
246
+ return;
247
+ }
248
+
249
+ // 清除之前的选择
250
+ commandButtons.forEach(btn => btn.classList.remove('selected'));
251
+
252
+ // 检查是否有足够的能量
253
+ if ((action === 'light-attack' && gameState.player.energy < 1) ||
254
+ (action === 'heavy-attack' && gameState.player.energy < 2) ||
255
+ (action === 'special' && gameState.player.energy < 5)) {
256
+ addLog('能量不足,无法执行此动作!');
257
+ return;
258
+ }
259
+
260
+ // 设置选中状态
261
+ document.getElementById(action).classList.add('selected');
262
+ gameState.player.selectedAction = action;
263
+
264
+ // 更新选择显示
265
+ const actionNames = {
266
+ 'gather': '集气',
267
+ 'defend': '防御',
268
+ 'light-attack': '轻攻击',
269
+ 'heavy-attack': '重攻击',
270
+ 'special': '绝招',
271
+ 'taunt': '嘴炮'
272
+ };
273
+ selectedActionText.textContent = actionNames[action];
274
+
275
+ // 显示确认弹窗
276
+ confirmModal.style.display = 'flex';
277
+ }
278
+
279
+ // 确认动作
280
+ function confirmAction() {
281
+ if (!gameState.player.selectedAction) return;
282
+
283
+ // 设置为等待确认状态
284
+ gameState.waitingForConfirmation = true;
285
+
286
+ // 禁用按钮
287
+ commandButtons.forEach(btn => {
288
+ btn.classList.add('disabled');
289
+ });
290
+
291
+ addLog(`${gameState.player.name}准备行动...`);
292
+
293
+ // 敌人AI选择动作
294
+ selectEnemyAction();
295
+
296
+ // 执行回合结算
297
+ setTimeout(executeTurn, 1000);
298
+ }
299
+
300
+ // 敌人AI选择动作
301
+ function selectEnemyAction() {
302
+ const enemy = gameState.enemy;
303
+ const player = gameState.player;
304
+ const style = enemy.style || '风'; // 默认风格
305
+
306
+ // 玩家气的威胁等级
307
+ const playerEnergy = player.energy;
308
+
309
+ // 嘴炮判定:玩家气满5时,敌人有较高概率嘴炮
310
+ if (playerEnergy >= 5) {
311
+ if (style === '山' && Math.random() < 0.5) {
312
+ enemy.selectedAction = 'taunt';
313
+ return;
314
+ }
315
+ if (style === '林' && Math.random() < 0.4) {
316
+ enemy.selectedAction = 'taunt';
317
+ return;
318
+ }
319
+ if (style === '火' && Math.random() < 0.25) {
320
+ enemy.selectedAction = 'taunt';
321
+ return;
322
+ }
323
+ if (style === '风' && Math.random() < 0.2) {
324
+ enemy.selectedAction = 'taunt';
325
+ return;
326
+ }
327
+ }
328
+
329
+ // 防御判定:玩家气较高时,敌人有概率防御
330
+ if (playerEnergy >= 1) {
331
+ if (style === '山' && Math.random() < 0.5) {
332
+ enemy.selectedAction = 'defend';
333
+ return;
334
+ }
335
+ if (style === '林' && Math.random() < 0.3) {
336
+ enemy.selectedAction = 'defend';
337
+ return;
338
+ }
339
+ if (style === '火' && Math.random() < 0.2) {
340
+ enemy.selectedAction = 'defend';
341
+ return;
342
+ }
343
+ if (style === '风' && Math.random() < 0.15) {
344
+ enemy.selectedAction = 'defend';
345
+ return;
346
+ }
347
+ }
348
+
349
+ // 风格主策略
350
+ if (style === '风') {
351
+ // 风:更倾向于轻攻击
352
+ if (enemy.energy >= 1 && Math.random() < 0.7) {
353
+ enemy.selectedAction = 'light-attack';
354
+ return;
355
+ }
356
+ if (enemy.energy < 10 && Math.random() < 0.6) {
357
+ enemy.selectedAction = 'gather';
358
+ return;
359
+ }
360
+ if (enemy.energy >= 2 && Math.random() < 0.3) {
361
+ enemy.selectedAction = 'heavy-attack';
362
+ return;
363
+ }
364
+ if (enemy.energy >= 5 && Math.random() < 0.2) {
365
+ enemy.selectedAction = 'special';
366
+ return;
367
+ }
368
+ enemy.selectedAction = 'gather';
369
+ return;
370
+ }
371
+
372
+ if (style === '火') {
373
+ // 火:更倾向于重攻击
374
+ if (enemy.energy >= 2 && Math.random() < 0.7) {
375
+ enemy.selectedAction = 'heavy-attack';
376
+ return;
377
+ }
378
+ if (enemy.energy >= 1 && Math.random() < 0.4) {
379
+ enemy.selectedAction = 'light-attack';
380
+ return;
381
+ }
382
+ if (enemy.energy < 10 && Math.random() < 0.5) {
383
+ enemy.selectedAction = 'gather';
384
+ return;
385
+ }
386
+ if (enemy.energy >= 5 && Math.random() < 0.2) {
387
+ enemy.selectedAction = 'special';
388
+ return;
389
+ }
390
+ enemy.selectedAction = 'gather';
391
+ return;
392
+ }
393
+
394
+ if (style === '林') {
395
+ // 林:更倾向于攒气用绝招
396
+ if (enemy.energy >= 5 && Math.random() < 0.7) {
397
+ enemy.selectedAction = 'special';
398
+ return;
399
+ }
400
+ if (enemy.energy < 10 && Math.random() < 0.7) {
401
+ enemy.selectedAction = 'gather';
402
+ return;
403
+ }
404
+ if (enemy.energy >= 2 && Math.random() < 0.2) {
405
+ enemy.selectedAction = 'heavy-attack';
406
+ return;
407
+ }
408
+ if (enemy.energy >= 1 && Math.random() < 0.2) {
409
+ enemy.selectedAction = 'light-attack';
410
+ return;
411
+ }
412
+ enemy.selectedAction = 'gather';
413
+ return;
414
+ }
415
+
416
+ if (style === '山') {
417
+ // 山:注重防守
418
+ if (enemy.currentHealth < enemy.maxHealth * 0.5 && playerEnergy >= 1 && Math.random() < 0.5) {
419
+ enemy.selectedAction = 'defend';
420
+ return;
421
+ }
422
+ if (enemy.energy < 10 && Math.random() < 0.6) {
423
+ enemy.selectedAction = 'gather';
424
+ return;
425
+ }
426
+ if (enemy.energy >= 1 && Math.random() < 0.4) {
427
+ enemy.selectedAction = 'light-attack';
428
+ return;
429
+ }
430
+ if (enemy.energy >= 2 && Math.random() < 0.3) {
431
+ enemy.selectedAction = 'heavy-attack';
432
+ return;
433
+ }
434
+ if (enemy.energy >= 5 && Math.random() < 0.1) {
435
+ enemy.selectedAction = 'special';
436
+ return;
437
+ }
438
+ enemy.selectedAction = 'gather';
439
+ return;
440
+ }
441
+
442
+ // 默认行为
443
+ enemy.selectedAction = 'gather';
444
+ }
445
+
446
+ // 执行回合
447
+ function executeTurn() {
448
+ const player = gameState.player;
449
+ const enemy = gameState.enemy;
450
+
451
+ // 获取双方行动
452
+ const playerAction = player.selectedAction;
453
+ const enemyAction = enemy.selectedAction;
454
+
455
+ addLog(`${enemy.name}选择了行动...`);
456
+
457
+ // 根据行动类型执行特效和结算
458
+ setTimeout(() => {
459
+ // 显示双方选择的动作
460
+ const actionNames = {
461
+ 'gather': '集气',
462
+ 'defend': '防御',
463
+ 'light-attack': '轻攻击',
464
+ 'heavy-attack': '重攻击',
465
+ 'special': '绝招',
466
+ 'taunt': '嘴炮'
467
+ };
468
+
469
+ addLog(`${player.name}使用了${actionNames[playerAction]}!${enemy.name}使用了${actionNames[enemyAction]}!`);
470
+
471
+ // 处理行动结果
472
+ processActions(playerAction, enemyAction);
473
+
474
+ // 检查游戏是否结束
475
+ if (checkGameOver()) {
476
+ return;
477
+ }
478
+
479
+ // 继续下一回合
480
+ continueGame();
481
+ }, 1000);
482
+ }
483
+
484
+ // 处理双方行动的结果
485
+ function processActions(playerAction, enemyAction) {
486
+ const player = gameState.player;
487
+ const enemy = gameState.enemy;
488
+ const gameContainer = document.querySelector('.game-container');
489
+ const npcPortraitLayer = document.querySelector('.npc-portrait-layer');
490
+ const screenFlash = document.querySelector('.screen-flash');
491
+ let playerWasHit = false;
492
+ let enemyWasHit = false;
493
+
494
+ // 处理集气
495
+ if (playerAction === 'gather') {
496
+ if (player.energy < player.maxEnergy) {
497
+ player.energy += 1;
498
+ addLog(`${player.name}集气成功,能量+1!`);
499
+ } else {
500
+ addLog(`${player.name}的能量已满!`);
501
+ }
502
+ }
503
+
504
+ if (enemyAction === 'gather') {
505
+ if (enemy.energy < enemy.maxEnergy) {
506
+ enemy.energy += 1;
507
+ addLog(`${enemy.name}集气成功,能量+1!`);
508
+ } else {
509
+ addLog(`${enemy.name}的能量已满!`);
510
+ }
511
+ }
512
+
513
+ // 处理防御状态
514
+ const playerDefending = playerAction === 'defend';
515
+ const enemyDefending = enemyAction === 'defend';
516
+
517
+ if (playerDefending) {
518
+ playerCharacter.classList.add('player-defend');
519
+ setTimeout(() => {
520
+ playerCharacter.classList.remove('player-defend');
521
+ }, 1000);
522
+ addLog(`${player.name}进入防御状态!`);
523
+ }
524
+
525
+ if (enemyDefending) {
526
+ enemyCharacter.classList.add('enemy-defend');
527
+ setTimeout(() => {
528
+ enemyCharacter.classList.remove('enemy-defend');
529
+ }, 1000);
530
+ addLog(`${enemy.name}进入防御状态!`);
531
+ }
532
+
533
+ // 嘴炮只能无效化绝招的伤害
534
+ let playerTauntSuccess = false;
535
+ let enemyTauntSuccess = false;
536
+
537
+ if (playerAction === 'taunt' && enemyAction === 'special') {
538
+ playerTauntSuccess = true;
539
+ addLog(`${player.name}的嘴炮成功无效化了${enemy.name}的绝招伤害!`);
540
+ // 注意:不在这里扣除敌人的能量,而是统一在特殊技能处理部分扣除
541
+ }
542
+
543
+ if (enemyAction === 'taunt' && playerAction === 'special') {
544
+ enemyTauntSuccess = true;
545
+ addLog(`${enemy.name}的嘴炮成功无效化了${player.name}的绝招伤害!`);
546
+ // 注意:不在这里扣除玩家的能量,而是统一在特殊技能处理部分扣除
547
+ }
548
+
549
+ // 处理绝招(无视防御)
550
+ if (playerAction === 'special') {
551
+ // 无论绝招是否被嘴炮无效化,都消耗能量
552
+ player.energy -= 5;
553
+ playerCharacter.classList.add('player-special');
554
+
555
+ if (!enemyTauntSuccess) {
556
+ enemyCharacter.classList.add('enemy-hit');
557
+
558
+ setTimeout(() => {
559
+ enemyCharacter.classList.remove('enemy-hit');
560
+ }, 1000);
561
+
562
+ const damage = player.basicDamage * 3;
563
+ enemy.currentHealth -= damage;
564
+ addLog(`${player.name}使用绝招,对${enemy.name}造成${damage}点伤害!`);
565
+ enemyWasHit = true;
566
+ } else {
567
+ addLog(`${player.name}使用绝招,但伤害被${enemy.name}的嘴炮无效化了!`);
568
+ }
569
+
570
+ setTimeout(() => {
571
+ playerCharacter.classList.remove('player-special');
572
+ }, 1000);
573
+
574
+ // 无效化敌人的普通攻击
575
+ if (enemyAction === 'light-attack' || enemyAction === 'heavy-attack') {
576
+ addLog(`${enemy.name}的攻击被${player.name}的绝招无效化了!`);
577
+ // 敌人消耗的能量不返还
578
+ if (enemyAction === 'light-attack') enemy.energy -= 1;
579
+ if (enemyAction === 'heavy-attack') enemy.energy -= 2;
580
+ }
581
+ }
582
+
583
+ if (enemyAction === 'special') {
584
+ // 无论绝招是否被嘴炮无效化,都消耗能量
585
+ enemy.energy -= 5;
586
+ enemyCharacter.classList.add('enemy-special');
587
+
588
+ if (!playerTauntSuccess) {
589
+ playerCharacter.classList.add('player-hit');
590
+
591
+ setTimeout(() => {
592
+ playerCharacter.classList.remove('player-hit');
593
+ }, 1000);
594
+
595
+ const damage = enemy.basicDamage * 3;
596
+ player.currentHealth -= damage;
597
+ addLog(`${enemy.name}使用绝招,对${player.name}造成${damage}点伤害!`);
598
+ playerWasHit = true;
599
+ } else {
600
+ addLog(`${enemy.name}使用绝招,但伤害被${player.name}的嘴炮无效化了!`);
601
+ }
602
+
603
+ setTimeout(() => {
604
+ enemyCharacter.classList.remove('enemy-special');
605
+ }, 1000);
606
+
607
+ // 无效化玩家的普通攻击
608
+ if (playerAction === 'light-attack' || playerAction === 'heavy-attack') {
609
+ addLog(`${player.name}的攻击被${enemy.name}的绝招无效化了!`);
610
+ // 玩家消耗的能量不返还
611
+ if (playerAction === 'light-attack') player.energy -= 1;
612
+ if (playerAction === 'heavy-attack') player.energy -= 2;
613
+ }
614
+ }
615
+
616
+ // 如果没有被绝招无效,处理重攻击
617
+ if (playerAction === 'heavy-attack' &&
618
+ enemyAction !== 'special' &&
619
+ playerAction !== 'special') {
620
+ player.energy -= 2;
621
+
622
+ // 检查是否被防御或是否无效对方轻攻击
623
+ if (enemyDefending) {
624
+ playerCharacter.classList.add('player-attack');
625
+
626
+ setTimeout(() => {
627
+ playerCharacter.classList.remove('player-attack');
628
+ }, 600);
629
+
630
+ addLog(`${player.name}的重攻击被${enemy.name}防御了!`);
631
+ } else if (enemyAction === 'light-attack') {
632
+ // 重攻击克制轻攻击
633
+ playerCharacter.classList.add('player-attack');
634
+ enemyCharacter.classList.add('enemy-hit');
635
+
636
+ setTimeout(() => {
637
+ playerCharacter.classList.remove('player-attack');
638
+ enemyCharacter.classList.remove('enemy-hit');
639
+ }, 600);
640
+
641
+ const damage = player.basicDamage * 1.5;
642
+ enemy.currentHealth -= damage;
643
+ enemy.energy -= 1; // 消耗敌人的能量
644
+ addLog(`${player.name}的重攻击无效化了${enemy.name}的轻攻击,并造成${damage}点伤害!`);
645
+ enemyWasHit = true;
646
+ } else {
647
+ playerCharacter.classList.add('player-attack');
648
+ enemyCharacter.classList.add('enemy-hit');
649
+
650
+ setTimeout(() => {
651
+ playerCharacter.classList.remove('player-attack');
652
+ enemyCharacter.classList.remove('enemy-hit');
653
+ }, 600);
654
+
655
+ const damage = player.basicDamage * 1.5;
656
+ enemy.currentHealth -= damage;
657
+ addLog(`${player.name}的重攻击对${enemy.name}造成${damage}点伤害!`);
658
+ enemyWasHit = true;
659
+ }
660
+ }
661
+
662
+ if (enemyAction === 'heavy-attack' &&
663
+ playerAction !== 'special' &&
664
+ enemyAction !== 'special') {
665
+ enemy.energy -= 2;
666
+
667
+ // 检查是否被防御或是否无效对方轻攻击
668
+ if (playerDefending) {
669
+ enemyCharacter.classList.add('enemy-attack');
670
+
671
+ setTimeout(() => {
672
+ enemyCharacter.classList.remove('enemy-attack');
673
+ }, 600);
674
+
675
+ addLog(`${enemy.name}的重攻击被${player.name}防御了!`);
676
+ } else if (playerAction === 'light-attack') {
677
+ // 重攻击克制轻攻击
678
+ enemyCharacter.classList.add('enemy-attack');
679
+ playerCharacter.classList.add('player-hit');
680
+
681
+ setTimeout(() => {
682
+ enemyCharacter.classList.remove('enemy-attack');
683
+ playerCharacter.classList.remove('player-hit');
684
+ }, 600);
685
+
686
+ const damage = enemy.basicDamage * 1.5;
687
+ player.currentHealth -= damage;
688
+ player.energy -= 1; // 消耗玩家的能量
689
+ addLog(`${enemy.name}的重攻击无效化了${player.name}的轻攻击,并造成${damage}点伤害!`);
690
+ playerWasHit = true;
691
+ } else {
692
+ enemyCharacter.classList.add('enemy-attack');
693
+ playerCharacter.classList.add('player-hit');
694
+
695
+ setTimeout(() => {
696
+ enemyCharacter.classList.remove('enemy-attack');
697
+ playerCharacter.classList.remove('player-hit');
698
+ }, 600);
699
+
700
+ const damage = enemy.basicDamage * 1.5;
701
+ player.currentHealth -= damage;
702
+ addLog(`${enemy.name}的重攻击对${player.name}造成${damage}点伤害!`);
703
+ playerWasHit = true;
704
+ }
705
+ }
706
+
707
+ // 如果没有被重攻击或绝招无效,处理轻攻击
708
+ if (playerAction === 'light-attack' &&
709
+ enemyAction !== 'heavy-attack' &&
710
+ enemyAction !== 'special') {
711
+ player.energy -= 1;
712
+
713
+ // 检查是否被防御
714
+ if (enemyDefending) {
715
+ playerCharacter.classList.add('player-attack');
716
+
717
+ setTimeout(() => {
718
+ playerCharacter.classList.remove('player-attack');
719
+ }, 600);
720
+
721
+ addLog(`${player.name}的轻攻击被${enemy.name}防御了!`);
722
+ } else {
723
+ playerCharacter.classList.add('player-attack');
724
+ enemyCharacter.classList.add('enemy-hit');
725
+
726
+ setTimeout(() => {
727
+ playerCharacter.classList.remove('player-attack');
728
+ enemyCharacter.classList.remove('enemy-hit');
729
+ }, 600);
730
+
731
+ const damage = player.basicDamage;
732
+ enemy.currentHealth -= damage;
733
+ addLog(`${player.name}的轻攻击对${enemy.name}造成${damage}点伤害!`);
734
+ enemyWasHit = true;
735
+ }
736
+ }
737
+
738
+ if (enemyAction === 'light-attack' &&
739
+ playerAction !== 'heavy-attack' &&
740
+ playerAction !== 'special') {
741
+ enemy.energy -= 1;
742
+
743
+ // 检查是否被防御
744
+ if (playerDefending) {
745
+ enemyCharacter.classList.add('enemy-attack');
746
+
747
+ setTimeout(() => {
748
+ enemyCharacter.classList.remove('enemy-attack');
749
+ }, 600);
750
+
751
+ addLog(`${enemy.name}的轻攻击被${player.name}防御了!`);
752
+ } else {
753
+ enemyCharacter.classList.add('enemy-attack');
754
+ playerCharacter.classList.add('player-hit');
755
+
756
+ setTimeout(() => {
757
+ enemyCharacter.classList.remove('enemy-attack');
758
+ playerCharacter.classList.remove('player-hit');
759
+ }, 600);
760
+
761
+ const damage = enemy.basicDamage;
762
+ player.currentHealth -= damage;
763
+ addLog(`${enemy.name}的轻攻击对${player.name}造成${damage}点伤害!`);
764
+ playerWasHit = true;
765
+ }
766
+ }
767
+
768
+ // 确保生命值不为负数
769
+ if (player.currentHealth < 0) player.currentHealth = 0;
770
+ if (enemy.currentHealth < 0) enemy.currentHealth = 0;
771
+
772
+ // 受击反馈动画
773
+ if (playerWasHit) {
774
+ gameContainer.classList.add('shake');
775
+ screenFlash.classList.add('active');
776
+ setTimeout(() => {
777
+ gameContainer.classList.remove('shake');
778
+ screenFlash.classList.remove('active');
779
+ }, 400);
780
+ }
781
+ if (enemyWasHit) {
782
+ npcPortraitLayer.classList.add('shake');
783
+ setTimeout(() => {
784
+ npcPortraitLayer.classList.remove('shake');
785
+ }, 400);
786
+ }
787
+
788
+ // 更新显示
789
+ updateDisplay();
790
+ }
791
+
792
+ // 继续游戏
793
+ function continueGame() {
794
+ // 重置选择状态
795
+ gameState.player.selectedAction = null;
796
+ gameState.enemy.selectedAction = null;
797
+ gameState.waitingForConfirmation = false;
798
+ selectedActionText.textContent = '无';
799
+
800
+ // 更新显示
801
+ updateDisplay();
802
+
803
+ // 继续游戏
804
+ addLog('准备下一回合...');
805
+
806
+ // 更新回合指示
807
+ setTimeout(() => {
808
+ addLog('请选择你的行动...');
809
+ }, 1000);
810
+ }
811
+
812
+ // 检查游戏是否结束
813
+ function checkGameOver() {
814
+ if (gameState.player.currentHealth <= 0) {
815
+ addLog(`${gameState.player.name}被击败了!游戏结束。`);
816
+ gameEnd(false);
817
+ return true;
818
+ } else if (gameState.enemy.currentHealth <= 0) {
819
+ addLog(`${gameState.enemy.name}被击败了!胜利!`);
820
+ gameEnd(true);
821
+ return true;
822
+ }
823
+ return false;
824
+ }
825
+
826
+ // 游戏结束
827
+ function gameEnd(isVictory) {
828
+ // 禁用所有按钮
829
+ commandButtons.forEach(btn => {
830
+ btn.classList.add('disabled');
831
+ });
832
+
833
+ // 显示结果
834
+ addLog(isVictory ? '恭喜你取得胜利!' : '游戏结束,再接再厉!');
835
+
836
+ // 添加重新开始游戏的按钮
837
+ const restartBtn = document.createElement('button');
838
+ restartBtn.textContent = '重新开始';
839
+ restartBtn.style.padding = '10px 20px';
840
+ restartBtn.style.margin = '10px auto';
841
+ restartBtn.style.display = 'block';
842
+ restartBtn.style.backgroundColor = '#4c3d2e';
843
+ restartBtn.style.color = 'white';
844
+ restartBtn.style.border = '1px solid #7c5a3d';
845
+ restartBtn.style.borderRadius = '4px';
846
+ restartBtn.style.cursor = 'pointer';
847
+ restartBtn.style.fontFamily = "'Ma Shan Zheng', cursive";
848
+ restartBtn.style.fontSize = '18px';
849
+ restartBtn.onclick = () => window.location.reload();
850
+
851
+ battleLog.appendChild(restartBtn);
852
+ }
853
+
854
+ // 键盘事件处理
855
+ function handleKeyPress(event) {
856
+ // 如果弹窗显示中,按ESC关闭
857
+ if (confirmModal.style.display === 'flex' && event.key === 'Escape') {
858
+ confirmModal.style.display = 'none';
859
+ gameState.player.selectedAction = null;
860
+ updateDisplay();
861
+ return;
862
+ }
863
+
864
+ // 如果弹窗显示中,按Enter确认
865
+ if (confirmModal.style.display === 'flex' && event.key === 'Enter') {
866
+ confirmModal.style.display = 'none';
867
+ confirmAction();
868
+ return;
869
+ }
870
+
871
+ // 如果不是玩家回合或正在等待确认,返回
872
+ if (gameState.currentTurn !== 'player' || gameState.waitingForConfirmation) return;
873
+
874
+ const key = event.key.toUpperCase();
875
+
876
+ switch (key) {
877
+ case 'Q':
878
+ selectAction('gather');
879
+ break;
880
+ case 'W':
881
+ selectAction('defend');
882
+ break;
883
+ case 'E':
884
+ selectAction('light-attack');
885
+ break;
886
+ case 'R':
887
+ selectAction('heavy-attack');
888
+ break;
889
+ case 'T':
890
+ selectAction('special');
891
+ break;
892
+ case 'Y':
893
+ selectAction('taunt');
894
+ break;
895
+ }
896
+ }
897
+
898
+ // 初始化游戏
899
+ document.addEventListener('DOMContentLoaded', () => {
900
+ // 设置主背景
901
+ const gameContainer = document.querySelector('.game-container');
902
+ if (gameContainer) {
903
+ // 保持立绘层的背景不变,只设置背景图层
904
+ const npcPortraitLayer = document.querySelector('.npc-portrait-layer');
905
+
906
+ gameContainer.style.backgroundImage = `url('${GAME_BG_URL}')`;
907
+
908
+ }
909
+ // 设置弹窗背景
910
+ const modalContents = document.querySelectorAll('.modal-content');
911
+ modalContents.forEach(modal => {
912
+ modal.style.background = `url('${MODAL_BG_URL}') center center / cover`;
913
+ });
914
+ initGame();
915
+ });
style.css ADDED
@@ -0,0 +1,575 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ * {
2
+ margin: 0;
3
+ padding: 0;
4
+ box-sizing: border-box;
5
+ user-select: none;
6
+ }
7
+
8
+ body {
9
+ font-family: 'ZCOOL XiaoWei', 'Microsoft YaHei', sans-serif;
10
+ background-color: #000;
11
+ color: #fff;
12
+ overflow: hidden;
13
+ }
14
+
15
+ .game-container {
16
+ width: 100vw;
17
+ height: 100vh;
18
+ position: relative;
19
+ /* background: ... 由JS动态设置 */
20
+ display: flex;
21
+ flex-direction: column;
22
+ background-size: cover;
23
+ background-position: center;
24
+ background-repeat: no-repeat;
25
+ }
26
+
27
+ .battle-scene {
28
+ flex: 1;
29
+ position: relative;
30
+ display: flex;
31
+ justify-content: space-between;
32
+ align-items: flex-end;
33
+ padding-bottom: 100px;
34
+ }
35
+
36
+ /* 状态区样式 */
37
+ .player-status-area {
38
+ position: absolute;
39
+ top: 15px;
40
+ left: 15px;
41
+ background-color: rgba(0, 0, 0, 0.7);
42
+ border-radius: 5px;
43
+ padding: 10px;
44
+ z-index: 5;
45
+ border: 1px solid rgba(255, 255, 255, 0.3);
46
+ box-shadow: 0 0 10px rgba(0, 0, 0, 0.5);
47
+ }
48
+
49
+ .enemy-status-area {
50
+ position: absolute;
51
+ top: 15px;
52
+ right: 15px;
53
+ background-color: rgba(0, 0, 0, 0.7);
54
+ border-radius: 5px;
55
+ padding: 10px;
56
+ z-index: 5;
57
+ border: 1px solid rgba(255, 255, 255, 0.3);
58
+ box-shadow: 0 0 10px rgba(0, 0, 0, 0.5);
59
+ }
60
+
61
+ .health-container {
62
+ display: flex;
63
+ align-items: center;
64
+ min-width: 200px;
65
+ margin-bottom: 5px;
66
+ position: relative;
67
+ }
68
+
69
+ .health-bar {
70
+ flex: 1;
71
+ height: 20px;
72
+ background-color: #333;
73
+ border-radius: 3px;
74
+ overflow: hidden;
75
+ margin-right: 60px;
76
+ border: 1px solid rgba(255, 255, 255, 0.2);
77
+ }
78
+
79
+ .health-fill {
80
+ height: 100%;
81
+ background: linear-gradient(to right, #ff0043, #ff6a00);
82
+ width: 100%;
83
+ transition: width 0.5s cubic-bezier(.4,2,.6,1);
84
+ }
85
+
86
+ .health-text {
87
+ position: absolute;
88
+ right: 0;
89
+ font-size: 14px;
90
+ color: #fff;
91
+ min-width: 60px;
92
+ text-align: right;
93
+ }
94
+
95
+ .energy-display {
96
+ display: flex;
97
+ justify-content: flex-end;
98
+ align-items: center;
99
+ }
100
+
101
+ .energy-value {
102
+ font-size: 14px;
103
+ color: #ffcc00;
104
+ margin-right: 5px;
105
+ }
106
+
107
+ .energy-icon {
108
+ color: #ffcc00;
109
+ font-size: 16px;
110
+ }
111
+
112
+ /* 回合指示器 */
113
+ .turn-indicator {
114
+ position: absolute;
115
+ top: 80px;
116
+ left: 20px;
117
+ background-color: rgba(0, 0, 0, 0.7);
118
+ padding: 8px 20px;
119
+ border-radius: 20px;
120
+ z-index: 5;
121
+ font-size: 18px;
122
+ font-weight: bold;
123
+ border: 1px solid rgba(255, 255, 255, 0.3);
124
+ box-shadow: 0 0 10px rgba(0, 0, 0, 0.5);
125
+ }
126
+
127
+ /* 命令区域 - 水墨风格 */
128
+ .command-area {
129
+ position: absolute;
130
+ bottom: 30px;
131
+ left: 50%;
132
+ transform: translateX(-50%);
133
+ width: 90%;
134
+ max-width: 800px;
135
+ background-color: rgba(0, 0, 0, 0.7);
136
+ border-radius: 10px;
137
+ padding: 15px;
138
+ z-index: 10;
139
+ border: 1px solid rgba(255, 255, 255, 0.3);
140
+ box-shadow: 0 0 20px rgba(0, 0, 0, 0.6);
141
+ }
142
+
143
+ .command-label {
144
+ margin-bottom: 10px;
145
+ font-size: 24px;
146
+ color: #eee;
147
+ text-align: center;
148
+ font-family: 'Ma Shan Zheng', cursive;
149
+ text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.5);
150
+ }
151
+
152
+ .command-buttons {
153
+ display: flex;
154
+ justify-content: space-around;
155
+ gap: 10px;
156
+ }
157
+
158
+ /* 指令按钮浮动样式 - 修复版本:始终紧贴左边缘 */
159
+ .command-buttons-floating {
160
+ position: absolute;
161
+ left: 0; /* 始终紧贴左边缘 */
162
+ bottom: 0;
163
+ display: flex;
164
+ flex-direction: row; /* 始终保持水平排列 */
165
+ gap: clamp(2px, 1vw, 12px); /* 自适应间距 */
166
+ padding: clamp(2px, 0.5vw, 8px) 0 0 clamp(2px, 0.5vw, 8px); /* 左边距很小 */
167
+ z-index: 10;
168
+ width: 50vw; /* 总宽度占页面50% */
169
+ min-width: 280px;
170
+ max-width: 50vw;
171
+ justify-content: space-between;
172
+ }
173
+
174
+ .command-btn {
175
+ flex: 1 1 0;
176
+ margin: 0;
177
+ /* 自适应内边距 */
178
+ padding: clamp(0.5vw, 1.2vw, 1.5vw) clamp(0.3vw, 0.8vw, 1vw);
179
+ /* 自适应高度 */
180
+ height: clamp(60px, 8vw, 120px);
181
+ border-radius: clamp(4px, 0.8vw, 8px);
182
+ background: #111 !important;
183
+ color: #fff !important;
184
+ border: 1px solid #333;
185
+ box-shadow: 1px 1px 4px rgba(0,0,0,0.15);
186
+ display: flex;
187
+ flex-direction: column;
188
+ align-items: center;
189
+ justify-content: center;
190
+ min-width: 0;
191
+ cursor: pointer;
192
+ transition: all 0.2s;
193
+ position: relative;
194
+ overflow: hidden;
195
+ }
196
+
197
+ .command-btn::before {
198
+ content: '';
199
+ position: absolute;
200
+ top: -2px;
201
+ left: -2px;
202
+ right: -2px;
203
+ bottom: -2px;
204
+ background: linear-gradient(45deg, transparent, rgba(255, 255, 255, 0.1), transparent);
205
+ z-index: -1;
206
+ border-radius: clamp(4px, 0.8vw, 8px);
207
+ }
208
+
209
+ .command-btn:hover:not(.disabled) {
210
+ background: #222 !important;
211
+ transform: translateY(-2px);
212
+ box-shadow: 0 6px 12px rgba(0, 0, 0, 0.4);
213
+ border-color: #666;
214
+ }
215
+
216
+ .command-btn:active:not(.disabled) {
217
+ background: #333 !important;
218
+ transform: translateY(0);
219
+ }
220
+
221
+ .command-btn.selected {
222
+ background: linear-gradient(135deg, #1a3a75, #0c1f3e) !important;
223
+ border-color: #3a6cbf;
224
+ box-shadow: 0 0 15px rgba(58, 108, 191, 0.6);
225
+ }
226
+
227
+ .command-btn.disabled {
228
+ opacity: 0.5;
229
+ cursor: not-allowed;
230
+ }
231
+
232
+ /* 键位提示自适应 */
233
+ .command-btn .key-hint {
234
+ position: absolute;
235
+ top: clamp(2px, 0.5vw, 6px);
236
+ left: clamp(2px, 0.5vw, 6px);
237
+ background-color: rgba(0, 0, 0, 0.7);
238
+ color: #fff;
239
+ font-size: clamp(0.7rem, 1.5vw, 1rem);
240
+ padding: clamp(1px, 0.3vw, 4px) clamp(3px, 0.6vw, 8px);
241
+ border-radius: clamp(2px, 0.4vw, 4px);
242
+ line-height: 1;
243
+ }
244
+
245
+ /* 按钮名称自适应 */
246
+ .command-btn .btn-name {
247
+ font-size: clamp(0.9rem, 2.2vw, 1.8rem);
248
+ font-weight: bold;
249
+ font-family: 'Ma Shan Zheng', cursive;
250
+ text-shadow: 1px 1px 2px rgba(0, 0, 0, 0.5);
251
+ text-align: center;
252
+ line-height: 1.1;
253
+ margin-top: clamp(2px, 0.5vw, 8px);
254
+ }
255
+
256
+ /* 战斗日志 - 水墨风 */
257
+ .battle-log {
258
+ height: 80px;
259
+ background-color: rgba(0, 0, 0, 0.8);
260
+ border-top: 1px solid #444;
261
+ padding: 10px 20px;
262
+ overflow-y: auto;
263
+ font-size: 16px;
264
+ line-height: 1.5;
265
+ border-bottom: 1px solid rgba(255, 255, 255, 0.2);
266
+ position: relative;
267
+ z-index: 10;
268
+ }
269
+
270
+ /* 确认弹窗 - 水墨风 */
271
+ .modal {
272
+ display: none;
273
+ position: fixed;
274
+ top: 0;
275
+ left: 0;
276
+ width: 100%;
277
+ height: 100%;
278
+ background-color: rgba(0, 0, 0, 0.7);
279
+ z-index: 100;
280
+ align-items: center;
281
+ justify-content: center;
282
+ }
283
+
284
+ .modal-content {
285
+ /* background: ... 由JS动态设置 */
286
+ width: 350px;
287
+ border-radius: 5px;
288
+ box-shadow: 0 0 20px rgba(0, 0, 0, 0.8);
289
+ color: #fff;
290
+ position: relative;
291
+ border: 2px solid #553c28;
292
+ overflow: hidden;
293
+ }
294
+
295
+ .modal-header {
296
+ padding: 15px;
297
+ background-color: rgba(0, 0, 0, 0.6);
298
+ font-size: 24px;
299
+ font-weight: bold;
300
+ text-align: center;
301
+ border-bottom: 1px solid rgba(255, 255, 255, 0.2);
302
+ font-family: 'Ma Shan Zheng', cursive;
303
+ }
304
+
305
+ .modal-body {
306
+ padding: 20px;
307
+ font-size: 18px;
308
+ text-align: center;
309
+ }
310
+
311
+ .modal-footer {
312
+ padding: 15px;
313
+ display: flex;
314
+ justify-content: space-around;
315
+ border-top: 1px solid rgba(255, 255, 255, 0.2);
316
+ }
317
+
318
+ .modal-footer button {
319
+ padding: 10px 20px;
320
+ border: none;
321
+ border-radius: 4px;
322
+ cursor: pointer;
323
+ font-size: 16px;
324
+ font-family: 'ZCOOL XiaoWei', sans-serif;
325
+ transition: all 0.3s;
326
+ }
327
+
328
+ #confirm-action {
329
+ background: linear-gradient(to bottom, #5c3b1c, #34210f);
330
+ color: white;
331
+ border: 1px solid #7c5a3d;
332
+ }
333
+
334
+ #confirm-action:hover {
335
+ background: linear-gradient(to bottom, #6c4a2b, #3e2914);
336
+ transform: translateY(-2px);
337
+ box-shadow: 0 2px 5px rgba(0, 0, 0, 0.3);
338
+ }
339
+
340
+ #cancel-action {
341
+ background: linear-gradient(to bottom, #444, #222);
342
+ color: #ddd;
343
+ border: 1px solid #666;
344
+ }
345
+
346
+ #cancel-action:hover {
347
+ background: linear-gradient(to bottom, #555, #333);
348
+ transform: translateY(-2px);
349
+ box-shadow: 0 2px 5px rgba(0, 0, 0, 0.3);
350
+ }
351
+
352
+ /* 动画效果 */
353
+ @keyframes attack {
354
+ 0% { transform: translateX(0); }
355
+ 25% { transform: translateX(40px); }
356
+ 50% { transform: translateX(0); }
357
+ 100% { transform: translateX(0); }
358
+ }
359
+
360
+ @keyframes enemy-attack {
361
+ 0% { transform: translateX(0); }
362
+ 25% { transform: translateX(-40px); }
363
+ 50% { transform: translateX(0); }
364
+ 100% { transform: translateX(0); }
365
+ }
366
+
367
+ @keyframes hit {
368
+ 0% { filter: brightness(1); }
369
+ 25% { filter: brightness(3) saturate(2); }
370
+ 50% { filter: brightness(1); }
371
+ 100% { filter: brightness(1); }
372
+ }
373
+
374
+ @keyframes defend {
375
+ 0% { filter: brightness(1); }
376
+ 50% { filter: brightness(1.5) hue-rotate(120deg); }
377
+ 100% { filter: brightness(1); }
378
+ }
379
+
380
+ @keyframes special {
381
+ 0% { filter: brightness(1); }
382
+ 25% { filter: brightness(2) saturate(2) hue-rotate(270deg); }
383
+ 50% { filter: brightness(1.5) saturate(1.5) hue-rotate(180deg); }
384
+ 75% { filter: brightness(2) saturate(2) hue-rotate(90deg); }
385
+ 100% { filter: brightness(1); }
386
+ }
387
+
388
+ .player-attack {
389
+ animation: attack 0.6s ease;
390
+ }
391
+
392
+ .enemy-attack {
393
+ animation: enemy-attack 0.6s ease;
394
+ }
395
+
396
+ .player-hit {
397
+ animation: hit 0.6s ease;
398
+ }
399
+
400
+ .enemy-hit {
401
+ animation: hit 0.6s ease;
402
+ }
403
+
404
+ .player-defend {
405
+ animation: defend 1s ease;
406
+ }
407
+
408
+ .enemy-defend {
409
+ animation: defend 1s ease;
410
+ }
411
+
412
+ .player-special {
413
+ animation: special 1s ease;
414
+ }
415
+
416
+ .enemy-special {
417
+ animation: special 1s ease;
418
+ }
419
+
420
+ /* 画面晃动动画 */
421
+ @keyframes shake {
422
+ 0% { transform: translate(0, 0); }
423
+ 20% { transform: translate(-10px, 0); }
424
+ 40% { transform: translate(10px, 0); }
425
+ 60% { transform: translate(-10px, 0); }
426
+ 80% { transform: translate(10px, 0); }
427
+ 100% { transform: translate(0, 0); }
428
+ }
429
+ .shake {
430
+ animation: shake 0.4s cubic-bezier(.36,.07,.19,.97) both;
431
+ }
432
+
433
+ /* 受击红色边缘高亮动画 */
434
+ @keyframes damage-flash {
435
+ 0% { box-shadow: 0 0 0 0 rgba(255,0,0,0.7); }
436
+ 30% { box-shadow: 0 0 0 20px rgba(255,0,0,0.5); }
437
+ 60% { box-shadow: 0 0 0 40px rgba(255,0,0,0.2); }
438
+ 100% { box-shadow: 0 0 0 0 rgba(255,0,0,0); }
439
+ }
440
+ .damage-flash {
441
+ animation: damage-flash 0.5s;
442
+ }
443
+
444
+ .npc-portrait-layer {
445
+ position: absolute;
446
+ left: 0; top: 0; right: 0; bottom: 0;
447
+ width: 100%;
448
+ height: 100%;
449
+ pointer-events: none;
450
+ z-index: 3;
451
+ background: none;
452
+ background-position: center center;
453
+ background-repeat: no-repeat;
454
+ background-size: cover;
455
+ transition: background-image 0.3s;
456
+ }
457
+
458
+ .npc-portrait-layer.shake {
459
+ animation: shake 0.4s cubic-bezier(.36,.07,.19,.97) both;
460
+ }
461
+
462
+ .screen-flash {
463
+ position: fixed;
464
+ left: 0; top: 0; right: 0; bottom: 0;
465
+ width: 100vw;
466
+ height: 100vh;
467
+ pointer-events: none;
468
+ z-index: 1000;
469
+ opacity: 0;
470
+ background: rgba(255,0,0,0.3);
471
+ box-shadow: 0 0 0 20px rgba(255,0,0,0.5), 0 0 60px 40px rgba(255,0,0,0.2) inset;
472
+ transition: opacity 0.2s;
473
+ }
474
+
475
+ .screen-flash.active {
476
+ opacity: 1;
477
+ transition: opacity 0.1s;
478
+ }
479
+
480
+ /* 移动端优化 - 始终保持紧贴左边缘的一排布局 */
481
+ @media (max-width: 900px) {
482
+ .battle-scene {
483
+ padding-bottom: 140px;
484
+ }
485
+
486
+ .command-buttons-floating {
487
+ width: 70vw; /* 在中等屏幕上稍微宽一点 */
488
+ min-width: 260px;
489
+ gap: clamp(2px, 0.8vw, 6px);
490
+ padding: clamp(2px, 0.4vw, 6px) 0 0 clamp(2px, 0.4vw, 6px);
491
+ /* 保持 left: 0,不要居中 */
492
+ }
493
+
494
+ .command-btn {
495
+ height: clamp(50px, 10vw, 80px);
496
+ }
497
+
498
+ .command-btn .btn-name {
499
+ font-size: clamp(0.8rem, 3vw, 1.2rem);
500
+ }
501
+
502
+ .command-btn .key-hint {
503
+ font-size: clamp(0.6rem, 2vw, 0.9rem);
504
+ }
505
+
506
+ .health-container {
507
+ min-width: 150px;
508
+ }
509
+ }
510
+
511
+ @media (max-width: 600px) {
512
+ .command-buttons-floating {
513
+ width: 85vw; /* 在小屏幕上占更多宽度 */
514
+ min-width: 240px;
515
+ /* 关键:不设置居中,保持 left: 0 */
516
+ gap: clamp(1px, 0.5vw, 4px);
517
+ padding: clamp(1px, 0.3vw, 4px) 0 0 clamp(1px, 0.3vw, 4px);
518
+ /* 确保 flex-direction 始终为 row */
519
+ flex-direction: row;
520
+ }
521
+
522
+ .command-btn {
523
+ height: clamp(40px, 12vw, 60px);
524
+ }
525
+
526
+ .command-btn .btn-name {
527
+ font-size: clamp(0.7rem, 3.5vw, 1rem);
528
+ }
529
+
530
+ .command-btn .key-hint {
531
+ font-size: clamp(0.5rem, 2.5vw, 0.8rem);
532
+ }
533
+ }
534
+
535
+ /* 超大屏幕优化 */
536
+ @media (min-width: 1400px) {
537
+ .command-buttons-floating {
538
+ width: 45vw; /* 在大屏幕上稍微收窄 */
539
+ max-width: 700px; /* 设置最大宽度避免过宽 */
540
+ }
541
+
542
+ .command-btn {
543
+ height: clamp(80px, 6vw, 100px);
544
+ }
545
+
546
+ .command-btn .btn-name {
547
+ font-size: clamp(1.2rem, 1.8vw, 1.6rem);
548
+ }
549
+ }
550
+
551
+ /* 超小屏幕优化 - 保持一排并紧贴左边缘 */
552
+ @media (max-width: 480px) {
553
+ .command-buttons-floating {
554
+ width: 95vw; /* 几乎占满整个宽度 */
555
+ min-width: 200px;
556
+ gap: clamp(1px, 0.2vw, 2px); /* 很小的间距 */
557
+ padding: 2px 0 0 2px; /* 很小的左边距 */
558
+ /* 确保始终水平排列 */
559
+ flex-direction: row;
560
+ }
561
+
562
+ .command-btn {
563
+ height: clamp(35px, 14vw, 50px);
564
+ padding: clamp(0.2vw, 0.8vw, 1vw) clamp(0.1vw, 0.4vw, 0.6vw);
565
+ }
566
+
567
+ .command-btn .btn-name {
568
+ font-size: clamp(0.6rem, 4vw, 0.9rem);
569
+ }
570
+
571
+ .command-btn .key-hint {
572
+ font-size: clamp(0.4rem, 3vw, 0.7rem);
573
+ padding: clamp(0.5px, 0.1vw, 2px) clamp(2px, 0.3vw, 4px);
574
+ }
575
+ }