Advertisement
theanonym

cata

Dec 16th, 2018 (edited)
39
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Perl 25.40 KB | None | 0 0
  1. #!/bin/perl
  2. ################################################################################
  3. #
  4. #                       Общая информация
  5. #
  6. # Кроссплатформенный лаунчер с рядом дополнительных функций:
  7. #   * Проверка наличия нового билда
  8. #   * Обновление игры с сохранением сейвов и настроек
  9. #   * Установка свежей версии тайлсета DeadPeople
  10. #   * Установка 2ch sound pack и 2ch soundtrack
  11. #   * Создание резервной копии и восстановление миров
  12. #
  13. # Для подробной информации нужно запустить скрипт с ключом --help.
  14. #
  15. #                           Установка
  16. #
  17. # Для винды нужно скачать и установить http://strawberryperl.com/
  18. # Stawberry включает в себя интерпретатор и все используемые скриптом модули.
  19. #
  20. # Скрипт помещается в папку с игрой и запускается следующим образом в командной
  21. # строке/терминале:
  22. #   perl cata.pl [параметры]
  23. #
  24. # На линуксах случае ошибки "Can't locate ХХХ/XXX.pm" нужно установить
  25. # cpanminus и с его помощью стянуть недостающие модули (от рута):
  26. #   curl -L https://cpanmin.us | perl - App::cpanminus
  27. #   cpanm --notest XXX::XXX
  28. #
  29. # Должно хватить этих:
  30. #   cpanm --notest File::Slurp File::Find::Rule List::MoreUtils Archive::Extract LWP JSON
  31. #
  32. #                          Мод Fast Cata
  33. #
  34. # Чтобы применить мод нужно запустить скрипт с ключом --fastmod.
  35. # Скрипт модифицирует игровые файлы с целью уменьшить простои вроде
  36. # установки каждой рамы по 2 часа и чтения одной книги весь день.
  37. # Настройки мода находятся ниже.
  38. #
  39. # Резервная копия оригинальных файлов сохраняется в data.bk в папке игры.
  40. # Оригинальные файлы можно восстановить запустив скрипт с ключом --restore.
  41. # Лог всех изменений сохраняется в cata.pl.log рядом со скриптом.
  42. #
  43. # Пример работы: https://pastebin.com/raw/CkSwDgnE
  44. #
  45. ################################################################################
  46.  
  47. use v5.20;
  48. use utf8;
  49. use autodie;
  50. no warnings "experimental";
  51.  
  52. use Getopt::Long;
  53. use POSIX qw/uname/;
  54. use Cwd qw/abs_path/;
  55. use File::Basename qw/basename/;
  56. use File::Spec::Functions qw/catfile catdir canonpath/;
  57. use File::Slurp qw/read_file write_file/;
  58. use File::Path qw/remove_tree make_path/;
  59. use File::Copy qw/copy move/;
  60. use File::Copy::Recursive qw/dircopy dirmove/;
  61. use File::Find::Rule;
  62. use List::Util qw/min max/;
  63. use List::MoreUtils qw/first_index first_value any only_value /;
  64. use Archive::Extract;  
  65. use LWP;
  66. use JSON;
  67.  
  68. ################################################################################
  69. #
  70. # Настройки мода Fast Cata
  71. #
  72. ################################################################################
  73. our %MOD_SETTINGS = (
  74.    # Коэффициенты времени выполнения
  75.    # 1 = 100%
  76.    parts_install_time => 0.2, # Время установки деталей 0.2 = 20%
  77.    parts_repair_time  => 0.2, # Ремонта
  78.    parts_removal_time => 0.2, # Удаления
  79.    
  80.    craft_time         => 0.2, # Время крафта
  81.    books_time         => 0.2, # Чтения
  82.    
  83.    # К указанной мутации добавляется эффект ускоренного сна
  84.    sleep_acceliration => 1.0,            # 1.0 = энергия восстанавливается на 100% быстрее
  85.    sleep_mutation_id  => "HEAVYSLEEPER", # Крепкий сон
  86. );
  87.  
  88. ################################################################################
  89. #
  90. # Глобальные переменные
  91. #
  92. ################################################################################
  93. our $VERSION_FILE = "_VERSION.txt";
  94. our $DATA_BACKUP  = "data.bk";
  95. our $MOD_LOG      = "cata.pl.log";
  96.  
  97. our $LWP = LWP::UserAgent->new;
  98. $LWP->agent("Mozilla/5.0 (Windows NT 6.1; rv:64.0) Gecko/20100101 Firefox/64.0");
  99. $LWP->cookie_jar({});
  100.  
  101. our %OPT;
  102.  
  103. ################################################################################
  104. #
  105. # Код лаунчера
  106. #
  107. ################################################################################
  108. sub get_build_version($) {
  109.    my($path_or_url) = @_;
  110.    return ($path_or_url =~ /(\d+)\D*$/)[0];
  111. }
  112.  
  113. sub fetch_latest_game_url() {
  114.    my($sysname, $arch) = (POSIX::uname)[0, 4];
  115.    my $page_url = sprintf "http://dev.narc.ro/cataclysm/jenkins-latest/%s%s/Tiles/",
  116.                           $sysname =~ /win/i ? "Windows" : "Linux",
  117.                           $arch =~ /64/  ? "" : "_x64";
  118.                      
  119.    my $res = $LWP->get($page_url);
  120.    die unless $res->is_success;
  121.  
  122.    my @archives = $res->content =~ m~href="(cataclysmdda.*?\d+(?:\.zip|\.tar\.gz))"~gs;
  123.    die unless @archives;
  124.    
  125.    return "$page_url" . (sort { $a <=> $b } @archives)[0];
  126. }
  127.  
  128. sub check_for_update() {
  129.    die "'$VERSION_FILE' not found! Try --update"
  130.       unless -s $VERSION_FILE;
  131.  
  132.    my $current_version = read_file $VERSION_FILE;
  133.    my $latest_version  = get_build_version fetch_latest_game_url;
  134.    my $is_latest = $current_version >= $latest_version;
  135.  
  136.    printf "Your build:   %d\nLatest build: %d (+%d)\n%s\n",
  137.           $current_version,
  138.           $latest_version,
  139.           $latest_version - $current_version,
  140.           $is_latest ? "Game is up to date!" :
  141.                        "Try --update";
  142.    return $is_latest;
  143. }
  144.  
  145. sub download_file($$) {
  146.    my($url, $path_to_save) = @_;
  147.    
  148.    $LWP->show_progress(1);
  149.    my $res = $LWP->get($url, ":content_file" => $path_to_save);
  150.    $LWP->show_progress(0);
  151.    
  152.    die unless $res->is_success && -s $path_to_save;
  153. }
  154.  
  155. sub backup_files($$) {
  156.    my($from_path, $to_path) =  @_;
  157.    
  158.    die "'$from_path' not found!" unless -d $from_path;
  159.    
  160.    unless(-d $to_path) {
  161.       printf "Create '%s'\n", basename $to_path;
  162.       mkdir $to_path;
  163.    }
  164.    
  165.    map { $_ = canonpath abs_path $_ } ($from_path, $to_path);
  166.  
  167.    for my $world_name ( map { basename $_ } grep { -d } glob catdir $from_path, "*") {
  168.    
  169.       my $old_world_path = catdir $to_path, $world_name;
  170.       if(-d $old_world_path) {
  171.          printf "Delete '%s'\n",  catdir(basename($to_path), $world_name);
  172.          remove_tree $old_world_path;
  173.       }
  174.      
  175.       printf "Copy '%s' -> '%s'\n", catdir(basename($from_path), $world_name),
  176.                                     catdir(basename($to_path), $world_name);
  177.       dircopy catdir($from_path, $world_name), catdir($to_path, $world_name);
  178.    }
  179. }
  180.  
  181. #------------------------------------------------------------
  182.  
  183. sub update_game() {
  184.    my $url = fetch_latest_game_url;
  185.    my $archive_name  = basename $url;
  186.    my $unpacked_folder = "$archive_name.unpacked";
  187.    
  188.    # Download
  189.    say "Download '$archive_name'";
  190.    $OPT{nodownload} && -s $archive_name ?  say "...skip download (--nodownload option)" :
  191.                                            download_file $url, $archive_name;
  192.  
  193.    # Extract  
  194.    say "Extract '$archive_name' -> '$unpacked_folder'";
  195.    if($OPT{nodownload} && -d $unpacked_folder) {
  196.       say "...skip download (--nodownload option)";
  197.    } else {
  198.       my $archive = Archive::Extract->new(archive => $archive_name);
  199.       $archive->extract(to => $unpacked_folder);
  200.       die $archive->error if $archive->error;
  201.    }
  202.  
  203.    # Save important files
  204.    my $data_folder = "data";
  205.    my $tmp_folder = "important_files.tmp";
  206.    
  207.    say "Create '$tmp_folder'";
  208.    make_path catdir $tmp_folder, $data_folder;
  209.    make_path catdir $tmp_folder, "gfx";
  210.    
  211.    for my $important_file(catfile($data_folder, "fontdata.json"),
  212.                           catfile($data_folder, "font"),
  213.                           catfile("gfx", "MSX++DeadPeopleEdition"),
  214.    ) {
  215.       my $new_path = catdir $tmp_folder, $important_file;
  216.      
  217.       say "Copy '$important_file' -> '$new_path'";
  218.       if(-d $important_file) {
  219.          dircopy $important_file, $new_path or die $!;
  220.       } elsif(-f $important_file) {
  221.          copy $important_file, $new_path or die $!;
  222.       } else {
  223.          say "'$important_file' not found";
  224.       }
  225.    }
  226.    
  227.    # Update
  228.    say "Delete '$data_folder'";
  229.    remove_tree $data_folder;
  230.    
  231.    printf "Copy '%s' -> '%s'\n", catdir($unpacked_folder, "*"), ".";
  232.    dircopy $unpacked_folder, ".";
  233.    write_file $VERSION_FILE, get_build_version $archive_name;
  234.    
  235.    printf "Copy '%s' -> '%s'\n", catdir($tmp_folder, $data_folder), ".";
  236.    dircopy $tmp_folder, ".";
  237.    
  238.    # Clean up
  239.    say "Delete '$tmp_folder'";
  240.    remove_tree $tmp_folder unless $OPT{keep};
  241.    
  242.    say "Delete '$unpacked_folder'";
  243.    remove_tree $unpacked_folder unless $OPT{keep};
  244.    
  245.    say "Delete '$archive_name'";
  246.    unlink $archive_name unless $OPT{keep};
  247.    
  248.    say "...skip all deletions (--keep option)" if $OPT{keep};
  249. }
  250.  
  251. sub update_2ch_tileset() {
  252.    my $url = "https://github.com/SomeDeadGuy/Cata-MSX-DeadPeopleTileset/archive/master.zip";
  253.    my $archive_name  = "DeadPeopleTileset.zip";
  254.    my $unpacked_folder = "$archive_name.unpacked";
  255.    
  256.    # Download
  257.    say "Download '$archive_name'";
  258.    ($OPT{nodownload} && -s $archive_name) ? say "...skip download (--nodownload option)" :
  259.                                             download_file $url, $archive_name;
  260.  
  261.    say "Extract '$archive_name' -> '$unpacked_folder'";
  262.    my $archive = Archive::Extract->new(archive => $archive_name);
  263.    $archive->extract(to => $unpacked_folder);
  264.    die $archive->error if $archive->error;
  265.  
  266.    # Update
  267.    my $new_tileset_dir = catdir($unpacked_folder, only_value { basename($_) eq "MSX++DeadPeopleEdition" } @{$archive->files});
  268.    my $new_mod_dir     = catdir($unpacked_folder, only_value { basename($_) eq "mods" } @{$archive->files});
  269.    my $tilesets_path   = catdir ".", "gfx", basename($new_tileset_dir);
  270.    my $mods_path       = catdir ".", "data", "mods";
  271.  
  272.    printf "Move '...%s' -> '%s'\n", basename($new_tileset_dir), $tilesets_path;
  273.    dirmove $new_tileset_dir, $tilesets_path or die $!;
  274.    printf "Move '...%s' -> '%s'\n", basename($new_mod_dir), $mods_path;
  275.    dirmove $new_mod_dir, $mods_path or die $!;
  276.    
  277.    # Clean up
  278.    say "Delete '$unpacked_folder'";
  279.    $OPT{keep} ? say "...skip deletion (--keep option)" :
  280.                 remove_tree $unpacked_folder;
  281.  
  282.    say "Delete '$archive_name'";
  283.    $OPT{keep} ? say "...skip deletion (--keep option)" :
  284.                 unlink $archive_name;
  285. }
  286.  
  287. sub update_2ch_soundpack() {
  288.    my $url = "https://docs.google.com/uc?id=1ZQRqnPL7d9pjfH1GdZWft8ZmZFuq6XpD&export=download";
  289.    my $archive_name  = "2chsound.zip";
  290.    my $unpacked_folder = catdir ".", "sound";
  291.    
  292.    # Download
  293.    say "Download '$archive_name'";
  294.    ($OPT{nodownload} && -s $archive_name) ? say "...skip download (--nodownload option)" :
  295.                                             download_file $url, $archive_name;
  296.  
  297.    # Extract
  298.    unless(-d $unpacked_folder) {
  299.       say "Create '$unpacked_folder'";
  300.       make_path $unpacked_folder;
  301.    }            
  302.    
  303.    say "Extract '$archive_name' -> '$unpacked_folder'";
  304.    my $archive = Archive::Extract->new(archive => $archive_name);
  305.    $archive->extract(to => $unpacked_folder);
  306.    die $archive->error if $archive->error;
  307.    
  308.    # Clean up
  309.    say "Delete '$archive_name'";
  310.    $OPT{keep} ? say "...skip deletion (--keep option)" :
  311.                 unlink $archive_name;
  312. }
  313.  
  314. sub update_2ch_musicpack() {
  315.    my $url = "https://docs.google.com/uc?id=1n7UWnZzQC270Q7bpHdczIK0Yp-LKa16i&export=download";
  316.    my $archive_name  = "2chmusic.zip";
  317.    my $unpacked_folder = catdir ".", "sound", "2ch sounpack";
  318.    
  319.    unless(-d $unpacked_folder) {
  320.       say "2ch Sound Pack must be installed first! Try --2chsound";
  321.       return;
  322.    }
  323.    
  324.    # Download
  325.    my $res = $LWP->get($url);
  326.    my($new_url) = $res->content =~ m~href="/(uc\?export\=download&amp;confirm\=.*?&amp;id\=.*?)">D~gms;
  327.    die unless $new_url;
  328.    $new_url = "https://docs.google.com/$new_url";
  329.    $new_url =~ s/&amp;/&/g;
  330.  
  331.    say "Download '$archive_name'";
  332.    ($OPT{nodownload} && -s $archive_name) ? say "...skip download (--nodownload option)" :
  333.                                             download_file $new_url, $archive_name;
  334.  
  335.    # Extract
  336.    say "Extract '$archive_name' -> '$unpacked_folder'";
  337.    my $archive = Archive::Extract->new(archive => $archive_name);
  338.    $archive->extract(to => $unpacked_folder);
  339.    die $archive->error if $archive->error;
  340.    
  341.    # Clean up
  342.    say "Delete '$archive_name'";
  343.    $OPT{keep} ? say "...skip deletion (--keep option)" :
  344.                 unlink $archive_name;
  345. }
  346.  
  347. ################################################################################
  348. #
  349. # Код мода
  350. #
  351. ################################################################################
  352. sub report(@) {
  353.    my(@strings) = map { "$_\n" } @_;
  354.  
  355.    state $log;
  356.    open $log, ">", $MOD_LOG unless defined $log;
  357.    #print @strings;
  358.    print $log @strings;
  359. }
  360.  
  361. sub json_to_perl($) {
  362.    my($json_string) = @_;
  363.    JSON->new->utf8->decode($json_string);
  364. }
  365.  
  366. sub perl_to_json($) {
  367.    my($array_ref) = @_;
  368.    JSON->new->utf8->allow_nonref->pretty->encode($array_ref);
  369. }
  370.  
  371. sub compute_new_time($$) {
  372.    my($original_time, $requirement_type) = @_;
  373.    #$original_time = max(60000, $original_time);
  374.    int max 0, $original_time * $MOD_SETTINGS{"parts_${requirement_type}_time"};
  375. }
  376.  
  377. sub compute_time_from_difficulty($$) {
  378.    my($difficulty, $requirement_type) = @_;
  379.    ($difficulty + 1) * 30000;
  380. }
  381.  
  382. sub has_standard_difficulty($) {
  383.    my($node) = @_;
  384.    exists $node->{difficulty};
  385. }
  386.  
  387. sub has_difficulty_in_requirements($$) {
  388.    my($node, $requirement_type) = @_;
  389.    exists $node->{requirements}->{$requirement_type}->{skills}
  390.           && any { "mechanics" } $node->{requirements}->{$requirement_type}->{skills};
  391. }
  392.  
  393. sub has_time_in_requirements($$) {
  394.    my($node, $requirement_type) = @_;
  395.    exists $node->{requirements}->{$requirement_type}->{time};
  396. }
  397.  
  398. sub has_parent($) {
  399.    my($node) = @_;
  400.    exists $node->{"copy-from"};
  401. }
  402.  
  403. sub get_parent($$) {
  404.    my($json, $node) = @_;
  405.    die perl_to_json $node unless has_parent $node;
  406.    
  407.    my $copy_from = $node->{"copy-from"};
  408.    first_value { $_->{id} eq $copy_from || $_->{abstract} eq $copy_from } @$json
  409. }
  410.  
  411. sub get_id($) {
  412.    my($node) = @_;
  413.    $node->{id} ? $node->{id} : $node->{result} ? $node->{result} : $node->{abstract};
  414. }
  415.  
  416. sub get_standard_difficulty($) {
  417.    my($node) = @_;
  418.    die perl_to_json $node unless has_standard_difficulty $node;
  419.    
  420.    $node->{difficulty};
  421. }
  422.  
  423. sub get_difficulty_from_requirements($$) {
  424.    my($node, $requirement_type) = @_;
  425.    die perl_to_json $node unless has_difficulty_in_requirements $node, $requirement_type;
  426.    
  427.    $node->{requirements}->{$requirement_type}->{skills}->[
  428.       first_index { "mechanics" } $node->{requirements}->{$requirement_type}->{skills}
  429.       + 1
  430.    ]->[1];
  431. }
  432.  
  433. sub get_time_from_requirements($$) {
  434.    my($node, $requirement_type) = @_;
  435.    die perl_to_json $node unless has_time_in_requirements $node, $requirement_type;
  436.    
  437.    $node->{requirements}->{$requirement_type}->{time};
  438. }
  439.  
  440. sub set_time_to_requirements($$$) {
  441.    my($node, $requirement_type, $time) = @_;
  442.    
  443.    $node->{requirements}->{$requirement_type}->{time} = int $time;
  444. }
  445.  
  446. sub set_difficulty_to_requirements($$$) {
  447.    my($node, $requirement_type, $difficulty) = @_;
  448.    
  449.    push @{ $node->{requirements}->{$requirement_type}->{skills} }, [ "mechanics", int $difficulty ];
  450. }
  451.  
  452. sub fast_mod_apply {
  453.    if(-d $DATA_BACKUP) {
  454.       say "Game files already modified. Try --restore first";
  455.       return;
  456.    }
  457.  
  458.    my %count = (checked => 0, modified => 0, parts => 0, books => 0, mutations => 0);
  459.  
  460.    for my $file_path (
  461.       File::Find::Rule->file->name("*.json")->in(
  462.          catdir(".", "data", "json", "vehicleparts"),
  463.          catdir(".", "data", "json", "items", "book"),
  464.          catdir(".", "data", "json", "recipes"),
  465.          catdir(".", "data", "mods"),
  466.       ),
  467.       catfile(".", "data", "json", "mutations.json"),
  468.    ) {
  469.       $count{checked}++;
  470.      
  471.       my $text = read_file $file_path;
  472.       my $file_modified = 0;
  473.      
  474.       my $json = json_to_perl($text);
  475.       next if ref $json ne "ARRAY";
  476.      
  477.       for my $node (@$json) {
  478.          next if ref $node ne "HASH";
  479.          next unless exists $node->{type};
  480.          
  481.          my $id = get_id($node);
  482.          my $node_modified = 0;
  483.          
  484.          given($node->{type}) {
  485.             when("vehicle_part") {
  486.                for my $requirement_type ("install", "repair", "removal") {
  487.                   my $original_difficulty;
  488.                   my $original_time;
  489.                  
  490.                   if(has_difficulty_in_requirements $node, $requirement_type) {
  491.                      $original_difficulty = get_difficulty_from_requirements $node, $requirement_type;
  492.                   } elsif (has_standard_difficulty $node) {
  493.                      $original_difficulty = get_standard_difficulty $node;
  494.                   } elsif(has_parent $node) {
  495.                      my $parent_node = get_parent($json, $node);
  496.                      if(has_standard_difficulty $parent_node) {
  497.                         $original_difficulty = get_standard_difficulty $parent_node;
  498.                      } elsif(has_difficulty_in_requirements $parent_node, $requirement_type) {
  499.                         $original_difficulty = get_difficulty_from_requirements $parent_node,
  500.                                                                                 $requirement_type;
  501.                      } else {
  502.                         report "Part '$id' has no difficulty";
  503.                      }
  504.                   }
  505.                  
  506.                   die if defined $original_difficulty && length $original_difficulty == 0;
  507.                  
  508.                   if(has_time_in_requirements $node, $requirement_type) {
  509.                      $original_time = get_time_from_requirements $node, $requirement_type;
  510.                      if(defined $original_difficulty) {
  511.                         $original_time = min($original_time,
  512.                                              compute_time_from_difficulty $original_difficulty,
  513.                                                                           $requirement_type);
  514.                      }
  515.                   } elsif(defined $original_difficulty) {
  516.                      $original_time = compute_time_from_difficulty $original_difficulty,
  517.                                                                    $requirement_type;
  518.                   }
  519.                  
  520.                   if(defined $original_time) {
  521.                      set_time_to_requirements $node,
  522.                                               $requirement_type,
  523.                                               compute_new_time $original_time, $requirement_type;
  524.                                              
  525.                      if(defined $original_difficulty && !has_difficulty_in_requirements $node, $requirement_type) {
  526.                         set_difficulty_to_requirements $node,
  527.                                                        $requirement_type,
  528.                                                        $original_difficulty;
  529.                      }
  530.  
  531.                      report sprintf "Part '%s'%s (difficulty: %d): change $requirement_type time %d -> %d",
  532.                         $id,
  533.                         has_parent($node)?" (parent: '" . get_id(get_parent($json, $node)) . "')":"",
  534.                         $original_difficulty,
  535.                         $original_time,
  536.                         compute_new_time $original_time, $requirement_type;
  537.                        
  538.                      $file_modified = 1;
  539.                      $node_modified = 1;
  540.                      $count{parts}++;
  541.                   } elsif(defined $original_difficulty && !exists $node->{abstract}) {
  542.                      report "Can't determine $requirement_type time for '$id'";
  543.                   }
  544.                }
  545.             }
  546.             when("BOOK") {
  547.                if(exists $node->{time}) {
  548.                   my $old_time = $node->{time};
  549.                   my $new_time = int($old_time * $MOD_SETTINGS{books_time});
  550.                   $new_time = 1 if $new_time < 1 && $old_time >= 1;
  551.                   $node->{time} = $new_time;
  552.                  
  553.                   report "Book '$node->{id}': change reading time $old_time -> $new_time";
  554.                  
  555.                   $file_modified = 1;
  556.                   $node_modified = 1;
  557.                   $count{books}++;
  558.                }
  559.             }
  560.             when("recipe") {
  561.                if(exists $node->{time}) {
  562.                   my $id = get_id($node);
  563.                   my $old_time = $node->{time};
  564.                   my $new_time = int($old_time * $MOD_SETTINGS{books_time});
  565.                   $new_time = 1 if $new_time < 1 && $old_time >= 1;
  566.                   $node->{time} = $new_time;
  567.                  
  568.                   report "Recipe '$id': change craft time $old_time -> $new_time";
  569.                  
  570.                   $file_modified = 1;
  571.                   $node_modified = 1;
  572.                   $count{recipes}++;
  573.                } else {
  574.                   report "Recipe '$id' has no time";
  575.                }
  576.             }
  577.             when("mutation") {
  578.                if($node->{id} eq $MOD_SETTINGS{sleep_mutation_id}) {
  579.                   $node->{fatigue_regen_modifier} = $MOD_SETTINGS{sleep_acceliration};
  580.                  
  581.                   report "Mutation '$node->{id}': faster sleep effect added";
  582.                  
  583.                   $file_modified = 1;
  584.                   $node_modified = 1;
  585.                   $count{mutations}++;
  586.                }
  587.             }
  588.          }
  589.          
  590.          if($node_modified) {
  591.             #$node->{MODIFIED} = $JSON::true;
  592.          }
  593.       }
  594.      
  595.       for my $node (grep { ref $_ eq "HASH" && $_->{type} eq "vehicle_part" } @$json) {
  596.          for my $requirement_type ("install", "repair", "removal") {
  597.             if(exists $node->{requirements}->{$requirement_type} && %{$node->{requirements}->{$requirement_type}} == 0) {
  598.                delete $node->{requirements}->{$requirement_type};
  599.             }
  600.          }
  601.       }
  602.      
  603.       if($file_modified) {
  604.          say "Edit file '$file_path'";
  605.          write_file $file_path, perl_to_json $json;
  606.          
  607.          $count{modified}++;
  608.       }
  609.    }
  610.  
  611.    report "\nFiles checked: $count{checked}",
  612.           "Files edited: $count{modified}",
  613.           "Parts: $count{parts}",
  614.           "Books: $count{books}",
  615.           "Recipes: $count{recipes}",
  616.           "Mutations: $count{mutations}";
  617. }
  618.  
  619. sub fast_mod_make_backup {
  620.    report "Backup original files to '$DATA_BACKUP'...";
  621.    dircopy catdir(".", "data", "json"), catdir(".", $DATA_BACKUP, "json");
  622.    dircopy catdir(".", "data", "mods"), catdir(".", $DATA_BACKUP, "mods");
  623.    report "Done";
  624. }
  625.  
  626. sub fast_mod_restore {
  627.    unless(-d $DATA_BACKUP) {
  628.       say "'$DATA_BACKUP' not found!";
  629.       return;
  630.    }
  631.  
  632.    say "Restoring original files...";
  633.    dircopy catdir(".", $DATA_BACKUP, "json"), catdir(".", "data", "json");
  634.    dircopy catdir(".", $DATA_BACKUP, "mods"), catdir(".", "data", "mods");
  635.    
  636.    say "Delete 'data.bk'";
  637.    $OPT{keep} ? say "...skip deletion (--keep option)" :
  638.                 remove_tree "data.bk";
  639.    
  640. }
  641.  
  642. ################################################################################
  643. #
  644. # Начало программы
  645. #
  646. ################################################################################
  647. GetOptions \%OPT,
  648.    "check", "update",
  649.    "2chtiles", "2chsound", "2chmusic",
  650.    "nodownload", "keep",
  651.    "save"      => sub { say "Backup saves...";  backup_files "save", "save.bk"; exit },
  652.    "load"      => sub { say "Restore saves..."; backup_files "save.bk", "save"; exit },
  653.    "help|?"    => sub {
  654.    print <<USAGE
  655. Game:
  656.    --check       Check for aviable update
  657.    --update      Install/Update game to latest version
  658.                  Warning: non-standard mods in data/mods will be deleted,
  659.                  use mods/ folder for them.
  660.                
  661.    --save        Backup saves
  662.    --load        Restore saves
  663.    
  664. Resources:
  665.    --2chtileset  Install/Update Dead People tileset
  666.    --2chsound    Install/Update 2ch Sounpack
  667.    --2chmusic    Install/Update 2ch Music Pack
  668.  
  669. Options:
  670.    --keep        Don't delete temporal files
  671.   --nodownload  Don't download if file with same name already present
  672.    
  673. "Fast Cata" mod:
  674.    --fastmod     Backup original files and apply mod
  675.    --restore     Restore original files
  676. USAGE
  677. ;   exit;
  678. };
  679.  
  680. #------------------------------------------------------------
  681.  
  682. unless(%OPT) {
  683.    say "Do nothing. Try --help";
  684.    exit;
  685. }
  686.  
  687. check_for_update      if $OPT{check};
  688. update_game           if $OPT{update};
  689. update_2ch_tileset    if $OPT{"2chtiles"};
  690. update_2ch_soundpack  if $OPT{"2chsound"};
  691. update_2ch_musicpack  if $OPT{"2chmusic"};
  692. fast_mod_apply        if $OPT{fastmod};
  693. fast_mod_restore      if $OPT{restore};
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement