ETH Price: $2,601.47 (+2.18%)

Transaction Decoder

Block:
5441025 at Apr-14-2018 08:33:10 PM +UTC
Transaction Fee:
0.0001886528 ETH $0.49
Gas Used:
117,908 Gas / 1.6 Gwei

Emitted Events:

80 DungeonRunCore.LogAttack( timestamp=1523737990, player=[Sender] 0x51852d9eafd93dd7f973607cc96e32ef122b0cb6, heroId=743, monsterLevel=5, damageByHero=19, damageByMonster=0, isMonsterDefeated=True, rewards=20000000000000000 )

Account State Difference:

  Address   Before After State Difference Code
0x0E6a831c...D29bE1B71 0.252279162406921387 Eth0.232279162406921387 Eth0.02
0x51852d9E...f122B0CB6
0.08157724196577595 Eth
Nonce: 423
0.10138858916577595 Eth
Nonce: 424
0.0198113472
(MiningPoolHub: Old Address)
31,345.431377265230547516 Eth31,345.431565918030547516 Eth0.0001886528

Execution Trace

DungeonRunCore.attack( _heroId=743 )
  • EDCoreVersion1.getHeroDetails( _id=743 ) => ( creationTime=1521058332, cooldownStartTime=1523307415, cooldownIndex=7, genes=571568317159269739227999781191649967890866351706782881611075168902752077, owner=0x51852d9EAFd93dD7F973607Cc96E32ef122B0CB6, isReady=True, cooldownRemainingTime=0 )
    • HeroTokenAuction.CALL( )
    • HeroTokenAuction.heroes( 743 ) => ( creationTime=1521058332, cooldownStartTime=1523307415, cooldownIndex=7, genes=571568317159269739227999781191649967890866351706782881611075168902752077 )
    • HeroTokenAuction.ownerOf( _tokenId=743 ) => ( 0x51852d9EAFd93dD7F973607Cc96E32ef122B0CB6 )
    • HeroTokenAuction.heroes( 743 ) => ( creationTime=1521058332, cooldownStartTime=1523307415, cooldownIndex=7, genes=571568317159269739227999781191649967890866351706782881611075168902752077 )
    • 0x51852d9eafd93dd7f973607cc96e32ef122b0cb6.CALL( )
    • EDCoreVersion1.getHeroPower( _genes=571568317159269739227999781191649967890866351706782881611075168902752077, _dungeonDifficulty=3 ) => ( totalPower=297, equipmentPower=216, statsPower=81, isSuper=False, superRank=0, superBoost=0 )
    • ETH 0.02 0x51852d9eafd93dd7f973607cc96e32ef122b0cb6.CALL( )
      File 1 of 3: DungeonRunCore
      pragma solidity 0.4.19;
      
      /**
       * @title Ownable
       * @dev The Ownable contract has an owner address, and provides basic authorization control
       * functions, this simplifies the implementation of "user permissions".
       */
      contract Ownable {
      
        address public owner;
      
        event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
      
        /**
         * @dev The Ownable constructor sets the original `owner` of the contract to the sender
         * account.
         */
        function Ownable() public {
          owner = msg.sender;
        }
      
        /**
         * @dev Throws if called by any account other than the owner.
         */
        modifier onlyOwner() {
          require(msg.sender == owner);
          _;
        }
      
        /**
         * @dev Allows the current owner to transfer control of the contract to a newOwner.
         * @param newOwner The address to transfer ownership to.
         */
        function transferOwnership(address newOwner) onlyOwner public {
          require(newOwner != address(0));
          OwnershipTransferred(owner, newOwner);
          owner = newOwner;
        }
      
      }
      
      
      /**
       * @title Pausable
       * @dev Base contract which allows children to implement an emergency stop mechanism.
       */
      contract Pausable is Ownable {
      
        event Pause();
        event Unpause();
      
        bool public paused = false;
      
        /**
         * @dev Modifier to make a function callable only when the contract is not paused.
         */
        modifier whenNotPaused() {
          require(!paused);
          _;
        }
      
        /**
         * @dev Modifier to make a function callable only when the contract is paused.
         */
        modifier whenPaused() {
          require(paused);
          _;
        }
      
        /**
         * @dev called by the owner to pause, triggers stopped state
         */
        function pause() onlyOwner whenNotPaused public {
          paused = true;
          Pause();
        }
      
        /**
         * @dev called by the owner to unpause, returns to normal state
         */
        function unpause() onlyOwner whenPaused public {
          paused = false;
          Unpause();
        }
      
      }
      
      
      /**
       * @title Destructible
       * @dev Base contract that can be destroyed by owner. All funds in contract will be sent to the owner.
       */
      contract Destructible is Ownable {
      
        function Destructible() public payable { }
      
        /**
         * @dev Transfers the current balance to the owner and terminates the contract.
         */
        function destroy() onlyOwner public {
          selfdestruct(owner);
        }
      
        function destroyAndSend(address _recipient) onlyOwner public {
          selfdestruct(_recipient);
        }
      
      }
      
      
      /// @dev Interface to the Core Contract of Ether Dungeon.
      contract EDCoreInterface {
      
          /// @dev The external function to get all the game settings in one call.
          function getGameSettings() external view returns (
              uint _recruitHeroFee,
              uint _transportationFeeMultiplier,
              uint _noviceDungeonId,
              uint _consolationRewardsRequiredFaith,
              uint _challengeFeeMultiplier,
              uint _dungeonPreparationTime,
              uint _trainingFeeMultiplier,
              uint _equipmentTrainingFeeMultiplier,
              uint _preparationPeriodTrainingFeeMultiplier,
              uint _preparationPeriodEquipmentTrainingFeeMultiplier
          );
      
          /**
           * @dev The external function to get all the relevant information about a specific player by its address.
           * @param _address The address of the player.
           */
          function getPlayerDetails(address _address) external view returns (
              uint dungeonId,
              uint payment,
              uint dungeonCount,
              uint heroCount,
              uint faith,
              bool firstHeroRecruited
          );
      
          /**
           * @dev The external function to get all the relevant information about a specific dungeon by its ID.
           * @param _id The ID of the dungeon.
           */
          function getDungeonDetails(uint _id) external view returns (
              uint creationTime,
              uint status,
              uint difficulty,
              uint capacity,
              address owner,
              bool isReady,
              uint playerCount
          );
      
          /**
           * @dev Split floor related details out of getDungeonDetails, just to avoid Stack Too Deep error.
           * @param _id The ID of the dungeon.
           */
          function getDungeonFloorDetails(uint _id) external view returns (
              uint floorNumber,
              uint floorCreationTime,
              uint rewards,
              uint seedGenes,
              uint floorGenes
          );
      
          /**
           * @dev The external function to get all the relevant information about a specific hero by its ID.
           * @param _id The ID of the hero.
           */
          function getHeroDetails(uint _id) external view returns (
              uint creationTime,
              uint cooldownStartTime,
              uint cooldownIndex,
              uint genes,
              address owner,
              bool isReady,
              uint cooldownRemainingTime
          );
      
          /// @dev Get the attributes (equipments + stats) of a hero from its gene.
          function getHeroAttributes(uint _genes) public pure returns (uint[]);
      
          /// @dev Calculate the power of a hero from its gene, it calculates the equipment power, stats power, and super hero boost.
          function getHeroPower(uint _genes, uint _dungeonDifficulty) public pure returns (
              uint totalPower,
              uint equipmentPower,
              uint statsPower,
              bool isSuper,
              uint superRank,
              uint superBoost
          );
      
          /// @dev Calculate the power of a dungeon floor.
          function getDungeonPower(uint _genes) public pure returns (uint);
      
          /**
           * @dev Calculate the sum of top 5 heroes power a player owns.
           *  The gas usage increased with the number of heroes a player owned, roughly 500 x hero count.
           *  This is used in transport function only to calculate the required tranport fee.
           */
          function calculateTop5HeroesPower(address _address, uint _dungeonId) public view returns (uint);
      
      }
      
      
      /**
       * @title Core Contract of "Dungeon Run" event game of the ED (Ether Dungeon) Platform.
       * @dev Dungeon Run is a single-player game mode added to the Ether Dungeon platform.
       *  The objective of Dungeon Run is to defeat as many monsters as possible.
       */
      contract DungeonRunCore is Pausable, Destructible {
      
          /*=================================
          =             STRUCTS             =
          =================================*/
      
          struct Monster {
              uint64 creationTime;
              uint8 level;
              uint16 initialHealth;
              uint16 health;
          }
      
      
          /*=================================
          =            CONTRACTS            =
          =================================*/
      
          /// @dev The address of the EtherDungeonCore contract.
          EDCoreInterface public edCoreContract = EDCoreInterface(0xf7eD56c1AC4d038e367a987258b86FC883b960a1);
      
      
          /*=================================
          =            CONSTANTS            =
          =================================*/
      
          /// @dev By defeating the checkPointLevel, half of the entranceFee is refunded.
          uint8 public constant checkpointLevel = 5;
      
          /// @dev By defeating the breakevenLevel, another half of the entranceFee is refunded.
          uint8 public constant breakevenLevel = 10;
      
          /// @dev By defeating the jackpotLevel, the player win the entire jackpot.
          uint8 public constant jackpotLevel = 12;
      
          /// @dev Dungeon difficulty to be used when calculating super hero power boost, 3 is 64 power boost.
          uint public constant dungeonDifficulty = 3;
      
          /// @dev The health of a monster is level * monsterHealth;
          uint16 public monsterHealth = 10;
      
          /// @dev When a monster flees, the hero health is reduced by monster level + monsterStrength.
          uint public monsterStrength = 4;
      
          /// @dev After a certain period of time, the monster will attack the hero and flee.
          uint64 public monsterFleeTime = 8 minutes;
      
      
          /*=================================
          =            SETTINGS             =
          =================================*/
      
          /// @dev To start a run, a player need to pay an entrance fee.
          uint public entranceFee = 0.04 ether;
      
          /// @dev Fee required to reset a run for a given hero, the fee will go to the jackpot.
          uint public reviveFee = 0.02 ether;
      
          /// @dev 0.1 ether is provided as the initial jackpot.
          uint public jackpot = 0.1 ether;
      
          /**
           * @dev The dungeon run entrance fee will first be deposited to a pool first, when the hero is
           *  defeated by a monster, then the fee will be added to the jackpot.
           */
          uint public entranceFeePool;
      
          /// @dev Private seed for the PRNG used for calculating damage amount.
          uint _seed;
      
      
          /*=================================
          =         STATE VARIABLES         =
          =================================*/
      
          /// @dev A mapping from hero ID to the current run monster, a 0 value indicates no current run.
          mapping(uint => Monster) public heroIdToMonster;
      
          /// @dev A mapping from hero ID to its current health.
          mapping(uint => uint) public heroIdToHealth;
      
          /// @dev A mapping from hero ID to the refunded fee.
          mapping(uint => uint) public heroIdToRefundedFee;
      
      
          /*==============================
          =            EVENTS            =
          ==============================*/
      
          /// @dev The LogAttack event is fired whenever a hero attack a monster.
          event LogAttack(uint timestamp, address indexed player, uint indexed heroId, uint indexed monsterLevel, uint damageByHero, uint damageByMonster, bool isMonsterDefeated, uint rewards);
      
          function DungeonRunAlpha() public payable {}
      
          /*=======================================
          =       PUBLIC/EXTERNAL FUNCTIONS       =
          =======================================*/
      
          /// @dev The external function to get all the game settings in one call.
          function getGameSettings() external view returns (
              uint _checkpointLevel,
              uint _breakevenLevel,
              uint _jackpotLevel,
              uint _dungeonDifficulty,
              uint _monsterHealth,
              uint _monsterStrength,
              uint _monsterFleeTime,
              uint _entranceFee,
              uint _reviveFee
          ) {
              _checkpointLevel = checkpointLevel;
              _breakevenLevel = breakevenLevel;
              _jackpotLevel = jackpotLevel;
              _dungeonDifficulty = dungeonDifficulty;
              _monsterHealth = monsterHealth;
              _monsterStrength = monsterStrength;
              _monsterFleeTime = monsterFleeTime;
              _entranceFee = entranceFee;
              _reviveFee = reviveFee;
          }
      
          /// @dev The external function to get the dungeon run details in one call.
          function getRunDetails(uint _heroId) external view returns (
              uint _heroPower,
              uint _heroStrength,
              uint _heroInitialHealth,
              uint _heroHealth,
              uint _monsterCreationTime,
              uint _monsterLevel,
              uint _monsterInitialHealth,
              uint _monsterHealth,
              uint _gameState // 0: NotStarted | 1: NewMonster | 2: Active | 3: RunEnded
          ) {
              uint genes;
              address owner;
              (,,, genes, owner,,) = edCoreContract.getHeroDetails(_heroId);
              (_heroPower,,,,) = edCoreContract.getHeroPower(genes, dungeonDifficulty);
              _heroStrength = (genes / (32 ** 8)) % 32 + 1;
              _heroInitialHealth = (genes / (32 ** 12)) % 32 + 1;
              _heroHealth = heroIdToHealth[_heroId];
      
              Monster memory monster = heroIdToMonster[_heroId];
              _monsterCreationTime = monster.creationTime;
      
              // Dungeon run is ended if either hero is defeated (health exhausted),
              // or hero failed to damage a monster before it flee.
              bool _dungeonRunEnded = monster.level > 0 && (
                  _heroHealth == 0 || 
                  now > _monsterCreationTime + monsterFleeTime * 2 ||
                  (monster.health == monster.initialHealth && now > monster.creationTime + monsterFleeTime)
              );
      
              // Calculate hero and monster stats based on different game state.
              if (monster.level == 0) {
                  // Dungeon run not started yet.
                  _heroHealth = _heroInitialHealth;
                  _monsterLevel = 1;
                  _monsterInitialHealth = monsterHealth;
                  _monsterHealth = _monsterInitialHealth;
                  _gameState = 0;
              } else if (_dungeonRunEnded) {
                  // Dungeon run ended.
                  _monsterLevel = monster.level;
                  _monsterInitialHealth = monster.initialHealth;
                  _monsterHealth = monster.health;
                  _gameState = 3;
              } else if (now > _monsterCreationTime + monsterFleeTime) {
                  // Previous monster just fled, new monster awaiting.
                  if (monster.level + monsterStrength > _heroHealth) {
                      _heroHealth = 0;
                      _monsterLevel = monster.level;
                      _monsterInitialHealth = monster.initialHealth;
                      _monsterHealth = monster.health;
                      _gameState = 2;
                  } else {
                      _heroHealth -= monster.level + monsterStrength;
                      _monsterCreationTime += monsterFleeTime;
                      _monsterLevel = monster.level + 1;
                      _monsterInitialHealth = _monsterLevel * monsterHealth;
                      _monsterHealth = _monsterInitialHealth;
                      _gameState = 1;
                  }
              } else {
                  // Active monster.
                  _monsterLevel = monster.level;
                  _monsterInitialHealth = monster.initialHealth;
                  _monsterHealth = monster.health;
                  _gameState = 2;
              }
          }
      
          /**
           * @dev To start a dungeon run, player need to call the attack function with an entranceFee.
           *  Future attcks required no fee, player just need to send a free transaction
           *  to the contract, before the monster flee. The lower the gas price, the larger the damage.
           *  This function is prevented from being called by a contract, using the onlyHumanAddress modifier.
           *  Note that each hero can only perform one dungeon run.
           */
          function attack(uint _heroId) whenNotPaused onlyHumanAddress external payable {
              uint genes;
              address owner;
              (,,, genes, owner,,) = edCoreContract.getHeroDetails(_heroId);
      
              // Throws if the hero is not owned by the player.
              require(msg.sender == owner);
      
              // Get the health and strength of the hero.
              uint heroInitialHealth = (genes / (32 ** 12)) % 32 + 1;
              uint heroStrength = (genes / (32 ** 8)) % 32 + 1;
      
              // Get the current monster and hero current health.
              Monster memory monster = heroIdToMonster[_heroId];
              uint currentLevel = monster.level;
              uint heroCurrentHealth = heroIdToHealth[_heroId];
      
              // A flag determine whether the dungeon run has ended.
              bool dungeonRunEnded;
      
              // To start a run, the player need to pay an entrance fee.
              if (currentLevel == 0) {
                  // Throws if not enough fee, and any exceeding fee will be transferred back to the player.
                  require(msg.value >= entranceFee);
                  entranceFeePool += entranceFee;
      
                  // Create level 1 monster, initial health is 1 * monsterHealth.
                  heroIdToMonster[_heroId] = Monster(uint64(now), 1, monsterHealth, monsterHealth);
                  monster = heroIdToMonster[_heroId];
      
                  // Set the hero initial health to storage.
                  heroIdToHealth[_heroId] = heroInitialHealth;
                  heroCurrentHealth = heroInitialHealth;
      
                  // Refund exceeding fee.
                  if (msg.value > entranceFee) {
                      msg.sender.transfer(msg.value - entranceFee);
                  }
              } else {
                  // If the hero health is 0, the dungeon run has ended.
                  require(heroCurrentHealth > 0);
          
                  // If a hero failed to damage a monster before it flee, the dungeon run ends,
                  // regardless of the remaining hero health.
                  dungeonRunEnded = now > monster.creationTime + monsterFleeTime * 2 ||
                      (monster.health == monster.initialHealth && now > monster.creationTime + monsterFleeTime);
      
                  if (dungeonRunEnded) {
                      // Add the non-refunded fee to jackpot.
                      uint addToJackpot = entranceFee - heroIdToRefundedFee[_heroId];
                  
                      if (addToJackpot > 0) {
                          jackpot += addToJackpot;
                          entranceFeePool -= addToJackpot;
                          heroIdToRefundedFee[_heroId] += addToJackpot;
                      }
      
                      // Sanity check.
                      assert(addToJackpot <= entranceFee);
                  }
                  
                  // Future attack do not require any fee, so refund all ether sent with the transaction.
                  msg.sender.transfer(msg.value);
              }
      
              if (!dungeonRunEnded) {
                  // All pre-conditions passed, call the internal attack function.
                  _attack(_heroId, genes, heroStrength, heroCurrentHealth);
              }
          }
          
          /**
           * @dev Reset a dungeon run for a given hero.
           */
          function revive(uint _heroId) whenNotPaused external payable {
              // Throws if not enough fee, and any exceeding fee will be transferred back to the player.
              require(msg.value >= reviveFee);
              
              // The revive fee will do directly to jackpot.
              jackpot += reviveFee;
              
              // Reset the dungeon run.
              delete heroIdToHealth[_heroId];
              delete heroIdToMonster[_heroId];
              delete heroIdToRefundedFee[_heroId];
          
              // Refund exceeding fee.
              if (msg.value > reviveFee) {
                  msg.sender.transfer(msg.value - reviveFee);
              }
          }
      
      
          /*=======================================
          =           SETTER FUNCTIONS            =
          =======================================*/
      
          function setEdCoreContract(address _newEdCoreContract) onlyOwner external {
              edCoreContract = EDCoreInterface(_newEdCoreContract);
          }
      
          function setEntranceFee(uint _newEntranceFee) onlyOwner external {
              entranceFee = _newEntranceFee;
          }
      
          function setReviveFee(uint _newReviveFee) onlyOwner external {
              reviveFee = _newReviveFee;
          }
      
      
          /*=======================================
          =      INTERNAL/PRIVATE FUNCTIONS       =
          =======================================*/
      
          /// @dev Internal function of attack, assume all parameter checking is done.
          function _attack(uint _heroId, uint _genes, uint _heroStrength, uint _heroCurrentHealth) internal {
              Monster storage monster = heroIdToMonster[_heroId];
              uint8 currentLevel = monster.level;
      
              // Get the hero power.
              uint heroPower;
              (heroPower,,,,) = edCoreContract.getHeroPower(_genes, dungeonDifficulty);
              
              uint damageByMonster;
              uint damageByHero;
      
              // Calculate the damage by hero first.
              // The damage formula is (strength + power / (10 * rand)) / gasprice,
              // where rand is a random integer from 1 to 5.
              damageByHero = (_heroStrength * 1e9 + heroPower * 1e9 / (10 * (1 + _getRandomNumber(5)))) / (tx.gasprice >= 0.5 * 1e9 ? tx.gasprice : 0.5 * 1e9);
              bool isMonsterDefeated = damageByHero >= monster.health;
      
              if (isMonsterDefeated) {
                  uint rewards;
      
                  // Monster is defeated, game continues with a new monster.
                  // Create next level monster.
                  uint8 newLevel = currentLevel + 1;
                  heroIdToMonster[_heroId] = Monster(uint64(now), newLevel, newLevel * monsterHealth, newLevel * monsterHealth);
                  monster = heroIdToMonster[_heroId];
      
                  // Determine the rewards based on current level.
                  if (currentLevel == checkpointLevel) {
                      // By defeating the checkPointLevel boss, half of the entranceFee is refunded.
                      rewards = entranceFee / 2;
                      heroIdToRefundedFee[_heroId] += rewards;
                      entranceFeePool -= rewards;
                  } else if (currentLevel == breakevenLevel) {
                      // By defeating the breakevenLevel boss, another half of the entranceFee is refunded.
                      rewards = entranceFee / 2;
                      heroIdToRefundedFee[_heroId] += rewards;
                      entranceFeePool -= rewards;
                  } else if (currentLevel == jackpotLevel) {
                      // By defeating the jackpotLevel, the player win the entire jackpot.
                      rewards = jackpot / 2;
                      jackpot -= rewards;
                  }
      
                  msg.sender.transfer(rewards);
              } else {
                  // Monster is damanged but not defeated, hurry up!
                  monster.health -= uint8(damageByHero);
      
                  // Calculate the damage by monster only if it is not defeated.
                  // Determine if the monster has fled due to hero failed to attack within flee period.
                  if (now > monster.creationTime + monsterFleeTime) {
                      // When a monster flees, the monster will attack the hero and flee.
                      // The damage is calculated by monster level + monsterStrength.
                      damageByMonster = currentLevel + monsterStrength;
                  } else {
                      // When a monster attack back the hero, the damage will be less than monster level / 2.
                      if (currentLevel >= 2) {
                          damageByMonster = _getRandomNumber(currentLevel / 2);
                      }
                  }
              }
      
              // Check if hero is defeated.
              if (damageByMonster >= _heroCurrentHealth) {
                  // Hero is defeated, the dungeon run ends.
                  heroIdToHealth[_heroId] = 0;
      
                  // Add the non-refunded fee to jackpot.
                  uint addToJackpot = entranceFee - heroIdToRefundedFee[_heroId];
                  
                  if (addToJackpot > 0) {
                      jackpot += addToJackpot;
                      entranceFeePool -= addToJackpot;
                      heroIdToRefundedFee[_heroId] += addToJackpot;
                  }
      
                  // Sanity check.
                  assert(addToJackpot <= entranceFee);
              } else {
                  // Hero is damanged but didn't defeated, game continues with a new monster.
                  if (damageByMonster > 0) {
                      heroIdToHealth[_heroId] -= damageByMonster;
                  }
      
                  // If monser fled, create next level monster.
                  if (now > monster.creationTime + monsterFleeTime) {
                      currentLevel++;
                      heroIdToMonster[_heroId] = Monster(uint64(monster.creationTime + monsterFleeTime),
                          currentLevel, currentLevel * monsterHealth, currentLevel * monsterHealth);
                      monster = heroIdToMonster[_heroId];
                  }
              }
      
              // Emit LogAttack event.
              LogAttack(now, msg.sender, _heroId, currentLevel, damageByHero, damageByMonster, isMonsterDefeated, rewards);
          }
      
          /// @dev Return a pseudo random uint smaller than _upper bounds.
          function _getRandomNumber(uint _upper) private returns (uint) {
              _seed = uint(keccak256(
                  _seed,
                  block.blockhash(block.number - 1),
                  block.coinbase,
                  block.difficulty
              ));
      
              return _seed % _upper;
          }
      
      
          /*==============================
          =           MODIFIERS          =
          ==============================*/
          
          /// @dev Throws if the caller address is a contract.
          modifier onlyHumanAddress() {
              address addr = msg.sender;
              uint size;
              assembly { size := extcodesize(addr) }
              require(size == 0);
              _;
          }
      
      }

      File 2 of 3: EDCoreVersion1
      pragma solidity ^0.4.19;
      
      /**
       * @title Ownable
       * @dev The Ownable contract has an owner address, and provides basic authorization control
       * functions, this simplifies the implementation of "user permissions".
       */
      contract Ownable {
          
        address public owner;
      
        event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
      
        /**
         * @dev The Ownable constructor sets the original `owner` of the contract to the sender
         * account.
         */
        function Ownable() public {
          owner = msg.sender;
        }
      
        /**
         * @dev Throws if called by any account other than the owner.
         */
        modifier onlyOwner() {
          require(msg.sender == owner);
          _;
        }
      
        /**
         * @dev Allows the current owner to transfer control of the contract to a newOwner.
         * @param newOwner The address to transfer ownership to.
         */
        function transferOwnership(address newOwner) onlyOwner public {
          require(newOwner != address(0));
          OwnershipTransferred(owner, newOwner);
          owner = newOwner;
        }
      
      }
      
      
      /**
       * @title EjectableOwnable
       * @dev The EjectableOwnable contract provides the function to remove the ownership of the contract.
       */
      contract EjectableOwnable is Ownable {
          
          /**
           * @dev Remove the ownership by setting the owner address to null, 
           * after calling this function, all onlyOwner function will be be able to be called by anyone anymore, 
           * the contract will achieve truly decentralisation.
          */
          function removeOwnership() onlyOwner public {
              owner = 0x0;
          }
          
      }
      
      
      /**
       * @title Pausable
       * @dev Base contract which allows children to implement an emergency stop mechanism.
       */
      contract Pausable is Ownable {
          
        event Pause();
        event Unpause();
      
        bool public paused = false;
      
        /**
         * @dev Modifier to make a function callable only when the contract is not paused.
         */
        modifier whenNotPaused() {
          require(!paused);
          _;
        }
      
        /**
         * @dev Modifier to make a function callable only when the contract is paused.
         */
        modifier whenPaused() {
          require(paused);
          _;
        }
      
        /**
         * @dev called by the owner to pause, triggers stopped state
         */
        function pause() onlyOwner whenNotPaused public {
          paused = true;
          Pause();
        }
      
        /**
         * @dev called by the owner to unpause, returns to normal state
         */
        function unpause() onlyOwner whenPaused public {
          paused = false;
          Unpause();
        }
        
      }
      
      
      /**
       * @title SafeMath
       * @dev Math operations with safety checks that throw on error
       */
      library SafeMath {
      
        /**
        * @dev Multiplies two numbers, throws on overflow.
        */
        function mul(uint256 a, uint256 b) internal pure returns (uint256) {
          if (a == 0) {
            return 0;
          }
          uint256 c = a * b;
          assert(c / a == b);
          return c;
        }
      
        /**
        * @dev Integer division of two numbers, truncating the quotient.
        */
        function div(uint256 a, uint256 b) internal pure returns (uint256) {
          // assert(b > 0); // Solidity automatically throws when dividing by 0
          uint256 c = a / b;
          // assert(a == b * c + a % b); // There is no case in which this doesn't hold
          return c;
        }
      
        /**
        * @dev Substracts two numbers, throws on overflow (i.e. if subtrahend is greater than minuend).
        */
        function sub(uint256 a, uint256 b) internal pure returns (uint256) {
          assert(b <= a);
          return a - b;
        }
      
        /**
        * @dev Adds two numbers, throws on overflow.
        */
        function add(uint256 a, uint256 b) internal pure returns (uint256) {
          uint256 c = a + b;
          assert(c >= a);
          return c;
        }
        
      }
      
      
      /**
       * @title PullPayment
       * @dev Base contract supporting async send for pull payments. Inherit from this
       * contract and use asyncSend instead of send.
       */
      contract PullPayment {
          
        using SafeMath for uint256;
      
        mapping(address => uint256) public payments;
        uint256 public totalPayments;
      
        /**
         * @dev withdraw accumulated balance, called by payee.
         */
        function withdrawPayments() public {
          address payee = msg.sender;
          uint256 payment = payments[payee];
      
          require(payment != 0);
          require(this.balance >= payment);
      
          totalPayments = totalPayments.sub(payment);
          payments[payee] = 0;
      
          assert(payee.send(payment));
        }
      
        /**
         * @dev Called by the payer to store the sent amount as credit to be pulled.
         * @param dest The destination address of the funds.
         * @param amount The amount to transfer.
         */
        function asyncSend(address dest, uint256 amount) internal {
          payments[dest] = payments[dest].add(amount);
          totalPayments = totalPayments.add(amount);
        }
        
      }
      
      
      /**
       * @title Destructible
       * @dev Base contract that can be destroyed by owner. All funds in contract will be sent to the owner.
       */
      contract Destructible is Ownable {
      
        function Destructible() public payable { }
      
        /**
         * @dev Transfers the current balance to the owner and terminates the contract.
         */
        function destroy() onlyOwner public {
          selfdestruct(owner);
        }
      
        function destroyAndSend(address _recipient) onlyOwner public {
          selfdestruct(_recipient);
        }
        
      }
      
      
      contract EDStructs {
          
          /**
           * @dev The main Dungeon struct. Every dungeon in the game is represented by this structure.
           * A dungeon is consists of an unlimited number of floors for your heroes to challenge, 
           * the power level of a dungeon is encoded in the floorGenes. Some dungeons are in fact more "challenging" than others,
           * the secret formula for that is left for user to find out.
           * 
           * Each dungeon also has a "training area", heroes can perform trainings and upgrade their stat,
           * and some dungeons are more effective in the training, which is also a secret formula!
           * 
           * When player challenge or do training in a dungeon, the fee will be collected as the dungeon rewards,
           * which will be rewarded to the player who successfully challenged the current floor.
           * 
           * Each dungeon fits in fits into three 256-bit words.
           */
          struct Dungeon {
              
              // Each dungeon has an ID which is the index in the storage array.
      
              // The timestamp of the block when this dungeon is created.
              uint32 creationTime;
              
              // The status of the dungeon, each dungeon can have 5 status, namely:
              // 0: Active | 1: Transport Only | 2: Challenge Only | 3: Train Only | 4: InActive
              uint8 status;
              
              // The dungeon's difficulty, the higher the difficulty, 
              // normally, the "rarer" the seedGenes, the higher the diffculty,
              // and the higher the contribution fee it is to challenge, train, and transport to the dungeon,
              // the formula for the contribution fee is in DungeonChallenge and DungeonTraining contracts.
              // A dungeon's difficulty never change.
              uint8 difficulty;
              
              // The dungeon's capacity, maximum number of players allowed to stay on this dungeon.
              // The capacity of the newbie dungeon (Holyland) is set at 0 (which is infinity).
              // Using 16-bit unsigned integers can have a maximum of 65535 in capacity.
              // A dungeon's capacity never change.
              uint16 capacity;
              
              // The current floor number, a dungeon is consists of an umlimited number of floors,
              // when there is heroes successfully challenged a floor, the next floor will be
              // automatically generated. Using 32-bit unsigned integer can have a maximum of 4 billion floors.
              uint32 floorNumber;
              
              // The timestamp of the block when the current floor is generated.
              uint32 floorCreationTime;
              
              // Current accumulated rewards, successful challenger will get a large proportion of it.
              uint128 rewards;
              
              // The seed genes of the dungeon, it is used as the base gene for first floor, 
              // some dungeons are rarer and some are more common, the exact details are, 
              // of course, top secret of the game! 
              // A dungeon's seedGenes never change.
              uint seedGenes;
              
              // The genes for current floor, it encodes the difficulty level of the current floor.
              // We considered whether to store the entire array of genes for all floors, but
              // in order to save some precious gas we're willing to sacrifice some functionalities with that.
              uint floorGenes;
              
          }
          
          /**
           * @dev The main Hero struct. Every hero in the game is represented by this structure.
           */
          struct Hero {
      
              // Each hero has an ID which is the index in the storage array.
              
              // The timestamp of the block when this dungeon is created.
              uint64 creationTime;
              
              // The timestamp of the block where a challenge is performed, used to calculate when a hero is allowed to engage in another challenge.
              uint64 cooldownStartTime;
              
              // Every time a hero challenge a dungeon, its cooldown index will be incremented by one.
              uint32 cooldownIndex;
              
              // The seed of the hero, the gene encodes the power level of the hero.
              // This is another top secret of the game! Hero's gene can be upgraded via
              // training in a dungeon.
              uint genes;
              
          }
          
      }
      
      
      /**
       * @title Interface for contracts conforming to ERC-721: Non-Fungible Tokens.
       */
      contract ERC721 {
          
          // Events
          event Transfer(address indexed from, address indexed to, uint indexed tokenId);
          event Approval(address indexed owner, address indexed approved, uint indexed tokenId);
          
          // ERC20 compatible functions.
          // function name() public constant returns (string);
          // function symbol() public constant returns (string);
          function totalSupply() public view returns (uint);
          function balanceOf(address _owner) public view returns (uint);
          
          // Functions that define ownership.
          function ownerOf(uint _tokenId) external view returns (address);
          function transfer(address _to, uint _tokenId) external;
          
          // Approval related functions, mainly used in auction contracts.
          function approve(address _to, uint _tokenId) external;
          function approvedFor(uint _tokenId) external view returns (address);
          function transferFrom(address _from, address _to, uint _tokenId) external;
          
          /**
           * @dev Each non-fungible token owner can own more than one token at one time. 
           * Because each token is referenced by its unique ID, however, 
           * it can get difficult to keep track of the individual tokens that a user may own. 
           * To do this, the contract keeps a record of the IDs of each token that each user owns.
           */
          mapping(address => uint[]) public ownerTokens;
      
      }
      
      
      contract DungeonTokenInterface is ERC721, EDStructs {
      
          /**
           * @notice Limits the number of dungeons the contract owner can ever create.
           */
          uint public constant DUNGEON_CREATION_LIMIT = 1024;
          
          /**
           * @dev Name of token.
           */
          string public constant name = "Dungeon";
          
          /**
           * @dev Symbol of token.
           */
          string public constant symbol = "DUNG";
          
          /**
           * @dev An array containing the Dungeon struct, which contains all the dungeons in existance.
           *  The ID for each dungeon is the index of this array.
           */ 
          Dungeon[] public dungeons;
      
          /**
           * @dev The external function that creates a new dungeon and stores it, only contract owners
           *  can create new token, and will be restricted by the DUNGEON_CREATION_LIMIT.
           *  Will generate a Mint event, a  NewDungeonFloor event, and a Transfer event.
           */ 
          function createDungeon(uint _difficulty, uint _capacity, uint _floorNumber, uint _seedGenes, uint _floorGenes, address _owner) external returns (uint);
          
          /**
           * @dev The external function to set dungeon status by its ID, 
           *  refer to DungeonStructs for more information about dungeon status.
           *  Only contract owners can alter dungeon state.
           */ 
          function setDungeonStatus(uint _id, uint _newStatus) external;
          
          /**
           * @dev The external function to add additional dungeon rewards by its ID, 
           *  only contract owners can alter dungeon state.
           */ 
          function addDungeonRewards(uint _id, uint _additinalRewards) external;
          
          /**
           * @dev The external function to add another dungeon floor by its ID, 
           *  only contract owners can alter dungeon state.
           */ 
          function addDungeonNewFloor(uint _id, uint _newRewards, uint _newFloorGenes) external;
          
      }
      
      
      contract HeroTokenInterface is ERC721, EDStructs {
          
          /**
           * @dev Name of token.
           */
          string public constant name = "Hero";
          
          /**
           * @dev Symbol of token.
           */
          string public constant symbol = "HERO";
      
          /**
           * @dev An array containing the Hero struct, which contains all the heroes in existance.
           *  The ID for each hero is the index of this array.
           */ 
          Hero[] public heroes;
      
          /**
           * @dev An external function that creates a new hero and stores it,
           *  only contract owners can create new token.
           *  method doesn't do any checking and should only be called when the
           *  input data is known to be valid.
           * @param _genes The gene of the new hero.
           * @param _owner The inital owner of this hero.
           * @return The hero ID of the new hero.
           */
          function createHero(uint _genes, address _owner) external returns (uint);
          
          /**
           * @dev The external function to set the hero genes by its ID, 
           *  only contract owners can alter hero state.
           */ 
          function setHeroGenes(uint _id, uint _newGenes) external;
      
          /**
           * @dev Set the cooldownStartTime for the given hero. Also increments the cooldownIndex.
           */
          function triggerCooldown(uint _id) external;
          
      }
      
      
      /**
       * SECRET
       */
      contract ChallengeFormulaInterface {
          
          /**
           * @dev given genes of current floor and dungeon seed, return a genetic combination - may have a random factor.
           * @param _floorGenes Genes of floor.
           * @param _seedGenes Seed genes of dungeon.
           * @return The resulting genes.
           */
          function calculateResult(uint _floorGenes, uint _seedGenes) external returns (uint);
          
      }
      
      
      /**
       * SECRET
       */
      contract TrainingFormulaInterface {
          
          /**
           * @dev given genes of hero and current floor, return a genetic combination - may have a random factor.
           * @param _heroGenes Genes of hero.
           * @param _floorGenes Genes of current floor.
           * @param _equipmentId Equipment index to train for, 0 is train all attributes.
           * @return The resulting genes.
           */
          function calculateResult(uint _heroGenes, uint _floorGenes, uint _equipmentId) external returns (uint);
          
      }
      
      
      /**
       * @title EDBase
       * @dev Base contract for Ether Dungeon. It implements all necessary sub-classes,
       *  holds all the contracts, constants, game settings, storage variables, events, and some commonly used functions.
       */
      contract EDBase is EjectableOwnable, Pausable, PullPayment, EDStructs {
          
          /* ======== CONTRACTS ======== */
          
          /// @dev The address of the ERC721 token contract managing all Dungeon tokens.
          DungeonTokenInterface public dungeonTokenContract;
          
          /// @dev The address of the ERC721 token contract managing all Hero tokens.
          HeroTokenInterface public heroTokenContract;
          
          /// @dev The address of the ChallengeFormula contract that handles the floor generation mechanics after challenge success.
          ChallengeFormulaInterface challengeFormulaContract;
          
          /// @dev The address of the TrainingFormula contract that handles the hero training mechanics.
          TrainingFormulaInterface trainingFormulaContract;
          
          
          /* ======== CONSTANTS / GAME SETTINGS (all variables are set to constant in order to save gas) ======== */
          
          // 1 finney = 0.001 ether
          // 1 szabo = 0.001 finney
          
          /// @dev Super Hero (full set of same-themed Rare Equipments, there are 8 in total)
          uint public constant SUPER_HERO_MULTIPLIER = 32;
          
          /// @dev Ultra Hero (full set of same-themed Epic Equipments, there are 4 in total)
          uint public constant ULTRA_HERO_MULTIPLIER = 64;
          
          /**
           * @dev Mega Hero (full set of same-themed Legendary Equipments, there are 2 in total)
           *  There are also 2 Ultimate Hero/Demon, Pangu and Chaos, which will use the MEGA_HERO_MULTIPLIER.
           */
          uint public constant MEGA_HERO_MULTIPLIER = 96;
          
          /// @dev The fee for recruiting a hero. The payment is accumulated to the rewards of the origin dungeon.
          uint public recruitHeroFee = 2 finney;
          
          /**
           * @dev The actual fee contribution required to call transport() is calculated by this feeMultiplier,
           *  times the dungeon difficulty of destination dungeon. The payment is accumulated to the rewards of the origin dungeon,
           *  and a large proportion will be claimed by whoever successfully challenged the floor.
           */
          uint public transportationFeeMultiplier = 250 szabo;
          
          ///@dev All hero starts in the novice dungeon, also hero can only be recruited in novice dungoen.
          uint public noviceDungeonId = 31; // < dungeon ID 31 = Abyss
          
          /// @dev Amount of faith required to claim a portion of the grandConsolationRewards.
          uint public consolationRewardsRequiredFaith = 100;
          
          /// @dev The percentage for which when a player can get from the grandConsolationRewards when meeting the faith requirement.
          uint public consolationRewardsClaimPercent = 50;
          
          /**
           * @dev The actual fee contribution required to call challenge() is calculated by this feeMultiplier,
           *  times the dungeon difficulty. The payment is accumulated to the dungeon rewards, 
           *  and a large proportion will be claimed by whoever successfully challenged the floor.
           */
          uint public constant challengeFeeMultiplier = 1 finney;
          
          /**
           * @dev The percentage for which successful challenger be rewarded of the dungeons' accumulated rewards.
           *  The remaining rewards subtract dungeon master rewards and consolation rewards will be used as the base rewards for new floor.
           */
          uint public constant challengeRewardsPercent = 45;
          
          /**
           * @dev The developer fee for dungeon master (owner of the dungeon token).
           *  Note that when Ether Dungeon becomes truly decentralised, contract ownership will be ejected,
           *  and the master rewards will be rewarded to the dungeon owner (Dungeon Masters).
           */
          uint public constant masterRewardsPercent = 8;
          
          /// @dev The percentage for which the challenge rewards is added to the grandConsolationRewards.
          uint public consolationRewardsPercent = 2;
          
          /// @dev The preparation time period where a new dungeon is created, before it can be challenged.
          uint public dungeonPreparationTime = 60 minutes;
          
          /// @dev The challenge rewards percentage used right after the preparation period.
          uint public constant rushTimeChallengeRewardsPercent = 22;
          
          /// @dev The number of floor in which the rushTimeChallengeRewardsPercent be applied.
          uint public constant rushTimeFloorCount = 30;
          
          /**
           * @dev The actual fee contribution required to call trainX() is calculated by this feeMultiplier,
           *  times the dungeon difficulty, times training times. The payment is accumulated to the dungeon rewards, 
           *  and a large proportion will be claimed by whoever successfully challenged the floor.
           */
          uint public trainingFeeMultiplier = 2 finney;
          
          /**
           * @dev The actual fee contribution required to call trainEquipment() is calculated by this feeMultiplier,
           *  times the dungeon difficulty. The payment is accumulated to the dungeon rewards.
           *  (No preparation period discount on equipment training.)
           */
          uint public equipmentTrainingFeeMultiplier = 8 finney;
          
          /// @dev The discounted training fee multiplier to be used during preparation period.
          uint public constant preparationPeriodTrainingFeeMultiplier = 1600 szabo;
          
          /// @dev The discounted equipment training fee multiplier to be used during preparation period.
          uint public constant preparationPeriodEquipmentTrainingFeeMultiplier = 6400 szabo;
          
          
          /* ======== STATE VARIABLES ======== */
          
          /**
           * @dev After each successful training, do not update Hero immediately to avoid exploit.
           *  The hero power will be auto updated during next challenge/training for any player.
           *  Or calling the setTempHeroPower() public function directly.
           */
          mapping(address => uint) playerToLastActionBlockNumber;
          uint tempSuccessTrainingHeroId;
          uint tempSuccessTrainingNewHeroGenes = 1; // value 1 is used as no pending update
          
          /// @dev The total accumulated consolidation jackpot / rewards amount.
          uint public grandConsolationRewards = 168203010964693559; // < migrated from previous contract
          
          /// @dev A mapping from token IDs to the address that owns them, the value can get by getPlayerDetails.
          mapping(address => uint) playerToDungeonID;
          
          /// @dev A mapping from player address to the player's faith value, the value can get by getPlayerDetails.
          mapping(address => uint) playerToFaith;
      
          /**
           * @dev A mapping from owner address to a boolean flag of whether the player recruited the first hero.
           *  Note that transferring a hero from other address do not count, the value can get by getPlayerDetails.
           */
          mapping(address => bool) playerToFirstHeroRecruited;
      
          /// @dev A mapping from owner address to count of tokens that address owns, the value can get by getDungeonDetails.
          mapping(uint => uint) dungeonIdToPlayerCount;
          
          
          /* ======== EVENTS ======== */
          
          /// @dev The PlayerTransported event is fired when user transported to another dungeon.
          event PlayerTransported(uint timestamp, address indexed playerAddress, uint indexed originDungeonId, uint indexed destinationDungeonId);
          
          /// @dev The DungeonChallenged event is fired when user finished a dungeon challenge.
          event DungeonChallenged(uint timestamp, address indexed playerAddress, uint indexed dungeonId, uint indexed heroId, uint heroGenes, uint floorNumber, uint floorGenes, bool success, uint newFloorGenes, uint successRewards, uint masterRewards);
        
          /// @dev The DungeonChallenged event is fired when user finished a dungeon challenge.
          event ConsolationRewardsClaimed(uint timestamp, address indexed playerAddress, uint consolationRewards);
        
          /// @dev The HeroTrained event is fired when user finished a training.
          event HeroTrained(uint timestamp, address indexed playerAddress, uint indexed dungeonId, uint indexed heroId, uint heroGenes, uint floorNumber, uint floorGenes, bool success, uint newHeroGenes);
          
          
          /* ======== PUBLIC/EXTERNAL FUNCTIONS ======== */
          
          /**
           * @dev Get the attributes (equipments + stats) of a hero from its gene.
           */
          function getHeroAttributes(uint _genes) public pure returns (uint[]) {
              uint[] memory attributes = new uint[](12);
              
              for (uint i = 0; i < 12; i++) {
                  attributes[11 - i] = _genes % 32;
                  _genes /= 32 ** 4;
              }
              
              return attributes;
          }
          
          /**
           * @dev Calculate the power of a hero from its gene,
           *  it calculates the equipment power, stats power, and super hero boost.
           */
          function getHeroPower(uint _genes, uint _dungeonDifficulty) public pure returns (
              uint totalPower, 
              uint equipmentPower, 
              uint statsPower, 
              bool isSuper, 
              uint superRank,
              uint superBoost
          ) {
              // Individual power of each equipment.
              // DUPLICATE CODE with _getDungeonPower: Constant array variable is not yet implemented,
              // so need to put it here in order to save gas.
              uint16[32] memory EQUIPMENT_POWERS = [
                  1, 2, 4, 5, 16, 17, 32, 33, // [Holy] Normal Equipments
                  8, 16, 16, 32, 32, 48, 64, 96, // [Myth] Normal Equipments
                  
                  4, 16, 32, 64, // [Holy] Rare Equipments
                  32, 48, 80, 128, // [Myth] Rare Equipments
                  
                  32, 96, // [Holy] Epic Equipments
                  80, 192, // [Myth] Epic Equipments
                  
                  192, // [Holy] Legendary Equipments
                  288, // [Myth] Legendary Equipments
                  
                  // Pangu / Chaos Legendary Equipments are reserved for far future use.
                  // Their existence is still a mystery.
                  384, // [Pangu] Legendary Equipments
                  512 // [Chaos] Legendary Equipments
              ];
              
              uint[] memory attributes = getHeroAttributes(_genes);
              
              // Calculate total equipment power.
              superRank = attributes[0];
              
              for (uint i = 0; i < 8; i++) {
                  uint equipment = attributes[i];
                  equipmentPower += EQUIPMENT_POWERS[equipment];
                  
                  // If any equipment is of difference index, set superRank to 0.
                  if (superRank != equipment) {
                      superRank = 0;
                  }
              }
              
              // Calculate total stats power.
              for (uint j = 8; j < 12; j++) {
                  // Stat power is gene number + 1.
                  statsPower += attributes[j] + 1;
              }
              
              // Calculate Super/Ultra/Mega Power Boost.
              isSuper = superRank >= 16;
              
              if (superRank >= 28) { // Mega Hero
                  superBoost = (_dungeonDifficulty - 1) * MEGA_HERO_MULTIPLIER;
              } else if (superRank >= 24) { // Ultra Hero
                  superBoost = (_dungeonDifficulty - 1) * ULTRA_HERO_MULTIPLIER;
              } else if (superRank >= 16) { // Super Hero
                  superBoost = (_dungeonDifficulty - 1) * SUPER_HERO_MULTIPLIER;
              }
              
              totalPower = statsPower + equipmentPower + superBoost;
          }
          
          /**
           * @dev Calculate the power of a dungeon floor.
           */
          function getDungeonPower(uint _genes) public pure returns (uint) {
              // Individual power of each equipment.
              // DUPLICATE CODE with getHeroPower
              uint16[32] memory EQUIPMENT_POWERS = [
                  1, 2, 4, 5, 16, 17, 32, 33, // [Holy] Normal Equipments
                  8, 16, 16, 32, 32, 48, 64, 96, // [Myth] Normal Equipments
                  
                  4, 16, 32, 64, // [Holy] Rare Equipments
                  32, 48, 80, 128, // [Myth] Rare Equipments
                  
                  32, 96, // [Holy] Epic Equipments
                  80, 192, // [Myth] Epic Equipments
                  
                  192, // [Holy] Legendary Equipments
                  288, // [Myth] Legendary Equipments
                  
                  // Pangu / Chaos Legendary Equipments are reserved for far future use.
                  // Their existence is still a mystery.
                  384, // [Pangu] Legendary Equipments
                  512 // [Chaos] Legendary Equipments
              ];
              
              // Calculate total dungeon power.
              uint dungeonPower;
              
              for (uint j = 0; j < 12; j++) {
                  dungeonPower += EQUIPMENT_POWERS[_genes % 32];
                  _genes /= 32 ** 4;
              }
              
              return dungeonPower;
          }
          
          /**
           * @dev Calculate the sum of top 5 heroes power a player owns.
           *  The gas usage increased with the number of heroes a player owned, roughly 500 x hero count.
           *  This is used in transport function only to calculate the required tranport fee.
           */
          function calculateTop5HeroesPower(address _address, uint _dungeonId) public view returns (uint) {
              uint heroCount = heroTokenContract.balanceOf(_address);
              
              if (heroCount == 0) {
                  return 0;
              }
              
              // Get the dungeon difficulty to factor in the super power boost when calculating hero power.
              uint difficulty;
              (,, difficulty,,,,,,) = dungeonTokenContract.dungeons(_dungeonId);
              
              // Compute all hero powers for further calculation.
              uint[] memory heroPowers = new uint[](heroCount);
              
              for (uint i = 0; i < heroCount; i++) {
                  uint heroId = heroTokenContract.ownerTokens(_address, i);
                  uint genes;
                  (,,, genes) = heroTokenContract.heroes(heroId);
                  (heroPowers[i],,,,,) = getHeroPower(genes, difficulty);
              }
              
              // Calculate the top 5 heroes power.
              uint result;
              uint curMax;
              uint curMaxIndex;
              
              for (uint j; j < 5; j++) {
                  for (uint k = 0; k < heroPowers.length; k++) {
                      if (heroPowers[k] > curMax) {
                          curMax = heroPowers[k];
                          curMaxIndex = k;
                      }
                  }
                  
                  result += curMax;
                  heroPowers[curMaxIndex] = 0;
                  curMax = 0;
                  curMaxIndex = 0;
              }
              
              return result;
          }
          
          /// @dev Set the previously temp stored upgraded hero genes. Can only be called by contract owner.
          function setTempHeroPower() onlyOwner public {
             _setTempHeroPower();
          }
          
          
          /* ======== SETTER FUNCTIONS ======== */
          
          /// @dev Set the address of the dungeon token contract.
          function setDungeonTokenContract(address _newDungeonTokenContract) onlyOwner external {
              dungeonTokenContract = DungeonTokenInterface(_newDungeonTokenContract);
          }
          
          /// @dev Set the address of the hero token contract.
          function setHeroTokenContract(address _newHeroTokenContract) onlyOwner external {
              heroTokenContract = HeroTokenInterface(_newHeroTokenContract);
          }
          
          /// @dev Set the address of the secret dungeon challenge formula contract.
          function setChallengeFormulaContract(address _newChallengeFormulaAddress) onlyOwner external {
              challengeFormulaContract = ChallengeFormulaInterface(_newChallengeFormulaAddress);
          }
          
          /// @dev Set the address of the secret hero training formula contract.
          function setTrainingFormulaContract(address _newTrainingFormulaAddress) onlyOwner external {
              trainingFormulaContract = TrainingFormulaInterface(_newTrainingFormulaAddress);
          }
          
          /// @dev Updates the fee for calling recruitHero().
          function setRecruitHeroFee(uint _newRecruitHeroFee) onlyOwner external {
              recruitHeroFee = _newRecruitHeroFee;
          }
          
          /// @dev Updates the fee contribution multiplier required for calling transport().
          function setTransportationFeeMultiplier(uint _newTransportationFeeMultiplier) onlyOwner external {
              transportationFeeMultiplier = _newTransportationFeeMultiplier;
          }
          
          /// @dev Updates the novice dungeon ID.
          function setNoviceDungeonId(uint _newNoviceDungeonId) onlyOwner external {
              noviceDungeonId = _newNoviceDungeonId;
          }
          
          /// @dev Updates the required amount of faith to get a portion of the consolation rewards.
          function setConsolationRewardsRequiredFaith(uint _newConsolationRewardsRequiredFaith) onlyOwner external {
              consolationRewardsRequiredFaith = _newConsolationRewardsRequiredFaith;
          }
          
          /// @dev Updates the percentage portion of consolation rewards a player get when meeting the faith requirement.
          function setConsolationRewardsClaimPercent(uint _newConsolationRewardsClaimPercent) onlyOwner external {
              consolationRewardsClaimPercent = _newConsolationRewardsClaimPercent;
          }
          
          /// @dev Updates the consolation rewards percentage.
          function setConsolationRewardsPercent(uint _newConsolationRewardsPercent) onlyOwner external {
              consolationRewardsPercent = _newConsolationRewardsPercent;
          }
          
          /// @dev Updates the challenge cooldown time.
          function setDungeonPreparationTime(uint _newDungeonPreparationTime) onlyOwner external {
              dungeonPreparationTime = _newDungeonPreparationTime;
          }
          
          /// @dev Updates the fee contribution multiplier required for calling trainX().
          function setTrainingFeeMultiplier(uint _newTrainingFeeMultiplier) onlyOwner external {
              trainingFeeMultiplier = _newTrainingFeeMultiplier;
          }
      
          /// @dev Updates the fee contribution multiplier required for calling trainEquipment().
          function setEquipmentTrainingFeeMultiplier(uint _newEquipmentTrainingFeeMultiplier) onlyOwner external {
              equipmentTrainingFeeMultiplier = _newEquipmentTrainingFeeMultiplier;
          }
          
          
          /* ======== INTERNAL/PRIVATE FUNCTIONS ======== */
          
          /**
           * @dev Internal function to set the previously temp stored upgraded hero genes. 
           * Every challenge/training will first call this function.
           */
          function _setTempHeroPower() internal {
              // Genes of 1 is used as no pending update.
              if (tempSuccessTrainingNewHeroGenes != 1) {
                  // ** STORAGE UPDATE **
                  heroTokenContract.setHeroGenes(tempSuccessTrainingHeroId, tempSuccessTrainingNewHeroGenes);
                  
                  // Reset the variables to indicate no pending update.
                  tempSuccessTrainingNewHeroGenes = 1;
              }
          }
          
          
          /* ======== MODIFIERS ======== */
          
          /**
           * @dev Throws if _dungeonId is not created yet.
           */
          modifier dungeonExists(uint _dungeonId) {
              require(_dungeonId < dungeonTokenContract.totalSupply());
              _;
          }
          
      }
      
      
      contract EDTransportation is EDBase {
      
          /* ======== PUBLIC/EXTERNAL FUNCTIONS ======== */
          
          /// @dev Recruit a new novice hero with no attributes (gene = 0).
          function recruitHero() whenNotPaused external payable returns (uint) {
              // Only allow recruiting hero in the novice dungeon, or first time recruiting hero.
              require(playerToDungeonID[msg.sender] == noviceDungeonId || !playerToFirstHeroRecruited[msg.sender]);
              
              // Checks for payment, any exceeding funds will be transferred back to the player.
              require(msg.value >= recruitHeroFee);
              
              // ** STORAGE UPDATE **
              // Increment the accumulated rewards for the dungeon, 
              // since player can only recruit hero in the novice dungeon, rewards is added there.
              dungeonTokenContract.addDungeonRewards(noviceDungeonId, recruitHeroFee);
      
              // Calculate any excess funds and make it available to be withdrawed by the player.
              asyncSend(msg.sender, msg.value - recruitHeroFee);
              
              // If it is the first time recruiting a hero, set the player's location to the novice dungeon.
              if (!playerToFirstHeroRecruited[msg.sender]) {
                  // ** STORAGE UPDATE **
                  dungeonIdToPlayerCount[noviceDungeonId]++;
                  playerToDungeonID[msg.sender] = noviceDungeonId;
                  playerToFirstHeroRecruited[msg.sender] = true;
              }
              
              return heroTokenContract.createHero(0, msg.sender);
          }
          
          /**
           * @dev The main external function to call when a player transport to another dungeon.
           *  Will generate a PlayerTransported event.
           *  Player must have at least one hero in order to perform
           */
          function transport(uint _destinationDungeonId) whenNotPaused dungeonCanTransport(_destinationDungeonId) playerAllowedToTransport() external payable {
              uint originDungeonId = playerToDungeonID[msg.sender];
              
              // Disallow transport to the same dungeon.
              require(_destinationDungeonId != originDungeonId);
              
              // Get the dungeon details from the token contract.
              uint difficulty;
              (,, difficulty,,,,,,) = dungeonTokenContract.dungeons(_destinationDungeonId);
              
              // Disallow weaker user to transport to "difficult" dungeon.
              uint top5HeroesPower = calculateTop5HeroesPower(msg.sender, _destinationDungeonId);
              require(top5HeroesPower >= difficulty * 12);
              
              // Checks for payment, any exceeding funds will be transferred back to the player.
              // The transportation fee is calculated by a base fee from transportationFeeMultiplier,
              // plus an additional fee increased with the total power of top 5 heroes owned.
              uint baseFee = difficulty * transportationFeeMultiplier;
              uint additionalFee = top5HeroesPower / 64 * transportationFeeMultiplier;
              uint requiredFee = baseFee + additionalFee;
              require(msg.value >= requiredFee);
              
              // ** STORAGE UPDATE **
              // Increment the accumulated rewards for the dungeon.
              dungeonTokenContract.addDungeonRewards(originDungeonId, requiredFee);
      
              // Calculate any excess funds and make it available to be withdrawed by the player.
              asyncSend(msg.sender, msg.value - requiredFee);
      
              _transport(originDungeonId, _destinationDungeonId);
          }
          
          
          /* ======== INTERNAL/PRIVATE FUNCTIONS ======== */
          
          /// @dev Internal function to assigns location of a player.
          function _transport(uint _originDungeonId, uint _destinationDungeonId) internal {
              // ** STORAGE UPDATE **
              // Update the dungeons' player count.
              // Normally the player count of original dungeon will already be > 0,
              // perform checking to avoid unexpected overflow
              if (dungeonIdToPlayerCount[_originDungeonId] > 0) {
                  dungeonIdToPlayerCount[_originDungeonId]--;
              }
              
              dungeonIdToPlayerCount[_destinationDungeonId]++;
              
              // ** STORAGE UPDATE **
              // Update player location.
              playerToDungeonID[msg.sender] = _destinationDungeonId;
                  
              // Emit the DungeonChallenged event.
              PlayerTransported(now, msg.sender, _originDungeonId, _destinationDungeonId);
          }
          
          
          /* ======== MODIFIERS ======== */
          
          /**
           * @dev Throws if dungeon status do not allow transportation, also check for dungeon existence.
           *  Also check if the capacity of the destination dungeon is reached.
           */
          modifier dungeonCanTransport(uint _destinationDungeonId) {
              require(_destinationDungeonId < dungeonTokenContract.totalSupply());
              
              uint status;
              uint capacity;
              (, status,, capacity,,,,,) = dungeonTokenContract.dungeons(_destinationDungeonId);
              require(status == 0 || status == 1);
              
              // Check if the capacity of the destination dungeon is reached.
              // Capacity 0 = Infinity
              require(capacity == 0 || dungeonIdToPlayerCount[_destinationDungeonId] < capacity);
              _;
          }
          
          /// @dev Throws if player did recruit first hero yet.
          modifier playerAllowedToTransport() {
              // Note that we check playerToFirstHeroRecruited instead of heroTokenContract.balanceOf
              // in order to prevent "capacity attack".
              require(playerToFirstHeroRecruited[msg.sender]);
              _;
          }
          
      }
      
      
      contract EDChallenge is EDTransportation {
          
          /* ======== PUBLIC/EXTERNAL FUNCTIONS ======== */
          
          /**
           * @dev The main external function to call when a player challenge a dungeon,
           *  it determines whether if the player successfully challenged the current floor.
           *  Will generate a DungeonChallenged event.
           */
          function challenge(uint _dungeonId, uint _heroId) whenNotPaused dungeonCanChallenge(_dungeonId) heroAllowedToChallenge(_heroId) external payable {
              // Set the last action block number, disallow player to perform another train or challenge in the same block.
              playerToLastActionBlockNumber[msg.sender] = block.number;
              
              // Set the previously temp stored upgraded hero genes.
              _setTempHeroPower();
              
              // Get the dungeon details from the token contract.
              uint difficulty;
              uint seedGenes;
              (,, difficulty,,,,, seedGenes,) = dungeonTokenContract.dungeons(_dungeonId);
              
              // Checks for payment, any exceeding funds will be transferred back to the player.
              uint requiredFee = difficulty * challengeFeeMultiplier;
              require(msg.value >= requiredFee);
              
              // ** STORAGE UPDATE **
              // Increment the accumulated rewards for the dungeon.
              dungeonTokenContract.addDungeonRewards(_dungeonId, requiredFee);
      
              // Calculate any excess funds and make it available to be withdrawed by the player.
              asyncSend(msg.sender, msg.value - requiredFee);
              
              // Split the challenge function into multiple parts because of stack too deep error.
              _challengePart2(_dungeonId, difficulty, _heroId);
          }
          
          
          /* ======== INTERNAL/PRIVATE FUNCTIONS ======== */
          
          /// @dev Compute the remaining time for which the hero can perform a challenge again.
          function _computeCooldownRemainingTime(uint _heroId) internal view returns (uint) {
              uint cooldownStartTime;
              uint cooldownIndex;
              (, cooldownStartTime, cooldownIndex,) = heroTokenContract.heroes(_heroId);
              
              // Cooldown period is FLOOR(challenge count / 2) ^ 2 minutes
              uint cooldownPeriod = (cooldownIndex / 2) ** 2 * 1 minutes;
              
              if (cooldownPeriod > 100 minutes) {
                  cooldownPeriod = 100 minutes;
              }
              
              uint cooldownEndTime = cooldownStartTime + cooldownPeriod;
              
              if (cooldownEndTime <= now) {
                  return 0;
              } else {
                  return cooldownEndTime - now;
              }
          }
          
          /// @dev Split the challenge function into multiple parts because of stack too deep error.
          function _challengePart2(uint _dungeonId, uint _dungeonDifficulty, uint _heroId) private {
              uint floorNumber;
              uint rewards;
              uint floorGenes;
              (,,,, floorNumber,, rewards,, floorGenes) = dungeonTokenContract.dungeons(_dungeonId);
              
              // Get the hero gene.
              uint heroGenes;
              (,,, heroGenes) = heroTokenContract.heroes(_heroId);
              
              bool success = _getChallengeSuccess(heroGenes, _dungeonDifficulty, floorGenes);
              
              uint newFloorGenes;
              uint masterRewards;
              uint consolationRewards;
              uint successRewards;
              uint newRewards;
              
              // Whether a challenge is success or not is determined by a simple comparison between hero power and floor power.
              if (success) {
                  newFloorGenes = _getNewFloorGene(_dungeonId);
                  
                  masterRewards = rewards * masterRewardsPercent / 100;
                  
                  consolationRewards = rewards * consolationRewardsPercent / 100;
                  
                  if (floorNumber < rushTimeFloorCount) { // rush time right after prepration period
                      successRewards = rewards * rushTimeChallengeRewardsPercent / 100;
                      
                      // The dungeon rewards for new floor as total rewards - challenge rewards - devleoper fee.
                      newRewards = rewards * (100 - rushTimeChallengeRewardsPercent - masterRewardsPercent - consolationRewardsPercent) / 100;
                  } else {
                      successRewards = rewards * challengeRewardsPercent / 100;
                      newRewards = rewards * (100 - challengeRewardsPercent - masterRewardsPercent - consolationRewardsPercent) / 100;
                  }
                  
                  // TRIPLE CONFIRM sanity check.
                  require(successRewards + masterRewards + consolationRewards + newRewards <= rewards);
                  
                  // ** STORAGE UPDATE **
                  // Add the consolation rewards to grandConsolationRewards.
                  grandConsolationRewards += consolationRewards;
                  
                  // Add new floor with the new floor genes and new rewards.
                  dungeonTokenContract.addDungeonNewFloor(_dungeonId, newRewards, newFloorGenes);
                  
                  // Mark the challenge rewards available to be withdrawed by the player.
                  asyncSend(msg.sender, successRewards);
                  
                  // Mark the master rewards available to be withdrawed by the dungeon master.
                  asyncSend(dungeonTokenContract.ownerOf(_dungeonId), masterRewards);
              }
              
              // ** STORAGE UPDATE **
              // Trigger the cooldown for the hero.
              heroTokenContract.triggerCooldown(_heroId);
                  
              // Emit the DungeonChallenged event.
              DungeonChallenged(now, msg.sender, _dungeonId, _heroId, heroGenes, floorNumber, floorGenes, success, newFloorGenes, successRewards, masterRewards);
          }
          
          /// @dev Split the challenge function into multiple parts because of stack too deep error.
          function _getChallengeSuccess(uint _heroGenes, uint _dungeonDifficulty, uint _floorGenes) private pure returns (bool) {
              // Determine if the player challenge successfuly the dungeon or not.
              uint heroPower;
              (heroPower,,,,,) = getHeroPower(_heroGenes, _dungeonDifficulty);
              
              uint floorPower = getDungeonPower(_floorGenes);
              
              return heroPower > floorPower;
          }
          
          /// @dev Split the challenge function into multiple parts because of stack too deep error.
          function _getNewFloorGene(uint _dungeonId) private returns (uint) {
              uint seedGenes;
              uint floorGenes;
              (,,,,,, seedGenes, floorGenes) = dungeonTokenContract.dungeons(_dungeonId);
              
              // Calculate the new floor gene.
              uint floorPower = getDungeonPower(floorGenes);
              
              // Call the external closed source secret function that determines the resulting floor "genes".
              uint newFloorGenes = challengeFormulaContract.calculateResult(floorGenes, seedGenes);
              uint newFloorPower = getDungeonPower(newFloorGenes);
              
              // If the power decreased, rollback to the current floor genes.
              if (newFloorPower < floorPower) {
                  newFloorGenes = floorGenes;
              }
              
              return newFloorGenes;
          }
          
          
          /* ======== MODIFIERS ======== */
          
          /**
           * @dev Throws if dungeon status do not allow challenge, also check for dungeon existence.
           *  Also check if the user is in the dungeon.
           *  Also check if the dungeon is not in preparation period.
           */
          modifier dungeonCanChallenge(uint _dungeonId) {
              require(_dungeonId < dungeonTokenContract.totalSupply());
              
              uint creationTime;
              uint status;
              (creationTime, status,,,,,,,) = dungeonTokenContract.dungeons(_dungeonId);
              require(status == 0 || status == 2);
              
              // Check if the user is in the dungeon.
              require(playerToDungeonID[msg.sender] == _dungeonId);
              
              // Check if the dungeon is not in preparation period.
              require(creationTime + dungeonPreparationTime <= now);
              _;
          }
          
          /**
           * @dev Throws if player does not own the hero, or the hero is still in cooldown period,
           *  and no pending power update.
           */
          modifier heroAllowedToChallenge(uint _heroId) {
              // You can only challenge with your own hero.
              require(heroTokenContract.ownerOf(_heroId) == msg.sender);
              
              // Hero must not be in cooldown period
              uint cooldownRemainingTime = _computeCooldownRemainingTime(_heroId);
              require(cooldownRemainingTime == 0);
              
              // Prevent player to perform training and challenge in the same block to avoid bot exploit.
              require(block.number > playerToLastActionBlockNumber[msg.sender]);
              _;
          }
          
      }
      
      
      contract EDTraining is EDChallenge {
          
          /* ======== PUBLIC/EXTERNAL FUNCTIONS ======== */
          
          /**
           * @dev The external function to call when a hero train with a dungeon,
           *  it determines whether whether a training is successfully, and the resulting genes.
           *  Will generate a DungeonChallenged event.
           */
          function train1(uint _dungeonId, uint _heroId) whenNotPaused dungeonCanTrain(_dungeonId) heroAllowedToTrain(_heroId) external payable {
              _train(_dungeonId, _heroId, 0, 1);
          }
          
          function train2(uint _dungeonId, uint _heroId) whenNotPaused dungeonCanTrain(_dungeonId) heroAllowedToTrain(_heroId) external payable {
              _train(_dungeonId, _heroId, 0, 2);
          }
          
          function train3(uint _dungeonId, uint _heroId) whenNotPaused dungeonCanTrain(_dungeonId) heroAllowedToTrain(_heroId) external payable {
              _train(_dungeonId, _heroId, 0, 3);
          }
          
          /**
           * @dev The external function to call when a hero train a particular equipment with a dungeon,
           *  it determines whether whether a training is successfully, and the resulting genes.
           *  Will generate a DungeonChallenged event.
           *  _equipmentIndex is the index of equipment: 0 is train all attributes, including equipments and stats.
           *  1: weapon | 2: shield | 3: armor | 4: shoe | 5: helmet | 6: gloves | 7: belt | 8: shawl
           */
          function trainEquipment(uint _dungeonId, uint _heroId, uint _equipmentIndex) whenNotPaused dungeonCanTrain(_dungeonId) heroAllowedToTrain(_heroId) external payable {
              require(_equipmentIndex <= 8);
              
              _train(_dungeonId, _heroId, _equipmentIndex, 1);
          }
          
          
          /* ======== INTERNAL/PRIVATE FUNCTIONS ======== */
          
          /**
           * @dev An internal function of a hero train with dungeon,
           *  it determines whether whether a training is successfully, and the resulting genes.
           *  Will generate a DungeonChallenged event.
           */
          function _train(uint _dungeonId, uint _heroId, uint _equipmentIndex, uint _trainingTimes) private {
              // Set the last action block number, disallow player to perform another train or challenge in the same block.
              playerToLastActionBlockNumber[msg.sender] = block.number;
              
              // Set the previously temp stored upgraded hero genes.
              _setTempHeroPower();
              
              // Get the dungeon details from the token contract.
              uint creationTime;
              uint difficulty;
              uint floorNumber;
              uint rewards;
              uint seedGenes;
              uint floorGenes;
              (creationTime,, difficulty,, floorNumber,, rewards, seedGenes, floorGenes) = dungeonTokenContract.dungeons(_dungeonId);
              
              // Check for _trainingTimes abnormality, we probably won't have any feature that train a hero 10 times with a single call.
              require(_trainingTimes < 10);
              
              // Checks for payment, any exceeding funds will be transferred back to the player.
              uint requiredFee;
              
              // Calculate the required training fee.
              if (now < creationTime + dungeonPreparationTime) {
                  // Apply preparation period discount. 
                  if (_equipmentIndex > 0) { // train specific equipments
                      requiredFee = difficulty * preparationPeriodEquipmentTrainingFeeMultiplier * _trainingTimes;
                  } else { // train all attributes
                      requiredFee = difficulty * preparationPeriodTrainingFeeMultiplier * _trainingTimes;
                  }
              } else {
                  if (_equipmentIndex > 0) { // train specific equipments
                      requiredFee = difficulty * equipmentTrainingFeeMultiplier * _trainingTimes;
                  } else { // train all attributes
                      requiredFee = difficulty * trainingFeeMultiplier * _trainingTimes;
                  }
              }
              
              require(msg.value >= requiredFee);
              
              // Get the hero gene.
              uint heroGenes;
              (,,, heroGenes) = heroTokenContract.heroes(_heroId);
              
              // ** STORAGE UPDATE **
              // Increment the accumulated rewards for the dungeon.
              dungeonTokenContract.addDungeonRewards(_dungeonId, requiredFee);
      
              // Calculate any excess funds and make it available to be withdrawed by the player.
              asyncSend(msg.sender, msg.value - requiredFee);
              
              // Split the _train function into multiple parts because of stack too deep error.
              _trainPart2(_dungeonId, _heroId, _equipmentIndex, _trainingTimes, difficulty, floorNumber, floorGenes, heroGenes);
          }
          
          /// @dev Split the _train function into multiple parts because of Stack Too Deep error.
          function _trainPart2(
              uint _dungeonId,
              uint _heroId,
              uint _equipmentIndex,
              uint _trainingTimes,
              uint _dungeonDifficulty,
              uint _floorNumber,
              uint _floorGenes,
              uint _heroGenes
          ) private {
              // Determine if the hero training is successful or not, and the resulting genes.
              uint heroPower;
              bool isSuper;
              (heroPower,,, isSuper,,) = getHeroPower(_heroGenes, _dungeonDifficulty);
              
              uint newHeroGenes;
              uint newHeroPower;
              (newHeroGenes, newHeroPower) = _calculateNewHeroPower(_dungeonDifficulty, _heroGenes, _equipmentIndex, _trainingTimes, heroPower, isSuper, _floorGenes);
      
              // Set the new hero genes if updated (sometimes there is no power increase during equipment forging).
              if (newHeroGenes != _heroGenes) {
                  if (newHeroPower >= 256) {
                      // Do not update immediately to prevent deterministic training exploit.
                      tempSuccessTrainingHeroId = _heroId;
                      tempSuccessTrainingNewHeroGenes = newHeroGenes;
                  } else {
                      // Immediately update the genes for small power hero.
                      // ** STORAGE UPDATE **
                      heroTokenContract.setHeroGenes(_heroId, newHeroGenes);
                  }
              }
              
              // Training is successful only when power increase, changing another equipment with same power is considered failure
              // and faith will be given accordingly.
              bool success = newHeroPower > heroPower;
              
              if (!success) {
                  // Handle training failure - consolation rewards mechanics.
                  _handleTrainingFailure(_equipmentIndex, _trainingTimes, _dungeonDifficulty);
              }
              
              // Emit the HeroTrained event.
              HeroTrained(now, msg.sender, _dungeonId, _heroId, _heroGenes, _floorNumber, _floorGenes, success, newHeroGenes);
          }
          
          /// @dev Determine if the hero training is successful or not, and the resulting genes and power.
          function _calculateNewHeroPower(
              uint _dungeonDifficulty, 
              uint _heroGenes, 
              uint _equipmentIndex, 
              uint _trainingTimes, 
              uint _heroPower, 
              bool _isSuper, 
              uint _floorGenes
          ) private returns (uint newHeroGenes, uint newHeroPower) {
              newHeroGenes = _heroGenes;
              newHeroPower = _heroPower;
              bool newIsSuper = _isSuper;
              
              // Train the hero multiple times according to _trainingTimes, 
              // each time if the resulting power is larger, update new hero power.
              for (uint i = 0; i < _trainingTimes; i++) {
                  // Call the external closed source secret function that determines the resulting hero "genes".
                  uint tmpHeroGenes = trainingFormulaContract.calculateResult(newHeroGenes, _floorGenes, _equipmentIndex);
                  
                  uint tmpHeroPower;
                  bool tmpIsSuper;
                  (tmpHeroPower,,, tmpIsSuper,,) = getHeroPower(tmpHeroGenes, _dungeonDifficulty);
                  
                  if (tmpHeroPower > newHeroPower) {
                      // Prevent Super Hero downgrade.
                      if (!(newIsSuper && !tmpIsSuper)) {
                          newHeroGenes = tmpHeroGenes;
                          newHeroPower = tmpHeroPower;
                      }
                  } else if (_equipmentIndex > 0 && tmpHeroPower == newHeroPower && tmpHeroGenes != newHeroGenes) {
                      // Allow Equipment Forging to replace current requipemnt with a same power equipment.
                      // The training is considered failed (faith will be given, but the equipment will change).
                      newHeroGenes = tmpHeroGenes;
                      newHeroPower = tmpHeroPower;
                  }
              }
          }
          
          /// @dev Calculate and assign the appropriate faith value to the player.
          function _handleTrainingFailure(uint _equipmentIndex, uint _trainingTimes, uint _dungeonDifficulty) private {
              // Failed training in a dungeon will add to player's faith value.
              uint faith = playerToFaith[msg.sender];
              uint faithEarned;
              
              if (_equipmentIndex == 0) { // Hero Training
                  // The faith earned is proportional to the training fee, i.e. _difficulty * _trainingTimes.
                  faithEarned = _dungeonDifficulty * _trainingTimes;
              } else { // Equipment Forging
                  // Equipment Forging faith earned is only 2 times normal training, not proportional to forging fee.
                  faithEarned = _dungeonDifficulty * _trainingTimes * 2;
              }
              
              uint newFaith = faith + faithEarned;
              
              // Hitting the required amount in faith will get a proportion of grandConsolationRewards
              if (newFaith >= consolationRewardsRequiredFaith) {
                  uint consolationRewards = grandConsolationRewards * consolationRewardsClaimPercent / 100;
                  
                  // ** STORAGE UPDATE **
                  grandConsolationRewards -= consolationRewards;
                  
                  // Mark the consolation rewards available to be withdrawed by the player.
                  asyncSend(msg.sender, consolationRewards);
                  
                  // Reset the faith value.
                  newFaith -= consolationRewardsRequiredFaith;
                  
                  ConsolationRewardsClaimed(now, msg.sender, consolationRewards);
              }
              
              // ** STORAGE UPDATE **
              playerToFaith[msg.sender] = newFaith;
          }
          
          
          /* ======== MODIFIERS ======== */
          
          /**
           * @dev Throws if dungeon status do not allow training, also check for dungeon existence.
           *  Also check if the user is in the dungeon.
           */
          modifier dungeonCanTrain(uint _dungeonId) {
              require(_dungeonId < dungeonTokenContract.totalSupply());
              uint status;
              (,status,,,,,,,) = dungeonTokenContract.dungeons(_dungeonId);
              require(status == 0 || status == 3);
              
              // Also check if the user is in the dungeon.
              require(playerToDungeonID[msg.sender] == _dungeonId);
              _;
          }
          
          /**
           * @dev Throws if player does not own the hero, and no pending power update.
           */
          modifier heroAllowedToTrain(uint _heroId) {
              require(heroTokenContract.ownerOf(_heroId) == msg.sender);
              
              // Prevent player to perform training and challenge in the same block to avoid bot exploit.
              require(block.number > playerToLastActionBlockNumber[msg.sender]);
              _;
          }
          
      }
      
      
      /**
       * @title EDCoreVersion1
       * @dev Core Contract of Ether Dungeon.
       *  When Version 2 launches, EDCoreVersion2 contract will be deployed and EDCoreVersion1 will be destroyed.
       *  Since all dungeons and heroes are stored as tokens in external contracts, they remains immutable.
       */
      contract EDCoreVersion1 is Destructible, EDTraining {
          
          /**
           * Initialize the EDCore contract with all the required contract addresses.
           */
          function EDCoreVersion1(
              address _dungeonTokenAddress,
              address _heroTokenAddress,
              address _challengeFormulaAddress, 
              address _trainingFormulaAddress
          ) public payable {
              dungeonTokenContract = DungeonTokenInterface(_dungeonTokenAddress);
              heroTokenContract = HeroTokenInterface(_heroTokenAddress);
              challengeFormulaContract = ChallengeFormulaInterface(_challengeFormulaAddress);
              trainingFormulaContract = TrainingFormulaInterface(_trainingFormulaAddress);
          }
      
          
          /* ======== PUBLIC/EXTERNAL FUNCTIONS ======== */
          
          /// @dev The external function to get all the game settings in one call.
          function getGameSettings() external view returns (
              uint _recruitHeroFee,
              uint _transportationFeeMultiplier,
              uint _noviceDungeonId,
              uint _consolationRewardsRequiredFaith,
              uint _challengeFeeMultiplier,
              uint _dungeonPreparationTime,
              uint _trainingFeeMultiplier,
              uint _equipmentTrainingFeeMultiplier,
              uint _preparationPeriodTrainingFeeMultiplier,
              uint _preparationPeriodEquipmentTrainingFeeMultiplier
          ) {
              _recruitHeroFee = recruitHeroFee;
              _transportationFeeMultiplier = transportationFeeMultiplier;
              _noviceDungeonId = noviceDungeonId;
              _consolationRewardsRequiredFaith = consolationRewardsRequiredFaith;
              _challengeFeeMultiplier = challengeFeeMultiplier;
              _dungeonPreparationTime = dungeonPreparationTime;
              _trainingFeeMultiplier = trainingFeeMultiplier;
              _equipmentTrainingFeeMultiplier = equipmentTrainingFeeMultiplier;
              _preparationPeriodTrainingFeeMultiplier = preparationPeriodTrainingFeeMultiplier;
              _preparationPeriodEquipmentTrainingFeeMultiplier = preparationPeriodEquipmentTrainingFeeMultiplier;
          }
          
          /**
           * @dev The external function to get all the relevant information about a specific player by its address.
           * @param _address The address of the player.
           */
          function getPlayerDetails(address _address) external view returns (
              uint dungeonId, 
              uint payment, 
              uint dungeonCount, 
              uint heroCount, 
              uint faith,
              bool firstHeroRecruited
          ) {
              payment = payments[_address];
              dungeonCount = dungeonTokenContract.balanceOf(_address);
              heroCount = heroTokenContract.balanceOf(_address);
              faith = playerToFaith[_address];
              firstHeroRecruited = playerToFirstHeroRecruited[_address];
              
              // If a player didn't recruit any hero yet, consider the player is in novice dungeon
              if (firstHeroRecruited) {
                  dungeonId = playerToDungeonID[_address];
              } else {
                  dungeonId = noviceDungeonId;
              }
          }
          
          /**
           * @dev The external function to get all the relevant information about a specific dungeon by its ID.
           * @param _id The ID of the dungeon.
           */
          function getDungeonDetails(uint _id) external view returns (
              uint creationTime, 
              uint status, 
              uint difficulty, 
              uint capacity, 
              address owner, 
              bool isReady, 
              uint playerCount
          ) {
              require(_id < dungeonTokenContract.totalSupply());
              
              // Didn't get the "floorCreationTime" because of Stack Too Deep error.
              (creationTime, status, difficulty, capacity,,,,,) = dungeonTokenContract.dungeons(_id);
              
              // Dungeon is ready to be challenged (not in preparation mode).
              owner = dungeonTokenContract.ownerOf(_id);
              isReady = creationTime + dungeonPreparationTime <= now;
              playerCount = dungeonIdToPlayerCount[_id];
          }
          
          /**
           * @dev Split floor related details out of getDungeonDetails, just to avoid Stack Too Deep error.
           * @param _id The ID of the dungeon.
           */
          function getDungeonFloorDetails(uint _id) external view returns (
              uint floorNumber, 
              uint floorCreationTime, 
              uint rewards, 
              uint seedGenes, 
              uint floorGenes
          ) {
              require(_id < dungeonTokenContract.totalSupply());
              
              // Didn't get the "floorCreationTime" because of Stack Too Deep error.
              (,,,, floorNumber, floorCreationTime, rewards, seedGenes, floorGenes) = dungeonTokenContract.dungeons(_id);
          }
      
          /**
           * @dev The external function to get all the relevant information about a specific hero by its ID.
           * @param _id The ID of the hero.
           */
          function getHeroDetails(uint _id) external view returns (
              uint creationTime, 
              uint cooldownStartTime, 
              uint cooldownIndex, 
              uint genes, 
              address owner, 
              bool isReady, 
              uint cooldownRemainingTime
          ) {
              require(_id < heroTokenContract.totalSupply());
      
              (creationTime, cooldownStartTime, cooldownIndex, genes) = heroTokenContract.heroes(_id);
              
              // Hero is ready to challenge (not in cooldown mode).
              owner = heroTokenContract.ownerOf(_id);
              cooldownRemainingTime = _computeCooldownRemainingTime(_id);
              isReady = cooldownRemainingTime == 0;
          }
          
          
          /* ======== MIGRATION FUNCTIONS ======== */
          
          /**
           * @dev Since the DungeonToken contract is re-deployed due to optimization.
           *  We need to migrate all dungeons from Beta token contract to Version 1.
           */
          function migrateDungeon(uint _id, uint _playerCount) external {
              // Migration will be finished before maintenance period ends, tx.origin is used within a short period only.
              require(now < 1520694000 && tx.origin == 0x47169f78750Be1e6ec2DEb2974458ac4F8751714);
              
              dungeonIdToPlayerCount[_id] = _playerCount;
          }
          
          /**
           * @dev We need to migrate all player location from Beta token contract to Version 1.
           */
          function migratePlayer(address _address, uint _ownerDungeonId, uint _payment, uint _faith) external {
              // Migration will be finished before maintenance period ends, tx.origin is used within a short period only.
              require(now < 1520694000 && tx.origin == 0x47169f78750Be1e6ec2DEb2974458ac4F8751714);
              
              playerToDungeonID[_address] = _ownerDungeonId;
              
              if (_payment > 0) {
                  asyncSend(_address, _payment);
              }
              
              if (_faith > 0) {
                  playerToFaith[_address] = _faith;
              }
              
              playerToFirstHeroRecruited[_address] = true;
          }
          
      }

      File 3 of 3: HeroTokenAuction
      pragma solidity ^0.4.19;
      
      /**
       * @title Ownable
       * @dev The Ownable contract has an owner address, and provides basic authorization control
       * functions, this simplifies the implementation of "user permissions".
       */
      contract Ownable {
      
        address public owner;
      
        event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
      
        /**
         * @dev The Ownable constructor sets the original `owner` of the contract to the sender
         * account.
         */
        function Ownable() public {
          owner = msg.sender;
        }
      
        /**
         * @dev Throws if called by any account other than the owner.
         */
        modifier onlyOwner() {
          require(msg.sender == owner);
          _;
        }
      
        /**
         * @dev Allows the current owner to transfer control of the contract to a newOwner.
         * @param newOwner The address to transfer ownership to.
         */
        function transferOwnership(address newOwner) onlyOwner public {
          require(newOwner != address(0));
          OwnershipTransferred(owner, newOwner);
          owner = newOwner;
        }
      
      }
      
      
      /**
       * @title JointOwnable
       * @dev Extension for the Ownable contract, where the owner can assign at most 2 other addresses
       *  to manage some functions of the contract, using the eitherOwner modifier.
       *  Note that onlyOwner modifier would still be accessible only for the original owner.
       */
      contract JointOwnable is Ownable {
      
        event AnotherOwnerAssigned(address indexed anotherOwner);
      
        address public anotherOwner1;
        address public anotherOwner2;
      
        /**
         * @dev Throws if called by any account other than the owner or anotherOwner.
         */
        modifier eitherOwner() {
          require(msg.sender == owner || msg.sender == anotherOwner1 || msg.sender == anotherOwner2);
          _;
        }
      
        /**
         * @dev Allows the current owner to assign another owner.
         * @param _anotherOwner The address to another owner.
         */
        function assignAnotherOwner1(address _anotherOwner) onlyOwner public {
          require(_anotherOwner != 0);
          AnotherOwnerAssigned(_anotherOwner);
          anotherOwner1 = _anotherOwner;
        }
      
        /**
         * @dev Allows the current owner to assign another owner.
         * @param _anotherOwner The address to another owner.
         */
        function assignAnotherOwner2(address _anotherOwner) onlyOwner public {
          require(_anotherOwner != 0);
          AnotherOwnerAssigned(_anotherOwner);
          anotherOwner2 = _anotherOwner;
        }
      
      }
      
      
      /**
       * @title Pausable
       * @dev Base contract which allows children to implement an emergency stop mechanism.
       */
      contract Pausable is Ownable {
      
        event Pause();
        event Unpause();
      
        bool public paused = false;
      
        /**
         * @dev Modifier to make a function callable only when the contract is not paused.
         */
        modifier whenNotPaused() {
          require(!paused);
          _;
        }
      
        /**
         * @dev Modifier to make a function callable only when the contract is paused.
         */
        modifier whenPaused() {
          require(paused);
          _;
        }
      
        /**
         * @dev called by the owner to pause, triggers stopped state
         */
        function pause() onlyOwner whenNotPaused public {
          paused = true;
          Pause();
        }
      
        /**
         * @dev called by the owner to unpause, returns to normal state
         */
        function unpause() onlyOwner whenPaused public {
          paused = false;
          Unpause();
        }
      
      }
      
      
      /**
       * @title Interface for contracts conforming to ERC-721: Non-Fungible Tokens.
       */
      contract ERC721 {
      
          // Events
          event Transfer(address indexed from, address indexed to, uint indexed tokenId);
          event Approval(address indexed owner, address indexed approved, uint indexed tokenId);
      
          // ERC20 compatible functions.
          // function name() public constant returns (string);
          // function symbol() public constant returns (string);
          function totalSupply() public view returns (uint);
          function balanceOf(address _owner) public view returns (uint);
      
          // Functions that define ownership.
          function ownerOf(uint _tokenId) external view returns (address);
          function transfer(address _to, uint _tokenId) external;
      
          // Approval related functions, mainly used in auction contracts.
          function approve(address _to, uint _tokenId) external;
          function approvedFor(uint _tokenId) external view returns (address);
          function transferFrom(address _from, address _to, uint _tokenId) external;
      
          /**
           * @dev Each non-fungible token owner can own more than one token at one time.
           * Because each token is referenced by its unique ID, however,
           * it can get difficult to keep track of the individual tokens that a user may own.
           * To do this, the contract keeps a record of the IDs of each token that each user owns.
           */
          mapping(address => uint[]) public ownerTokens;
      
      }
      
      
      /**
       * @title The ERC-721 compliance token contract.
       */
      contract ERC721Token is ERC721, Pausable {
      
          /* ======== STATE VARIABLES ======== */
      
          /**
           * @dev A mapping from token IDs to the address that owns them.
           */
          mapping(uint => address) tokenIdToOwner;
      
          /**
           * @dev A mapping from token ids to an address that has been approved to call
           *  transferFrom(). Each token can only have one approved address for transfer
           *  at any time. A zero value means no approval is outstanding.
           */
          mapping (uint => address) tokenIdToApproved;
      
          /**
           * @dev A mapping from token ID to index of the ownerTokens' tokens list.
           */
          mapping(uint => uint) tokenIdToOwnerTokensIndex;
      
      
          /* ======== PUBLIC/EXTERNAL FUNCTIONS ======== */
      
          /**
           * @dev Returns the number of tokens owned by a specific address.
           * @param _owner The owner address to check.
           */
          function balanceOf(address _owner) public view returns (uint) {
              return ownerTokens[_owner].length;
          }
      
          /**
           * @dev Returns the address currently assigned ownership of a given token.
           */
          function ownerOf(uint _tokenId) external view returns (address) {
              require(tokenIdToOwner[_tokenId] != address(0));
      
              return tokenIdToOwner[_tokenId];
          }
      
          /**
          * @dev Returns the approved address of a given token.
          */
          function approvedFor(uint _tokenId) external view returns (address) {
              return tokenIdToApproved[_tokenId];
          }
      
          /**
           * @dev Get an array of IDs of each token that an user owns.
           */
          function getOwnerTokens(address _owner) external view returns(uint[]) {
              return ownerTokens[_owner];
          }
      
          /**
           * @dev External function to transfers a token to another address.
           * @param _to The address of the recipient, can be a user or contract.
           * @param _tokenId The ID of the token to transfer.
           */
          function transfer(address _to, uint _tokenId) whenNotPaused external {
              // Safety check to prevent against an unexpected 0x0 default.
              require(_to != address(0));
      
              // Disallow transfers to this contract to prevent accidental misuse.
              require(_to != address(this));
      
              // You can only send your own token.
              require(_owns(msg.sender, _tokenId));
      
              // Reassign ownership, clear pending approvals, emit Transfer event.
              _transfer(msg.sender, _to, _tokenId);
          }
      
          /**
           * @dev Grant another address the right to transfer a specific Kitty via
           *  transferFrom(). This is the preferred flow for transfering NFTs to contracts.
           * @param _to The address to be granted transfer approval. Pass address(0) to
           *  clear all approvals.
           * @param _tokenId The ID of the Kitty that can be transferred if this call succeeds.
           */
          function approve(address _to, uint _tokenId) whenNotPaused external {
              // Only an owner can grant transfer approval.
              require(_owns(msg.sender, _tokenId));
      
              // Register the approval (replacing any previous approval).
              _approve(_tokenId, _to);
      
              // Emit approval event.
              Approval(msg.sender, _to, _tokenId);
          }
      
          /**
           * @dev Transfer a Kitty owned by another address, for which the calling address
           *  has previously been granted transfer approval by the owner.
           * @param _from The address that owns the Kitty to be transfered.
           * @param _to The address that should take ownership of the Kitty. Can be any address,
           *  including the caller.
           * @param _tokenId The ID of the Kitty to be transferred.
           */
          function transferFrom(address _from, address _to, uint _tokenId) whenNotPaused external {
              // Safety check to prevent against an unexpected 0x0 default.
              require(_to != address(0));
      
              // Check for approval and valid ownership
              require(tokenIdToApproved[_tokenId] == msg.sender);
              require(_owns(_from, _tokenId));
      
              // Reassign ownership (also clears pending approvals and emits Transfer event).
              _transfer(_from, _to, _tokenId);
          }
      
      
          /* ======== INTERNAL/PRIVATE FUNCTIONS ======== */
      
          /**
           * @dev Assigns ownership of a specific token to an address.
           */
          function _transfer(address _from, address _to, uint _tokenId) internal {
              // Step 1: Remove token from _form address.
              // When creating new token, _from is 0x0.
              if (_from != address(0)) {
                  uint[] storage fromTokens = ownerTokens[_from];
                  uint tokenIndex = tokenIdToOwnerTokensIndex[_tokenId];
      
                  // Put the last token to the transferred token index and update its index in ownerTokensIndexes.
                  uint lastTokenId = fromTokens[fromTokens.length - 1];
      
                  // Do nothing if the transferring token is the last item.
                  if (_tokenId != lastTokenId) {
                      fromTokens[tokenIndex] = lastTokenId;
                      tokenIdToOwnerTokensIndex[lastTokenId] = tokenIndex;
                  }
      
                  fromTokens.length--;
              }
      
              // Step 2: Add token to _to address.
              // Transfer ownership.
              tokenIdToOwner[_tokenId] = _to;
      
              // Add the _tokenId to ownerTokens[_to] and remember the index in ownerTokensIndexes.
              tokenIdToOwnerTokensIndex[_tokenId] = ownerTokens[_to].length;
              ownerTokens[_to].push(_tokenId);
      
              // Emit the Transfer event.
              Transfer(_from, _to, _tokenId);
          }
      
          /**
           * @dev Marks an address as being approved for transferFrom(), overwriting any previous
           *  approval. Setting _approved to address(0) clears all transfer approval.
           */
          function _approve(uint _tokenId, address _approved) internal {
              tokenIdToApproved[_tokenId] = _approved;
          }
      
      
          /* ======== MODIFIERS ======== */
      
          /**
           * @dev Throws if _dungeonId is not created yet.
           */
          modifier tokenExists(uint _tokenId) {
              require(_tokenId < totalSupply());
              _;
          }
      
          /**
           * @dev Checks if a given address is the current owner of a particular token.
           * @param _claimant The address we are validating against.
           * @param _tokenId Token ID
           */
          function _owns(address _claimant, uint _tokenId) internal view returns (bool) {
              return tokenIdToOwner[_tokenId] == _claimant;
          }
      
      }
      
      
      contract EDStructs {
      
          /**
           * @dev The main Dungeon struct. Every dungeon in the game is represented by this structure.
           * A dungeon is consists of an unlimited number of floors for your heroes to challenge,
           * the power level of a dungeon is encoded in the floorGenes. Some dungeons are in fact more "challenging" than others,
           * the secret formula for that is left for user to find out.
           *
           * Each dungeon also has a "training area", heroes can perform trainings and upgrade their stat,
           * and some dungeons are more effective in the training, which is also a secret formula!
           *
           * When player challenge or do training in a dungeon, the fee will be collected as the dungeon rewards,
           * which will be rewarded to the player who successfully challenged the current floor.
           *
           * Each dungeon fits in fits into three 256-bit words.
           */
          struct Dungeon {
      
              // Each dungeon has an ID which is the index in the storage array.
      
              // The timestamp of the block when this dungeon is created.
              uint32 creationTime;
      
              // The status of the dungeon, each dungeon can have 5 status, namely:
              // 0: Active | 1: Transport Only | 2: Challenge Only | 3: Train Only | 4: InActive
              uint8 status;
      
              // The dungeon's difficulty, the higher the difficulty,
              // normally, the "rarer" the seedGenes, the higher the diffculty,
              // and the higher the contribution fee it is to challenge, train, and transport to the dungeon,
              // the formula for the contribution fee is in DungeonChallenge and DungeonTraining contracts.
              // A dungeon's difficulty never change.
              uint8 difficulty;
      
              // The dungeon's capacity, maximum number of players allowed to stay on this dungeon.
              // The capacity of the newbie dungeon (Holyland) is set at 0 (which is infinity).
              // Using 16-bit unsigned integers can have a maximum of 65535 in capacity.
              // A dungeon's capacity never change.
              uint16 capacity;
      
              // The current floor number, a dungeon is consists of an umlimited number of floors,
              // when there is heroes successfully challenged a floor, the next floor will be
              // automatically generated. Using 32-bit unsigned integer can have a maximum of 4 billion floors.
              uint32 floorNumber;
      
              // The timestamp of the block when the current floor is generated.
              uint32 floorCreationTime;
      
              // Current accumulated rewards, successful challenger will get a large proportion of it.
              uint128 rewards;
      
              // The seed genes of the dungeon, it is used as the base gene for first floor,
              // some dungeons are rarer and some are more common, the exact details are,
              // of course, top secret of the game!
              // A dungeon's seedGenes never change.
              uint seedGenes;
      
              // The genes for current floor, it encodes the difficulty level of the current floor.
              // We considered whether to store the entire array of genes for all floors, but
              // in order to save some precious gas we're willing to sacrifice some functionalities with that.
              uint floorGenes;
      
          }
      
          /**
           * @dev The main Hero struct. Every hero in the game is represented by this structure.
           */
          struct Hero {
      
              // Each hero has an ID which is the index in the storage array.
      
              // The timestamp of the block when this dungeon is created.
              uint64 creationTime;
      
              // The timestamp of the block where a challenge is performed, used to calculate when a hero is allowed to engage in another challenge.
              uint64 cooldownStartTime;
      
              // Every time a hero challenge a dungeon, its cooldown index will be incremented by one.
              uint32 cooldownIndex;
      
              // The seed of the hero, the gene encodes the power level of the hero.
              // This is another top secret of the game! Hero's gene can be upgraded via
              // training in a dungeon.
              uint genes;
      
          }
      
      }
      
      
      contract HeroTokenInterface is ERC721, EDStructs {
      
          /**
           * @dev Name of token.
           */
          string public constant name = "Hero";
      
          /**
           * @dev Symbol of token.
           */
          string public constant symbol = "HERO";
      
          /**
           * @dev An array containing the Hero struct, which contains all the heroes in existance.
           *  The ID for each hero is the index of this array.
           */
          Hero[] public heroes;
      
          /**
           * @dev An external function that creates a new hero and stores it,
           *  only contract owners can create new token.
           *  method doesn't do any checking and should only be called when the
           *  input data is known to be valid.
           * @param _genes The gene of the new hero.
           * @param _owner The inital owner of this hero.
           * @return The hero ID of the new hero.
           */
          function createHero(uint _genes, address _owner) external returns (uint);
      
          /**
           * @dev The external function to set the hero genes by its ID,
           *  only contract owners can alter hero state.
           */
          function setHeroGenes(uint _id, uint _newGenes) external;
      
          /**
           * @dev Set the cooldownStartTime for the given hero. Also increments the cooldownIndex.
           */
          function triggerCooldown(uint _id) external;
      
      }
      
      
      /**
       * @title The ERC-721 compliance token contract for the Hero tokens.
       * @dev See the DungeonStructs contract to see the details of the Hero token data structure.
       */
      contract HeroToken is HeroTokenInterface, ERC721Token, JointOwnable {
      
      
          /* ======== EVENTS ======== */
      
          /**
           * @dev The Mint event is fired whenever a new hero is created.
           */
          event Mint(address indexed owner, uint newTokenId, uint genes);
      
      
          /* ======== PUBLIC/EXTERNAL FUNCTIONS ======== */
      
          /**
           * @dev Returns the total number of tokens currently in existence.
           */
          function totalSupply() public view returns (uint) {
              return heroes.length;
          }
      
          /**
           * @dev An external function that creates a new hero and stores it,
           *  only contract owners can create new token.
           *  method doesn't do any checking and should only be called when the
           *  input data is known to be valid.
           * @param _genes The gene of the new hero.
           * @param _owner The inital owner of this hero.
           * @return The hero ID of the new hero.
           */
          function createHero(uint _genes, address _owner) eitherOwner external returns (uint) {
              return _createHero(_genes, _owner);
          }
      
          /**
           * @dev The external function to set the hero genes by its ID,
           *  only contract owners can alter hero state.
           */
          function setHeroGenes(uint _id, uint _newGenes) eitherOwner tokenExists(_id) external {
              heroes[_id].genes = _newGenes;
          }
      
          /**
           * @dev Set the cooldownStartTime for the given hero. Also increments the cooldownIndex.
           */
          function triggerCooldown(uint _id) eitherOwner tokenExists(_id) external {
              Hero storage hero = heroes[_id];
      
              hero.cooldownStartTime = uint64(now);
              hero.cooldownIndex++;
          }
      
      
          /* ======== PRIVATE/INTERNAL FUNCTIONS ======== */
      
          function _createHero(uint _genes, address _owner) private returns (uint) {
              // ** STORAGE UPDATE **
              // Create a new hero.
              heroes.push(Hero(uint64(now), 0, 0, _genes));
      
              // Token id is the index in the storage array.
              uint newTokenId = heroes.length - 1;
      
              // Emit the token mint event.
              Mint(_owner, newTokenId, _genes);
      
              // This will assign ownership, and also emit the Transfer event.
              _transfer(0, _owner, newTokenId);
      
              return newTokenId;
          }
      
      
          /* ======== MIGRATION FUNCTIONS ======== */
      
      
          /**
           * @dev Since the HeroToken contract is re-deployed due to optimization.
           *  We need to migrate all heroes from Beta token contract to Version 1.
           */
          function migrateHero(uint _genes, address _owner) external {
              // Migration will be finished before maintenance period ends, tx.origin is used within a short period only.
              require(now < 1520694000 && tx.origin == 0x47169f78750Be1e6ec2DEb2974458ac4F8751714);
      
              _createHero(_genes, _owner);
          }
      
      }
      
      
      /**
       * @title ERC721DutchAuction
       * @dev Dutch auction / Decreasing clock auction for ERC721 tokens.
       */
      contract ERC721DutchAuction is Ownable, Pausable {
      
          /* ======== STRUCTS/ENUMS ======== */
      
          // Represents an auction of an ERC721 token.
          struct Auction {
      
              // Current owner of the ERC721 token.
              address seller;
      
              // Price (in wei) at beginning of auction.
              uint128 startingPrice;
      
              // Price (in wei) at end of auction.
              uint128 endingPrice;
      
              // Duration (in seconds) of auction.
              uint64 duration;
      
              // Time when auction started.
              // NOTE: 0 if this auction has been concluded.
              uint64 startedAt;
      
          }
      
      
          /* ======== CONTRACTS ======== */
      
          // Reference to contract tracking ERC721 token ownership.
          ERC721 public nonFungibleContract;
      
      
          /* ======== STATE VARIABLES ======== */
      
          // Cut owner takes on each auction, measured in basis points (1/100 of a percent).
          // Values 0-10,000 map to 0%-100%
          uint public ownerCut;
      
          // Map from token ID to their corresponding auction.
          mapping (uint => Auction) tokenIdToAuction;
      
      
          /* ======== EVENTS ======== */
      
          event AuctionCreated(uint timestamp, address indexed seller, uint indexed tokenId, uint startingPrice, uint endingPrice, uint duration);
          event AuctionSuccessful(uint timestamp, address indexed seller, uint indexed tokenId, uint totalPrice, address winner);
          event AuctionCancelled(uint timestamp, address indexed seller, uint indexed tokenId);
      
          /**
           * @dev Constructor creates a reference to the ERC721 token ownership contract and verifies the owner cut is in the valid range.
           * @param _tokenAddress - address of a deployed contract implementing the Nonfungible Interface.
           * @param _ownerCut - percent cut the owner takes on each auction, must be between 0-10,000.
           */
          function ERC721DutchAuction(address _tokenAddress, uint _ownerCut) public {
              require(_ownerCut <= 10000);
      
              nonFungibleContract = ERC721(_tokenAddress);
              ownerCut = _ownerCut;
          }
      
      
          /* ======== PUBLIC/EXTERNAL FUNCTIONS ======== */
      
          /**
           * @dev Bids on an open auction, completing the auction and transferring
           *  ownership of the token if enough Ether is supplied.
           * @param _tokenId - ID of token to bid on.
           */
          function bid(uint _tokenId) whenNotPaused external payable {
              // _bid will throw if the bid or funds transfer fails.
              _bid(_tokenId, msg.value);
      
              // Transfers the token owned by this contract to another address. It will throw if transfer fails.
              nonFungibleContract.transfer(msg.sender, _tokenId);
          }
      
          /**
           * @dev Cancels an auction that hasn't been won yet. Returns the token to original owner.
           * @notice This is a state-modifying function that can be called while the contract is paused.
           * @param _tokenId - ID of token on auction
           */
          function cancelAuction(uint _tokenId) external {
              Auction storage auction = tokenIdToAuction[_tokenId];
              require(_isOnAuction(auction));
      
              address seller = auction.seller;
              require(msg.sender == seller);
      
              _cancelAuction(_tokenId, seller);
          }
      
          /**
           * @dev Cancels an auction when the contract is paused.
           *  Only the owner may do this, and tokens are returned to
           *  the seller. This should only be used in emergencies.
           * @param _tokenId - ID of the token on auction to cancel.
           */
          function cancelAuctionWhenPaused(uint _tokenId) whenPaused onlyOwner external {
              Auction storage auction = tokenIdToAuction[_tokenId];
              require(_isOnAuction(auction));
      
              _cancelAuction(_tokenId, auction.seller);
          }
      
          /**
           * @dev Remove all Ether from the contract, which is the owner's cuts
           *  as well as any Ether sent directly to the contract address.
           */
          function withdrawBalance() onlyOwner external {
              msg.sender.transfer(this.balance);
          }
      
          /**
           * @dev Returns auction info for an token on auction.
           * @param _tokenId - ID of token on auction.
           */
          function getAuction(uint _tokenId) external view returns (
              address seller,
              uint startingPrice,
              uint endingPrice,
              uint duration,
              uint startedAt
          ) {
              Auction storage auction = tokenIdToAuction[_tokenId];
              require(_isOnAuction(auction));
      
              return (
                  auction.seller,
                  auction.startingPrice,
                  auction.endingPrice,
                  auction.duration,
                  auction.startedAt
              );
          }
      
          /**
           * @dev Returns the current price of an auction.
           * @param _tokenId - ID of the token price we are checking.
           */
          function getCurrentPrice(uint _tokenId) external view returns (uint) {
              Auction storage auction = tokenIdToAuction[_tokenId];
              require(_isOnAuction(auction));
      
              return _computeCurrentPrice(auction);
          }
      
      
          /* ======== INTERNAL/PRIVATE FUNCTIONS ======== */
      
          /**
           * @dev Creates and begins a new auction. Perform all the checkings necessary.
           * @param _tokenId - ID of token to auction, sender must be owner.
           * @param _startingPrice - Price of item (in wei) at beginning of auction.
           * @param _endingPrice - Price of item (in wei) at end of auction.
           * @param _duration - Length of time to move between starting
           *  price and ending price (in seconds).
           * @param _seller - Seller, if not the message sender
           */
          function _createAuction(
              uint _tokenId,
              uint _startingPrice,
              uint _endingPrice,
              uint _duration,
              address _seller
          ) internal {
              // Sanity check that no inputs overflow how many bits we've allocated to store them in the auction struct.
              require(_startingPrice == uint(uint128(_startingPrice)));
              require(_endingPrice == uint(uint128(_endingPrice)));
              require(_duration == uint(uint64(_duration)));
      
              // If the token is already on any auction, this will throw
              // because it will be owned by the auction contract.
              require(nonFungibleContract.ownerOf(_tokenId) == msg.sender);
      
              // Throw if the _endingPrice is larger than _startingPrice.
              require(_startingPrice >= _endingPrice);
      
              // Require that all auctions have a duration of at least one minute.
              require(_duration >= 1 minutes);
      
              // Transfer the token from its owner to this contract. It will throw if transfer fails.
              nonFungibleContract.transferFrom(msg.sender, this, _tokenId);
      
              Auction memory auction = Auction(
                  _seller,
                  uint128(_startingPrice),
                  uint128(_endingPrice),
                  uint64(_duration),
                  uint64(now)
              );
      
              _addAuction(_tokenId, auction);
          }
      
          /**
           * @dev Adds an auction to the list of open auctions. Also fires the
           *  AuctionCreated event.
           * @param _tokenId The ID of the token to be put on auction.
           * @param _auction Auction to add.
           */
          function _addAuction(uint _tokenId, Auction _auction) internal {
              tokenIdToAuction[_tokenId] = _auction;
      
              AuctionCreated(
                  now,
                  _auction.seller,
                  _tokenId,
                  _auction.startingPrice,
                  _auction.endingPrice,
                  _auction.duration
              );
          }
      
          /**
           * @dev Computes the price and transfers winnings.
           *  Does NOT transfer ownership of token.
           */
          function _bid(uint _tokenId, uint _bidAmount) internal returns (uint) {
              // Get a reference to the auction struct
              Auction storage auction = tokenIdToAuction[_tokenId];
      
              // Explicitly check that this auction is currently live.
              // (Because of how Ethereum mappings work, we can't just count
              // on the lookup above failing. An invalid _tokenId will just
              // return an auction object that is all zeros.)
              require(_isOnAuction(auction));
      
              // Check that the bid is greater than or equal to the current price
              uint price = _computeCurrentPrice(auction);
              require(_bidAmount >= price);
      
              // Grab a reference to the seller before the auction struct
              // gets deleted.
              address seller = auction.seller;
      
              // The bid is good! Remove the auction before sending the fees
              // to the sender so we can't have a reentrancy attack.
              _removeAuction(_tokenId);
      
              // Transfer proceeds to seller (if there are any!)
              if (price > 0) {
                  // Calculate the auctioneer's cut.
                  uint auctioneerCut = price * ownerCut / 10000;
                  uint sellerProceeds = price - auctioneerCut;
      
                  seller.transfer(sellerProceeds);
              }
      
              // Calculate any excess funds included with the bid. If the excess
              // is anything worth worrying about, transfer it back to bidder.
              // NOTE: We checked above that the bid amount is greater than or
              // equal to the price so this cannot underflow.
              uint bidExcess = _bidAmount - price;
      
              // Return the funds. Similar to the previous transfer, this is
              // not susceptible to a re-entry attack because the auction is
              // removed before any transfers occur.
              msg.sender.transfer(bidExcess);
      
              // Tell the world!
              AuctionSuccessful(now, seller, _tokenId, price, msg.sender);
      
              return price;
          }
      
          /**
           * @dev Cancels an auction unconditionally.
           */
          function _cancelAuction(uint _tokenId, address _seller) internal {
              _removeAuction(_tokenId);
      
              // Transfers the token owned by this contract to its original owner. It will throw if transfer fails.
              nonFungibleContract.transfer(_seller, _tokenId);
      
              AuctionCancelled(now, _seller, _tokenId);
          }
      
          /**
           * @dev Removes an auction from the list of open auctions.
           * @param _tokenId - ID of token on auction.
           */
          function _removeAuction(uint _tokenId) internal {
              delete tokenIdToAuction[_tokenId];
          }
      
          /**
           * @dev Returns current price of an token on auction. Broken into two
           *  functions (this one, that computes the duration from the auction
           *  structure, and the other that does the price computation) so we
           *  can easily test that the price computation works correctly.
           */
          function _computeCurrentPrice(Auction storage _auction) internal view returns (uint) {
              uint secondsPassed = 0;
      
              // A bit of insurance against negative values (or wraparound).
              // Probably not necessary (since Ethereum guarnatees that the
              // now variable doesn't ever go backwards).
              if (now > _auction.startedAt) {
                  secondsPassed = now - _auction.startedAt;
              }
      
              if (secondsPassed >= _auction.duration) {
                  // We've reached the end of the dynamic pricing portion
                  // of the auction, just return the end price.
                  return _auction.endingPrice;
              } else {
                  // Starting price can be higher than ending price (and often is!), so
                  // this delta can be negative.
                  int totalPriceChange = int(_auction.endingPrice) - int(_auction.startingPrice);
      
                  // This multiplication can't overflow, _secondsPassed will easily fit within
                  // 64-bits, and totalPriceChange will easily fit within 128-bits, their product
                  // will always fit within 256-bits.
                  int currentPriceChange = totalPriceChange * int(secondsPassed) / int(_auction.duration);
      
                  // currentPriceChange can be negative, but if so, will have a magnitude
                  // less that startingPrice. Thus, this result will always end up positive.
                  int currentPrice = int(_auction.startingPrice) + currentPriceChange;
      
                  return uint(currentPrice);
              }
          }
      
      
          /* ======== MODIFIERS ======== */
      
          /**
           * @dev Returns true if the token is on auction.
           * @param _auction - Auction to check.
           */
          function _isOnAuction(Auction storage _auction) internal view returns (bool) {
              return (_auction.startedAt > 0);
          }
      
      }
      
      
      contract HeroTokenAuction is HeroToken, ERC721DutchAuction {
      
          function HeroTokenAuction(uint _ownerCut) ERC721DutchAuction(this, _ownerCut) public { }
      
          /**
           * @dev Creates and begins a new auction.
           * @param _tokenId - ID of token to auction, sender must be owner.
           * @param _startingPrice - Price of item (in wei) at beginning of auction.
           * @param _endingPrice - Price of item (in wei) at end of auction.
           * @param _duration - Length of time to move between starting price and ending price (in seconds).
           */
          function createAuction(
              uint _tokenId,
              uint _startingPrice,
              uint _endingPrice,
              uint _duration
          ) whenNotPaused external {
              _approve(_tokenId, this);
      
              // This will perform all the checkings necessary.
              _createAuction(_tokenId, _startingPrice, _endingPrice, _duration, msg.sender);
          }
      
      }