Вход Регистрация
Файл: system/v50_features.php
Строк: 457
<?php
declare(strict_types=1);
/* v50: кольца, 16 достижений, новости турниров, перерасчёты. by Метриум (Стэлп) */

function game_v50_bootstrap(): void {
    static 
$done=false; if($done) return; $done=true;
    
$ver=(int)(function_exists('game_meta_get')?game_meta_get('v50_schema','0'):0);
    if(
$ver>=2) return;
    
db_query("CREATE TABLE IF NOT EXISTS `achievement_v50_bonus` (`user` int NOT NULL,`grades` int NOT NULL DEFAULT 0,PRIMARY KEY(`user`)) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci");
    
db_query("CREATE TABLE IF NOT EXISTS `automation_log` (`code` varchar(64) NOT NULL,`period_key` varchar(32) NOT NULL,`created_at` int NOT NULL,PRIMARY KEY(`code`,`period_key`)) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci");
    if(
function_exists('game_meta_set')) game_meta_set('v50_schema','2');
}

function 
game_ring_effects(int $level,string $kind='rage'): array {
    
$level=max(1,$level);
    
$chance=min(4010 + (int)floor($level/3));
    switch(
$kind){
        case 
'guard':
            
$bonus=min(9018 + (int)floor($level*1.45));
            return [
'label'=>'Макс. бонус','unit'=>'% к броне','bonus'=>$bonus,'chance'=>$chance,'proc_label'=>'Шанс срабатывания'];
        case 
'revive':
            
$bonus=min(25+ (int)floor($level/6));
            return [
'label'=>'Бонус','unit'=>'% жизни','bonus'=>$bonus,'chance'=>min(30,10 + (int)floor($level/8)),'proc_label'=>'Шанс срабатывания'];
        case 
'rage':
        default:
            
$bonus=min(9022 + (int)floor($level*1.35));
            return [
'label'=>'Макс. бонус','unit'=>'% к урону крита','bonus'=>$bonus,'chance'=>$chance,'proc_label'=>'Шанс срабатывания'];
    }
}


/** Реальные улучшения магических колец. */
function game_ring_rune_values(): array { return [0=>0,1=>75,2=>150,3=>250,4=>600,5=>1000,6=>2000]; }
function 
game_ring_rune_costs(): array { return [1=>175,2=>1400,3=>16000,4=>20000,5=>35000,6=>70000]; }
function 
game_ring_rune_stat(string $kind): string { return match($kind){'guard'=>'def','revive'=>'vit',default=>'str'}; }
function 
game_ring_rune_stat_label(string $kind): string { return match($kind){'guard'=>'броне','revive'=>'жизни',default=>'силе'}; }
function 
game_ring_bonus_max(int $level): int { return 90; }
function 
game_ring_bonus_per_stat(): int { return 6; } // 4 x 6 = +24 к сумме параметров за единицу бонуса.
function game_ring_smith_per_stat(): int { return 23; } // +35 = +3220 к сумме параметров, как в референсе.
function game_ring_star_per_stat(): int { return 100; } // 5 звезд = +2000 к сумме параметров.
function game_ring_star_costs(): array { return [0=>10,1=>25,2=>50,3=>100,4=>200]; }
function 
game_ring_discount_percent(int $id): int {
    if(
function_exists('game_active_discount_percent')) return min(90,game_active_discount_percent($id));
    
$row=db_fetch_assoc(db_query('SELECT `zena`,`time` FROM `skilka` WHERE `id`='.(int)$id.' LIMIT 1'));
    if(!
$row || (int)($row['time']??0)<=time()) return 0;
    return 
max(0,min(90,(int)($row['zena']??0)));
}
function 
game_ring_discounted_cost(int $base,int $discountId): int {
    
$base=max(0,$base); $pct=game_ring_discount_percent($discountId);
    return 
max(0,$base-(int)round($base*$pct/100));
}
function 
game_ring_add_stats(int $uid,array $delta): void {
    
$allowed=['str','vit','agi','def']; $sets=[]; $params=['uid'=>$uid];
    foreach(
$allowed as $stat){
        
$d=(int)($delta[$stat]??0); if($d===0) continue;
        
$key='d_'.$stat$sets[]='`'.$stat.'`=`'.$stat.'`+:'.$key$params[$key]=$d;
    }
    if(!
$sets) return;
    
db_execute('UPDATE `users` SET '.implode(',',$sets).' WHERE `id`=:uid',$params);
}
function 
game_ring_total_upgrade_bonus(array $ring): int {
    
$values=game_ring_rune_values();
    
$rune=(int)($values[(int)($ring['rune']??0)]??0);
    
$bonus=max(0,(int)($ring['bonus']??0))*game_ring_bonus_per_stat()*4;
    
$smith=max(0,(int)($ring['smith']??0))*game_ring_smith_per_stat()*4;
    
$stars=max(0,min(5,(int)($ring['stars']??0)))*game_ring_star_per_stat()*4;
    return 
$rune+$bonus+$smith+$stars;
}

function 
game_achievement_catalog_v50(array $user): array {
    
$uid=(int)($user['id']??0);
    
$collector=db_fetch_assoc(db_query("SELECT * FROM `collector` WHERE `user`=$uid LIMIT 1")) ?: ['coll'=>1,'stats'=>0];
    
$trophies=0; for($i=1;$i<=9;$i++){ if((int)($user['troph'.$i]??0)===1$trophies++; }
    
$smithCount=(int)(db_result(db_query("SELECT COUNT(*) FROM `inv` WHERE `user`=$uid AND `equip`=1 AND `smith`>=15"),0) ?: 0);
    
$smithCount+=(int)(db_result(db_query("SELECT COUNT(*) FROM `user_rings` WHERE `user`=$uid AND `slot`>0 AND `smith`>=15"),0) ?: 0);
    
$runeCount=(int)(db_result(db_query("SELECT COUNT(*) FROM `inv` WHERE `user`=$uid AND `equip`=1 AND `rune`>0"),0) ?: 0);
    
$runeCount+=(int)(db_result(db_query("SELECT COUNT(*) FROM `user_rings` WHERE `user`=$uid AND `slot`>0 AND `rune`>0"),0) ?: 0);
    
$bonusSum=(int)(db_result(db_query("SELECT COALESCE(SUM(`bonus`),0) FROM `inv` WHERE `user`=$uid AND `equip`=1"),0) ?: 0);
    
$bonusSum+=(int)(db_result(db_query("SELECT COALESCE(SUM(`bonus`),0) FROM `user_rings` WHERE `user`=$uid AND `slot`>0"),0) ?: 0);
    
$sackSum=(int)(db_result(db_query("SELECT COALESCE(`1`,0)+COALESCE(`2`,0)+COALESCE(`3`,0)+COALESCE(`4`,0)+COALESCE(`5`,0)+COALESCE(`6`,0)+COALESCE(`7`,0)+COALESCE(`8`,0)+COALESCE(`9`,0) FROM `sack` WHERE `user`=$uid LIMIT 1"),0) ?: 0);
    
$petLevel=(int)(db_result(db_query("SELECT COALESCE(MAX(GREATEST(`lvl_str`,`lvl_vit`,`lvl_agi`,`lvl_def`)),0) FROM `pet_u` WHERE `user_id`=$uid"),0) ?: (int)($user['pet_lvl']??0));
    
$ach=[
      [
'key'=>'lvl','name'=>'Путь героя','link'=>'/user/'.$uid,'icon'=>'/images/icon/exp.png','progress'=>(int)($user['level']??0),'levels'=>[5,10,20,35,50,70],'condition'=>'Достигни %s уровня'],
      [
'key'=>'train','name'=>'Мастер тренировки','link'=>'/train/','icon'=>'/images/icon/train.png','progress'=>(int)($user['skill']??0),'levels'=>[5,15,35,70,120,200],'condition'=>'Получи %s мастерства'],
      [
'key'=>'quests','name'=>'Хранитель поручений','link'=>'/quest/','icon'=>'/images/icon/quest.png','progress'=>(int)($user['quests']??0),'levels'=>[5,15,40,90,180,320],'condition'=>'Выполни %s заданий'],
      [
'key'=>'arena_fights','name'=>'Боец арены','link'=>'/arena/','icon'=>'/images/icon/fights.png','progress'=>(int)($user['boy_arena']??0),'levels'=>[10,30,80,180,450,1000],'condition'=>'Проведи %s боёв на арене'],
      [
'key'=>'arena_wins','name'=>'Победитель арены','link'=>'/arena/','icon'=>'/images/icon/fights.png','progress'=>(int)($user['arena_pobed']??0),'levels'=>[5,15,40,100,260,600],'condition'=>'Победи %s раз на арене'],
      [
'key'=>'duel_fights','name'=>'Дуэлянт','link'=>'/duel/','icon'=>'/images/icon/fights.png','progress'=>(int)($user['duel_fights']??0),'levels'=>[5,15,35,80,160,300],'condition'=>'Проведи %s дуэлей'],
      [
'key'=>'duel_rating','name'=>'Вершитель судеб','link'=>'/duel/','icon'=>'/images/icon/fights.png','progress'=>(int)($user['duel_rating']??0),'levels'=>[20,70,160,320,600,1000],'condition'=>'Набери %s рейтинга дуэлей'],
      [
'key'=>'undying','name'=>'Страх короля бессмертных','link'=>'/undying/','icon'=>'/images/icon/heart.png','progress'=>(int)($user['undying']??0),'levels'=>[3,10,25,60,140,300],'condition'=>'Победи %s бессмертных'],
      [
'key'=>'cave','name'=>'Собиратель ресурсов','link'=>'/cave/','icon'=>'/images/icon/silver.png','progress'=>$sackSum,'levels'=>[5,20,60,150,320,650],'condition'=>'Добудь %s ресурсов в пещере'],
      [
'key'=>'collections','name'=>'Легенда коллекций','link'=>'/collector/'.$uid.'/','icon'=>'/images/icon/quest.png','progress'=>max(0,(int)($collector['coll']??1)-1),'levels'=>[1,2,3,4,5,6],'condition'=>'Собери %s коллекций'],
      [
'key'=>'trophies','name'=>'Охотник за трофеями','link'=>'/medal/','icon'=>'/images/icon/valor.png','progress'=>$trophies,'levels'=>[1,2,3,4,6,9],'condition'=>'Получи %s трофеев'],
      [
'key'=>'smith','name'=>'Кузнечный мастер','link'=>'/smith/smith/','icon'=>'/images/icon/hammer.png','progress'=>$smithCount,'levels'=>[1,2,4,6,7,8],'condition'=>'Заточи до +15 минимум %s предметов'],
      [
'key'=>'runes','name'=>'Рунописец','link'=>'/smith/runes/','icon'=>'/images/icon/hammer.png','progress'=>$runeCount,'levels'=>[1,2,3,4,6,8],'condition'=>'Установи руны на %s предметов'],
      [
'key'=>'bonus','name'=>'Усиления','link'=>'/smith/bonus/','icon'=>'/images/icon/exp.png','progress'=>$bonusSum,'levels'=>[10,30,70,120,220,360],'condition'=>'Получи суммарно %s бонуса экипировки'],
      [
'key'=>'pet','name'=>'Повелитель питомцев','link'=>'/petshop/','icon'=>'/images/icon/heart.png','progress'=>$petLevel,'levels'=>[5,10,18,28,40,55],'condition'=>'Прокачай питомца до %s уровня'],
      [
'key'=>'valor','name'=>'Слава доблести','link'=>'/olimp/','icon'=>'/images/icon/valor.png','progress'=>(int)($user['lvl_dobl']??0),'levels'=>[1,3,7,15,30,50],'condition'=>'Достигни %s уровня доблести'],
    ];
    
$qNames=['нет','Обычное','Улучшенное','Редкое','Эпическое','Легендарное','Мифическое'];
    
$qColors=['#d5c7a5','#75d65c','#70b7ff','#d184ff','#ff9a42','#ffe16d','#ff6b6b'];
    foreach(
$ach as &$a){
        
$grade=0; foreach($a['levels'] as $target){ if((int)$a['progress'] >= (int)$target$grade++; }
        
$a['grade']=$grade$a['max_grade']=count($a['levels']);
        
$next=$a['levels'][$grade] ?? end($a['levels']);
        
$a['next_target']=(int)$next;
        
$a['percent']=$grade>=$a['max_grade'] ? 100 : (int)max(0,min(100,round(((int)$a['progress']/max(1,(int)$next))*100)));
        
$a['quality_name']=$qNames[$grade] ?? 'Мифическое';
        
$a['quality_color']=$qColors[$grade] ?? '#ff6b6b';
        
$a['condition_text']=$grade>=$a['max_grade'] ? 'Все качества достижения получены' sprintf((string)$a['condition'],n_f((int)$next));
    }
    unset(
$a);
    return 
$ach;
}
function 
game_achievement_total_grades_v50(array $user): int {
    
$sum=0; foreach(game_achievement_catalog_v50($user) as $a){ $sum += (int)$a['grade']; } return $sum;
}
function 
game_achievement_summary_v50(array $user): array {
    
$list=game_achievement_catalog_v50($user);
    
$started=0$fullyCompleted=0$totalBonus=0$maxBonus=0$grades=0$maxGrades=0;
    foreach(
$list as $a){
        
$grade=(int)($a['grade'] ?? 0);
        
$maxGrade=(int)($a['max_grade'] ?? 0);
        if(
$grade>0$started++;
        if(
$maxGrade>&& $grade>=$maxGrade$fullyCompleted++;
        
$grades += $grade;
        
$maxGrades += $maxGrade;
        
$totalBonus += $grade*2;
        
$maxBonus += $maxGrade*2;
    }
    return [
        
'started'=>$started,
        
'completed'=>$fullyCompleted,
        
'total'=>count($list),
        
'bonus'=>$totalBonus,
        
'max_bonus'=>$maxBonus,
        
'grades'=>$grades,
        
'max_grades'=>$maxGrades,
    ];
}
function 
game_achievement_v50_sync(array &$user): void {
    if(empty(
$user['id'])) return;
    
game_v50_bootstrap();
    
$uid=(int)$user['id'];
    
$total=game_achievement_total_grades_v50($user);
    
db_query("INSERT IGNORE INTO `achievement_v50_bonus` (`user`,`grades`) VALUES ($uid,0)");
    
$stored=(int)(db_result(db_query("SELECT `grades` FROM `achievement_v50_bonus` WHERE `user`=$uid LIMIT 1"),0) ?: 0);
    
// Достижение является постоянным: уже полученные ступени не отнимаем,
    // даже если игрок снял предмет/руну и текущий вычисляемый прогресс уменьшился.
    // Это также исключает циклическое снятие/возврат параметров.
    
if($total <= $stored) return;
    
$delta=$total-$stored;
    
$statDelta=$delta*2;

    
// При отключённых эмулируемых prepared statements PDO/MySQL нельзя повторно
    // использовать один и тот же именованный placeholder в одном запросе.
    
db_execute(
        
'UPDATE `users` SET '
        
.'`str`=`str`+:d_str,'
        
.'`vit`=`vit`+:d_vit,'
        
.'`agi`=`agi`+:d_agi,'
        
.'`def`=`def`+:d_def,'
        
.'`mana`=`mana`+:d_mana,'
        
.'`mp`=`mp`+:d_mp,'
        
.'`hp`=`hp`+:d_hp '
        
.'WHERE `id`=:u',
        [
            
'd_str'=>$statDelta,
            
'd_vit'=>$statDelta,
            
'd_agi'=>$statDelta,
            
'd_def'=>$statDelta,
            
'd_mana'=>$statDelta,
            
'd_mp'=>$statDelta,
            
'd_hp'=>$statDelta,
            
'u'=>$uid,
        ]
    );
    
db_execute('UPDATE `achievement_v50_bonus` SET `grades`=:g WHERE `user`=:u',["g"=>$total,"u"=>$uid]);
    foreach([
'str','vit','agi','def','mana','mp','hp'] as $k){ $user[$k]=(int)($user[$k]??0)+$statDelta; }
}

function 
game_forum_news_post(string $title,string $text,int $authorId=2,int $sub=1): void {
    
$title=trim($title); $text=trim($text); if($title===''||$text==='') return;
    
db_execute('INSERT INTO `forum_topic` (`sub`,`name`,`stick`,`user`,`text`,`time`) VALUES (:s,:n,0,:u,:t,:tm)',[
        
's'=>$sub,'n'=>mb_substr($title,0,200,'UTF-8'),'u'=>$authorId,'t'=>$text,'tm'=>time()
    ]);
}
Онлайн: 4
Реклама