diff --git a/package-lock.json b/package-lock.json index 62879f0..f04ac24 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,8 +1,221 @@ { "name": "west", "version": "0.0.1", - "lockfileVersion": 1, + "lockfileVersion": 2, "requires": true, + "packages": { + "": { + "name": "west", + "version": "0.0.1", + "dependencies": { + "http-server": "^0.12.3" + } + }, + "node_modules/async": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/async/-/async-2.6.3.tgz", + "integrity": "sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg==", + "dependencies": { + "lodash": "^4.17.14" + } + }, + "node_modules/basic-auth": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/basic-auth/-/basic-auth-1.1.0.tgz", + "integrity": "sha1-RSIe5Cn37h5QNb4/UVM/HN/SmIQ=", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/colors": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz", + "integrity": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==", + "engines": { + "node": ">=0.1.90" + } + }, + "node_modules/corser": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/corser/-/corser-2.0.1.tgz", + "integrity": "sha1-jtolLsqrWEDc2XXOuQ2TcMgZ/4c=", + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/debug": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/ecstatic": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/ecstatic/-/ecstatic-3.3.2.tgz", + "integrity": "sha512-fLf9l1hnwrHI2xn9mEDT7KIi22UDqA2jaCwyCbSUJh9a1V+LEUSL/JO/6TIz/QyuBURWUHrFL5Kg2TtO1bkkog==", + "dependencies": { + "he": "^1.1.1", + "mime": "^1.6.0", + "minimist": "^1.1.0", + "url-join": "^2.0.5" + }, + "bin": { + "ecstatic": "lib/ecstatic.js" + } + }, + "node_modules/eventemitter3": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", + "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==" + }, + "node_modules/follow-redirects": { + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.13.0.tgz", + "integrity": "sha512-aq6gF1BEKje4a9i9+5jimNFIpq4Q1WiwBToeRK5NvZBd/TRsmW8BsJfOEGkr76TbOyPVD3OVDN910EcUNtRYEA==", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", + "bin": { + "he": "bin/he" + } + }, + "node_modules/http-proxy": { + "version": "1.18.1", + "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz", + "integrity": "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==", + "dependencies": { + "eventemitter3": "^4.0.0", + "follow-redirects": "^1.0.0", + "requires-port": "^1.0.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/http-server": { + "version": "0.12.3", + "resolved": "https://registry.npmjs.org/http-server/-/http-server-0.12.3.tgz", + "integrity": "sha512-be0dKG6pni92bRjq0kvExtj/NrrAd28/8fCXkaI/4piTwQMSDSLMhWyW0NI1V+DBI3aa1HMlQu46/HjVLfmugA==", + "dependencies": { + "basic-auth": "^1.0.3", + "colors": "^1.4.0", + "corser": "^2.0.1", + "ecstatic": "^3.3.2", + "http-proxy": "^1.18.0", + "minimist": "^1.2.5", + "opener": "^1.5.1", + "portfinder": "^1.0.25", + "secure-compare": "3.0.1", + "union": "~0.5.0" + }, + "bin": { + "hs": "bin/http-server", + "http-server": "bin/http-server" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/lodash": { + "version": "4.17.20", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.20.tgz", + "integrity": "sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA==" + }, + "node_modules/mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/minimist": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", + "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==" + }, + "node_modules/mkdirp": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", + "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", + "dependencies": { + "minimist": "^1.2.5" + }, + "bin": { + "mkdirp": "bin/cmd.js" + } + }, + "node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "node_modules/opener": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/opener/-/opener-1.5.2.tgz", + "integrity": "sha512-ur5UIdyw5Y7yEj9wLzhqXiy6GZ3Mwx0yGI+5sMn2r0N0v3cKJvUmFH5yPP+WXh9e0xfyzyJX95D8l088DNFj7A==", + "bin": { + "opener": "bin/opener-bin.js" + } + }, + "node_modules/portfinder": { + "version": "1.0.28", + "resolved": "https://registry.npmjs.org/portfinder/-/portfinder-1.0.28.tgz", + "integrity": "sha512-Se+2isanIcEqf2XMHjyUKskczxbPH7dQnlMjXX6+dybayyHvAf/TCgyMRlzf/B6QDhAEFOGes0pzRo3by4AbMA==", + "dependencies": { + "async": "^2.6.2", + "debug": "^3.1.1", + "mkdirp": "^0.5.5" + }, + "engines": { + "node": ">= 0.12.0" + } + }, + "node_modules/qs": { + "version": "6.9.4", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.9.4.tgz", + "integrity": "sha512-A1kFqHekCTM7cz0udomYUoYNWjBebHm/5wzU/XqrBRBNWectVH0QIiN+NEcZ0Dte5hvzHwbr8+XQmguPhJ6WdQ==", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/requires-port": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", + "integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=" + }, + "node_modules/secure-compare": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/secure-compare/-/secure-compare-3.0.1.tgz", + "integrity": "sha1-8aAymzCLIh+uN7mXTz1XjQypmeM=" + }, + "node_modules/union": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/union/-/union-0.5.0.tgz", + "integrity": "sha512-N6uOhuW6zO95P3Mel2I2zMsbsanvvtgn6jVqJv4vbVcz/JN0OkL9suomjQGmWtxJQXOCqUJvquc1sMeNz/IwlA==", + "dependencies": { + "qs": "^6.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/url-join": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/url-join/-/url-join-2.0.5.tgz", + "integrity": "sha1-WvIvGMBSoACkjXuCxenC4v7tpyg=" + } + }, "dependencies": { "async": { "version": "2.6.3", diff --git a/src/TaskQueue.js b/src/TaskQueue.js index f3a9c6a..1f4dbf8 100644 --- a/src/TaskQueue.js +++ b/src/TaskQueue.js @@ -1,10 +1,10 @@ -const TaskQueue = function() { - function TaskQueue() { +class TaskQueue { + constructor(props) { this.tasks = []; this.running = false; } - TaskQueue.prototype.push = function(run, dispose, duration) { + push (run, dispose, duration) { if (duration === undefined || duration === null) { this.tasks.push({runAndContinue: run, dispose}); } else { @@ -18,14 +18,14 @@ const TaskQueue = function() { dispose }); } - runNextTask(this); - }; + this.#runNextTask(this); + } - TaskQueue.prototype.continueWith = function(action) { + continueWith (action) { this.push(action, null, 0); }; - function runNextTask(taskQueue) { + #runNextTask(taskQueue) { if (taskQueue.running || taskQueue.tasks.length === 0) { return; } @@ -39,17 +39,15 @@ const TaskQueue = function() { taskQueue.running = false; setTimeout(() => { - runNextTask(taskQueue); + this.#runNextTask(taskQueue); }); }); }, 0); } else { - runNextTask(taskQueue); + this.#runNextTask(taskQueue); } } +} - return TaskQueue; -}(); - -export default TaskQueue; +export default TaskQueue; \ No newline at end of file diff --git a/src/index.js b/src/index.js index a01f912..a180a80 100644 --- a/src/index.js +++ b/src/index.js @@ -1,18 +1,16 @@ -import Card from './Card.js'; import Game from './Game.js'; +import Card from './Card.js'; import TaskQueue from './TaskQueue.js'; import SpeedRate from './SpeedRate.js'; - +//region classes // Отвечает является ли карта уткой. function isDuck(card) { return card && card.quacks && card.swims; } - // Отвечает является ли карта собакой. function isDog(card) { return card instanceof Dog; } - // Дает описание существа по схожести с утками и собаками function getCreatureDescription(card) { if (isDuck(card) && isDog(card)) { @@ -24,43 +22,229 @@ function getCreatureDescription(card) { if (isDog(card)) { return 'Собака'; } - return 'Существо'; -} + function getCreatureDescription(card) { + } + return 'Существо'; + } + + class Creature extends Card { + constructor(name, maxPower, image) { + super(name, maxPower, image); + } + get power() { + return this.currentPower; + } + set power(value) { + this.currentPower = Math.min(this.maxPower, this.currentPower + value); + } + + getDescriptions() { + return [getCreatureDescription(this), super.getDescriptions()] + } + } // Основа для утки. -function Duck() { - this.quacks = function () { console.log('quack') }; - this.swims = function () { console.log('float: both;') }; -} + class Duck extends Creature { + constructor(name = "Мирная утка", maxPower = 2, image) { + super(name, maxPower); + } + + quacks() { + console.log('quack') + }; + swims() { + console.log('float: both;') + }; + } // Основа для собаки. -function Dog() { -} + class Dog extends Creature { + constructor(name = "Пес-бандит", maxPower = 3, image) { + super(name, maxPower); + } + } + + class Traher extends Dog { + constructor(name = "Дядя Богдан Трахер", maxPower = 5, image) { + super(name, maxPower, image); + } + + modifyTakenDamage(value, toCard, gameContext, continuation) { + this.view.signalAbility(() => continuation(value - 1)) + } + + } + + class Gatling extends Creature { + constructor(name = "Большая дик", maxPower = 6, image) { + super(name, maxPower); + } + + attack(gameContext, continuation) { + const taskQueue = new TaskQueue(); + + const {currentPlayer, oppositePlayer, position, updateView} = gameContext; + + taskQueue.push(onDone => this.view.showAttack(onDone)); + const enemies = gameContext.oppositePlayer.table; + for (const enemy of gameContext.oppositePlayer.table) { + if (enemies) { + taskQueue.push(onDone => { + this.dealDamageToCreature(this.currentPower, enemy, gameContext, onDone); + }); + } else { + taskQueue.push(onDone => this.dealDamageToPlayer(1, gameContext, onDone)); + } + } + + taskQueue.continueWith(continuation); + } + } + + class Lad extends Dog { + static #count = 0; + static getBonus() { + return Lad.#count * (Lad.#count + 1) / 2; + } -// Колода Шерифа, нижнего игрока. -const seriffStartDeck = [ - new Card('Мирный житель', 2), - new Card('Мирный житель', 2), - new Card('Мирный житель', 2), -]; + constructor(name = "Фраерки Чотка", maxPower = 2, image) { + super(name, maxPower, image); + } -// Колода Бандита, верхнего игрока. -const banditStartDeck = [ - new Card('Бандит', 3), -]; + doAfterComingIntoPlay(gameContext, continuation) { + Lad.#count++; + super.doAfterComingIntoPlay(gameContext, continuation); + } + + modifyTakenDamage(value, toCard, gameContext, continuation) { + this.view.signalAbility(() => + super.modifyTakenDamage(value - Lad.getBonus(), toCard, gameContext, continuation)); + } + + doBeforeRemoving(gameContext, continuation) { + Lad.#count--; + super.doBeforeRemoving(gameContext, continuation); + } + + modifyDealedDamageToCreature(value, toCard, gameContext, continuation) { + super.modifyDealedDamageToCreature(value + Lad.getBonus(), toCard, gameContext, continuation) + } + + getDescriptions() { + if (Lad.prototype.hasOwnProperty('modifyDealedDamageToCreature')) + return ["Бригада, вместе мы сильнее ", ...super.getDescriptions()]; + return super.getDescriptions(); + } + } + +//endregion + class Rogue extends Creature { + constructor(name = "Вор трусов", maxPower = 2, image) { + super(name, maxPower, image); + } + + doBeforeAttack (gameContext, continuation) { + const {currentPlayer, oppositePlayer, position, updateView} = gameContext; + + if(oppositePlayer.table[position]) { + let cardOpponent = Object.getPrototypeOf(oppositePlayer.table[position]); + if (cardOpponent.modifyDealedDamageToCreature) { + this["modifyDealedDamageToCreature"] = cardOpponent["modifyDealedDamageToCreature"]; + delete cardOpponent["modifyDealedDamageToCreature"]; + } + if (cardOpponent.modifyTakenDamage) { + this["modifyTakenDamage"] = cardOpponent["modifyTakenDamage"]; + delete cardOpponent["modifyTakenDamage"]; + } + if (cardOpponent.modifyDealedDamageToPlayer) { + this["modifyDealedDamageToPlayer"] = cardOpponent["modifyDealedDamageToPlayer"]; + delete cardOpponent["modifyDealedDamageToPlayer"]; + } + } + + updateView(); + continuation(); + }; + } + + class Brewer extends Duck { + constructor(name = "Пьяный Мастер Ли", maxPower = 2, image) { + super(name, maxPower); + } + + doBeforeAttack (gameContext, continuation) { + const {currentPlayer, oppositePlayer, position, updateView} = gameContext; + let allCards = currentPlayer.table.concat(oppositePlayer.table) + + for (let card of allCards) { + if (isDuck(card)) { + card.maxPower += 1; + card.power += 2; + } + } + + this.view.signalHeal(continuation) + + updateView(); + }; + } + + class PseudoDuck extends Dog { + constructor(name = "Псевдо утка", maxPower = 3, image) { + super(name, maxPower); + } + + quacks() { + console.log('quack') + }; + + swims() { + console.log('float: both;') + }; + } + + class Nemo extends Creature { + constructor(name = "Немо", maxPower = 4, image) { + super(name, maxPower); + } + + getDescriptions() { + return ["The one without a name without an honest heart as compass", ...super.getDescriptions()]; + } + + doBeforeAttack (gameContext, continuation) { + const {currentPlayer, oppositePlayer, position, updateView} = gameContext; + + if(oppositePlayer.table[position]) { + let cardOpponent = Object.getPrototypeOf(oppositePlayer.table[position]); + Object.setPrototypeOf(this, cardOpponent); + } + + updateView(); + continuation( this.doBeforeAttack(gameContext, continuation)); + + }; + } + const seriffStartDeck = [ + new Nemo(), + ]; + const banditStartDeck = [ + new Brewer(), + new Brewer(), + ]; // Создание игры. -const game = new Game(seriffStartDeck, banditStartDeck); + const game = new Game(seriffStartDeck, banditStartDeck); // Глобальный объект, позволяющий управлять скоростью всех анимаций. -SpeedRate.set(1); + SpeedRate.set(1.5); // Запуск игры. -game.play(false, (winner) => { - alert('Победил ' + winner.name); -}); + game.play(false, (winner) => { + alert('Победил ' + winner.name); + }); diff --git a/src/styles.css b/src/styles.css index 5715729..35fca31 100644 --- a/src/styles.css +++ b/src/styles.css @@ -1,7 +1,6 @@ body { margin: 0px; } - .container { font-family: Arial; display: grid; @@ -12,12 +11,10 @@ body { padding: 10px; background-color: lightgoldenrodyellow; } - .playerRow { display: flex; align-items: center; } - .playerImage { position: relative; margin-left: 20px; @@ -27,92 +24,75 @@ body { border: 2px solid saddlebrown; border-radius: 80px; } - .playerPower { margin-left: 20px; font-size: 20px; font-weight: bold; } - .playerTable { display: flex; } - .playerImage img { width: 80px; } - .cardPlaceContainer { margin: 0 5px; width: 170px; height: 230px; } - .cardPlace { position: relative; } - .cardPlaceEmpty { border: 2px solid saddlebrown; border-radius: 2px; width: 160px; height: 220px; } - .deckPlaceContainer { margin: 0 5px; width: 170px; height: 230px; } - .deckPlace { position: relative; } - .deckPlaceEmpty { border: 2px solid saddlebrown; border-radius: 2px; width: 160px; height: 220px; } - .card { transform-style: preserve-3d; position: absolute; width: 164px; height: 224px; } - .card.flipped { transform: rotateY(180deg); } - .card.fadeOut { opacity: 0; } - .card.attackUp { animation-name: attackUpAnimation; animation-timing-function: ease-in-out; } - .card.attackDown { animation-name: attackDownAnimation; animation-timing-function: ease-in-out; } - @keyframes attackUpAnimation { 0% { top: 0; } 50% { top: -18px; } 100% { top: 0; } } - @keyframes attackDownAnimation { 0% { top: 0; } 50% { top: 18px; } 100% { top: 0; } } - .cardBack { position: absolute; border: 2px solid saddlebrown; @@ -127,7 +107,6 @@ body { transform: rotateY(180deg); backface-visibility: hidden; } - .cardBack .pattern { margin: 10px; width: 110px; @@ -136,7 +115,6 @@ body { font-size: 20px; text-align: center; } - .cardFront { position: absolute; border: 2px solid saddlebrown; @@ -148,24 +126,20 @@ body { grid-template-rows: 30px auto 30px; backface-visibility: hidden; } - .cardHeader { grid-row: 1; background: palegoldenrod; padding: 5px; } - .cardName { font-weight: bold; font-size: 14px; text-align: center; } - .cardBody { grid-row: 2; position: relative; } - .cardImage { left: 5px; right: 5px; @@ -173,11 +147,9 @@ body { height: 100%; text-align: center; } - .cardImage img { height: 100%; } - .cardDescriptions { left: 5px; right: 5px; @@ -190,19 +162,16 @@ body { color: white; text-shadow: 1px 0 0 #000, 0 -1px 0 #000, 0 1px 0 #000, -1px 0 0 #000; } - .cardFooter { grid-row: 3; background: palegoldenrod; padding: 5px; } - .cardPower { font-size: 14px; font-weight: bold; text-align: center; } - .cardSignal, .playerSignal { position: absolute; @@ -212,40 +181,34 @@ body { opacity: 0.0; } -.cardSignal { - transform: rotateY(180deg); -} +/*.cardSignal {*/ +/* transform: rotateY(180deg);*/ +/*}*/ .cardSignal.damage, .playerSignal.damage { background: darkred; } - .cardSignal.heal, .playerSignal.heal { background: mediumseagreen; } - .cardSignal.ability { background: white; } - .playerSignal.turnStart { background: white; } - .cardSignal.blink, .playerSignal.blink { animation-name: blinkAnimation; animation-timing-function: ease-in-out; } - @keyframes blinkAnimation { 0% { opacity: 0.0; } 50% { opacity: 0.5; } 100% { opacity: 0.0; } } - .templates { display: none; } \ No newline at end of file