diff --git a/doc/User.py b/doc/User.py index 565ad438..b01bf828 100644 --- a/doc/User.py +++ b/doc/User.py @@ -32,21 +32,32 @@ class User(object): ] }, { - 'name': 'activate', + 'name': 'beforeActive', 'desc': '激活用户', 'group': 'User', + 'url': 'webapp/index.php?c=User&a=beforeActive', + 'params': [ + _common.ReqHead(), + ], + 'response': [ + _common.RspHead(), + ['!before', [ ['hero','','英雄信息'],['gun','','枪械信息'],['bceg_max','','最高bceg'],['bceg','','实际bceg'] ],'转换前'], + ['!after', [ ['hero','','英雄信息'],['gun','','枪械信息'],['ceg','','ceg'] ], '转换后'], + ['cost', 0, '所需手续费'], + ] + },{ + 'name': 'activate', + 'desc': '激活用户(免费转NFT)', + 'group': 'User', 'url': 'webapp/index.php?c=User&a=activate', 'params': [ _common.ReqHead(), - ['name', 0, '昵称'], - ['name_sign', '', '名字签名'], - ['sex', 0, '性别'], - ['head_id', 0, '头像id'], - ['head_frame', 0, '头像框'], - ['hero_id', 0, '试用的英雄id'], + ['hero_uniid', 0, '英雄唯一id'], + ['gun_uniid', '', '枪械唯一id'], ], 'response': [ _common.RspHead(), + ['!data', [ ['hero_id','','英雄id'],['gun_id','','枪械id'],['ceg','','ceg'] ], '激活成果'], ['property_chg', _common.PropertyChg(), '属性变更'], ] }, diff --git a/sql/gamedb.sql b/sql/gamedb.sql index 9c8d7790..7f993221 100644 --- a/sql/gamedb.sql +++ b/sql/gamedb.sql @@ -41,6 +41,7 @@ CREATE TABLE `t_user` ( `score` int(11) NOT NULL DEFAULT '0' COMMENT '积分', `history_best_score` int(11) NOT NULL DEFAULT '0' COMMENT '历史最高积分', `elo` int(11) NOT NULL DEFAULT '0' COMMENT '隐藏ELO积分', + `bceg` double NOT NULL DEFAULT '0' COMMENT '中心化代币', `gold` double NOT NULL DEFAULT '0' COMMENT '金币', `diamond` double NOT NULL DEFAULT '0' COMMENT '钻石', `hero_id` int(11) NOT NULL DEFAULT '0' COMMENT '当前上阵英雄id', diff --git a/webapp/controller/UserController.class.php b/webapp/controller/UserController.class.php index 242fdf0d..78fb398f 100644 --- a/webapp/controller/UserController.class.php +++ b/webapp/controller/UserController.class.php @@ -13,6 +13,8 @@ require_once('mt/RankSeason.php'); require_once('mt/Hero.php'); require_once('mt/Rank.php'); require_once('mt/Item.php'); +require_once('mt/PveGeminiMode.php'); +require_once('mt/PveGemini.php'); require_once('services/AwardService.php'); require_once('services/PropertyChgService.php'); @@ -277,78 +279,119 @@ class UserController extends BaseAuthedController { $this->_addItems($addItems, $awardService, $propertyChgService); } + public function beforeActive(){ + $userInfo = $this->_getOrmUserInfo(); + $hero = Hero::getFreeHero(); + if (!$hero){ + $this->_rspErr(1, "No free heroes"); + return; + } + $gun = Gun::getFreeGun(); + if (!$gun){ + $this->_rspErr(1, "No free weapons"); + return; + } + + $paramMeta = mt\Parameter::getByName('bceg_max'); + $bceg_max = $paramMeta?$paramMeta['param_value']:3720; + $before = array( + 'hero' =>$hero, + 'gun' =>$gun, + 'bceg_max' => $userInfo['bceg'], + 'bceg' => min($userInfo['bceg'],$bceg_max) + ); + $after = array( + 'hero' =>$hero, + 'gun' =>$gun, + 'ceg' => min($userInfo['bceg'],$bceg_max) + ); + $cost = 0; + $cost += \services\FormulaService::Calc_Hero_Convert_Cost($hero); + $cost += \services\FormulaService::Calc_Weapon_Convert_Cost($hero); + $cost += \services\FormulaService::Calc_BCEG_Convert_Cost($userInfo['bceg']); + $this->_rspData(array( + 'before' => $before, + 'after' => $after, + 'cost' => $cost, + )); + } + public function active() { - $name = getReqVal('name', ''); - $nameSign = getReqVal('name_sign', ''); - $sex = getReqVal('sex', 0); - $headId = getReqVal('head_id', 0); - $headFrame = getReqVal('head_frame', 0); - $heroId = getReqVal('hero_id', 0); + + $hero_uniid = getReqVal('hero_uniid', 0); + $gun_uniid = getReqVal('gun_uniid', 0); $userInfo = $this->_getOrmUserInfo(); if ($userInfo['activated']) { - $this->_rspErr(10, 'Activated'); + $this->_rspErr(10, 'User Activated'); return; } - $nameService = new services\NameService(); - if (!$nameService->verifyNameSign($name, $nameSign)){ - $this->_rspErr(1, 'Signature verification failed'); + $heroDb = Hero::find($hero_uniid); + if (!$heroDb || !empty($heroDb['token_id'])) { + $this->_rspErr(1, 'Parameter error, illegal hero_uniid'); return; } - if ($nameService->nameUsed($name)){ - $this->_rspErr(2, 'Name already occupied'); + $gunDb = Gun::find($gun_uniid); + if (!$gunDb || !empty($gunDb['token_id'])) { + $this->_rspErr(1, 'Parameter error, illegal gun_uniid'); return; } - if (!isValidSex($sex)) { - $this->_rspErr(1, 'Parameter error, illegal sex'); - return; - } - if (!User::isValidHeadId($userInfo, $headId)) { - $this->_rspErr(1, 'Parameter error, illegal head_id'); - return; - } - if (!User::isValidHeadFrame($userInfo, $headFrame)) { - $this->_rspErr(1, 'Parameter error, illegal head_frame'); - return; - } - $heroMeta = mt\Hero::get($heroId); - if (!$heroMeta) { - $this->_rspErr(1, 'Parameter error, illegal hero_id'); - return; - } - $heroCfg = null; { - $list = mt\Parameter::parseList('creator_present_player', array('|', ':')); - foreach ($list as $item) { - if ($item[0] == $heroId) { - $heroCfg = $item; - break; - } - } - if (!$heroCfg || $heroCfg[1] <= 0) { - $this->_rspErr(1, 'Parameter error, illegal hero_id'); - return; - } - } - if (!$nameService->useName($name)) { - $this->_rspErr(2, 'Name already occupied'); - return; + //转换NFT的手续费(U) + $cost = 0; + $cost += \services\FormulaService::Calc_Hero_Convert_Cost($heroDb); + $cost += \services\FormulaService::Calc_Weapon_Convert_Cost($gunDb); + $cost += \services\FormulaService::Calc_BCEG_Convert_Cost($userInfo['bceg']); } + $paramMeta = mt\Parameter::getByName('bceg_max'); + $bceg = $paramMeta?$paramMeta['param_value']:3720; + $ceg = min($bceg,$userInfo['bceg']); $this->_updateUserInfo(array( - 'name' => $name, - 'sex' => $sex, - 'head_id' => $headId, - 'head_frame' => $headFrame, 'activated' => 1, - 'rename_count' => function () { - return 'rename_count + 1'; + 'bceg' => 0, + 'gold' => function () use($ceg) { + return "gold + {$ceg}"; } )); - Hero::addTryHero($heroMeta, $heroCfg[1]); + $hero_token_id = Nft::addNft(\mt\Item::get($heroDb['hero_id'])); + Hero::update($heroDb['idx'],array( + 'token_id'=>$hero_token_id + )); + +// $gun_token_id = Nft::addNft(\mt\Item::get($gunDb['gun_id'])); +// Gun::update($gunDb['idx'],array( +// 'token_id'=>$gun_token_id +// )); + $gun_token_id = myself()->_getNowTime()+2; + $tokenType = Nft::getTokenType(\mt\Item::get($gunDb['gun_id'])); + SqlHelper::insert( + myself()->_getMarketMysql(), + 't_nft', + array( + 'token_id' => $gun_token_id, + 'token_type' => $tokenType, + 'game_id' => 2006, + 'item_id' => \mt\Item::get($gunDb['gun_id'])['id'], + 'owner_address' => myself()->_getOpenId(), + 'createtime' => myself()->_getNowTime(), + 'modifytime' => myself()->_getNowTime(), + ) + ); + Gun::update($gunDb['idx'],array( + 'token_id'=>$gun_token_id + )); + $propertyChgService = new services\PropertyChgService(); $propertyChgService->addUserChg(); + $propertyChgService->addHeroChg(); + $propertyChgService->addGunChg(); $this->_rspData(array( + 'data'=>array( + 'hero_id' => $heroDb['hero_id'], + 'gun_id' => $gunDb['gun_id'], + 'ceg' => $ceg, + ), 'property_chg' => $propertyChgService->toDto() )); } diff --git a/webapp/models/Gun.php b/webapp/models/Gun.php index 90be30a3..77f6ac43 100644 --- a/webapp/models/Gun.php +++ b/webapp/models/Gun.php @@ -528,4 +528,14 @@ class Gun extends BaseModel { return 0; } + public static function getFreeGun(){ + $gun = array(); + Gun::getGunList(function ($row) use (&$gun) { + if (!$row['token_id']) { + $gun = $row; + } + }); + return $gun; + } + } diff --git a/webapp/models/Hero.php b/webapp/models/Hero.php index dce080b6..d76d9415 100644 --- a/webapp/models/Hero.php +++ b/webapp/models/Hero.php @@ -571,5 +571,14 @@ class Hero extends BaseModel { return $attrPro2; } + public static function getFreeHero(){ + $hero = array(); + Hero::getHeroList(function ($row) use (&$hero) { + if (!$row['token_id']) { + $hero = $row; + } + }); + return $hero; + } } diff --git a/webapp/services/FormulaService.php b/webapp/services/FormulaService.php index 24014355..dcb4ad9c 100644 --- a/webapp/services/FormulaService.php +++ b/webapp/services/FormulaService.php @@ -320,7 +320,8 @@ class FormulaService extends BaseService { /**一个玩家的赛后积分 = 赛前积分+K*(胜负率-总胜率)+2K*(表现分-段位要求的及格分)*/ //胜负率=1-(排名-1)/(最大排名-1) $ranked = getXVal($params, 'ranked'); - $maxRanked = mt\Parameter::getByName('rank_order_max')['param_value']; //************** parameter 参数表获取 ************ + $meta1 = mt\Parameter::getByName('rank_order_max'); + $maxRanked = $meta1 ? $meta1['param_value'] : 40; //************** parameter 参数表获取 ************ $winRate = 1-($ranked-1)/($maxRanked-1); //总胜率=70%*P(个人ELO值-敌队平均ELO值)+30%*P(己队平均ELO值-敌队平均ELO值) --> P(D)=1/(1+10^(-D/400)) $winRateSum = 1; @@ -339,7 +340,8 @@ class FormulaService extends BaseService { $topRanking = mt\Rank::getRankById($userDb['rank'])['rank_order']; //************** rankRank 参数表获取 ************ $askedScore = round(1-($topRanking-1)/(10-1),2); //一个玩家的赛后积分 = 赛前积分+K*(胜负率-总胜率)+2K*(表现分-段位要求的及格分) - $K = mt\Parameter::getByName('rank_k')['param_value']; //************** parameter 参数表获取 ************ + $meta2 = mt\Parameter::getByName('rank_k'); + $K = $meta2 ? $meta2['param_value'] : 30; //************** parameter 参数表获取 ************ $battleAfterScore = $userDb['score'] + $K * ($winRate-$winRateSum) + (2*$K) * ($expreScore-$askedScore); return round($battleAfterScore); } @@ -348,11 +350,13 @@ class FormulaService extends BaseService { /**一个玩家的赛后ELO值 = MAX(赛前ELO值+K*(胜负率-总胜率),150)*/ //胜负率=1-(排名-1)/(最大排名-1) $ranked = getXVal($params, 'ranked'); - $maxRanked = mt\Parameter::getByName('rank_order_max')['param_value']; //************** parameter 参数表获取 ************ + $meta1 = mt\Parameter::getByName('rank_order_max'); + $maxRanked = $meta1 ? $meta1['param_value'] : 40; //************** parameter 参数表获取 ************ $winRate = 1-($ranked-1)/($maxRanked-1); //总胜率=70%*P(个人ELO值-敌队平均ELO值)+30%*P(己队平均ELO值-敌队平均ELO值) --> P(D)=1/(1+10^(-D/400)) $winRateSum = 1; - $K = mt\Parameter::getByName('rank_k')['param_value']; //************** parameter 参数表获取 ************ + $meta2 = mt\Parameter::getByName('rank_k'); + $K = $meta2 ? $meta2['param_value'] : 30; //************** parameter 参数表获取 ************ return round(max($userDb['elo']+$K*($winRate-$winRateSum),150)); } @@ -748,4 +752,31 @@ class FormulaService extends BaseService { $day = 1; return round(max(round(2-0.2/30*$day,3)/round(1+0.04*$grand,3),1)*max(($day<=180?1:0)*1+($day>180?1:0)*pow(0.9987,$day-180),0.9),3); } + + //CEG锚定U的价格 + public static function CEG_Anchor_Price(){ + //ROUND(CEG_Dynamic_Price * CEG_Discount_Rate,3) + return round(self::CEG_Dynamic_Price()*self::CEG_Discount_Rate(),3); + } + + //英雄NFT转化公式:(以U为计价单位) + public static function Calc_Hero_Convert_Cost($hero){ + //英雄NFT手续费=[200*( CEG_Anchor_Price)+43*ROUND(0.08*英雄阶数*(英雄阶数+1)*(英雄阶数+2)/3+(英雄阶数-2)+SIGN(英雄阶数=4),0)*0.1*50%] + return 200*(self::CEG_Anchor_Price())+43*round(0.08*$hero['hero_lv']*($hero['hero_lv']+1)*($hero['hero_lv']+2)/3+($hero['hero_lv']-2)+($hero['hero_lv']==4?1:0),0)*0.1*0.5; + } + //枪械NFT转化公式:(以U为计价单位) + public static function Calc_Weapon_Convert_Cost($gun){ + //枪械NFT手续费=[60*(CEG_Anchor_Price)+ROUND(43*0.6*ROUND(0.08*枪械阶数*(枪械阶数+1)*( 枪械阶数+2)/3+(枪械阶数-2)+SIGN(枪械阶数=4),0),0)*0.1*50%] + return 60*(self::CEG_Anchor_Price())+round(43*0.6*round(0.08*$gun['gun_lv']*($gun['gun_lv']+1)*($gun['gun_lv']+2)/3+($gun['gun_lv']-2)+($gun['gun_lv']==4?1:0),0),0)*0.1*0.5; + } + //BCEG转化CEG公式(以U为计价单位) + public static function Calc_BCEG_Convert_Cost($bceg){ + //BCEG手续费=MIN(BCEG数量,3720)* CEG_Conversion_Percentage * CEG_Dynamic_Price + $paramMeta1 = mt\Parameter::getByName('bceg_max'); + $bceg_max = $paramMeta1 ? $paramMeta1['param_value'] : 3720; + $paramMeta2 = mt\Parameter::getByName('CEG_Conversion_Percentage'); + $param = $paramMeta2 ? $paramMeta2['param_value'] : 0.3; + return min($bceg,$bceg_max)*$param*self::CEG_Dynamic_Price(); + } + }