Advertisement
theanonym

cata_edit.pl

Dec 13th, 2018
240
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Perl 12.33 KB | None | 0 0
  1. #############################################################
  2. #
  3. # Скрипт модифицирует игровые файлы с целью уменьшить простои вроде
  4. # установки каждой рамы по 2 часа и чтения одной книги весь день.
  5. #
  6. # Резервная копия оригинальных файлов сохраняется в data.bk в папке игры.
  7. # Оригинальные файлы можно восстановить запустив скрипт с ключом --restore.
  8. # Лог всех изменений сохраняется в cata_edit.log рядом со скриптом.
  9. # Пример лога: https://pastebin.com/raw/CkSwDgnE
  10. #
  11. #
  12. # В случае ошибки "Can't locate ХХХ/XXX.pm" установить зависимости:
  13. #
  14. # # curl -L https://cpanmin.us | perl - App::cpanminus
  15. # # cpanm --notest XXX::XXX
  16. #
  17. #############################################################
  18.  
  19. use v5.20;
  20. use autodie;
  21. no warnings "experimental";
  22.  
  23. use File::Slurp qw/read_file write_file/;
  24. use File::Find::Rule;
  25. use File::Copy::Recursive qw/dircopy/;
  26. use File::Path qw/remove_tree/;
  27. use List::Util qw/min max/;
  28. use List::MoreUtils qw/first_index first_value any/;
  29. use JSON;
  30.  
  31. #------------------------------------------------------------
  32.  
  33. # Путь к игре где лежит папка data
  34. our $game_path = "c:/Games/Cataclysm";
  35.  
  36. # Настройки
  37. our %settings = (
  38.    # Коэффициенты времени выполнения
  39.    # 1 = 100%
  40.    parts_install_time => 0.2, # Время установки деталей 0.2 = 20%
  41.    parts_repair_time  => 0.2, # Ремонта
  42.    parts_removal_time => 0.2, # Удаления
  43.    
  44.    craft_time         => 0.2, # Время крафта
  45.    books_time         => 0.2, # Чтения
  46.    
  47.    # К указанной мутации добавляется эффект ускоренного сна
  48.    sleep_acceliration => 1.0,            # 1.0 = энергия восстанавливается на 100% быстрее
  49.    sleep_mutation_id  => "HEAVYSLEEPER", # Крепкий сон
  50. );
  51.  
  52. #------------------------------------------------------------
  53.  
  54. sub report($;@) {
  55.    my(@strings) = map { "$_\n" } @_;
  56.  
  57.    state $log;
  58.    open $log, ">", "cata_edit.log" unless defined $log;
  59.    #print @strings;
  60.    print $log @strings;
  61. }
  62.  
  63. sub json_to_perl($) {
  64.    my($json_string) = @_;
  65.    JSON->new->utf8->decode($json_string);
  66. }
  67.  
  68. sub perl_to_json($) {
  69.    my($array_ref) = @_;
  70.    JSON->new->utf8->allow_nonref->pretty->encode($array_ref);
  71. }
  72.  
  73. sub compute_new_time($$) {
  74.    my($original_time, $requirement_type) = @_;
  75.    #$original_time = max(60000, $original_time);
  76.    int max 0, $original_time * $settings{"parts_${requirement_type}_time"};
  77. }
  78.  
  79. sub compute_time_from_difficulty($$) {
  80.    my($difficulty, $requirement_type) = @_;
  81.    ($difficulty + 1) * 30000;
  82. }
  83.  
  84. sub has_standard_difficulty($) {
  85.    my($node) = @_;
  86.    exists $node->{difficulty};
  87. }
  88.  
  89. sub has_difficulty_in_requirements($$) {
  90.    my($node, $requirement_type) = @_;
  91.    exists $node->{requirements}->{$requirement_type}->{skills}
  92.           && any { "mechanics" } $node->{requirements}->{$requirement_type}->{skills};
  93. }
  94.  
  95. sub has_time_in_requirements($$) {
  96.    my($node, $requirement_type) = @_;
  97.    exists $node->{requirements}->{$requirement_type}->{time};
  98. }
  99.  
  100. sub has_parent($) {
  101.    my($node) = @_;
  102.    exists $node->{"copy-from"};
  103. }
  104.  
  105. sub get_parent($$) {
  106.    my($json, $node) = @_;
  107.    die perl_to_json $node unless has_parent $node;
  108.    
  109.    my $copy_from = $node->{"copy-from"};
  110.    first_value { $_->{id} eq $copy_from || $_->{abstract} eq $copy_from } @$json
  111. }
  112.  
  113. sub get_id($) {
  114.    my($node) = @_;
  115.    $node->{id} ? $node->{id} : $node->{result} ? $node->{result} : $node->{abstract};
  116. }
  117.  
  118. sub get_standard_difficulty($) {
  119.    my($node) = @_;
  120.    die perl_to_json $node unless has_standard_difficulty $node;
  121.    
  122.    $node->{difficulty};
  123. }
  124.  
  125. sub get_difficulty_from_requirements($$) {
  126.    my($node, $requirement_type) = @_;
  127.    die perl_to_json $node unless has_difficulty_in_requirements $node, $requirement_type;
  128.    
  129.    $node->{requirements}->{$requirement_type}->{skills}->[
  130.       first_index { "mechanics" } $node->{requirements}->{$requirement_type}->{skills}
  131.       + 1
  132.    ]->[1];
  133. }
  134.  
  135. sub get_time_from_requirements($$) {
  136.    my($node, $requirement_type) = @_;
  137.    die perl_to_json $node unless has_time_in_requirements $node, $requirement_type;
  138.    
  139.    $node->{requirements}->{$requirement_type}->{time};
  140. }
  141.  
  142. sub set_time_to_requirements($$$) {
  143.    my($node, $requirement_type, $time) = @_;
  144.    
  145.    $node->{requirements}->{$requirement_type}->{time} = int $time;
  146. }
  147.  
  148. sub set_difficulty_to_requirements($$$) {
  149.    my($node, $requirement_type, $difficulty) = @_;
  150.    
  151.    push @{ $node->{requirements}->{$requirement_type}->{skills} }, [ "mechanics", int $difficulty ];
  152. }
  153.  
  154. sub check_flag($$) {
  155.    my($node, $flag) = @_;
  156.    any { $flag } $node->{flags};
  157. }
  158.  
  159. #------------------------------------------------------------
  160.  
  161. if(-d "$game_path/data.bk") {
  162.    if(any { "--restore" } @ARGV) {
  163.       say "Restoring original files...";
  164.       dircopy "$game_path/data.bk/json", "$game_path/data/json";
  165.       dircopy "$game_path/data.bk/mods", "$game_path/data/mods";
  166.       remove_tree "$game_path/data.bk";
  167.       say "Done";
  168.    } else {
  169.       say "Game files already modified, try --restore first";
  170.    }
  171.    
  172.    exit;
  173. } else {
  174.    report "Backup original files to '$game_path/data.bk'...";
  175.    dircopy "$game_path/data/json", "$game_path/data.bk/json";
  176.    dircopy "$game_path/data/mods", "$game_path/data.bk/mods";
  177.    report "Done";
  178. }
  179.  
  180. #------------------------------------------------------------
  181.  
  182. my %count = (checked => 0, modified => 0, parts => 0, books => 0, mutations => 0);
  183.  
  184. for my $file_path (
  185.    File::Find::Rule->file->name("*.json")->in(
  186.       "$game_path/data/json/vehicleparts",
  187.       "$game_path/data/json/items/book",
  188.       "$game_path/data/json/recipes",
  189.       "$game_path/data/mods"
  190.    ),
  191.    "$game_path/data/json/mutations.json"
  192. ) {
  193.    $count{checked}++;
  194.    
  195.    my $text = read_file $file_path;
  196.    my $file_modified = 0;
  197.    
  198.    my $json = json_to_perl($text);
  199.    next if ref $json ne "ARRAY";
  200.    
  201.    for my $node (@$json) {
  202.       next if ref $node ne "HASH";
  203.       next unless exists $node->{type};
  204.      
  205.       my $id = get_id($node);
  206.       my $node_modified = 0;
  207.      
  208.       given($node->{type}) {
  209.          when("vehicle_part") {
  210.             for my $requirement_type ("install", "repair", "removal") {
  211.                my $original_difficulty;
  212.                my $original_time;
  213.                
  214.                if(has_difficulty_in_requirements $node, $requirement_type) {
  215.                   $original_difficulty = get_difficulty_from_requirements $node, $requirement_type;
  216.                } elsif (has_standard_difficulty $node) {
  217.                   $original_difficulty = get_standard_difficulty $node;
  218.                } elsif(has_parent $node) {
  219.                   my $parent_node = get_parent($json, $node);
  220.                   if(has_standard_difficulty $parent_node) {
  221.                      $original_difficulty = get_standard_difficulty $parent_node;
  222.                   } elsif(has_difficulty_in_requirements $parent_node, $requirement_type) {
  223.                      $original_difficulty = get_difficulty_from_requirements $parent_node,
  224.                                                                              $requirement_type;
  225.                   } else {
  226.                      report "Part '$id' has no difficulty";
  227.                   }
  228.                }
  229.                
  230.                die if defined $original_difficulty && length $original_difficulty == 0;
  231.                
  232.                if(has_time_in_requirements $node, $requirement_type) {
  233.                   $original_time = get_time_from_requirements $node, $requirement_type;
  234.                   if(defined $original_difficulty) {
  235.                      $original_time = min($original_time,
  236.                                           compute_time_from_difficulty $original_difficulty,
  237.                                                                        $requirement_type);
  238.                   }
  239.                } elsif(defined $original_difficulty) {
  240.                   $original_time = compute_time_from_difficulty $original_difficulty,
  241.                                                                 $requirement_type;
  242.                }
  243.                
  244.                if(defined $original_time) {
  245.                   set_time_to_requirements $node,
  246.                                            $requirement_type,
  247.                                            compute_new_time $original_time, $requirement_type;
  248.                                            
  249.                   if(defined $original_difficulty && !has_difficulty_in_requirements $node, $requirement_type) {
  250.                      set_difficulty_to_requirements $node,
  251.                                                     $requirement_type,
  252.                                                     $original_difficulty;
  253.                   }
  254.  
  255.                   report sprintf "Part '%s'%s (difficulty: %d): change $requirement_type time %d -> %d",
  256.                      $id,
  257.                      has_parent($node)?" (parent: '" . get_id(get_parent($json, $node)) . "')":"",
  258.                      $original_difficulty,
  259.                      $original_time,
  260.                      compute_new_time $original_time, $requirement_type;
  261.                      
  262.                   $file_modified = 1;
  263.                   $node_modified = 1;
  264.                   $count{parts}++;
  265.                } elsif(defined $original_difficulty && !exists $node->{abstract}) {
  266.                   report "Can't determine $requirement_type time for '$id'";
  267.                }
  268.             }
  269.          }
  270.          when("BOOK") {
  271.             if(exists $node->{time}) {
  272.                my $old_time = $node->{time};
  273.                my $new_time = int($old_time * $settings{books_time});
  274.                $new_time = 1 if $new_time < 1 && $old_time >= 1;
  275.                $node->{time} = $new_time;
  276.                
  277.                report "Book '$node->{id}': change reading time $old_time -> $new_time";
  278.                
  279.                $file_modified = 1;
  280.                $node_modified = 1;
  281.                $count{books}++;
  282.             }
  283.          }
  284.          when("recipe") {
  285.             if(exists $node->{time}) {
  286.                my $id = get_id($node);
  287.                my $old_time = $node->{time};
  288.                my $new_time = int($old_time * $settings{books_time});
  289.                $new_time = 1 if $new_time < 1 && $old_time >= 1;
  290.                $node->{time} = $new_time;
  291.                
  292.                report "Recipe '$id': change craft time $old_time -> $new_time";
  293.                
  294.                $file_modified = 1;
  295.                $node_modified = 1;
  296.                $count{recipes}++;
  297.             } else {
  298.                report "Recipe '$id' has no time";
  299.             }
  300.          }
  301.          when("mutation") {
  302.             if($node->{id} eq $settings{sleep_mutation_id}) {
  303.                $node->{fatigue_regen_modifier} = $settings{sleep_acceliration};
  304.                
  305.                report "Mutation '$node->{id}': faster sleep effect added";
  306.                
  307.                $file_modified = 1;
  308.                $node_modified = 1;
  309.                $count{mutations}++;
  310.             }
  311.          }
  312.       }
  313.      
  314.       if($node_modified) {
  315.          #$node->{MODIFIED} = $JSON::true;
  316.       }
  317.    }
  318.    
  319.    for my $node (grep { ref $_ eq "HASH" && $_->{type} eq "vehicle_part" } @$json) {
  320.       for my $requirement_type ("install", "repair", "removal") {
  321.          if(exists $node->{requirements}->{$requirement_type} && %{$node->{requirements}->{$requirement_type}} == 0) {
  322.             delete $node->{requirements}->{$requirement_type};
  323.          }
  324.       }
  325.    }
  326.    
  327.    if($file_modified) {
  328.       say "Edit file '$file_path'";
  329.       write_file $file_path, perl_to_json $json;
  330.      
  331.       $count{modified}++;
  332.    }
  333. }
  334.  
  335. #------------------------------------------------------------
  336.  
  337. report "\nFiles checked: $count{checked}",
  338.        "Files edited: $count{modified}",
  339.        "Parts: $count{parts}",
  340.        "Books: $count{books}",
  341.        "Recipes: $count{recipes}",
  342.        "Mutations: $count{mutations}";
  343.  
  344. #------------------------------------------------------------
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement