<?php
defined( 'IN_WEB') or die( 'Include Error!');
class ModelAttack{
    const OutBFShieldQueue =1;
    const OutAllShieldQueue =2;
    const OutShieldQueue =3;
    public $cfg =[];
    public function __construct()
    {
        $this->cfg =  oo::cfg("stealattack")["attack"];
    }
    //================条件判别,状态获取更新===============
    /**
     * Notes:建筑条件检测
     * User: wsc
     * Time: 2021/7/28 11:08
     * @param $uid
     * @return bool
     */
    public function checkBuildDamaged($uid,$lv=-1){
        $userLevelData = oo::commonOprModel('member')->getUserLevel($uid);
        $levelId  = $userLevelData['levelId'];
        $maxLevel = intval(oo::commonOprModel('readconfig')->getCon('basic',"curMaxLevel"));
        $element = $userLevelData['element'];
        if ($lv!=-1&&$levelId!=$lv){//等级异常
            $this->OutAttackQueue($uid,$levelId,self::OutAllShieldQueue);
            $this->OutAttackQueue($uid,$lv,self::OutAllShieldQueue);
            oo::logs()->commlog(["uid"=>$uid,"newLevel"=>$levelId,"queueLevel"=>$lv],"attack/attack_error_level");
            return false;
         }
        if($levelId<=$this->cfg["minLv"]){//等级不足
            return false;
        }
        if($levelId >= $maxLevel){//最大等级且满25星不可打
            if(array_sum(array_column($element,'level')) == 25){
                return false;
            }
        }
        if(empty($element)||count($element)<5){ //没有岛,不进行攻击
            oo::logs()->debug3(['uid' => $uid, 'userLevelData' => $userLevelData],'checkbuilddmg_err');//写日志
            return false;
        }
        foreach ($element as $row){//存在大于1级的建筑,或等于一级未破损的建筑时返回建筑
            if($row['level'] > 1 || ($row['level'] == 1 && $row['status'] == 0)){
                return $userLevelData;
            }
        }
        return false;
    }

    /**
     * Notes:设置攻击次数
     * User: wsc
     * Time: 2021/7/28 11:14
     * @param $uid
     */
    public function setAttackLimit($uid){
        $dateKey= date("Ymd",time());
        $key = okeys::UserBeAttackLimit($dateKey,$uid);
        $limit = oo::commonOprRedis('common')->hIncrBy($key,$uid,1);
        $len = oo::commonOprRedis('common')->hLen($key);
        if($len<2){
            oo::commonOprRedis('common')->expire($key,oo::todayDeadline());
        }
        return $limit;
    }

    /**
     * Notes:获取攻击次数
     * User: wsc
     * Time: 2021/7/28 11:14
     * @param $uid
     */
    public function getAttackLimit($uid){
        $date= date("Ymd",time());
        $key = okeys::UserBeAttackLimit($date,$uid);
        $limit = oo::commonOprRedis('common')->hGet($key,$uid);
        return intval($limit);
    }

    /**
     * Notes:是否达到最大攻击次数
     * User: wsc
     * Time: 2021/7/28 12:37
     * @param $uid
     * @return bool
     */
    public function IsAtMaxAttackLimit($uid){
        if($this->cfg["maxLimit"]<=$this->getAttackLimit($uid)){
            return true;
        }
        return false;
    }

    /**
     * Notes:设置保护时间
     * User: wsc
     * Time: 2021/7/28 11:15
     * @param $uid
     * @param $time
     */
    public function setProtectTime($uid,$time){
        $now = time();
        $nowDay = date("Ymd",$now);
        $key = okeys::AttackProtectDayList($nowDay,$uid);
        $oldTime = oo::commonOprRedis("common")->hGet($key,$uid);
        if($oldTime>$now&&$time<($oldTime-$now)){//不做处理
            return true;
        }else{
            $ovTime = $now+$time;
        }
        $newDay = date("Ymd",$ovTime);//要设置的时间
        if($newDay>$nowDay){//跨天
            $key2 = okeys::AttackProtectDayList($newDay,$uid);
            oo::commonOprRedis("common")->hSet($key2,$uid,$ovTime);
            $nlen = oo::commonOprRedis('server')->hLen($key2);
            if($nlen<2){//第一次设置过期，减少数据堆积
                oo::commonOprRedis('server')->expireAt($key2,strtotime($newDay)+86400-1);
            }
        }
        oo::commonOprRedis("common")->hSet($key,$uid,$ovTime);
        $len = oo::commonOprRedis('server')->hLen($key);
        if($len<2){//第一次设置过期，减少数据堆积
            oo::commonOprRedis('server')->expireAt($key,strtotime($newDay)+86400-1);
        }
        return true;
    }

    /**
     * Notes:获取保护时间
     * User: wsc
     * Time: 2021/7/28 11:17
     * @param $uid
     * @return int
     */
    public function getProtectTime($uid){
        $date= date("Ymd",time());
        $key = okeys::AttackProtectDayList($date,$uid);
        $time = oo::commonOprRedis("common")->hGet($key,$uid);
        return intval($time);
    }

    /**
     * Notes:是否在保护中
     * User: wsc
     * Time: 2021/7/28 11:18
     * @param $uid
     * @return bool
     */
    public function IsProtect($uid){
        if($this->getProtectTime($uid)>time()){
            return true;
        }
        return false;
    }

    /**
     * Notes:是否被其他玩家锁定
     * User: wsc
     * Time: 2021/7/28 15:41
     * @param $uid
     * @return false
     */
    public function IsBeLock($uid){
        return oo::commonOprRedis('common')->get(okeys::beAttactLock($uid));//被锁定
    }

    /**
     * Notes:是否可被打判断
     * User: wsc
     * Time: 2021/7/28 15:43
     * @param $uid
     * @return bool
     */
    public function verifyIsPass($uid){
        if($this->IsBeLock($uid)){
            return false;
        }
        if($this->IsProtect($uid)){
            return false;
        }
        if($this->IsAtMaxAttackLimit($uid)){
            return false;
        }
        return true;
    }

    /**
     * Notes:设置仇人
     * User: wsc
     * Time: 2021/7/28 17:19
     * @param $uid
     * @param $toUid
     */
    function setEnemy($uid,$toUid,$type=1){
        if($type==1){
            $list = $this->getMyEnemyList($toUid);
            if(empty($list)||!in_array($uid,$list)){
                $key = okeys::NewEnemyUidList($toUid);
                oo::commonOprRedis('common')->zAdd($key,time(),$uid);
                oo::commonOprRedis('common')->expire($key,7*86400);
                $count = oo::commonOprRedis('common')->zSize($key);
                if($count>15){
                    oo::commonOprRedis('common')->zDeleteRangeByRank($key,0,$count-16);
                }
            }
        }else{
            $list = $this->getMyEnemyList($uid);
            if(in_array($toUid,$list)){
                oo::commonOprRedis('common')->zDelete(okeys::NewEnemyUidList($uid),$toUid);
            }
        }
    }


    /**
     * Notes:完成打后,关系处理
     * User: wsc
     * Time: 2021/7/28 17:24
     * @param $uid
     * @param $toUid
     * @param $toLevelId
     * @param $shieldNum
     * @param $sumTotal
     */
    public function SetAttackLog($uid,$toUid,$toLevelId,$shieldNum,$sumTotal){

        $friendList = oo::commonOprModel('friend')->getUserAllFriend($uid);
        $enemyList = $this->getMyEnemyList($uid);
        $filterArr = array_unique(array_merge($friendList,$enemyList));//过滤仇人及好友
        if(in_array($toUid,$filterArr)){
            $limit = $this->getAttackLimit($uid);
        }else{
            $limit = $this->setAttackLimit($toUid);
        }
        //非好友设置保护时间
//        if(!oo::commonOprModel('friend')->isfriend($uid,$toUid)){
            if($limit>=$this->cfg["proteCfg"]["changeProteTimeLimit"]){
                $time = $this->cfg["proteCfg"]["overChangeProteTimeLimit"];
            }else{
                $time = $this->cfg["proteCfg"]["beforeChangeProteTimeLimit"];
            }
            $this->setProtectTime($toUid,$time);
//        }

        //设置仇人关系
        $this->setEnemy($uid,$toUid,1);//为$toUid设置仇人
        $this->setEnemy($uid,$toUid,2);//为uid清理仇人

        //打池维护
        $this->OutAttackQueue($toUid,$toLevelId,self::OutAllShieldQueue);
        if($sumTotal>1){
            $this->JoinAttackQueue($toUid,$toLevelId,$shieldNum);
        }
    }

    //=======================攻击池维护======================
    /**
     * Notes:入攻击池
     * User: wsc
     * Time: 2021/7/28 16:12
     * @param $uid
     * @param $levelId
     * @param $shieldNum
     */
    public function JoinAttackQueue($uid,$levelId,$shieldNum){
        if(!$this->checkBuildDamaged($uid,$levelId)){
            $this->OutAttackQueue($uid,$levelId,self::OutAllShieldQueue);
            return false;
        }
        $key1 = okeys::AttackShieldBFList($levelId);
        $key2 = okeys::AttackShieldList($levelId);
        if(!$this->verifyIsPass($uid)){
            $this->OutAttackQueue($uid,$levelId, self::OutShieldQueue);
            oo::commonOprRedis("common")->zAdd($key1,$shieldNum,$uid);
            return false;
        }
        oo::commonOprRedis("common")->zDelete($key1,$uid);
        oo::commonOprRedis("common")->zAdd($key2,$shieldNum,$uid);
        return true;
    }

    /**
     * Notes:出攻击池
     * User: wsc
     * Time: 2021/7/28 16:12
     * @param $uid
     * @param $levelId
     * @param $type
     */
    public function OutAttackQueue($uid,$levelId,$type){
        $key1 = okeys::AttackShieldBFList($levelId);
        $key2 = okeys::AttackShieldList($levelId);
        switch ($type){
            case self::OutBFShieldQueue://
                oo::commonOprRedis("common")->zDelete($key1,$uid);
                break;
            case self::OutAllShieldQueue://用户升级用,用户没有建筑可打
                oo::commonOprRedis("common")->zDelete($key1,$uid);
                oo::commonOprRedis("common")->zDelete($key2,$uid);
                break;
            case self::OutShieldQueue://用户被打用,用户被锁定
                oo::commonOprRedis("common")->zDelete($key2,$uid);
                break;
        }
        return true;
    }

    /**
     * Notes:定时器维护攻击池
     * User: wsc
     * Time: 2021/7/28 16:19
     */
    public function TaskToJoinQueue(){
        $maxLevel = intval(oo::commonOprModel('readconfig')->getCon('basic',"curMaxLevel"));
        $robotList = oo::commonOprModel("robot")->getAllRobot();
        for($lv=4;$lv<=$maxLevel;$lv++){
            $list = oo::commonOprRedis('common')->zRevRange(okeys::AttackShieldBFList($lv),0,-1,true);
            if(!empty($list)){
                foreach ($list as $uid=>$shieldNum){
                    if(in_array($uid,$robotList)){
                        $this->OutAttackQueue($uid,$lv,2);
                        continue;
                    }
                    $this->JoinAttackQueue($uid,$lv,$shieldNum);
                }
            }
        }
    }
    //检测出队
    public function TaskToOutQueue($page){
        $maxLevel = intval(oo::commonOprModel('readconfig')->getCon('basic',"curMaxLevel"));
        $star = $page==1?4:($page-1)*10;
        if($star>$maxLevel){
            return false;
        }
        $maxLevel = $page*10<$maxLevel&&$page<10?$page*10:$maxLevel;
        $robotList = oo::commonOprModel("robot")->getAllRobot();
        $stime =oo::getMsectime();
        for($lv=$star;$lv<=$maxLevel;$lv++){
            $list = oo::commonOprRedis('common')->zRevRange(okeys::AttackShieldList($lv),0,-1,true);
            if(!empty($list)){
                foreach ($list as $uid=>$shieldNum){
                    if(in_array($uid,$robotList)){
                        $this->OutAttackQueue($uid,$lv,2);
                        continue;
                    }
                    $this->JoinAttackQueue($uid,$lv,$shieldNum);
                }
            }
        }
        $etime =oo::getMsectime();
        oo::logs()->commlog(["page"=>$page,"star"=>$star,"end"=>$maxLevel,"ts"=>($etime-$stime)/1000],"attack/TaskToOutQueue");
    }
    //=======================end======================

    //===========================获取攻击对象============================
    public function getSumTotal($element){
        $sumTotal =0;
        if(count($element)<5){
            return 0;
        }
        foreach ($element as $v){
            if(($v["status"]==0&&$v["level"]==1)||$v["level"]>1){
                $sumTotal+=$v["level"];
            }
        }
        return $sumTotal;
    }
    /**
     * Notes:获取机器人信息
     * User: wsc
     * Time: 2021/7/28 15:13
     * @return array
     */
    public function getRobotInfo($uid, $levelId = 0){
        $str = oo::commonOprRedis('common')->get(okeys::robotEnemyInfo($uid));
        $info =  $str ? (array)json_decode($str, true) : [];
        if(!empty($info)){
            return $info;
        }
        $levelId = $levelId?$levelId:max(oo::commonOprModel('member')->getUserLevelId($uid),4);
        $elemnet = [];
        $sumStar =0;
        for ($i=0;$i<5;$i++){
            $level = mt_rand(2,4);
            $one = [
                "id"=>$i+1,
                "level"=>$level,
                "maxLevel"=>mt_rand($level,5),
                "status"=>mt_rand(0,1)
            ];
            array_push($elemnet,$one);
            $sumStar += $level;
        }
        $sumStar +=mt_rand(10,100);
        $info = ['element' => $elemnet, 'levelId' => $levelId,"star"=>$levelId*25+$sumStar];
        $this->setUserAttackRobotInfo($uid, $info);
        return $info;
    }
    /**
     * Notes:获取仇人uidlist
     * User: wsc
     * Time: 2021/7/28 15:42
     * @param $uid
     * @return array [uid,....]
     */
    public function getMyEnemyList($uid){
        $list = oo::commonOprRedis("common")->zRevRange(okeys::NewEnemyUidList($uid),0,-1,true);
        if(empty($list)){
            $list = oo::commonOprRedis('common')->hGetAll(okeys::NewEnemyID($uid));//老板兼容,新版待删除
            if(!empty($list)){
                foreach ($list as $k=>$v){
                    oo::commonOprRedis("common")->zAdd(okeys::NewEnemyUidList($uid),$v,$k);
                }
                oo::commonOprRedis('common')->delete(okeys::NewEnemyID($uid));
            }
        }
        return array_keys($list);
    }

    /**
     * Notes:好友中获取攻击对象
     * User: wsc
     * Time: 2021/7/28 14:15
     * @param $uid
     * @return int
     */
    public function getAttackerFromFriend($uid){
        $toUid =0;
        $num =0;
        $friendList = oo::commonOprModel('friend')->getUserAllFriend($uid);
        foreach ($friendList as $fid){
            if($this->verifyIsPass($fid)&&$this->checkBuildDamaged($fid)){//过滤建筑不足,锁定,时间保护,次数保护 的用户
                $toUid = $fid;
                break;
            }
        }
        //同一好友最大每日被随机3次
        if($toUid!=0){
            $num = oo::commonOprRedis("common")->hIncrBy(okeys::userTadayAttackFriendLog($uid),$toUid,1);
            oo::commonOprRedis("common")->expire(okeys::userTadayAttackFriendLog($uid),oo::todayDeadline());
        }
        if ($num>3){
            return 0;
        }
        return (int)$toUid;
    }

    /**
     * Notes:复仇列表获取攻击对象
     * User: wsc
     * Time: 2021/7/28 14:14
     * @param $uid
     * @return int
     */
    public function getAttackerFromEnemyList($uid){
        $toUid =0;
        $enemyList  = $this->getMyEnemyList($uid);
        foreach ($enemyList as $eid){
            if($this->checkBuildDamaged($eid)&&!$this->IsAtMaxAttackLimit($eid)&&!$this->IsBeLock($eid)){//过滤建筑不足,次数保护,锁定 的用户
                $toUid = $eid;
                break;
            }
        }
        return (int)$toUid;
    }

    /**
     * Notes: 获取随机攻击对象
     * User: wsc
     * Time: 2021/7/28 14:50
     * @param $uid
     * @return int
     */
    public function getAttackerFromRandList($uid, $filterArr = []){
        $toUid =0;
        $levelId = oo::commonOprModel('member')->getUserLevelId($uid);
        $actionLevel    = oo::getActionLevel('attack',$levelId);
        $curMaxLevel    = oo::commonOprModel('config')->getCurMaxLevel();
        $actionMaxLevel = $actionLevel['max'];
        $min = $actionLevel['min'];
        $trueMax = min($curMaxLevel,$actionMaxLevel);
        $rand = rand(0,100);
        if($rand < 40){
            $max = $trueMax;
        }else if($rand < 85){
            $max = max(ceil($actionMaxLevel - $levelId/2),4);
        }else{
            $max = max($levelId - 5,4);
        }
        $lv2=4;
        for($lv=$max;$lv >= $min;$lv--){
            $cacheKey = okeys::AttackShieldList($lv);
            $ret = oo::commonOprRedis('User')->zRevRange($cacheKey,0,1,true);
            if(!empty($ret)&&is_array($ret)){
                foreach ($ret as $toUid2=>$v){
                    if($toUid2!=$uid && !in_array($toUid2, $filterArr)){
                        $toUid =  $toUid2;
                        $lv2 = $lv;
                        break;
                    }
                }
            }
            if($toUid){
                break;
            }
        }
        if($toUid&&!$this->checkBuildDamaged($toUid)){
            //不可打,直接出攻击池
            $this->OutAttackQueue($toUid,$lv2,self::OutAllShieldQueue);
            $toUid = 0;
        }
        return (int)$toUid;
    }
    //===============================end===============================

//=========================================================================
    /**
     * Notes:变更打对象
     * User: wsc
     * Time: 2021/7/28 22:05
     * @param $uid
     * @param $toUid
     */
    public function changeAttack($uid,$toUid){
        //获取原本绑定的默认攻击对象,是否也绑定自己
        $toUid2 = oo::commonOprRedis("common")->get(okeys::DefaultEnemy($uid));
        $isRobot = in_array($toUid2,oo::commonOprModel("robot")->getAllRobot());
        if(!$isRobot){
            $uid2=oo::commonOprRedis("common")->get(okeys::beAttactLock($toUid2));
            if($uid2==$uid){
                oo::commonOprRedis("common")->delete(okeys::beAttactLock($toUid2));
            }
        }
        oo::commonOprRedis("common")->setex(okeys::beAttactLock($toUid),$uid,3*60);
        oo::commonOprRedis("common")->setex(okeys::DefaultEnemy($uid),$toUid,3*60);
        return $isRobot;
    }

    public function getAttackerUid($uid,&$data){
        $toUid = oo::commonOprRedis("common")->get(okeys::DefaultEnemy($uid));
//        //优先取好友
        $randNum =mt_rand(1,100);
        if($toUid==0&&$randNum<=20) {
            $toUid = $this->getAttackerFromFriend($uid);
        }
//        //取仇人
//        if($toUid==0){
//            $toUid = $this->getAttackerFromEnemyList($uid);
//            if($toUid>0){
//                $data["isRevenge"]=1;
//            }
//        }
        //随机玩家
        if($toUid==0){//如果无好友
            $friendList = oo::commonOprModel('friend')->getUserAllFriend($uid);
            $enemyList = $this->getMyEnemyList($uid);
            $filterArr = array_unique(array_merge($friendList,$enemyList));//过滤仇人及好友
            $randUid = $this->getAttackerFromRandList($uid,$filterArr);
            if($randUid>0){
                $toUid = $randUid;
                oo::commonOprRedis("common")->setex(okeys::randAttacker($uid),$randUid,10*60);//设置随机攻击对象
            }
        }
//            var_dump("随机:",$toUid);

        $robotList = oo::commonOprModel("robot")->getAllRobot();
        if($toUid>0&&!$this->checkBuildDamaged($toUid)&&!in_array($toUid, $robotList)){//再次检查建筑
            $levelId = oo::commonOprModel('member')->getUserLevelId($toUid);
            $this->OutAttackQueue($toUid,$levelId,self::OutAllShieldQueue);
            $uid2 = oo::commonOprRedis('common')->get(okeys::beAttactLock($toUid));
            oo::commonOprRedis("common")->delete(okeys::DefaultEnemy($uid2));
            oo::commonOprRedis("common")->delete(okeys::beAttactLock($toUid));
            $toUid=0;
        }
        //机器人
        if($toUid==0){
            $toUid     = $robotList[array_rand($robotList,1)];
            $data['isRobot']   = 1;
            oo::commonOprRedis("common")->setex(okeys::randAttacker($uid),$toUid,20*60);//设置随机攻击对象
//            var_dump("机器人:",$toUid);
        }else{
            if(in_array($toUid, $robotList)){
                $data['isRobot'] = 1;
                oo::commonOprRedis("common")->setex(okeys::randAttacker($uid),$toUid,20*60);//设置随机攻击对象
            }
        }
        oo::commonOprRedis("common")->setex(okeys::DefaultEnemy($uid),$toUid,10*60);
        return (int)$toUid;
    }
    /**
     * Notes:获取默认攻击对象详细信息
     * User: wsc
     * Time: 2021/7/28 11:11
     * @param $uid
     * @return array
     */
    public function getDefaultAttackerInfo($uid,$levelId,$multiple,$toUid2=0,$isRobot=0){
        $data = [];

        $data['isRobot'] =$isRobot?$isRobot:0;
        $data['isRevenge']=0;
        if(!$toUid2){
            $toUid  = $this->getAttackerUid($uid,$data);
        }else{
            $toUid  = $toUid2;
        }

        if($data['isRobot']){
            $info            = $this->getRobotInfo($uid);
            $data['element'] = $info['element'];
            $data['levelId'] = $info['levelId'];
        }else{
            $levelInfo=oo::commonOprModel('member')->getUserLevel($toUid);
            $data["levelId"] = $levelInfo['levelId'];
            $data['element'] = $levelInfo['element'];
        }
        $sumTotal = $this->getSumTotal($data['element']);

        if($sumTotal<1&&$toUid2==0){//防止意外空建筑
            $data['element'] =$this->getRobotInfo($uid)["element"];
        }

        $userInfo = oo::commonOprModel("member")->getUserBasic($toUid);
        $data['nick']   = oo::commonOprModel('member')->getUserFirstName($userInfo['nick']);
        $data['s_picture'] = $userInfo['s_picture'];
        $data['vip']    = $userInfo['vip'];
        $data['vipLv']  = $userInfo['vipLv'];
        $data['u_flag'] = $userInfo['u_flag'];
        $data['avatar'] = $userInfo['avatar'];
        $data['shield'] = $userInfo['shield'];
        $data['isRobot'] = $userInfo['isRobot'];
        $data["toUid"] = $toUid;
        $data["uid"] = $toUid;
        $data["star"] = $userInfo["star"];

        $userPetSkill = oo::commonOprModel('pet')->usePetSkill($uid,3,1);     //攻击技能
        $userPetSkill && oo::commonOprRedis('usercache')->setex(okeys::PetSkill($uid, 3),1,5*60);
        if(!$data['isRobot']&&!in_array($toUid,oo::commonOprModel("robot")->getAllRobot())){
            oo::commonOprRedis("common")->setex(okeys::beAttactLock($toUid),$uid,3*60);
            $this->OutAttackQueue($toUid,$data["levelId"],self::OutShieldQueue);
            $this->JoinAttackQueue($toUid,$data["levelId"],$data['shield']);

            $toUserPetSkill = oo::commonOprModel('pet')->usePetSkill($toUid, 2); //防御技能
            if ($toUserPetSkill){
                oo::commonOprRedis('usercache')->setex(okeys::PetSkill($toUid, 2),1,5*60);
                $data['shield'] =1;
            }
        }else{
            $data["star"] =$info["star"];
        }
        oo::commonOprRedis("common")->setex(okeys::attackShieldCache($toUid),intval($data['shield']),3*60);

        $attackAwardCfg = oo::commonOprModel("config")->getAttackCoinConfig($levelId);
        $data['defenseCoins'] = intval($attackAwardCfg['shield'])*$multiple;
        $data['attackCoins'] = intval($attackAwardCfg['no_shield'])*$multiple;
        $data['userPetSkill']   = $userPetSkill ? 1 : 0;
        $data['toUserPetSkill'] = intval($toUserPetSkill);
        return $data;
    }

    /**
     * 设置玩家打机器人默认信息
     * @param int $uid 玩家uid
     * @param int $info 机器人建筑信息
     * @return bool
     */
    public function setUserAttackRobotInfo($uid, array $info) {
        return oo::commonOprRedis('common')->setex(okeys::robotEnemyInfo($uid), json_encode($info), 10*60); 
    }

    public function getRandUid($uid){
        $randUid = oo::commonOprRedis("common")->get(okeys::randAttacker($uid));
        if(!$randUid){
            $robotList = oo::commonOprModel("robot")->getAllRobot();
            $randUid     = $robotList[array_rand($robotList,1)];
            oo::commonOprRedis("common")->setex(okeys::randAttacker($uid),$randUid,20*60);//设置随机攻击对象
            $this->getRobotInfo($uid);
            oo::commonOprRedis("common")->setex(okeys::DefaultEnemy($uid),$randUid,20*60);
        }
        return intval($randUid);
    }

    /**
     * Notes:获取满足条件的复仇列表
     * User: wsc
     * Time: 2021/7/28 14:17
     * @param $uid
     * @return array [uid,...]
     */
    public function getEnemyList($uid){
        $data= [];
        $uidList =[];
        $randUid = $this->getRandUid($uid);
        $enemyList  = $this->getMyEnemyList($uid);
//        rsort($enemyList);
        foreach ($enemyList as $eid){
            //if($this->checkBuildDamaged($eid)&&!$this->IsAtMaxAttackLimit($eid)&&!$this->IsBeLock($eid)){ //建筑满足,攻击次数满足
            if(!$this->IsAtMaxAttackLimit($eid)&&!$this->IsBeLock($eid)){ //建筑满足,攻击次数满足
                $uidList[] = $eid;
            }
            if(count($uidList)>=10){//复仇列表只显示10人
                break;
            }
        }
        if(!in_array($randUid,$uidList)){
           array_unshift($uidList,$randUid);
        }
        //如果仇人列表只有1个且为自己好友时,也添加一个随机对象
        if(empty($uidList)||(count($uidList) == 1 && oo::commonOprModel('friend')->isFriend($uid, $uidList[0]))){
            //$eUid = $this->getAttackerFromRandList($uid, [$uidList[0]]);
            //if(empty($eUid)){
                $robotList = oo::commonOprModel("robot")->getAllRobot();
                $eUid     = $robotList[array_rand($robotList,1)];
            //}
            $eUid && $uidList[] = (int)$eUid;
        }
        return $uidList;
    }

    /**
     * Notes:获取攻击好友列表
     * User: wsc
     * Time: 2021/7/28 14:40
     * @param $uid
     * @return array [uid=>是否保护,...]
     */
    public function getAttackerFriendList($uid){
        $uidList = [];
        $friendList = oo::commonOprModel('friend')->getUserAllFriend($uid);
        foreach ($friendList as $fid){
            $lv = oo::commonOprModel('member')->getUserLevelId($fid);
            if($lv>$this->cfg["minLv"]){
                $uidList[$fid] = intval($this->getProtectTime($fid));
//                if($this->IsAtMaxAttackLimit($fid)){
//                    $uidList[$fid] = timeFuns::today()[1];
//                }
            }
        }
        return $uidList;
    }

    /**
     * Notes:发起打
     * User: wsc
     * Time: 2021/7/28 17:25
     * @param $uid
     * @param $toUid
     */
    public function ToAttack($uid,$toUid,$attId){
        if(intval(oo::commonOprRedis('usercache')->get(okeys::slotTypeLimit(4,$uid)))<=0){
            oo::logs()->debug3(["ts"=>date('Y-m-d H:i:s'),"uid"=>$uid,"toUid"=>$toUid,"err"=>"没有转直接打"],'attackerr.log');
            return ['code' => -1, 'msg' => 'Please stop doing it wrong','data'=>[]];
        }
        oo::commonOprRedis('usercache')->set(okeys::slotTypeLimit(4,$uid),0);
        $bet = intval(oo::commonOprRedis('usercache')->get(okeys::curUserBet($uid)));
        $bet = $bet?$bet:1;
        $isRobot =false;
        $dataAbnormal = false;//是否有效打真人
        $userPetSkill = false;//攻击发起者的攻击宠物状态
        $toUserPetSkill = false;//被打人的防御宠物状态
        $msgType=0;
        $toUidLevelInfo = oo::commonOprModel('member')->getUserLevel($toUid);
        $toUidUserInfo = oo::commonOprModel('member')->getUserAssetsInfo($toUid);
        $userElement = $toUidLevelInfo['element'];
        $ElementOne = &$userElement[$attId-1];
        $sumTotal = $this->getSumTotal($userElement);

        $myUserInfo= oo::commonOprModel('member')->getUserBasic($uid);
        $attackAwardCfg = oo::commonOprModel("config")->getAttackCoinConfig($myUserInfo['levelId']);
        $baseNumber = $attackAwardCfg['shield'];

        //打机器人
        $robotList = oo::commonOprModel("robot")->getAllRobot();
        if(in_array($toUid,$robotList)){
            $isRobot = true;
            oo::commonOprRedis('common')->delete(okeys::robotEnemyInfo($uid));
            $dataAbnormal =true;
        }
        //打对象建筑异常
        if($sumTotal==0||($ElementOne["level"]==1&&$ElementOne["status"]==1)||$ElementOne["level"]<1){
            $dataAbnormal =true;
            $this->OutAttackQueue($toUid,$ElementOne["level"],self::OutAllShieldQueue);
            $this->OutAttackQueue($toUid,$ElementOne["level"]-1,self::OutAllShieldQueue);
        }
        //被打对象锁定的玩家不是uid
        $uid2  =oo::commonOprRedis('common')->get(okeys::beAttactLock($toUid));
        if($uid2!=$uid){
            $dataAbnormal =true;
        }
        //宠物
        $res1 = oo::commonOprRedis('usercache')->get(okeys::PetSkill($uid, 3));
        if($res1){
            $userPetSkill = true;
            oo::commonOprRedis('usercache')->delete(okeys::PetSkill($uid, 3));
        }
        if(!$dataAbnormal){
            $res2 = oo::commonOprRedis('usercache')->get(okeys::PetSkill($toUid, 2));
            if($res2){
                $toUserPetSkill = true;
                oo::commonOprRedis('usercache')->delete(okeys::PetSkill($toUid, 2));
            }
        }
        if(!$dataAbnormal){
            if($toUserPetSkill){//防御宠物
                $ext = "打中防御宠物获得的金币奖励:{$toUid}";
                $toUidpetGetExp =  oo::commonOprModel('pet')->addUserPetExpBy($toUid,2,"defenseAddExp",1,122,'防御宠物触发');

            }else if(intval($toUidUserInfo["shield"])>=1){//有盾牌,打盾牌
                $ext = "摧毁盾牌获得的金币奖励:{$toUid}";
                oo::commonOprModel('member')->optProperty($toUid,array('shield'=>1),'-',6,'防御攻击扣除盾牌:'.$uid);
            }else{//打建筑
                $ext ="摧毁建筑获得的金币奖励:{$toUid}";
                if($ElementOne['status'] == 1){
                    $ElementOne['level'] = max($ElementOne['level'] - 1,1);
                }else{
                    $ElementOne['status']=1;
                }
                oo::commonOprModel('member')->setUserLevel($toUid,$toUidLevelInfo['levelId'],$userElement);
                oo::commonOprModel('member')->optProperty($toUid,array('star'=>1),'-',6,'建筑被损毁损失星星:'.$uid);
            }
        }else{
            $ext ="摧毁机器人或系统保护盾牌获得的金币奖励:{$toUid}";
        }
        $cacheShield=oo::commonOprRedis("common")->get(okeys::attackShieldCache($toUid));
        if(intval($cacheShield)>0){
            $data["data"]["shield"] =1;//有盾
            $data["data"]["type"] =0;//打盾
            $msgType =2;
            $rid = 3;
            $attackType = 2;//攻击类型2打盾1打建筑
        }else{
            $data["data"]["shield"] =0;//无盾
            $data["data"]["type"] =2;//打建筑
            $baseNumber = $attackAwardCfg['no_shield'];
            $rid = 2;
            $attackType =1;
            $msgType=3;
        }
        oo::commonOprRedis("common")->delete(okeys::attackShieldCache($toUid));

        $coins = $baseNumber*$bet;
        oo::commonOprRedis('User')->setex(okeys::LastAttackCoinsNum($uid),$coins,2*60*60);//设置广告加倍条件
        //=====攻击发起者奖励发放=====
        //发金币
        oo::commonOprModel('member')->optProperty($uid,array('money'=>$coins),'+',$rid,$ext);

        //宠物效果
        if($userPetSkill){
            $petAddRate=oo::commonOprModel('pet')->usePetSkill($uid,3,1);
            $userPetSkillNum = intval(strval($coins*($petAddRate)));
            //宠物加成金币
            if($userPetSkillNum > 0){
                $userPetSkill = true;
                oo::commonOprModel('member')->optProperty($uid,array('money'=>$userPetSkillNum),'+',2,'攻击宠物技能获得金币');
                $data['data']['petCoins'] = $userPetSkillNum;
            }
            //宠物得经验
            $data['data']['petGetExp']= oo::commonOprModel('pet')->addUserPetExpBy($uid,3,$attackType == 1?"attackAddExp":"defenseAddExp",$bet,122,"打宠物触发");
            //通行证活动-任务6
            oo::commonOprModel('activitynew')->addTrafficPermitNum($uid,6,$bet);
        }
        //vip金币加成倍率
        $vipRate = oo::commonOprModel('newvip')->vipRewardConf($uid,'attackCoinsPro');
        $data['data']['vipCoins'] = intval($vipRate * $coins);
        if($data['data']['vipCoins'] > 0){
            oo::commonOprModel('member')->optProperty($uid,['money'=>$data['data']['vipCoins']],'+',353,"VIP加成：攻击 {$toUid}");
        }
        //金币大爆炸金币加成倍率
        $blastRate = oo::commonOprModel('activitynew')->getCoinBlastBetByType($uid,'attack');
        $data['data']['coin_blast_Coins'] = intval(strval((1+$vipRate+$petAddRate)*$coins*$blastRate));
        if($data['data']['coin_blast_Coins']>0){
            oo::commonOprModel('member')->optProperty($uid,array('money'=>$data['data']['coin_blast_Coins']),'+',219,"攻击 {$toUid}");
        }

        //收集排行榜活动
        $symbol =$AcRankData=false;
        $retData =oo::commonOprModel('activitynew')->setRateByDo($uid,'attack',$attackType,$bet);
        if(isset($retData['collectNum'])){
            $symbol = oo::commonOprModel('activitynew')->getUserActData($uid,'super_collect');
        }
        $data['data']['symbol'] = $symbol;
        if(isset($retData['rankCollectNum'])) {
              $AcRankData=oo::commonOprModel('activitynew')->getUserActData($uid, 'rank');
        }
        $data['data']['AcRankData'] = $AcRankData;
        $data['data']['AcRankNoProData'] =  oo::commonOprModel('activitynew')->getUserActData($uid,'rank2');

        //通行证活动
        $data['data']['trafficPermit'] = oo::commonOprModel('activitynew')->getUserActData($uid,'traffic_permit');
        //|-任务4
        oo::commonOprModel('activitynew')->addTrafficPermitNum($uid,4,$bet);

        //=========================

        //清理缓存
        $uid2 = oo::commonOprRedis("common")->get(okeys::beAttactLock($toUid));
        if($uid2==$uid){
            oo::commonOprRedis("common")->delete(okeys::beAttactLock($toUid));
        }
        oo::commonOprRedis("common")->delete(okeys::DefaultEnemy($uid));//删除默认攻击对象
        oo::commonOprRedis("common")->delete(okeys::randAttacker($uid));//删除随机攻击对象
        if(!$isRobot){
            //设置关系-仇人,保护次数,保护时间,池子维护
            $this->SetAttackLog($uid,$toUid,$toUidLevelInfo["levelId"],$toUidUserInfo["shield"],$sumTotal);
        }
        //==========================
        $data['data']['userPetSkill']   = $userPetSkill?1:0;
        $data['data']['toUserPetSkill'] = $toUserPetSkill?1:0;
        //获取当前用户的最终金币
        $userAssetsInfo = oo::commonOprModel('member')->getUserAssetsInfo($uid);
        $data['data']['lastCoins'] = intval($userAssetsInfo['money']);

        //消息发送
        if(!$dataAbnormal){
            $nick = oo::commonOprModel('member')->getUserFirstName($myUserInfo['nick']);
            oo::commonOprModel('Workerman')->push($toUid,ocmd::$SVR_SELF_ATTACK_MESSAGE,[
                'attId'    =>$attId,
                'freeEnd'  =>0,
                'nick'     =>$nick,
                'vip'      =>$myUserInfo['vip'],
                'vipLv'    =>$myUserInfo['vipLv'],
                'vipExpire'=>$myUserInfo['vip_expire'],
                'avatar'   =>intval($myUserInfo['avatar']),
                'u_flag'   =>$myUserInfo['u_flag'],
                'url'      =>$myUserInfo['s_picture'],
                'shield'   =>intval($myUserInfo['shield']),
                'isDefense'=>intval($msgType),
                'star'     =>intval($myUserInfo['star']),
            ]);
            $s_picture = $myUserInfo['s_picture'];
            oo::commonOprModel('message')->addMessage($toUid,$uid,$nick,$s_picture,0,$msgType,1,['petGetExp'=>$toUidpetGetExp]);
            if($msgType==3){
                oo::commonOprModel('push')->pushNews($toUid,'push.title.attack','push.content.attack', [$nick],'attack');
            }
        }

        //数数事件--完成打
        $isFriend = oo::commonOprModel('friend')->isfriend($uid,$toUid);
        $petInfo = oo::commonOprModel('pet')->getUserPet($uid,3);
        $attack_pet_remain_time =intval($petInfo['feedEffecteTime'])>time()?$petInfo['feedEffecteTime']-time():0;
        $ssEventData =[
            "attack_target_user"=>$toUid,
            "attack_relation"=>$isFriend?3:($isRobot?1:2),
            "attack_result"=>intval($attackType),
            "attack_bet"=>intval($bet),
            "attack_collect_symbol"=>intval($retData["collectNum"]),
            "attack_rank_symbol"=>intval($retData['rankCollectNum']),
            "attack_coin_basic"=>$baseNumber,
            "attack_coin_final"=>$coins+intval($userPetSkillNum)+intval($data['data']['vipCoins'])+intval($data['data']['coin_blast_Coins']),
            "attack_pet_remain_time"=>$attack_pet_remain_time,
            "attack_pet_level"=>intval($petInfo['lv']),
        ];
        oo::commonOprModel('ta')->setEventData($uid,'attack',$ssEventData);
//        $data["data"]["baseCoins"] = $baseNumber;
        $data["data"]['getCoins']=$coins;
        $data["data"]['lastshield']=$userAssetsInfo["shield"];
        $data["code"]=1;
        return $data;
    }

}
