HelloSun commited on
Commit
3250fa0
路
verified 路
1 Parent(s): f932ebf

Fix CPU fight round, KO and match end flow

Browse files
Files changed (2) hide show
  1. js/port.js +60 -11
  2. js/runtime.js +14 -0
js/port.js CHANGED
@@ -99,10 +99,15 @@ function parseCommands(text) {
99
  }
100
 
101
  function startMatch() {
 
 
 
102
  game = {
103
- p1: new Fighter(assets, -72, 1, '#c84b39', true), p2: new Fighter(assets, 72, -1, '#3159a4'),
104
- tick: 0, time: 99 * 60, round: 'ROUND 1', roundLeft: 80, shake: 0,
 
105
  };
 
106
  window.game = game;
107
  }
108
 
@@ -124,16 +129,57 @@ document.querySelector('#restart').onclick = () => startMatch();
124
  function step() {
125
  if (!game) return;
126
  game.tick++;
127
- if (game.roundLeft > 0) game.roundLeft--;
128
- else if (game.p1.life > 0 && game.p2.life > 0) game.roundLeft = 20;
129
- if (game.roundLeft === 20) game.round = 'FIGHT!';
130
- if (game.roundLeft <= 20) {
131
- if (game.roundLeft === 0) game.round = '';
 
132
  game.p1.update(null, game.p2, game);
133
  game.p2.update(null, game.p1, game);
134
  resolveCollisions(game.p1, game.p2, game);
135
- if (game.p1.life <= 0 || game.p2.life <= 0) game.round = game.p1.life > game.p2.life ? 'KUNG FU MAN WINS' : 'K.O.';
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
136
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
137
  }
138
 
139
  function worldBoxes(f, boxes) {
@@ -239,8 +285,12 @@ function drawHud(w, h) {
239
  const fill = 156 * Math.max(0, f.life / f.maxLife); ctx.fillStyle = col; ctx.fillRect(mirror ? x + 158 - fill : x + 2, 10, fill, 7);
240
  ctx.fillStyle = '#f6f1df'; ctx.font = 'bold 9px system-ui'; ctx.fillText(f.name, x, 31);
241
  }
242
- ctx.textAlign = 'center'; ctx.fillStyle = '#fff6d8'; ctx.font = 'bold 21px ui-monospace'; ctx.fillText(String(Math.ceil(game.time / 60)).padStart(2, '0'), unitW / 2, 25);
243
- if (game.roundLeft > 0 && game.round !== 'FIGHT!') { ctx.font = 'bold 21px system-ui'; ctx.fillText(game.round, unitW / 2, 82); }
 
 
 
 
244
  ctx.restore();
245
  }
246
 
@@ -249,7 +299,6 @@ function loop(now) {
249
  if (!paused && game && intro.hidden) {
250
  accum += dt;
251
  for (let n = 0; accum >= 1000 / 60 && n < 5; n++) { step(); accum -= 1000 / 60; }
252
- if (game.roundLeft <= 20) game.time = Math.max(0, game.time - dt * .06);
253
  }
254
  draw(); requestAnimationFrame(loop);
255
  }
 
99
  }
100
 
101
  function startMatch() {
102
+ const p1 = new Fighter(assets, -72, 1, '#c84b39', true);
103
+ const p2 = new Fighter(assets, 72, -1, '#3159a4');
104
+ p1.name = 'CPU 1 路 KFM'; p2.name = 'CPU 2 路 KFM';
105
  game = {
106
+ p1, p2,
107
+ tick: 0, time: 99, roundFrames: 99 * 60, round: 'ROUND 1', phase: 'intro', phaseTicks: 75,
108
+ roundNo: 1, roundsToWin: 2, shake: 0,
109
  };
110
+ game.p1.resetMatch(); game.p2.resetMatch();
111
  window.game = game;
112
  }
113
 
 
129
  function step() {
130
  if (!game) return;
131
  game.tick++;
132
+ if (game.phase === 'intro') {
133
+ if (--game.phaseTicks === 25) game.round = 'FIGHT!';
134
+ if (game.phaseTicks <= 0) { game.phase = 'fight'; game.round = ''; }
135
+ return;
136
+ }
137
+ if (game.phase === 'fight') {
138
  game.p1.update(null, game.p2, game);
139
  game.p2.update(null, game.p1, game);
140
  resolveCollisions(game.p1, game.p2, game);
141
+ if (game.p1.life <= 0 || game.p2.life <= 0) {
142
+ const winner = game.p1.life === game.p2.life ? null : game.p1.life > game.p2.life ? game.p1 : game.p2;
143
+ finishRound(winner, 'K.O.');
144
+ } else if (--game.roundFrames <= 0) {
145
+ const winner = game.p1.life === game.p2.life ? null : game.p1.life > game.p2.life ? game.p1 : game.p2;
146
+ finishRound(winner, 'TIME OVER');
147
+ }
148
+ game.time = Math.ceil(Math.max(0, game.roundFrames) / 60);
149
+ return;
150
+ }
151
+ if (game.phaseTicks > 0) { game.phaseTicks--; return; }
152
+ if (game.phase === 'roundEnd') {
153
+ const winner = [game.p1, game.p2].find(f => f.roundsWon >= game.roundsToWin);
154
+ if (winner) {
155
+ game.phase = 'matchEnd'; game.phaseTicks = 240;
156
+ game.round = `${winner.name} WINS THE MATCH`;
157
+ } else {
158
+ game.roundNo++;
159
+ game.p1.resetRound(); game.p2.resetRound();
160
+ game.round = `ROUND ${game.roundNo}`; game.roundFrames = 99 * 60; game.time = 99;
161
+ game.phase = 'intro'; game.phaseTicks = 75;
162
+ }
163
+ return;
164
  }
165
+ if (game.phase === 'matchEnd') {
166
+ game.p1.resetMatch(); game.p2.resetMatch();
167
+ game.p1.x = -72; game.p2.x = 72; game.p1.facing = 1; game.p2.facing = -1;
168
+ game.p1.name = 'CPU 1 路 KFM'; game.p2.name = 'CPU 2 路 KFM';
169
+ game.roundNo = 1; game.roundFrames = 99 * 60; game.time = 99;
170
+ game.round = 'ROUND 1'; game.phase = 'intro'; game.phaseTicks = 75;
171
+ }
172
+ }
173
+
174
+ function finishRound(winner, result) {
175
+ if (game.phase !== 'fight') return;
176
+ if (winner) winner.roundsWon++;
177
+ const loser = winner ? (winner === game.p1 ? game.p2 : game.p1) : null;
178
+ if (winner) winner.setAction(181, 181);
179
+ if (loser) loser.setAction(5151, 5151);
180
+ if (!winner) { game.p1.setAction(5151, 5151); game.p2.setAction(5151, 5151); }
181
+ game.phase = 'roundEnd'; game.phaseTicks = 135;
182
+ game.round = winner ? `${winner === game.p1 ? 'KUNG FU MAN' : 'CPU'} WINS` : `DRAW 路 ${result}`;
183
  }
184
 
185
  function worldBoxes(f, boxes) {
 
285
  const fill = 156 * Math.max(0, f.life / f.maxLife); ctx.fillStyle = col; ctx.fillRect(mirror ? x + 158 - fill : x + 2, 10, fill, 7);
286
  ctx.fillStyle = '#f6f1df'; ctx.font = 'bold 9px system-ui'; ctx.fillText(f.name, x, 31);
287
  }
288
+ ctx.textAlign = 'center'; ctx.fillStyle = '#fff6d8'; ctx.font = 'bold 21px ui-monospace'; ctx.fillText(String(game.time).padStart(2, '0'), unitW / 2, 25);
289
+ for (let n = 0; n < game.roundsToWin; n++) {
290
+ ctx.fillStyle = n < game.p1.roundsWon ? '#ffd36a' : '#59636d'; ctx.beginPath(); ctx.arc(10 + n * 14, 39, 4, 0, Math.PI * 2); ctx.fill();
291
+ ctx.fillStyle = n < game.p2.roundsWon ? '#ffd36a' : '#59636d'; ctx.beginPath(); ctx.arc(unitW - 10 - n * 14, 39, 4, 0, Math.PI * 2); ctx.fill();
292
+ }
293
+ if (game.round) { ctx.fillStyle = '#fff6d8'; ctx.font = 'bold 21px system-ui'; ctx.fillText(game.round, unitW / 2, 82); }
294
  ctx.restore();
295
  }
296
 
 
299
  if (!paused && game && intro.hidden) {
300
  accum += dt;
301
  for (let n = 0; accum >= 1000 / 60 && n < 5; n++) { step(); accum -= 1000 / 60; }
 
302
  }
303
  draw(); requestAnimationFrame(loop);
304
  }
js/runtime.js CHANGED
@@ -98,6 +98,7 @@ export class Fighter {
98
  this.grounded = true; this.crouch = false; this.airJumps = 0; this.dirHistory = [];
99
  this.aiWait = 0; this.lastAI = 0;
100
  this.prevKeys = new Set();
 
101
  this.frame = this.currentFrame();
102
  }
103
  setAction(action, state = this.state) {
@@ -118,6 +119,19 @@ export class Fighter {
118
  }
119
  this.frame = this.currentFrame();
120
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
121
  currentFrame() {
122
  const a = this.assets.actions.get(this.action);
123
  if (!a?.frames.length) return null;
 
98
  this.grounded = true; this.crouch = false; this.airJumps = 0; this.dirHistory = [];
99
  this.aiWait = 0; this.lastAI = 0;
100
  this.prevKeys = new Set();
101
+ this.roundsWon = 0;
102
  this.frame = this.currentFrame();
103
  }
104
  setAction(action, state = this.state) {
 
119
  }
120
  this.frame = this.currentFrame();
121
  }
122
+ resetRound() {
123
+ this.life = this.maxLife;
124
+ this.x = this.player ? -68 : 68;
125
+ this.y = this.vx = this.vy = 0;
126
+ this.facing = this.player ? 1 : -1;
127
+ this.state = 0; this.stateFrame = this.actionFrame = this.elemTick = 0;
128
+ this.hitstun = this.hitPause = this.hurtFlash = 0;
129
+ this.ctrl = true; this.grounded = true; this.crouch = false;
130
+ this.hit = null; this.hitDefs = []; this.prevKeys.clear(); this.dirHistory.length = 0;
131
+ this._power = 0;
132
+ this.setAction(0, 0);
133
+ }
134
+ resetMatch() { this.roundsWon = 0; this.resetRound(); }
135
  currentFrame() {
136
  const a = this.assets.actions.get(this.action);
137
  if (!a?.frames.length) return null;