Skip to content

dev branch #10

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 5 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,16 @@

1. **`npm run setup`** at the root
2. **`npm run dev`** at the root
3. open **`http://localhost:7500/`**
3. open **`http://localhost:7800/`**

OR

1. **`npm i`** at the root
2. **`npx simple-git-hooks`** at the root
3. **`npm run dev`** at the root
4. open **`http://localhost:7500/`**
4. open **`http://localhost:7800/`**

## 💡 PS
## ℹ️ PS

The project has a [Git Hooks](https://www.atlassian.com/git/tutorials/git-hooks), [Prettier](https://prettier.io/) and [Eslint](https://eslint.org/) set up, to validate your JS code.

Expand Down
Empty file added [email protected]
Empty file.
4 changes: 2 additions & 2 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@
<title>Street Fighter</title>
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<noscript>You need to enable JavaScript to run this application.</noscript>
<div id="root"></div>
<div id="loading-overlay">
<div id="loading-backdrop">
<img src="resources/logo.png"/>
</div>
<script type="module" src="./src/index.js"></script>
Expand Down
1,064 changes: 539 additions & 525 deletions package-lock.json

Large diffs are not rendered by default.

16 changes: 10 additions & 6 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
{
"name": "street-fighter",
"engines": {
"node": ">=16",
"npm": ">=8"
"node": ">=18",
"npm": ">=10"
},
"type": "module",
"version": "1.0.0",
"description": "",
"description": "JS lecture starter",
"main": "index.js",
"scripts": {
"setup": "npm i && npx simple-git-hooks",
Expand All @@ -16,8 +16,12 @@
"lint": "eslint --ext .js .",
"lint:fix": "npm run lint -- --fix"
},
"author": "Binary Studio",
"author": "Binary Studio developers",
"license": "ISC",
"repository": {
"type": "git",
"url": "git+https://github.com/BinaryStudioAcademy/lecture-starter-js.git"
},
"devDependencies": {
"commitlint": "^17.6.5",
"eslint": "^8.42.0",
Expand All @@ -26,8 +30,8 @@
"eslint-plugin-prettier": "^4.2.1",
"lint-staged": "^13.2.2",
"prettier": "^2.8.8",
"simple-git-hooks": "^2.8.1",
"vite": "^5.2.12"
"simple-git-hooks": "^2.13.0",
"vite": "^5.4.19"
},
"simple-git-hooks": {
"pre-commit": "npx lint-staged",
Expand Down
15 changes: 10 additions & 5 deletions resources/api/fighters.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,23 +3,28 @@
"_id": "1",
"name": "Ryu",
"source": "https://media.giphy.com/media/kdHa4JvihB2gM/giphy.gif"
}, {
},
{
"_id": "2",
"name": "Dhalsim",
"source": "https://i.pinimg.com/originals/c0/53/f2/c053f2bce4d2375fee8741acfb35d44d.gif"
}, {
},
{
"_id": "3",
"name": "Guile",
"source": "https://66.media.tumblr.com/tumblr_lq8g3548bC1qd0wh3o1_400.gif"
}, {
},
{
"_id": "4",
"name": "Zangief",
"source": "https://media1.giphy.com/media/nlbIvY9K0jfAA/source.gif"
}, {
},
{
"_id": "5",
"name": "Ken",
"source": "https://i.pinimg.com/originals/46/4b/36/464b36a7aecd988e3c51e56a823dbedc.gif"
}, {
},
{
"_id": "6",
"name": "Bison",
"source": "http://www.fightersgeneration.com/np5/char/ssf2hd/bison-hdstance.gif"
Expand Down
2 changes: 1 addition & 1 deletion src/javascript/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import fighterService from './services/fightersService';
class App {
static rootElement = document.getElementById('root');

static loadingElement = document.getElementById('loading-overlay');
static loadingElement = document.getElementById('loading-backdrop');

static async startApplication() {
try {
Expand Down
6 changes: 6 additions & 0 deletions src/javascript/components/arena.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import createElement from '../helpers/domHelper';
import { createFighterImage } from './fighterPreview';
import showWinnerModal from './modal/winner';
import { fight } from './fight';

function createFighter(fighter, position) {
const imgElement = createFighterImage(fighter);
Expand Down Expand Up @@ -69,4 +71,8 @@ export default function renderArena(selectedFighters) {
// todo:
// - start the fight
// - when fight is finished show winner
const [firstFighter, secondFighter] = selectedFighters;

const winner = fight(firstFighter, secondFighter);
winner.then(winnerData => showWinnerModal(winnerData));
}
177 changes: 168 additions & 9 deletions src/javascript/components/fight.js
Original file line number Diff line number Diff line change
@@ -1,19 +1,178 @@
import controls from '../../constants/controls';

export async function fight(firstFighter, secondFighter) {
return new Promise(resolve => {
// resolve the promise with the winner when fight is over
});
}
const {
PlayerOneAttack,
PlayerOneBlock,
PlayerTwoAttack,
PlayerTwoBlock,
PlayerOneCriticalHitCombination,
PlayerTwoCriticalHitCombination
} = controls;

export function getDamage(attacker, defender) {
// return damage
export function criticalHitChance() {
return Math.random() + 1;
}

export function dodgeChance() {
return Math.random() + 1;
}
export function getHitPower(fighter) {
// return hit power
return fighter.attack * criticalHitChance();
}

export function getBlockPower(fighter) {
// return block power
return fighter.defense * dodgeChance();
}

export function criticalHit(fighter) {
return fighter.attack * 2;
}

export function getDamage(attacker, defender, isBlocked) {
let damage;
if (isBlocked) {
damage = getHitPower(attacker) - getBlockPower(defender);
} else {
damage = getHitPower(attacker);
}

return Math.max(0, damage);
}

let firstFighterBlockActive = false;
let secondFighterBlockActive = false;

let criticalAttackDelayOneEnd = true;
let criticalAttackDelayTwoEnd = true;

function isCriticalAttackReady() {
const keysStatuses = Object.values(this);
const isCombinationNotReady = keysStatuses.includes(false);
if (isCombinationNotReady) {
return false;
}
return true;
}

const firstFighterCriticalAttackKeys = {
[PlayerOneCriticalHitCombination[0]]: false,
[PlayerOneCriticalHitCombination[1]]: false,
[PlayerOneCriticalHitCombination[2]]: false
};

const secondFighterCriticalAttackKeys = {
[PlayerTwoCriticalHitCombination[0]]: false,
[PlayerTwoCriticalHitCombination[1]]: false,
[PlayerTwoCriticalHitCombination[2]]: false
};

const fighterOneCriticalAttackReady = isCriticalAttackReady.bind(firstFighterCriticalAttackKeys);
const fighterTwoCriticalAttackReady = isCriticalAttackReady.bind(secondFighterCriticalAttackKeys);

export async function fight(firstFighter, secondFighter) {
let firstFighterHealth = firstFighter.health;
let secondFighterHealth = secondFighter.health;

const leftFighterIndicator = document.getElementById('left-fighter-indicator');
const rightFighterIndicator = document.getElementById('right-fighter-indicator');

return new Promise(resolve => {
document.addEventListener('keydown', e => {
switch (e.code) {
case PlayerOneAttack:
if (!secondFighterBlockActive && !e.repeat) {
const damage = getDamage(firstFighter, secondFighter, secondFighterBlockActive);

secondFighterHealth = Math.max(0, secondFighterHealth - damage);
}

break;
case PlayerTwoAttack:
if (!firstFighterBlockActive && !e.repeat) {
const damage = getDamage(secondFighter, firstFighter, firstFighterBlockActive);

firstFighterHealth = Math.max(0, firstFighterHealth - damage);
}
break;

case PlayerOneBlock:
firstFighterBlockActive = true;
break;

case PlayerTwoBlock:
secondFighterBlockActive = true;
break;

case PlayerOneCriticalHitCombination[0]:
case PlayerOneCriticalHitCombination[1]:
case PlayerOneCriticalHitCombination[2]:
firstFighterCriticalAttackKeys[e.code] = true;

if (fighterOneCriticalAttackReady() && !e.repeat && criticalAttackDelayOneEnd) {
const damage = criticalHit(firstFighter);
secondFighterHealth -= damage;
criticalAttackDelayOneEnd = false;
setTimeout(() => {
criticalAttackDelayOneEnd = true;
}, 10000);
}
break;

case PlayerTwoCriticalHitCombination[0]:
case PlayerTwoCriticalHitCombination[1]:
case PlayerTwoCriticalHitCombination[2]:
secondFighterCriticalAttackKeys[e.code] = true;
if (fighterTwoCriticalAttackReady() && !e.repeat && criticalAttackDelayTwoEnd) {
const damage = criticalHit(secondFighter);
firstFighterHealth -= damage;
criticalAttackDelayTwoEnd = false;
setTimeout(() => {
criticalAttackDelayTwoEnd = true;
}, 10000);
}
break;
default:
break;
}
const leftHealthBarWidth = (firstFighterHealth / firstFighter.health) * 100;
const rightHealhBarWidth = (secondFighterHealth / secondFighter.health) * 100;

leftFighterIndicator.style.width = `${leftHealthBarWidth}%`;
rightFighterIndicator.style.width = `${rightHealhBarWidth}%`;

if (firstFighterHealth <= 0) {
leftFighterIndicator.style.width = '0px';
resolve(secondFighter);
} else if (secondFighterHealth <= 0) {
rightFighterIndicator.style.width = '0px';
resolve(firstFighter);
}
});

document.addEventListener('keyup', e => {
switch (e.code) {
case PlayerOneBlock:
firstFighterBlockActive = false;
break;

case PlayerTwoBlock:
secondFighterBlockActive = false;
break;

case PlayerOneCriticalHitCombination[0]:
case PlayerOneCriticalHitCombination[1]:
case PlayerOneCriticalHitCombination[2]:
firstFighterCriticalAttackKeys[e.code] = false;
break;

case PlayerTwoCriticalHitCombination[0]:
case PlayerTwoCriticalHitCombination[1]:
case PlayerTwoCriticalHitCombination[2]:
secondFighterCriticalAttackKeys[e.code] = false;
break;
default:
break;
}
});
});
}
42 changes: 30 additions & 12 deletions src/javascript/components/fighterPreview.js
Original file line number Diff line number Diff line change
@@ -1,17 +1,5 @@
import createElement from '../helpers/domHelper';

export function createFighterPreview(fighter, position) {
const positionClassName = position === 'right' ? 'fighter-preview___right' : 'fighter-preview___left';
const fighterElement = createElement({
tagName: 'div',
className: `fighter-preview___root ${positionClassName}`
});

// todo: show fighter info (image, name, health, etc.)

return fighterElement;
}

export function createFighterImage(fighter) {
const { source, name } = fighter;
const attributes = {
Expand All @@ -27,3 +15,33 @@ export function createFighterImage(fighter) {

return imgElement;
}

export function createFighterPreview(fighter, position) {
const positionClassName = position === 'right' ? 'fighter-preview___right' : 'fighter-preview___left';
const fighterElement = createElement({
tagName: 'div',
className: `fighter-preview___root ${positionClassName}`
});

const fighterName = createElement({
tagName: 'h2',
className: 'fighterName'
});

const fighterStats = createElement({
tagName: 'div',
className: 'fighterStats'
});

// todo: show fighter info (image, name, health, etc.)
if (fighter) {
const { name, health, attack, defense } = fighter;
const image = createFighterImage(fighter);
fighterName.innerHTML = name;
fighterStats.innerHTML = `<p>HP: ${health}</p><p>ATK: ${attack}</p><p>DEF: ${defense}</p>`;

fighterElement.append(image, fighterName, fighterStats);
}

return fighterElement;
}
4 changes: 4 additions & 0 deletions src/javascript/components/fighterSelector.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,15 @@ import createElement from '../helpers/domHelper';
import renderArena from './arena';
import versusImg from '../../../resources/versus.png';
import { createFighterPreview } from './fighterPreview';
import fighterService from '../services/fightersService';

const fighterDetailsMap = new Map();

export async function getFighterInfo(fighterId) {
// get fighter info from fighterDetailsMap or from service and write it to fighterDetailsMap
const details = await fighterService.getFighterDetails(fighterId);
fighterDetailsMap.set(fighterId, details);
return details;
}

function startFight(selectedFighters) {
Expand Down
Loading