-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathsolc-input-controls.json
40 lines (40 loc) · 41.1 KB
/
solc-input-controls.json
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
{
"language": "Solidity",
"sources": {
"./contracts/Controls.sol": {
"content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.7;\n\nimport \"@chainlink/contracts/src/v0.8/interfaces/VRFCoordinatorV2Interface.sol\";\nimport \"@chainlink/contracts/src/v0.8/VRFConsumerBaseV2.sol\";\nimport \"./Main.sol\";\n\ninterface IData {\n function initializeContinents() external;\n\n function getContinentOwner(uint256 continent) external view returns (uint8);\n\n function getContinentBonus(uint256 continent) external view returns (uint8);\n\n function pushToTerritories(uint8) external;\n\n function addTroopToTerritory(uint256 index) external;\n\n function updateContinents() external;\n\n function setControlsAddress(address controls) external;\n\n function getNeighbours(uint256 territory) external view returns (uint8[] memory);\n\n function getTerritoryOwner(uint256) external returns (uint8);\n\n function getTroopCount(uint256 territory) external view returns (uint256);\n\n function removeTroopFromTerritory(uint256 index) external;\n\n function changeOwner(uint256 territory, uint8 newOwner) external;\n\n function resetData() external;\n}\n\ncontract Controls is IControls, VRFConsumerBaseV2 {\n event CurrentPlayer(address indexed player);\n event ReceivedMain(address indexed main);\n event PlayerDeploying(address indexed player);\n event PlayerAttacking(address indexed player);\n event PlayerFortifying(address indexed player);\n event DiceRolled();\n event RollingDice(uint256 indexed s_requestId);\n event GameOver(address indexed winner);\n event TransferTroopsAvailable(uint256 indexed territoryBeingAttacked);\n\n // enums\n\n enum mainAddressSent {\n TRUE,\n FALSE\n }\n\n // Chainlink VRF Variables\n VRFCoordinatorV2Interface private immutable i_vrfCoordinator;\n uint64 private immutable i_subscriptionId;\n bytes32 private immutable i_gasLane;\n uint32 private immutable i_callbackGasLimit;\n uint16 private constant REQUEST_CONFIRMATIONS = 3;\n\n // variables\n uint256 s_recentAttackingArmies;\n uint256 s_recentDefendingArmies;\n uint8 s_recentTerritoryAttacking;\n uint8 s_recentTerritoryBeingAttacked;\n\n address private main_address;\n address private data_address;\n\n mainAddressSent public s_mainSet;\n uint256 public s_requestId;\n uint8 public s_troopsToDeploy;\n uint8 public s_playerTurn;\n\n address payable[] s_playersArray;\n uint256[] s_diceWords;\n\n bool s_attackSuccess;\n bool s_gameIsOver;\n\n constructor(\n address vrfCoordinatorV2,\n uint64 subscriptionId,\n bytes32 gasLane,\n uint32 callbackGasLimit,\n address data\n ) VRFConsumerBaseV2(vrfCoordinatorV2) {\n i_vrfCoordinator = VRFCoordinatorV2Interface(vrfCoordinatorV2);\n i_subscriptionId = subscriptionId;\n i_gasLane = gasLane;\n i_callbackGasLimit = callbackGasLimit;\n data_address = data;\n s_mainSet = mainAddressSent.FALSE;\n s_playerTurn = 3;\n s_troopsToDeploy = 0;\n s_attackSuccess = false;\n s_gameIsOver = false;\n }\n\n modifier onlyMain() {\n require(msg.sender == main_address);\n _;\n }\n\n modifier gameIsOver() {\n require(s_gameIsOver == true);\n _;\n }\n\n function set_main_address(address main) external {\n require(s_mainSet == mainAddressSent.FALSE);\n emit ReceivedMain(main);\n main_address = main;\n s_mainSet = mainAddressSent.TRUE;\n IData(data_address).setControlsAddress(address(this));\n }\n\n function set_players(address payable[] memory players) external onlyMain {\n s_playersArray = players;\n IData(data_address).initializeContinents();\n next_player();\n }\n\n function next_player() private {\n s_playerTurn++;\n if (s_playerTurn == s_playersArray.length) {\n s_playerTurn = 0;\n }\n IData(data_address).updateContinents();\n s_troopsToDeploy = 0;\n for (uint256 c = 0; c < 6; c++) {\n if (IData(data_address).getContinentOwner(c) == s_playerTurn) {\n s_troopsToDeploy += IData(data_address).getContinentBonus(c);\n }\n }\n\n uint8 totalTerritories = 0;\n for (uint256 i = 0; i < 42; i++) {\n if (IData(data_address).getTerritoryOwner(i) == s_playerTurn) {\n totalTerritories++;\n }\n }\n if (totalTerritories < 9) {\n s_troopsToDeploy += 3;\n } else {\n s_troopsToDeploy += totalTerritories / 3;\n }\n }\n\n function deploy_control(uint8 amountToDeploy, uint8 location) external onlyMain returns (bool) {\n require(IData(data_address).getTerritoryOwner(location) == s_playerTurn, \"You do not own this territory\");\n emit PlayerDeploying(s_playersArray[s_playerTurn]);\n for (uint256 i = 0; i < amountToDeploy; i++) {\n IData(data_address).addTroopToTerritory(location);\n }\n s_troopsToDeploy -= amountToDeploy;\n if (s_troopsToDeploy == 0) {\n return false; // returns false if all troops have not been deployed\n }\n return true;\n }\n\n function attack_control(\n uint8 territoryOwned,\n uint8 territoryAttacking,\n uint256 attackingArmies // could\n ) external onlyMain {\n require(\n validate_attackable(territoryOwned, territoryAttacking),\n \"Territory you are trying to attack is not a neighbour!\"\n );\n require(\n (attackingArmies < IData(data_address).getTroopCount(territoryOwned)) && (attackingArmies > 0),\n \"You cannot attack with that many troops!\"\n );\n emit PlayerAttacking(s_playersArray[s_playerTurn]);\n\n uint256 defendingArmies = IData(data_address).getTroopCount(territoryAttacking);\n if (defendingArmies >= 2) {\n defendingArmies = 2;\n } else {\n defendingArmies = 1;\n }\n uint8 num_words = getArmies(attackingArmies, defendingArmies); // attackingArmies, defendingArmies not returning correct numbers\n s_recentTerritoryAttacking = territoryOwned;\n s_recentTerritoryBeingAttacked = territoryAttacking;\n s_recentAttackingArmies = attackingArmies;\n s_recentDefendingArmies = defendingArmies;\n diceRoller(num_words);\n\n // 1. Player clicks on their own territory\n // 2. Player clicks on enemy territory.\n // 3. Player chooses how many troops to attack with.\n // 4. Player attacks\n }\n\n function battle(\n uint256 attackingArmies,\n uint256 defendingArmies,\n uint256 territoryAttacking,\n uint256 territoryBeingAttacked,\n uint256[] memory randomWords\n ) private {\n uint256[] memory attackerRolls = new uint256[](attackingArmies);\n uint256[] memory defenderRolls = new uint256[](defendingArmies);\n for (uint256 i = 0; i < (attackingArmies + defendingArmies); i++) {\n if (i < attackingArmies) {\n attackerRolls[i] = randomWords[i] % 6;\n } else {\n defenderRolls[i - attackingArmies] = randomWords[i] % 6;\n }\n }\n\n // Sorting the two rolls arrays\n insertionSort(attackerRolls);\n insertionSort(defenderRolls);\n\n for (uint256 i = 0; i < attackerRolls.length; i++) {}\n for (uint256 i = 0; i < defenderRolls.length; i++) {}\n\n uint256 attacks; // either 1 or 2\n if (attackingArmies > defendingArmies) {\n attacks = defendingArmies;\n } else {\n attacks = attackingArmies;\n }\n for (uint256 i = 0; i < attacks; i++) {\n if (attackerRolls[i] > defenderRolls[i]) {\n // 3 v 1 , 2 v 1 , 1 v 1, 2 v 2, 2 v 1, 1 v 1 //\n // attacker wins, defender dies\n IData(data_address).removeTroopFromTerritory(territoryBeingAttacked);\n if (\n // Attacker has killed all troops in the defending territory\n IData(data_address).getTroopCount(territoryBeingAttacked) == 0\n ) {\n // Territory now becomes Attackers\n IData(data_address).changeOwner(territoryBeingAttacked, s_playerTurn);\n IData(data_address).removeTroopFromTerritory(territoryAttacking);\n IData(data_address).addTroopToTerritory(territoryBeingAttacked);\n // Attacker can select how many troops he wants to deploy to territory\n s_attackSuccess = true;\n uint256 defeatedPlayer = IData(data_address).getTerritoryOwner(territoryBeingAttacked);\n if (getTotalTroops(defeatedPlayer) == 0) {\n // if that was the last armies of the player\n killPlayer(defeatedPlayer); // player is removed from the game\n }\n if (s_playersArray.length == 1) {\n gameOver();\n s_gameIsOver = true;\n } else {\n emit TransferTroopsAvailable(territoryBeingAttacked);\n }\n }\n } else {\n // defender wins\n IData(data_address).removeTroopFromTerritory(territoryAttacking);\n }\n }\n }\n\n // This is a function that is executed when a button is clicked.\n function troopTransferAfterAttack(uint256 amountOfTroops) public {\n require(s_attackSuccess);\n require(s_playersArray[s_playerTurn] == msg.sender);\n require(\n amountOfTroops < IData(data_address).getTroopCount(s_recentTerritoryAttacking) && (amountOfTroops > 0),\n \"You cannot move that amount of troops!\"\n );\n\n for (uint256 i = 0; i < amountOfTroops; i++) {\n IData(data_address).addTroopToTerritory(s_recentTerritoryBeingAttacked);\n IData(data_address).removeTroopFromTerritory(s_recentTerritoryAttacking);\n }\n s_attackSuccess = false;\n }\n\n function diceRoller(uint32 num_words) private {\n s_requestId = i_vrfCoordinator.requestRandomWords(\n i_gasLane,\n i_subscriptionId,\n REQUEST_CONFIRMATIONS,\n i_callbackGasLimit,\n num_words\n );\n emit RollingDice(s_requestId);\n }\n\n function fulfillRandomWords(\n uint256, /* requestId */\n uint256[] memory randomWords\n ) internal override {\n s_diceWords = randomWords;\n emit DiceRolled();\n battle(\n s_recentAttackingArmies,\n s_recentDefendingArmies,\n s_recentTerritoryAttacking,\n s_recentTerritoryBeingAttacked,\n randomWords\n );\n }\n\n function transferTroops(\n uint8 territoryMovingFrom,\n uint8 territoryMovingTo,\n uint256 troopsMoving\n ) public {\n require(\n (troopsMoving < IData(data_address).getTroopCount(territoryMovingFrom)) && (troopsMoving > 0),\n \"You cannot move that amount of troops!\"\n );\n\n for (uint256 i = 0; i < troopsMoving; i++) {\n IData(data_address).addTroopToTerritory(territoryMovingTo);\n IData(data_address).removeTroopFromTerritory(territoryMovingFrom);\n }\n }\n\n function fortify_control(\n uint8 territoryMovingFrom,\n uint8 territoryMovingTo,\n uint256 troopsMoving\n ) external onlyMain returns (bool) {\n //need to add parameters\n emit PlayerFortifying(s_playersArray[s_playerTurn]);\n require(\n validateFortifiable(territoryMovingFrom, territoryMovingTo),\n \"Territory you are trying move troops to is not one of your neighbours!\"\n );\n transferTroops(territoryMovingFrom, territoryMovingTo, troopsMoving);\n\n next_player();\n return true;\n }\n\n function validate_owner(uint8 territory_clicked) internal returns (bool) {\n uint8 territory_owner = IData(data_address).getTerritoryOwner(territory_clicked);\n if (territory_owner == s_playerTurn) {\n return true;\n } else {\n return false;\n }\n }\n\n function validateFortifiable(uint8 territoryMovingFrom, uint8 territoryMovingTo) internal returns (bool) {\n require(IData(data_address).getTroopCount(territoryMovingFrom) > 1, \"You must have more than 1 troop to move!\");\n require(\n validate_owner(territoryMovingFrom) && validate_owner(territoryMovingTo),\n \"You must own both territories to move troops!\"\n );\n uint8[] memory neighbours = IData(data_address).getNeighbours(territoryMovingFrom);\n for (uint256 i = 0; i < 6; i++) {\n if ((territoryMovingTo == neighbours[i])) {\n return true;\n }\n }\n return false;\n }\n\n function validate_attackable(uint8 territoryOwned, uint8 territoryAttacking) internal returns (bool) {\n require(\n IData(data_address).getTroopCount(territoryOwned) > 1,\n \"You must have at least 1 troop remaining in your territory to attack!\"\n );\n require(!validate_owner(territoryAttacking), \"You cannot attack your own territory!\"); //checks if the player owns the territory they are trying to attack\n uint8[] memory neighbours = IData(data_address).getNeighbours(territoryOwned);\n for (uint256 i = 0; i < 6; i++) {\n if ((territoryAttacking == neighbours[i])) {\n return true;\n }\n }\n return false;\n }\n\n function getArmies(uint256 attackingArmies, uint256 defendingArmies) private pure returns (uint8) {\n uint8 num_words = 0;\n if (attackingArmies == 3) {\n num_words = 3;\n } else if (attackingArmies == 2) {\n num_words = 2;\n } else {\n num_words = 1;\n }\n if (defendingArmies == 2) {\n num_words += 2;\n } else {\n num_words += 1;\n }\n return num_words;\n }\n\n function gameOver() public gameIsOver {\n address winner = s_playersArray[s_playerTurn];\n emit GameOver(winner);\n (bool success, ) = main_address.call(abi.encodeWithSignature(\"payWinner(address)\", winner));\n require(success, \"call to main failed\");\n IData(data_address).resetData();\n resetControls();\n }\n\n function resetControls() private {\n s_playerTurn = 3;\n s_troopsToDeploy = 0;\n s_attackSuccess = false;\n s_gameIsOver = false;\n s_playersArray = new address payable[](0);\n }\n\n function add_troop_to_territory(uint256 index) external onlyMain {\n IData(data_address).addTroopToTerritory(index);\n }\n\n function killPlayer(uint256 deadPlayer) private {\n delete s_playersArray[deadPlayer];\n }\n\n function getTotalTroops(uint256 player) public returns (uint256) {\n uint256 totalTroops = 0;\n for (uint256 i = 0; i < 42; i++) {\n if (IData(data_address).getTerritoryOwner(i) == player) {\n totalTroops += IData(data_address).getTroopCount(i);\n }\n }\n return totalTroops;\n }\n\n function get_territory_owner(uint256 j) external onlyMain returns (uint256) {\n return IData(data_address).getTerritoryOwner(j);\n }\n\n function get_troops_to_deploy() public view returns (uint8) {\n return s_troopsToDeploy;\n }\n\n function getPlayerTurn() public view returns (address) {\n return s_playersArray[s_playerTurn];\n }\n\n function getRequestId() public view returns (uint256) {\n return s_requestId;\n }\n\n function push_to_territories(uint8 playerAwarded) external onlyMain {\n IData(data_address).pushToTerritories(playerAwarded);\n }\n\n function getAttackStatus() public view returns (bool) {\n return s_attackSuccess;\n }\n\n function insertionSort(uint256[] memory arr) private pure {\n uint256 i;\n uint256 key;\n int256 j;\n for (i = 1; i < arr.length; i++) {\n key = arr[i];\n j = int256(i - 1);\n while (j >= 0 && arr[uint256(j)] < key) {\n arr[uint256(j + 1)] = arr[uint256(j)];\n j = j - 1;\n }\n arr[uint256(j + 1)] = key;\n }\n }\n}\n"
},
"./contracts/Main.sol": {
"content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.7;\nimport \"@chainlink/contracts/src/v0.8/interfaces/VRFCoordinatorV2Interface.sol\";\nimport \"@chainlink/contracts/src/v0.8/VRFConsumerBaseV2.sol\";\n\n/**@title Cryptorisk Main Contract\n * @author Michael King and Mitchell Spencer\n * @dev Implements the Chainlink VRF V2\n */\n\ninterface IControls {\n function set_players(address payable[] memory) external;\n\n function push_to_territories(uint8 playerAwarded) external;\n\n function get_territory_owner(uint256) external returns (uint256);\n\n function add_troop_to_territory(uint256) external;\n\n function set_main_address(address main) external;\n\n function deploy_control(uint8 amountToDeploy, uint8 location) external returns (bool);\n\n function attack_control(\n uint8 territoryOwned,\n uint8 territoryAttacking,\n uint256 troopQuantity\n ) external;\n\n function fortify_control(\n uint8 territoryMovingFrom,\n uint8 territoryMovingTo,\n uint256 troopsMoving\n ) external returns (bool);\n\n function get_troops_to_deploy() external view returns (uint8);\n\n function getPlayerTurn() external view returns (address);\n\n function getAttackStatus() external view returns (bool);\n}\n\ncontract Main is VRFConsumerBaseV2 {\n /* Type declarations */\n enum TerritoryState {\n INCOMPLETE,\n COMPLETE\n }\n enum LobbyState {\n OPEN,\n CLOSED\n }\n enum GameState {\n DEPLOY,\n ATTACK,\n FORTIFY,\n INACTIVE\n }\n\n enum mainAddressSent {\n TRUE,\n FALSE\n }\n\n /* Variables */\n // Chainlink VRF Variables\n VRFCoordinatorV2Interface private immutable i_vrfCoordinator;\n uint64 private immutable i_subscriptionId;\n bytes32 private immutable i_gasLane;\n uint32 private immutable i_callbackGasLimit;\n uint16 private constant REQUEST_CONFIRMATIONS = 3;\n\n // Setup Variables\n uint256 private immutable i_entranceFee;\n address private immutable controls_address;\n address private immutable data_address;\n\n uint8[4] private territoriesAssigned = [0, 0, 0, 0]; // Used to track if player receives enough territory.\n uint256[] s_randomWordsArray;\n TerritoryState public s_territoryState;\n GameState public s_gameState;\n LobbyState public s_lobbyState;\n address payable[] public s_players;\n address public player_turn;\n mainAddressSent public s_mainSet;\n mapping(address => bool) public duplicateAddresses;\n address payable[] public s_lobbyEntrants;\n\n /* Events */\n event RequestedTerritoryRandomness(uint256 indexed requestId);\n event RequestedTroopRandomness(uint256 indexed requestId);\n event ReceivedRandomWords();\n event GameSetupComplete();\n event PlayerJoinedLobby(address indexed player);\n event GameStarting();\n event WinnerSentFunds(address indexed player);\n event MainReset();\n\n /* Errors */\n error Transfer___Failed();\n\n constructor(\n address vrfCoordinatorV2,\n uint64 subscriptionId,\n bytes32 gasLane, // keyHash\n uint32 callbackGasLimit,\n uint256 entranceFee,\n address controls,\n address data\n ) VRFConsumerBaseV2(vrfCoordinatorV2) {\n i_vrfCoordinator = VRFCoordinatorV2Interface(vrfCoordinatorV2);\n i_subscriptionId = subscriptionId;\n i_gasLane = gasLane;\n i_callbackGasLimit = callbackGasLimit;\n i_entranceFee = entranceFee;\n s_lobbyState = LobbyState.OPEN;\n s_gameState = GameState.INACTIVE;\n s_mainSet = mainAddressSent.FALSE;\n controls_address = controls;\n data_address = data;\n }\n\n /* Modifiers */\n\n modifier onlyPlayer() {\n require(msg.sender == IControls(controls_address).getPlayerTurn());\n _;\n }\n\n modifier onlyControls() {\n require(msg.sender == controls_address);\n _;\n //testttt\n }\n\n /* Functions */\n\n function enterLobby() public payable {\n require(msg.value >= i_entranceFee, \"Send More to Enter Lobby\");\n require(s_lobbyState == LobbyState.OPEN, \"Lobby is full\"); // require or if statement?\n require(duplicateAddresses[msg.sender] == false, \"You've already entered the game!\");\n s_players.push(payable(msg.sender));\n s_lobbyEntrants.push(payable(msg.sender));\n emit PlayerJoinedLobby(msg.sender);\n duplicateAddresses[msg.sender] = true;\n if (s_players.length == 4) {\n s_lobbyState = LobbyState.CLOSED;\n emit GameStarting();\n requestRandomness(42);\n }\n }\n\n // call this function as soon as contract is deployed\n function setMainAddress() public {\n require(s_mainSet == mainAddressSent.FALSE, \"Controls contract has already received Main address\");\n IControls(controls_address).set_main_address(address(this));\n s_mainSet = mainAddressSent.TRUE;\n }\n\n function requestRandomness(uint32 num_words) private {\n uint256 requestId = i_vrfCoordinator.requestRandomWords(\n i_gasLane,\n i_subscriptionId,\n REQUEST_CONFIRMATIONS,\n i_callbackGasLimit,\n num_words\n );\n if (s_territoryState == TerritoryState.COMPLETE) {\n emit RequestedTroopRandomness(requestId);\n } else {\n emit RequestedTerritoryRandomness(requestId);\n }\n }\n\n function fulfillRandomWords(\n uint256, /* requestId */\n uint256[] memory randomWords\n ) internal override {\n s_randomWordsArray = randomWords;\n emit ReceivedRandomWords();\n if (s_territoryState == TerritoryState.INCOMPLETE) {\n assignTerritory(randomWords);\n } else {\n assignTroops(randomWords);\n }\n }\n\n /**\n * Function receives array of 42 random words which are then used to assign each territory (0-41) an owner (0-3).\n * Mutates a globally declared array s_territories.\n */\n function assignTerritory(uint256[] memory randomWords) private {\n uint8[4] memory playerSelection = [0, 1, 2, 3]; // Eligible players to be assigned territory, each is popped until no players left to receive.\n uint8 territoryCap = 10; // Initial cap is 10, moves up to 11 after two players assigned 10.\n uint8 remainingPlayers = 4; // Ticks down as players hit their territory cap\n uint256 indexAssignedTerritory; // Index of playerSelection that contains a list of eligible players to receive territory.\n uint8 playerAwarded; // Stores the player to be awarded territory, for pushing into the s_territories array.'\n for (uint256 i = 0; i < randomWords.length; i++) {\n indexAssignedTerritory = randomWords[i] % remainingPlayers; // Calculates which index from playerSelection will receive the territory\n playerAwarded = playerSelection[indexAssignedTerritory]; // Player to be awarded territory\n IControls(controls_address).push_to_territories(playerAwarded);\n territoriesAssigned[playerAwarded]++;\n if (territoriesAssigned[playerAwarded] == territoryCap) {\n delete playerSelection[playerAwarded]; // Removes awarded player from the array upon hitting territory cap.\n remainingPlayers--;\n if (remainingPlayers == 2) {\n territoryCap = 11; // Moves up instead of down, to remove situation where the cap goes down and we have players already on the cap then receiving too much territory.\n }\n }\n }\n s_territoryState = TerritoryState.COMPLETE;\n requestRandomness(78);\n }\n\n function assignTroops(uint256[] memory randomWords) private {\n uint256 randomWordsIndex = 0;\n // s_territories.length == 42\n // playerTerritoryIndexes.length == 10 or 11\n for (uint256 i = 0; i < 4; i++) {\n uint256[] memory playerTerritoryIndexes = new uint256[](territoriesAssigned[i]); // Initializes array of indexes for territories owned by player i\n uint256 index = 0;\n for (uint256 j = 0; j < 42; j++) {\n if (IControls(controls_address).get_territory_owner(j) == i) {\n playerTerritoryIndexes[index++] = j;\n }\n }\n\n for (uint256 j = 0; j < 30 - territoriesAssigned[i]; j++) {\n uint256 territoryAssignedTroop = randomWords[randomWordsIndex++] % territoriesAssigned[i];\n IControls(controls_address).add_troop_to_territory(playerTerritoryIndexes[territoryAssignedTroop]);\n }\n }\n emit GameSetupComplete();\n s_gameState = GameState.DEPLOY;\n IControls(controls_address).set_players(s_players);\n }\n\n function deploy(uint8 amountToDeploy, uint8 location) public onlyPlayer {\n require(s_gameState == GameState.DEPLOY, \"It is currently not deploy phase!\");\n require(\n amountToDeploy <= IControls(controls_address).get_troops_to_deploy(),\n \"You do not have that many troops to deploy!\"\n );\n bool troopsLeft = IControls(controls_address).deploy_control(amountToDeploy, location);\n if (troopsLeft == false) {\n s_gameState = GameState.ATTACK;\n }\n }\n\n function attack(\n uint8 territoryOwned,\n uint8 territoryAttacking,\n uint256 troopQuantity\n ) public onlyPlayer {\n require(IControls(controls_address).getAttackStatus() == false);\n require(s_gameState == GameState.ATTACK, \"It is currently not attack phase!\");\n IControls(controls_address).attack_control(territoryOwned, territoryAttacking, troopQuantity);\n }\n\n // player clicks this button when they have finished attacking\n function finishAttack() public onlyPlayer {\n require(IControls(controls_address).getAttackStatus() == false);\n s_gameState = GameState.FORTIFY;\n }\n\n function fortify(\n uint8 territoryMovingFrom,\n uint8 territoryMovingTo,\n uint256 troopsMoving\n ) public onlyPlayer {\n require(s_gameState == GameState.FORTIFY, \"It is currently not fortify phase!\");\n require(\n IControls(controls_address).fortify_control(territoryMovingFrom, territoryMovingTo, troopsMoving) == true,\n \"Your fortification attempt failed\"\n );\n s_gameState = GameState.DEPLOY;\n }\n\n function payWinner(address winner) public onlyControls returns (bool) {\n (bool success, ) = winner.call{value: address(this).balance}(\"\");\n if (!success) {\n revert Transfer___Failed();\n }\n emit WinnerSentFunds(winner);\n resetMain();\n return success;\n }\n\n /** Getter Functions */\n\n function getRandomWordsArray() public view returns (uint256[] memory) {\n return s_randomWordsArray;\n }\n\n function getRandomWordsArrayIndex(uint256 index) public view returns (uint256) {\n return s_randomWordsArray[index];\n }\n\n function getSubscriptionId() public view returns (uint64) {\n return i_subscriptionId;\n }\n\n function getGasLane() public view returns (bytes32) {\n return i_gasLane;\n }\n\n function getCallbackGasLimit() public view returns (uint32) {\n return i_callbackGasLimit;\n }\n\n function getTerritoryState() public view returns (TerritoryState) {\n return s_territoryState;\n }\n\n function getRequestConfirmations() public pure returns (uint256) {\n return REQUEST_CONFIRMATIONS;\n }\n\n function getPlayer(uint256 index) public view returns (address) {\n return s_players[index];\n }\n\n function getNumberOfPlayers() public view returns (uint256) {\n return s_players.length;\n }\n\n function getEntranceFee() public view returns (uint256) {\n return i_entranceFee;\n }\n\n function getLobbyState() public view returns (LobbyState) {\n return s_lobbyState;\n }\n\n // Resets everything\n function resetMain() internal {\n s_lobbyState = LobbyState.OPEN;\n s_players = new address payable[](0);\n s_gameState = GameState.INACTIVE;\n territoriesAssigned = [0, 0, 0, 0];\n for (uint256 i = 0; i < s_lobbyEntrants.length; i++) {\n duplicateAddresses[s_lobbyEntrants[i]] = false;\n }\n emit MainReset();\n }\n}\n"
},
"@chainlink/contracts/src/v0.8/interfaces/VRFCoordinatorV2Interface.sol": {
"content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ninterface VRFCoordinatorV2Interface {\n /**\n * @notice Get configuration relevant for making requests\n * @return minimumRequestConfirmations global min for request confirmations\n * @return maxGasLimit global max for request gas limit\n * @return s_provingKeyHashes list of registered key hashes\n */\n function getRequestConfig()\n external\n view\n returns (\n uint16,\n uint32,\n bytes32[] memory\n );\n\n /**\n * @notice Request a set of random words.\n * @param keyHash - Corresponds to a particular oracle job which uses\n * that key for generating the VRF proof. Different keyHash's have different gas price\n * ceilings, so you can select a specific one to bound your maximum per request cost.\n * @param subId - The ID of the VRF subscription. Must be funded\n * with the minimum subscription balance required for the selected keyHash.\n * @param minimumRequestConfirmations - How many blocks you'd like the\n * oracle to wait before responding to the request. See SECURITY CONSIDERATIONS\n * for why you may want to request more. The acceptable range is\n * [minimumRequestBlockConfirmations, 200].\n * @param callbackGasLimit - How much gas you'd like to receive in your\n * fulfillRandomWords callback. Note that gasleft() inside fulfillRandomWords\n * may be slightly less than this amount because of gas used calling the function\n * (argument decoding etc.), so you may need to request slightly more than you expect\n * to have inside fulfillRandomWords. The acceptable range is\n * [0, maxGasLimit]\n * @param numWords - The number of uint256 random values you'd like to receive\n * in your fulfillRandomWords callback. Note these numbers are expanded in a\n * secure way by the VRFCoordinator from a single random value supplied by the oracle.\n * @return requestId - A unique identifier of the request. Can be used to match\n * a request to a response in fulfillRandomWords.\n */\n function requestRandomWords(\n bytes32 keyHash,\n uint64 subId,\n uint16 minimumRequestConfirmations,\n uint32 callbackGasLimit,\n uint32 numWords\n ) external returns (uint256 requestId);\n\n /**\n * @notice Create a VRF subscription.\n * @return subId - A unique subscription id.\n * @dev You can manage the consumer set dynamically with addConsumer/removeConsumer.\n * @dev Note to fund the subscription, use transferAndCall. For example\n * @dev LINKTOKEN.transferAndCall(\n * @dev address(COORDINATOR),\n * @dev amount,\n * @dev abi.encode(subId));\n */\n function createSubscription() external returns (uint64 subId);\n\n /**\n * @notice Get a VRF subscription.\n * @param subId - ID of the subscription\n * @return balance - LINK balance of the subscription in juels.\n * @return reqCount - number of requests for this subscription, determines fee tier.\n * @return owner - owner of the subscription.\n * @return consumers - list of consumer address which are able to use this subscription.\n */\n function getSubscription(uint64 subId)\n external\n view\n returns (\n uint96 balance,\n uint64 reqCount,\n address owner,\n address[] memory consumers\n );\n\n /**\n * @notice Request subscription owner transfer.\n * @param subId - ID of the subscription\n * @param newOwner - proposed new owner of the subscription\n */\n function requestSubscriptionOwnerTransfer(uint64 subId, address newOwner) external;\n\n /**\n * @notice Request subscription owner transfer.\n * @param subId - ID of the subscription\n * @dev will revert if original owner of subId has\n * not requested that msg.sender become the new owner.\n */\n function acceptSubscriptionOwnerTransfer(uint64 subId) external;\n\n /**\n * @notice Add a consumer to a VRF subscription.\n * @param subId - ID of the subscription\n * @param consumer - New consumer which can use the subscription\n */\n function addConsumer(uint64 subId, address consumer) external;\n\n /**\n * @notice Remove a consumer from a VRF subscription.\n * @param subId - ID of the subscription\n * @param consumer - Consumer to remove from the subscription\n */\n function removeConsumer(uint64 subId, address consumer) external;\n\n /**\n * @notice Cancel a subscription\n * @param subId - ID of the subscription\n * @param to - Where to send the remaining LINK to\n */\n function cancelSubscription(uint64 subId, address to) external;\n}\n"
},
"@chainlink/contracts/src/v0.8/VRFConsumerBaseV2.sol": {
"content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.4;\n\n/** ****************************************************************************\n * @notice Interface for contracts using VRF randomness\n * *****************************************************************************\n * @dev PURPOSE\n *\n * @dev Reggie the Random Oracle (not his real job) wants to provide randomness\n * @dev to Vera the verifier in such a way that Vera can be sure he's not\n * @dev making his output up to suit himself. Reggie provides Vera a public key\n * @dev to which he knows the secret key. Each time Vera provides a seed to\n * @dev Reggie, he gives back a value which is computed completely\n * @dev deterministically from the seed and the secret key.\n *\n * @dev Reggie provides a proof by which Vera can verify that the output was\n * @dev correctly computed once Reggie tells it to her, but without that proof,\n * @dev the output is indistinguishable to her from a uniform random sample\n * @dev from the output space.\n *\n * @dev The purpose of this contract is to make it easy for unrelated contracts\n * @dev to talk to Vera the verifier about the work Reggie is doing, to provide\n * @dev simple access to a verifiable source of randomness. It ensures 2 things:\n * @dev 1. The fulfillment came from the VRFCoordinator\n * @dev 2. The consumer contract implements fulfillRandomWords.\n * *****************************************************************************\n * @dev USAGE\n *\n * @dev Calling contracts must inherit from VRFConsumerBase, and can\n * @dev initialize VRFConsumerBase's attributes in their constructor as\n * @dev shown:\n *\n * @dev contract VRFConsumer {\n * @dev constructor(<other arguments>, address _vrfCoordinator, address _link)\n * @dev VRFConsumerBase(_vrfCoordinator) public {\n * @dev <initialization with other arguments goes here>\n * @dev }\n * @dev }\n *\n * @dev The oracle will have given you an ID for the VRF keypair they have\n * @dev committed to (let's call it keyHash). Create subscription, fund it\n * @dev and your consumer contract as a consumer of it (see VRFCoordinatorInterface\n * @dev subscription management functions).\n * @dev Call requestRandomWords(keyHash, subId, minimumRequestConfirmations,\n * @dev callbackGasLimit, numWords),\n * @dev see (VRFCoordinatorInterface for a description of the arguments).\n *\n * @dev Once the VRFCoordinator has received and validated the oracle's response\n * @dev to your request, it will call your contract's fulfillRandomWords method.\n *\n * @dev The randomness argument to fulfillRandomWords is a set of random words\n * @dev generated from your requestId and the blockHash of the request.\n *\n * @dev If your contract could have concurrent requests open, you can use the\n * @dev requestId returned from requestRandomWords to track which response is associated\n * @dev with which randomness request.\n * @dev See \"SECURITY CONSIDERATIONS\" for principles to keep in mind,\n * @dev if your contract could have multiple requests in flight simultaneously.\n *\n * @dev Colliding `requestId`s are cryptographically impossible as long as seeds\n * @dev differ.\n *\n * *****************************************************************************\n * @dev SECURITY CONSIDERATIONS\n *\n * @dev A method with the ability to call your fulfillRandomness method directly\n * @dev could spoof a VRF response with any random value, so it's critical that\n * @dev it cannot be directly called by anything other than this base contract\n * @dev (specifically, by the VRFConsumerBase.rawFulfillRandomness method).\n *\n * @dev For your users to trust that your contract's random behavior is free\n * @dev from malicious interference, it's best if you can write it so that all\n * @dev behaviors implied by a VRF response are executed *during* your\n * @dev fulfillRandomness method. If your contract must store the response (or\n * @dev anything derived from it) and use it later, you must ensure that any\n * @dev user-significant behavior which depends on that stored value cannot be\n * @dev manipulated by a subsequent VRF request.\n *\n * @dev Similarly, both miners and the VRF oracle itself have some influence\n * @dev over the order in which VRF responses appear on the blockchain, so if\n * @dev your contract could have multiple VRF requests in flight simultaneously,\n * @dev you must ensure that the order in which the VRF responses arrive cannot\n * @dev be used to manipulate your contract's user-significant behavior.\n *\n * @dev Since the block hash of the block which contains the requestRandomness\n * @dev call is mixed into the input to the VRF *last*, a sufficiently powerful\n * @dev miner could, in principle, fork the blockchain to evict the block\n * @dev containing the request, forcing the request to be included in a\n * @dev different block with a different hash, and therefore a different input\n * @dev to the VRF. However, such an attack would incur a substantial economic\n * @dev cost. This cost scales with the number of blocks the VRF oracle waits\n * @dev until it calls responds to a request. It is for this reason that\n * @dev that you can signal to an oracle you'd like them to wait longer before\n * @dev responding to the request (however this is not enforced in the contract\n * @dev and so remains effective only in the case of unmodified oracle software).\n */\nabstract contract VRFConsumerBaseV2 {\n error OnlyCoordinatorCanFulfill(address have, address want);\n address private immutable vrfCoordinator;\n\n /**\n * @param _vrfCoordinator address of VRFCoordinator contract\n */\n constructor(address _vrfCoordinator) {\n vrfCoordinator = _vrfCoordinator;\n }\n\n /**\n * @notice fulfillRandomness handles the VRF response. Your contract must\n * @notice implement it. See \"SECURITY CONSIDERATIONS\" above for important\n * @notice principles to keep in mind when implementing your fulfillRandomness\n * @notice method.\n *\n * @dev VRFConsumerBaseV2 expects its subcontracts to have a method with this\n * @dev signature, and will call it once it has verified the proof\n * @dev associated with the randomness. (It is triggered via a call to\n * @dev rawFulfillRandomness, below.)\n *\n * @param requestId The Id initially returned by requestRandomness\n * @param randomWords the VRF output expanded to the requested number of words\n */\n function fulfillRandomWords(uint256 requestId, uint256[] memory randomWords) internal virtual;\n\n // rawFulfillRandomness is called by VRFCoordinator when it receives a valid VRF\n // proof. rawFulfillRandomness then calls fulfillRandomness, after validating\n // the origin of the call\n function rawFulfillRandomWords(uint256 requestId, uint256[] memory randomWords) external {\n if (msg.sender != vrfCoordinator) {\n revert OnlyCoordinatorCanFulfill(msg.sender, vrfCoordinator);\n }\n fulfillRandomWords(requestId, randomWords);\n }\n}\n"
}
},
"settings": {
"metadata": {
"useLiteralContent": true
},
"optimizer": {
"enabled": true,
"runs": 200
},
"outputSelection": {
"*": {
"*": [
"abi",
"evm.bytecode",
"evm.deployedBytecode",
"evm.methodIdentifiers"
],
"": [
"id",
"ast"
]
}
}
}
}