diff --git a/.gitignore b/.gitignore index 7a367038..10c8ebc7 100755 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,7 @@ .DS_Store node_modules/ dist/ +.firebase npm-debug.log test/unit/coverage .idea diff --git a/public/static/cardImages/BatteryBackup.png b/public/static/cardImages/BatteryBackup.png deleted file mode 100644 index 1fdea5a6..00000000 Binary files a/public/static/cardImages/BatteryBackup.png and /dev/null differ diff --git a/public/static/cardImages/Generator.png b/public/static/cardImages/Generator.png deleted file mode 100644 index 12c3eb7b..00000000 Binary files a/public/static/cardImages/Generator.png and /dev/null differ diff --git a/public/static/cardImages/Hacker.png b/public/static/cardImages/Hacker.png deleted file mode 100644 index 7b0e0e51..00000000 Binary files a/public/static/cardImages/Hacker.png and /dev/null differ diff --git a/public/static/cardImages/Malware.png b/public/static/cardImages/Malware.png deleted file mode 100644 index 28325c6b..00000000 Binary files a/public/static/cardImages/Malware.png and /dev/null differ diff --git a/public/static/cardImages/OverClock.png b/public/static/cardImages/OverClock.png deleted file mode 100644 index 73fa17c7..00000000 Binary files a/public/static/cardImages/OverClock.png and /dev/null differ diff --git a/public/static/cardImages/PowerOutage.png b/public/static/cardImages/PowerOutage.png deleted file mode 100644 index 6524cef4..00000000 Binary files a/public/static/cardImages/PowerOutage.png and /dev/null differ diff --git a/public/static/cardImages/AntiVirus.png b/public/static/cardImages/antivirus0.png similarity index 100% rename from public/static/cardImages/AntiVirus.png rename to public/static/cardImages/antivirus0.png diff --git a/public/static/cardImages/backOfCard.png.old b/public/static/cardImages/backOfCard.png.old deleted file mode 100644 index 23f6516d..00000000 Binary files a/public/static/cardImages/backOfCard.png.old and /dev/null differ diff --git a/public/static/cardImages/effects/ANTIVIRUS.png b/public/static/cardImages/effects/ANTIVIRUS.png index 0dffd76a..a0a15f37 100644 Binary files a/public/static/cardImages/effects/ANTIVIRUS.png and b/public/static/cardImages/effects/ANTIVIRUS.png differ diff --git a/public/static/cardImages/effects/BATTERYBACKUP.png b/public/static/cardImages/effects/BATTERYBACKUP.png deleted file mode 100644 index 385435af..00000000 Binary files a/public/static/cardImages/effects/BATTERYBACKUP.png and /dev/null differ diff --git a/public/static/cardImages/effects/DISCARD.png b/public/static/cardImages/effects/DISCARD.png new file mode 100644 index 00000000..47c16f6c Binary files /dev/null and b/public/static/cardImages/effects/DISCARD.png differ diff --git a/public/static/cardImages/effects/FIREWALL.png b/public/static/cardImages/effects/FIREWALL.png index f61e178f..8a58c2bc 100644 Binary files a/public/static/cardImages/effects/FIREWALL.png and b/public/static/cardImages/effects/FIREWALL.png differ diff --git a/public/static/cardImages/effects/GENERATOR.png b/public/static/cardImages/effects/GENERATOR.png deleted file mode 100644 index aefe8b53..00000000 Binary files a/public/static/cardImages/effects/GENERATOR.png and /dev/null differ diff --git a/public/static/cardImages/effects/GROUP2.png b/public/static/cardImages/effects/GROUP2.png new file mode 100644 index 00000000..1d0346e3 Binary files /dev/null and b/public/static/cardImages/effects/GROUP2.png differ diff --git a/public/static/cardImages/effects/GROUP3.png b/public/static/cardImages/effects/GROUP3.png new file mode 100644 index 00000000..5e7611d8 Binary files /dev/null and b/public/static/cardImages/effects/GROUP3.png differ diff --git a/public/static/cardImages/effects/GROUP4.png b/public/static/cardImages/effects/GROUP4.png new file mode 100644 index 00000000..b401a98c Binary files /dev/null and b/public/static/cardImages/effects/GROUP4.png differ diff --git a/public/static/cardImages/effects/GROUP5.png b/public/static/cardImages/effects/GROUP5.png new file mode 100644 index 00000000..78871595 Binary files /dev/null and b/public/static/cardImages/effects/GROUP5.png differ diff --git a/public/static/cardImages/effects/GROUP6.png b/public/static/cardImages/effects/GROUP6.png new file mode 100644 index 00000000..c549ef66 Binary files /dev/null and b/public/static/cardImages/effects/GROUP6.png differ diff --git a/public/static/cardImages/effects/HACK.png b/public/static/cardImages/effects/HACK.png deleted file mode 100644 index 9781e31e..00000000 Binary files a/public/static/cardImages/effects/HACK.png and /dev/null differ diff --git a/public/static/cardImages/effects/INSTRUCTION1.png b/public/static/cardImages/effects/INSTRUCTION1.png new file mode 100644 index 00000000..dadc6df4 Binary files /dev/null and b/public/static/cardImages/effects/INSTRUCTION1.png differ diff --git a/public/static/cardImages/effects/INSTRUCTION2.png b/public/static/cardImages/effects/INSTRUCTION2.png new file mode 100644 index 00000000..02c54795 Binary files /dev/null and b/public/static/cardImages/effects/INSTRUCTION2.png differ diff --git a/public/static/cardImages/effects/INSTRUCTION3.png b/public/static/cardImages/effects/INSTRUCTION3.png new file mode 100644 index 00000000..216e5551 Binary files /dev/null and b/public/static/cardImages/effects/INSTRUCTION3.png differ diff --git a/public/static/cardImages/effects/OVERCLOCK.png b/public/static/cardImages/effects/OVERCLOCK.png deleted file mode 100644 index a9390015..00000000 Binary files a/public/static/cardImages/effects/OVERCLOCK.png and /dev/null differ diff --git a/public/static/cardImages/effects/POWEROUTAGE.png b/public/static/cardImages/effects/POWEROUTAGE.png deleted file mode 100644 index 06af791b..00000000 Binary files a/public/static/cardImages/effects/POWEROUTAGE.png and /dev/null differ diff --git a/public/static/cardImages/effects/RANSOM.png b/public/static/cardImages/effects/RANSOM.png new file mode 100644 index 00000000..f759b48e Binary files /dev/null and b/public/static/cardImages/effects/RANSOM.png differ diff --git a/public/static/cardImages/effects/REDRAW.png b/public/static/cardImages/effects/REDRAW.png new file mode 100644 index 00000000..0fd39cdd Binary files /dev/null and b/public/static/cardImages/effects/REDRAW.png differ diff --git a/public/static/cardImages/effects/REPEAT1.png b/public/static/cardImages/effects/REPEAT1.png new file mode 100644 index 00000000..622af055 Binary files /dev/null and b/public/static/cardImages/effects/REPEAT1.png differ diff --git a/public/static/cardImages/effects/REPEAT2.png b/public/static/cardImages/effects/REPEAT2.png new file mode 100644 index 00000000..25b64e80 Binary files /dev/null and b/public/static/cardImages/effects/REPEAT2.png differ diff --git a/public/static/cardImages/effects/REPEAT3.png b/public/static/cardImages/effects/REPEAT3.png new file mode 100644 index 00000000..779f81e9 Binary files /dev/null and b/public/static/cardImages/effects/REPEAT3.png differ diff --git a/public/static/cardImages/effects/REPEAT4.png b/public/static/cardImages/effects/REPEAT4.png new file mode 100644 index 00000000..cfbcf8a2 Binary files /dev/null and b/public/static/cardImages/effects/REPEAT4.png differ diff --git a/public/static/cardImages/effects/SCAN.png b/public/static/cardImages/effects/SCAN.png new file mode 100644 index 00000000..701f9b8e Binary files /dev/null and b/public/static/cardImages/effects/SCAN.png differ diff --git a/public/static/cardImages/effects/SPYWARE.png b/public/static/cardImages/effects/SPYWARE.png new file mode 100644 index 00000000..53cb5c71 Binary files /dev/null and b/public/static/cardImages/effects/SPYWARE.png differ diff --git a/public/static/cardImages/effects/TROJAN.png b/public/static/cardImages/effects/TROJAN.png new file mode 100644 index 00000000..31e97c1f Binary files /dev/null and b/public/static/cardImages/effects/TROJAN.png differ diff --git a/public/static/cardImages/effects/VARIABLE3.png b/public/static/cardImages/effects/VARIABLE3.png new file mode 100644 index 00000000..f1e1201a Binary files /dev/null and b/public/static/cardImages/effects/VARIABLE3.png differ diff --git a/public/static/cardImages/effects/VARIABLE4.png b/public/static/cardImages/effects/VARIABLE4.png new file mode 100644 index 00000000..2e7564e5 Binary files /dev/null and b/public/static/cardImages/effects/VARIABLE4.png differ diff --git a/public/static/cardImages/effects/VARIABLE5.png b/public/static/cardImages/effects/VARIABLE5.png new file mode 100644 index 00000000..9f9a8e3c Binary files /dev/null and b/public/static/cardImages/effects/VARIABLE5.png differ diff --git a/public/static/cardImages/effects/VARIABLE6.png b/public/static/cardImages/effects/VARIABLE6.png new file mode 100644 index 00000000..4652b77e Binary files /dev/null and b/public/static/cardImages/effects/VARIABLE6.png differ diff --git a/public/static/cardImages/effects/VIRUS.png b/public/static/cardImages/effects/VIRUS.png index 55652342..4bb06189 100644 Binary files a/public/static/cardImages/effects/VIRUS.png and b/public/static/cardImages/effects/VIRUS.png differ diff --git a/public/static/cardImages/Firewall.png b/public/static/cardImages/firewall0.png similarity index 100% rename from public/static/cardImages/Firewall.png rename to public/static/cardImages/firewall0.png diff --git a/public/static/cardImages/Group2.png b/public/static/cardImages/group2.png similarity index 100% rename from public/static/cardImages/Group2.png rename to public/static/cardImages/group2.png diff --git a/public/static/cardImages/Group3.png b/public/static/cardImages/group3.png similarity index 100% rename from public/static/cardImages/Group3.png rename to public/static/cardImages/group3.png diff --git a/public/static/cardImages/Group4.png b/public/static/cardImages/group4.png similarity index 100% rename from public/static/cardImages/Group4.png rename to public/static/cardImages/group4.png diff --git a/public/static/cardImages/Group5.png b/public/static/cardImages/group5.png similarity index 100% rename from public/static/cardImages/Group5.png rename to public/static/cardImages/group5.png diff --git a/public/static/cardImages/Group6.png b/public/static/cardImages/group6.png similarity index 100% rename from public/static/cardImages/Group6.png rename to public/static/cardImages/group6.png diff --git a/public/static/cardImages/Instruction1.png b/public/static/cardImages/instruction1.png similarity index 100% rename from public/static/cardImages/Instruction1.png rename to public/static/cardImages/instruction1.png diff --git a/public/static/cardImages/Instruction2.png b/public/static/cardImages/instruction2.png similarity index 100% rename from public/static/cardImages/Instruction2.png rename to public/static/cardImages/instruction2.png diff --git a/public/static/cardImages/Instruction3.png b/public/static/cardImages/instruction3.png similarity index 100% rename from public/static/cardImages/Instruction3.png rename to public/static/cardImages/instruction3.png diff --git a/public/static/cardImages/ransom0.png b/public/static/cardImages/ransom0.png new file mode 100644 index 00000000..8d418d52 Binary files /dev/null and b/public/static/cardImages/ransom0.png differ diff --git a/public/static/cardImages/RepetitionX.png b/public/static/cardImages/repeat1.png similarity index 100% rename from public/static/cardImages/RepetitionX.png rename to public/static/cardImages/repeat1.png diff --git a/public/static/cardImages/Repetition2.png b/public/static/cardImages/repeat2.png similarity index 100% rename from public/static/cardImages/Repetition2.png rename to public/static/cardImages/repeat2.png diff --git a/public/static/cardImages/Repetition3.png b/public/static/cardImages/repeat3.png similarity index 100% rename from public/static/cardImages/Repetition3.png rename to public/static/cardImages/repeat3.png diff --git a/public/static/cardImages/Repetition4.png b/public/static/cardImages/repeat4.png similarity index 100% rename from public/static/cardImages/Repetition4.png rename to public/static/cardImages/repeat4.png diff --git a/public/static/cardImages/scan0.png b/public/static/cardImages/scan0.png new file mode 100644 index 00000000..b85ecdfc Binary files /dev/null and b/public/static/cardImages/scan0.png differ diff --git a/public/static/cardImages/spyware0.png b/public/static/cardImages/spyware0.png new file mode 100644 index 00000000..8d80f7cf Binary files /dev/null and b/public/static/cardImages/spyware0.png differ diff --git a/public/static/cardImages/trojan0.png b/public/static/cardImages/trojan0.png new file mode 100644 index 00000000..18189c94 Binary files /dev/null and b/public/static/cardImages/trojan0.png differ diff --git a/public/static/cardImages/Variable3.png b/public/static/cardImages/variable3.png similarity index 100% rename from public/static/cardImages/Variable3.png rename to public/static/cardImages/variable3.png diff --git a/public/static/cardImages/Variable4.png b/public/static/cardImages/variable4.png similarity index 100% rename from public/static/cardImages/Variable4.png rename to public/static/cardImages/variable4.png diff --git a/public/static/cardImages/Variable5.png b/public/static/cardImages/variable5.png similarity index 100% rename from public/static/cardImages/Variable5.png rename to public/static/cardImages/variable5.png diff --git a/public/static/cardImages/Variable6.png b/public/static/cardImages/variable6.png similarity index 100% rename from public/static/cardImages/Variable6.png rename to public/static/cardImages/variable6.png diff --git a/public/static/cardImages/virus0.png b/public/static/cardImages/virus0.png new file mode 100644 index 00000000..6c432dbf Binary files /dev/null and b/public/static/cardImages/virus0.png differ diff --git a/public/static/miscIcons/arrow.png b/public/static/miscIcons/arrow.png new file mode 100644 index 00000000..e30990d6 Binary files /dev/null and b/public/static/miscIcons/arrow.png differ diff --git a/public/static/miscIcons/noIcon.png b/public/static/miscIcons/noIcon.png new file mode 100644 index 00000000..37e87574 Binary files /dev/null and b/public/static/miscIcons/noIcon.png differ diff --git a/public/static/playerImages/player0.png b/public/static/playerImages/player0.png new file mode 100644 index 00000000..06832578 Binary files /dev/null and b/public/static/playerImages/player0.png differ diff --git a/public/static/playerImages/player1.png b/public/static/playerImages/player1.png new file mode 100644 index 00000000..acc68008 Binary files /dev/null and b/public/static/playerImages/player1.png differ diff --git a/public/static/playerImages/player2.png b/public/static/playerImages/player2.png new file mode 100644 index 00000000..a19b4332 Binary files /dev/null and b/public/static/playerImages/player2.png differ diff --git a/public/static/playerImages/player3.png b/public/static/playerImages/player3.png new file mode 100644 index 00000000..49641208 Binary files /dev/null and b/public/static/playerImages/player3.png differ diff --git a/public/static/playerImages/player4.png b/public/static/playerImages/player4.png new file mode 100644 index 00000000..b54482bf Binary files /dev/null and b/public/static/playerImages/player4.png differ diff --git a/public/static/playerImages/player5.png b/public/static/playerImages/player5.png new file mode 100644 index 00000000..2830ff8c Binary files /dev/null and b/public/static/playerImages/player5.png differ diff --git a/public/static/playerImages/player6.png b/public/static/playerImages/player6.png new file mode 100644 index 00000000..4dba0f89 Binary files /dev/null and b/public/static/playerImages/player6.png differ diff --git a/public/static/playerImages/player7.png b/public/static/playerImages/player7.png new file mode 100644 index 00000000..ced6728c Binary files /dev/null and b/public/static/playerImages/player7.png differ diff --git a/public/static/playerImages/robo_0.jpg b/public/static/playerImages/robo_0.jpg deleted file mode 100644 index e5184306..00000000 Binary files a/public/static/playerImages/robo_0.jpg and /dev/null differ diff --git a/public/static/playerImages/robo_1.jpg b/public/static/playerImages/robo_1.jpg deleted file mode 100644 index 142d8f12..00000000 Binary files a/public/static/playerImages/robo_1.jpg and /dev/null differ diff --git a/public/static/playerImages/robo_2.jpg b/public/static/playerImages/robo_2.jpg deleted file mode 100644 index b76ea462..00000000 Binary files a/public/static/playerImages/robo_2.jpg and /dev/null differ diff --git a/public/static/playerImages/robo_3.jpg b/public/static/playerImages/robo_3.jpg deleted file mode 100644 index 3d7210cf..00000000 Binary files a/public/static/playerImages/robo_3.jpg and /dev/null differ diff --git a/src/classes/ai/AiHandler.js b/src/classes/ai/AiHandler.js index 3b090981..c8577135 100644 --- a/src/classes/ai/AiHandler.js +++ b/src/classes/ai/AiHandler.js @@ -38,9 +38,16 @@ export default class AiHandler { chooseAction(hand, players, stacks, scores) { // Try all the action handlers until one returns a turn object for (let action of this.actionHandlers) { - let result = action.handle(hand, players, stacks, scores) - if (result) { - return result + try { + let result = action.handle(hand, players, stacks, scores) + if (result) { + return result + } + + // Ensure that a component error does not stop the AI turn + } catch (err) { + console.log("AI handler error:", err) // eslint-disable-line + continue } } // If no handler can handle this action use the default action diff --git a/src/classes/ai/AiHandlerFactory.js b/src/classes/ai/AiHandlerFactory.js index 34d311bf..6d338141 100644 --- a/src/classes/ai/AiHandlerFactory.js +++ b/src/classes/ai/AiHandlerFactory.js @@ -12,15 +12,15 @@ const CARD_ORDER = { basic: ["VARIABLE", "REPEAT", "INSTRUCTION"], standard: [ "GROUP", "VARIABLE", "REPEAT", "INSTRUCTION", "ANTIVIRUS", "FIREWALL", - "OVERCLOCK", "HACK", "VIRUS" + "OVERCLOCK", "RANSOM", "TROJAN", "VIRUS" ], aggressive: [ - "HACK", "VIRUS", "VARIABLE", "REPEAT", "INSTRUCTION", "GROUP", + "VIRUS", "RANSOM", "TROJAN", "VARIABLE", "REPEAT", "INSTRUCTION", "GROUP", "FIREWALL", "ANTIVIRUS", "OVERCLOCK" ], defensive: [ "FIREWALL", "ANTIVIRUS", "OVERCLOCK", "GROUP", "VARIABLE", "REPEAT", - "INSTRUCTION", "VIRUS", "HACK" + "INSTRUCTION", "TROJAN", "VIRUS", "RANSOM" ] } diff --git a/src/classes/ai/PlayBestCardAction.js b/src/classes/ai/PlayBestCardAction.js index e4c9598f..f545ceee 100644 --- a/src/classes/ai/PlayBestCardAction.js +++ b/src/classes/ai/PlayBestCardAction.js @@ -156,24 +156,24 @@ export default class PlayBestCardAction extends ActionHandler { } /** - * Hack another players stack under specific conditions. - * Will not hack single card stacks as this is a waste. Picks the biggest + * play a virus on another players stack under specific conditions. + * Will not attack single card stacks as this is a waste. Picks the biggest * stack available that meets the criteria. * @param card The card to attempt to play. * @param state an object with all the state needed to make a decision * @return a move object for hacking a stack, or undefined if - * no stack can be hacked. + * no stack can be attacked. */ - hack (card, state) { + virus (card, state) { let stack = state.stacks.filter((s) => { - return s.playerId !== this.player.id && s.cards.length > 1 && s.isHackable() + return s.playerId !== this.player.id && s.cards.length > 1 }).sort((a, b) => { return b.getScore() - a.getScore() }).shift() if (stack) { return { - playType: 'hackStack', + playType: 'playCardOnStack', card: card, player: this.player, target: stack @@ -238,6 +238,7 @@ export default class PlayBestCardAction extends ActionHandler { let groupable = state.stacks.filter((s) => { // don't group single group cards with the same value as card return s.playerId === this.player.id && s.getScore() <= card.value + && s.getTop().type !== 'VIRUS' }) if (groupable.length == 0) { return undefined } diff --git a/src/classes/game/Card.js b/src/classes/game/Card.js index 4c352439..ef1ddf3a 100755 --- a/src/classes/game/Card.js +++ b/src/classes/game/Card.js @@ -3,6 +3,9 @@ * @author Steve modified on 2020-05-25 */ +// Function to create a unique object id +const uuidV1 = require('uuid/v1') + /** * A Playing card. */ @@ -10,35 +13,39 @@ export default class Card { /** * Constructor for the Card class * @constructor Card - * @param {int} id The ID of the card * @param {int} value The value of the card * @param {char} type The type of the card - * @param {char} image is a string pointing to the image of the card */ - constructor (id, value, type, image) { - this.id = id + constructor (type, value) { this.value = value this.type = type - this.image = image + this.id = uuidV1() + this.image = 'static/cardImages/' + type.toLowerCase() + value + '.png' + this.isExtra = false + this.isMimic = false } /** - * Checks if this card is an attack card. + * Checks if this card is an attack card that is played with a popup and + * not placed. */ isAttack () { - return this.type === "VIRUS" + return this.type === "RANSOM" || this.type === "SPYWARE" + || this.type === "TROJAN" } /** - * Checks if this card is a safety or remedy card + * Checks if this card is a safety or remedy card that is played with a + * popup and not placed. */ isSafety () { - return this.type === "OVERCLOCK" - || this.type === "FIREWALL" || this.type === "ANTIVIRUS" + return this.type === "SCAN" || this.type === "FIREWALL" + || this.type === "ANTIVIRUS" } /** - * Checks if this card is an attack or safety card. + * Checks if this card is an attack or safety card that is played with + * a popup and not placed. */ isSpecial () { return this.isSafety() || this.isAttack() diff --git a/src/classes/game/CyberEffect.js b/src/classes/game/CyberEffect.js new file mode 100644 index 00000000..8d3fdaa2 --- /dev/null +++ b/src/classes/game/CyberEffect.js @@ -0,0 +1,42 @@ +/** + * @file CyberEffect.js file + * @author Steve on 2020-06-18 + */ + +// Function to create a unique object id +const uuidV1 = require('uuid/v1') + +/** + * An effect for threat prevention or cyber attack on a player. + */ +export default class CyberEffect { + /** + * Constructor for the CyberEffect class. + * @constructor CyberEffect + */ + constructor (type, targetId, attackerId = undefined) { + this.id = uuidV1() + this.type = type + this.targetId = targetId + this.attackerId = attackerId + this.turnsLeft = undefined + if (type === "SPYWARE") { + this.turnsLeft = 2 + } + this.image = 'static/cardImages/effects/' + type + '.png' + } + + /** + * Decrements turnsLeft and returns the result + */ + takeTurn () { + if (this.turnsLeft === 0) { + return 0 + } else if (this.turnsLeft === undefined) { + return 9999 + } + this.turnsLeft -= 1 + return this.turnsLeft + } +} + diff --git a/src/classes/game/Deck.js b/src/classes/game/Deck.js index d09af140..60b68f62 100755 --- a/src/classes/game/Deck.js +++ b/src/classes/game/Deck.js @@ -5,68 +5,28 @@ import Card from './Card' +// card types along with {value: numCard} pairs for each +const cardTypes = { + "INSTRUCTION": {1: 9, 2: 12, 3: 9}, + "GROUP": {2: 1, 3: 2, 4: 3, 5: 2, 6: 1}, + "REPEAT": {1: 5, 2: 3, 3: 5, 4: 3}, + "VARIABLE": {3: 2, 4: 2, 5: 2, 6: 1}, + "VIRUS": {0: 3}, + "RANSOM": {0: 3}, + "SPYWARE": {0: 3}, + "TROJAN": {0: 3}, + "ANTIVIRUS": {0: 1}, + "FIREWALL": {0: 2}, + "SCAN": {0: 5}, +} -// Constants to determine how many of a card type and value to add to the deck - -const instruction1 = 9 -const instruction2 = 9 -const instruction3 = 9 - -const group2 = 1 -const group3 = 2 -const group4 = 3 -const group5 = 2 -const group6 = 1 - -const repetition2 = 3 -const repetition3 = 3 -const repetition4 = 3 -const repetitionX = 5 - -const variable3 = 2 -const variable4 = 2 -const variable5 = 2 -const variable6 = 1 - -const hack = 3 -const malware = 3 - -const overClock = 3 - -const antiVirus = 1 -const firewall = 1 - -// A list of object of card information used to setup the deck. -const cardDeck = [ - {type: 'INSTRUCTION', cardValue: 1, imgSrc: 'static/cardImages/Instruction1.png', howMany: instruction1}, - {type: 'INSTRUCTION', cardValue: 2, imgSrc: 'static/cardImages/Instruction2.png', howMany: instruction2}, - {type: 'INSTRUCTION', cardValue: 3, imgSrc: 'static/cardImages/Instruction3.png', howMany: instruction3}, - - {type: 'REPEAT', cardValue: 2, imgSrc: 'static/cardImages/Repetition2.png', howMany: repetition2}, - {type: 'REPEAT', cardValue: 3, imgSrc: 'static/cardImages/Repetition3.png', howMany: repetition3}, - {type: 'REPEAT', cardValue: 4, imgSrc: 'static/cardImages/Repetition4.png', howMany: repetition4}, - {type: 'REPEAT', cardValue: 1, imgSrc: 'static/cardImages/RepetitionX.png', howMany: repetitionX}, - - {type: 'GROUP', cardValue: 2, imgSrc: 'static/cardImages/Group2.png', howMany: group2}, - {type: 'GROUP', cardValue: 3, imgSrc: 'static/cardImages/Group3.png', howMany: group3}, - {type: 'GROUP', cardValue: 4, imgSrc: 'static/cardImages/Group4.png', howMany: group4}, - {type: 'GROUP', cardValue: 5, imgSrc: 'static/cardImages/Group5.png', howMany: group5}, - {type: 'GROUP', cardValue: 6, imgSrc: 'static/cardImages/Group6.png', howMany: group6}, - - {type: 'VARIABLE', cardValue: 3, imgSrc: 'static/cardImages/Variable3.png', howMany: variable3}, - {type: 'VARIABLE', cardValue: 4, imgSrc: 'static/cardImages/Variable4.png', howMany: variable4}, - {type: 'VARIABLE', cardValue: 5, imgSrc: 'static/cardImages/Variable5.png', howMany: variable5}, - {type: 'VARIABLE', cardValue: 6, imgSrc: 'static/cardImages/Variable6.png', howMany: variable6}, - - {type: 'HACK', cardValue: 0, imgSrc: 'static/cardImages/Hacker.png', howMany: hack}, - {type: 'VIRUS', cardValue: 0, imgSrc: 'static/cardImages/Malware.png', howMany: malware}, - - {type: 'OVERCLOCK', cardValue: 0, imgSrc: 'static/cardImages/OverClock.png', howMany: overClock}, - - {type: 'FIREWALL', cardValue: 0, imgSrc: 'static/cardImages/Firewall.png', howMany: firewall}, - {type: 'ANTIVIRUS', cardValue: 0, imgSrc: 'static/cardImages/AntiVirus.png', howMany: antiVirus} +// cards to add in when the deck is refreshed +const refreshCards = { + "GROUP": {4: 1, 5: 1, 6: 1}, + "REPEAT": {1: 2, 3: 2, 4: 2}, + "VARIABLE": {4: 1, 5: 1, 6: 1}, +} -] /** * A deck for a program wars game. @@ -76,42 +36,29 @@ const cardDeck = [ export default class Deck { /** * Constructor for the Deck class. - * @param {int} numPlayers The number of players using the deck. */ - constructor (numPlayers) { + constructor () { this.cards = [] this.discard = [] - this.initDeck(numPlayers) + this.addCards(cardTypes, 4) } /** * Initializes the deck with a pre determined number and type of cards. * Shuffles the deck. - * @param {int} numPlayers The number of players using the deck. */ - initDeck (numPlayers) { - let cardId = 0 - for (let k = 0; k < numPlayers; k++) { - for (let i = 0; i < cardDeck.length; i++) { - for (let j = 0; j < cardDeck[i].howMany; j++) { - if (cardDeck[i].type === 'FIREWALL' && (k === 1 || k === 3)) { - this.cards.push(new Card(cardId, cardDeck[i].cardValue, - cardDeck[i].type, cardDeck[i].imgSrc)) - cardId++ - } else if (cardDeck[i].type === 'ANTIVIRUS' && (k === 1 || k === 3)) { - this.cards.push(new Card(cardId, cardDeck[i].cardValue, - cardDeck[i].type, cardDeck[i].imgSrc)) - cardId++ - } else if (cardDeck[i].type !== 'ANTIVIRUS' - && cardDeck[i].type !== 'FIREWALL') { - this.cards.push(new Card(cardId, cardDeck[i].cardValue, - cardDeck[i].type, cardDeck[i].imgSrc)) - cardId++ - } + addCards (cardsToAdd, shuffles) { + for (let [type, values] of Object.entries(cardsToAdd)) { + for (let [value, number] of Object.entries(values)) { + for (let i = 0; i < number; i++) { + this.cards.push(new Card(type, parseInt(value))) } } } - this.shuffle(this.cards) + // Shuffle a few times to try and get a good random order + for (let i = 0; i < shuffles; i++) { + this.shuffle(this.cards) + } } /** @@ -140,10 +87,16 @@ export default class Deck { /** * Refreshes the deck by adding back the discard pile and shuffling. + * Also, adds some more group, variable, and repeat cards to keep the game + * moving. Especially in 4 player games these cards are moslty used up by + * the time the deck runs out, so we add some more in to ensure players + * can still play. */ refresh () { this.cards = this.cards.concat(this.discard) this.discard = [] - this.shuffle(this.cards) + if (this.cards.length < 80) { + this.addCards(refreshCards) + } } } diff --git a/src/classes/game/Objectives.js b/src/classes/game/Objectives.js index 20cd8a26..1cab879c 100644 --- a/src/classes/game/Objectives.js +++ b/src/classes/game/Objectives.js @@ -5,14 +5,15 @@ // Bonuses for each card played const GROUP_BONUS = 5 -const REPEAT_BONUS = 2 -const VAR_BONUS = 3 -const SAFETY_BONUS = 10 +const REPEAT_BONUS = 3 +const VAR_BONUS = 2 +const SAFETY_BONUS = 3 // Objective Bonuses -const DEFENSIVE_BONUS = 10 +const ANTIVIRUS_BONUS = 10 +const FIREWALL_BONUS = 5 const CLEAN_BONUS = 10 -const COMPLETE_BONUS = 10 +const COMPLETE_BONUS = 5 /** @@ -55,7 +56,7 @@ export default class Objectives { */ getSafetyBonus () { let safetyCards = this.cardsPlayed.filter((c) => { - return c.type === "ANTIVIRUS" || c.type === "FIREWALL" + return c.type === "ANTIVIRUS" || c.type === "FIREWALL" || c.type === "SCAN" }) return SAFETY_BONUS * safetyCards.length } @@ -66,8 +67,10 @@ export default class Objectives { * Is 0 if the player does not meet the requirements for the bonus. */ getDefensiveBonus () { - if (this.player.helpedBy("ANTIVIRUS") && this.player.helpedBy("FIREWALL")) { - return DEFENSIVE_BONUS + if (this.player.helpedBy("ANTIVIRUS")) { + return ANTIVIRUS_BONUS + } else if (this.player.hasPositive('FIREWALL')) { + return FIREWALL_BONUS } return 0 } @@ -77,20 +80,34 @@ export default class Objectives { * Clean bonus is given if the player has no Virus. * Is 0 if the player does not meet the requirements for the bonus. */ - getCleanBonus () { - return this.player.hurtBy("VIRUS") ? 0 : CLEAN_BONUS + getCleanBonus (playerHand, playerStacks) { + if(this.player.hurtBy('RANSOM')|| this.player.hurtBy('SPYWARE')){ + return 0 + } + // check for viruses + for (let stack of playerStacks) { + if (stack.getTop().type === 'VIRUS') { + return 0 + } + } + // check for trojans + for (let card of playerHand.cards) { + if (card.isMimic) { + return 0 + } + } + return CLEAN_BONUS } /** - * Return the bonus given if a player has at least one complete stack. + * Return a bonus for each stack that a player has with 2 repeats (Rx has to + * have variable on it). * Is 0 if the player has no complete stacks. * @param playerStacks An array of the player's stacks */ getCompleteBonus (playerStacks) { - if (playerStacks.filter(s => s.isComplete()).length > 0) { - return COMPLETE_BONUS - } - return 0 + let complete = playerStacks.filter(s => s.isComplete()) + return complete.length * COMPLETE_BONUS } /** @@ -98,13 +115,13 @@ export default class Objectives { * Requires the stacks of the player for complete program bonus. * @param stacks An array of the player's stacks */ - getBonuses (stacks) { + getBonuses (hand, stacks) { let bonuses = {} bonuses.group = this.player.objectives.getGroupBonus() bonuses.repeat = this.player.objectives.getRepeatBonus() bonuses.variable = this.player.objectives.getVariableBonus() bonuses.safety = this.player.objectives.getSafetyBonus() - bonuses.clean = this.player.objectives.getCleanBonus() + bonuses.clean = this.player.objectives.getCleanBonus(hand, stacks) bonuses.defensive = this.player.objectives.getDefensiveBonus() bonuses.complete = this.getCompleteBonus(stacks) diff --git a/src/classes/game/Player.js b/src/classes/game/Player.js index 67d5358e..f5962a35 100755 --- a/src/classes/game/Player.js +++ b/src/classes/game/Player.js @@ -4,6 +4,7 @@ */ import Objectives from '@/classes/game/Objectives' +import CyberEffect from '@/classes/game/CyberEffect' /** * A player in the game. @@ -19,67 +20,125 @@ export default class Player { constructor (id, name, isAi) { this.id = id this.name = name - this.positiveEffects = new Set() - this.negativeEffects = new Set() - this.objectives = new Objectives(this) this.isAi = isAi + this.positiveEffects = [] + this.negativeEffects = [] + this.objectives = new Objectives(this) + this.image = 'static/playerImages/player' + id + '.png' } /** - * Checks to see if the player has a positive effect. - * @param {string} effect The effect to check for. + * Checks to see if the player has the given positive effect type specificaly. */ - helpedBy (effect) { - if (effect === "OVERCLOCK" && this.positiveEffects.has("ANTIVIRUS")) { + hasPositive (type) { + return this.positiveEffects.find(e => e.type === type) !== undefined + } + + /** + * Checks to see if the player is helped by a positive effect. + * Some effects offer similar protection and will return true from this when + * they would return false from hasPositive. + * eg) A player that has ANTIVIRUS is helped by FIREWALL as antivirus protects + * against the same effects as FIREWALL plus some. + * @param {string} type The effect type to check for. + */ + helpedBy (type) { + if ((type === "SCAN" || type === "FIREWALL") && this.helpedBy('ANTIVIRUS')) { return true } - return this.positiveEffects.has(effect) + return this.hasPositive(type) } /** - * Check to see if a player has a negative effect. - * @param {string} effect The effect to check for. + * Checks to see if the player has the given negative effect type specificaly. */ - hurtBy (effect) { - return this.negativeEffects.has(effect) + hasNegative (type) { + return this.negativeEffects.find(e => e.type === type) !== undefined } + /** + * Check to see if a player is hurt by a negative effect. + * @param {string} type The effect type to check for. + */ + hurtBy (type) { + return this.hasNegative(type) + } + + /** * Find out if a player is protected from an effect. * @param {string} effect The effect to check. * @return true if the player is protected, false otherwise. */ - isProtectedFrom (effect) { - if (effect === "HACK") { + isProtectedFrom (type) { + if (type === "TROJAN" || type === "RANSOM") { return this.helpedBy("FIREWALL") - } else if (effect === "VIRUS") { - return this.helpedBy("ANTIVIRUS") } - return false + return this.helpedBy('ANTIVIRUS') } /** * Adds a positive effect and alters negative effects if necessary. */ - addPositive (effect) { - if (effect === "ANTIVIRUS") { - this.negativeEffects.delete("VIRUS") - this.positiveEffects.delete("OVERCLOCK") - } else if (effect === "OVERCLOCK" && this.hurtBy("VIRUS")) { - this.negativeEffects.delete("VIRUS") + addPositive (type) { + if (this.helpedBy(type)) { return } - this.positiveEffects.add(effect) + + if (type === "ANTIVIRUS") { + this.cleanAll() + } else if (type === "FIREWALL") { + this.removeNegative('RANSOM') + } // if we have gotten to here with SCAN it should be added + this.positiveEffects.push(new CyberEffect(type, this.id)) } /** * Adds a negative effect and alters positive effects if necessary. */ - addNegative (effect) { - if (effect === "VIRUS" && this.helpedBy("OVERCLOCK")) { - this.positiveEffects.delete("OVERCLOCK") - return + addNegative (type, attackerId) { + if (this.hurtBy(type)) { + return } - this.negativeEffects.add(effect) + + if (this.helpedBy('SCAN')) { + this.removePositive('SCAN') + return + } + + let effect = new CyberEffect(type, this.id, attackerId) + this.negativeEffects.push(effect) + } + + /** + * Removes all positive effects of a given type. + */ + removePositive (type) { + this.positiveEffects = this.positiveEffects.filter(e => e.type !== type) + } + + /** + * Removes all negative effects of a given type. + */ + removeNegative (type) { + this.negativeEffects = this.negativeEffects.filter(e => e.type !== type) + } + + /** + * Removes a specific effect from the effect list it is in. + */ + removeEffect (effect) { + this.positiveEffects = this.positiveEffects.filter(e => e !== effect) + this.negativeEffects = this.negativeEffects.filter(e => e !== effect) + } + + /** + * Removes all negative effects and weaker positive effects. + */ + cleanAll () { + this.negativeEffects = [] + this.removePositive('FIREWALL') + this.removePositive('SCAN') } } + diff --git a/src/classes/game/Stack.js b/src/classes/game/Stack.js index 878a7227..1384b01a 100755 --- a/src/classes/game/Stack.js +++ b/src/classes/game/Stack.js @@ -3,6 +3,7 @@ * @author Josh on 2017-03-13, Steven modified on 2020-05-25 */ +// Function to create a unique object id const uuidV1 = require('uuid/v1') // The maximum number of repeats allowed in a stack @@ -41,9 +42,13 @@ export default class Stack { let score = this.getBase().value for (let i = 1; i < this.cards.length; i++) { - score *= this.cards[i].value + if (this.cards[i].type === "VIRUS") { + score *= this.getBase().type === "GROUP" ? 0.5 : 0 + } else { + score *= this.cards[i].value + } } - return score + return Math.floor(score) } /** @@ -73,14 +78,6 @@ export default class Stack { return numRepeats >= MAX_REPEATS } - /** - * Checks to see if the stack is hackable or not. - * @return {bool} true if the stack can be hacked, false otherwise. - */ - isHackable () { - return !this.isEmpty() && this.getBase().type !== 'GROUP' - } - /** * Returns true if the stack has at least one variable card. */ @@ -126,6 +123,12 @@ export default class Stack { */ willAccept (card) { let top = this.getTop() + // stacks with virus on top cannot be played on, but otherwise always accept virus + if (top.type === "VIRUS") { + return false + } else if (card.type === "VIRUS") { + return true + } // Variable cards can only go on Rx cards or replace other variables if (card.type === "VARIABLE") { if (top.type === "REPEAT" && top.value === 1) { @@ -154,6 +157,9 @@ export default class Stack { * where if a repeat card is an Rx it must be matched to a variable. */ isComplete () { + if (this.getTop().type === 'VIRUS') { + return false + } // Checks to make sure there are no unpaired Rx cards for (let idx in this.cards) { let card = this.cards[idx] diff --git a/src/classes/game/Trojan.js b/src/classes/game/Trojan.js new file mode 100644 index 00000000..f6a3cbdc --- /dev/null +++ b/src/classes/game/Trojan.js @@ -0,0 +1,41 @@ +/** + * @file Trojan.js file + * @author Steve on 2020-06-17 + */ + +import Card from '@/classes/game/Card' + +/** + * A Card that will pretend to be another card but will change the cards effect + * when played. + */ +export default class Trojan extends Card { + /** + * Constructor for the Trojan class + * @constructor Trojan + * @param {Card} card The card the trojan is hiding behind. + */ + constructor (card, player) { + super(card.type, card.value) + this.card = card + this.player = player + this.isMimic = true + } + + /** + * Returns a new card to replace the one that was being mimicked. + */ + replace () { + let card + if (this.isSafety() || this.type === "GROUP" || this.type === "INSTRUCTION") { + card = new Card("RANSOM", 0) + } else if (this.isAttack() || this.type === "VIRUS") { + card = new Card("SPYWARE", 0) + } else { + card = new Card("VIRUS", 0) + } + card.isExtra = true + return card + } +} + diff --git a/src/components/game/CardStack.vue b/src/components/game/CardStack.vue index f6793f7e..f26e5b39 100644 --- a/src/components/game/CardStack.vue +++ b/src/components/game/CardStack.vue @@ -7,7 +7,7 @@
Group cards can be used to group stacks with total points equal to the group card's value. The group card will replace all cards that are grouped in a single new stack.
-Hack cards can be dragged onto any opponent stack that is highlighted red - to remove that stack from the opponents Playfield.
-The scores from each stack are added up to help the player reach the score total. - If the player or the stack is affected by a negative effect the stack score - will change to red. This means the stacks is not contributing it's full score. - An example is the Malware card which reduces the players total score to 75% of - its actual value.
+Virus cards can be dragged onto any opponent stack that is highlighted red. + Stacks with a Virus card on top will not be able to be added to. Those + started with instructions cards will be worth 0 points and those started with + Group cards will be worth 50%. Virus cards can be removed with Antivirus and + Scan cards to restore your stacks full value
+The scores from each stack are added up to help the player reach the score total.
@@ -93,7 +92,7 @@ export default { return false } return this.playerStacks.reduce((acc, stack) => { - return acc || stack.getScore() <= this.groupCardValue + return acc || (stack.getScore() <= this.groupCardValue && stack.getTop().type !== 'VIRUS') }, false) }, groupCardValue () { @@ -110,7 +109,7 @@ export default { * So instead we add a new stack containing the card. */ onDrop (evt) { - let cardId = parseInt(evt.dataTransfer.getData('cardId')) + let cardId = evt.dataTransfer.getData('cardId') let hand = this.getCurrentPlayerHand let card = hand.cards.find(c => c.id === cardId) @@ -142,8 +141,9 @@ export default { && stack.cards[0].value === this.groupCardValue) { return false } - return this.isGrouping && (this.grouped.hasStack(stack) - || this.grouped.score + stack.getScore() <= this.groupCardValue) + return this.isGrouping && stack.getTop().type !== 'VIRUS' + && (this.grouped.hasStack(stack) + || this.grouped.score + stack.getScore() <= this.groupCardValue) }, /** * Adds or removes the stack from the grouped stacks. diff --git a/src/components/game/PlayerInfo.vue b/src/components/game/PlayerInfo.vue index 9ceb944c..5b4c26c8 100644 --- a/src/components/game/PlayerInfo.vue +++ b/src/components/game/PlayerInfo.vue @@ -4,15 +4,30 @@ {{ player.name }} + + +Threat prevention shows all the safety and remedy cards that are active on the player. You can mouse over them to be reminded of what their effect is.
Active Threats shows all the cyber attack cards that are active on the player. - These effects can be removed or prevented by different remedy and safety cards. - eg) Malware can be removed or prevented by Overclock and Anti-Virus cards.
+ These effects can be removed or prevented by safety cards. + eg) Antivirus removes all malware effects. @@ -79,7 +94,8 @@ export default { props: ['player', 'side'], data () { return { - update: true + update: true, + showHand: false } }, components: { @@ -89,7 +105,8 @@ export default { ...mapState([ 'scoreLimit', 'stacks', - 'activePlayer' + 'activePlayer', + 'hands' ]), playerImagePath () { // later change to imageId to get the specific image they want @@ -100,6 +117,20 @@ export default { }, opposite () { return this.side === 'right' ? 'left' : 'right' + }, + canSpy () { + let spies = this.player.negativeEffects.filter(e => e.type === 'SPYWARE') + return spies.find(s => s.attackerId === this.activePlayer.id) !== undefined + }, + playerCards () { + let hand = this.hands.find(h => h.playerId === this.player.id) + return hand.cards + }, + spyText () { + return this.showHand ? 'End Spy' : 'Spy' + }, + spyStyle () { + return this.showHand ? 'btn-danger' : 'btn-primary' } }, methods: { @@ -119,6 +150,9 @@ export default { let scores = this.$store.getters.getPlayerScores() let scoreInfo = scores.find(scr => scr.playerId === this.player.id) return scoreInfo.score + }, + spyHand () { + this.showHand = !this.showHand } }, created () { @@ -126,6 +160,9 @@ export default { // Scores and effect lists must be updated when a card is played this.update = !this.update }) + bus.$on('end-turn', () => { + this.showHand = false + }) } } @@ -162,15 +199,6 @@ export default { height: 24px; } -#score-text { - position: absolute; - margin: 0; - left: 40%; - top: 10%; - z-index: 40; - color: black; -} - #score-meter { position: absolute; top: 0; @@ -198,9 +226,24 @@ export default { } #info-button { - position: relative; - margin-top: 1.5%; - margin-left: 35%; + position: absolute; + top: 4%; + right: 20%; +} + +#spy-button { + position: absolute; + top: 17%; +} + +#hand-box { + position: fixed; + top: 50px; + left: 27.5%; + background-color: #DFDFDF; + border: solid black 3px; + border-radius: 5px; + z-index: 200; } .left { @@ -221,7 +264,12 @@ export default { width: 30px; height: 30px; margin: 20px 5px; - border: solid black 2px; +} + +.spy-card { + margin: 10px; + width: 100px; + height: auto; } ul { @@ -230,6 +278,10 @@ ul { padding: 0; } +li { + display: inline; +} + h5 { margin: 0; } diff --git a/src/components/game/SideObjectives.vue b/src/components/game/SideObjectives.vue index f2d75a7c..07ab5d93 100644 --- a/src/components/game/SideObjectives.vue +++ b/src/components/game/SideObjectives.vue @@ -1,5 +1,5 @@ -