Advertisement
Guest User

patchmarriage.pl

a guest
Oct 27th, 2019
581
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Perl 2.83 KB | None | 0 0
  1. #!/usr/bin/env perl
  2.  
  3. use v5.26.1;
  4. use strict;
  5. use warnings;
  6. use autodie qw(:all);
  7.  
  8. our $VERSION = 'v1.0';
  9.  
  10. use Digest::file qw(digest_file_base64);
  11. use File::Copy;
  12. use File::Temp;
  13. use Getopt::Long;
  14. use Pod::Usage;
  15. use IO::File;
  16.  
  17. my $original_path;
  18. my $patched_path;
  19. my $range = 15;
  20. my $invert = 1;
  21. my $help = 0;
  22.  
  23. GetOptions('original=s' => \$original_path,
  24.            'patched=s' => \$patched_path,
  25.            'range=i' => \$range,
  26.            'invert!' => \$invert,
  27.            'help|?' => \$help);
  28.  
  29. pod2usage(0) if $help;
  30.  
  31. if (!defined($original_path) || !defined($patched_path)
  32.     || !defined($range) || !defined($invert)) {
  33.     pod2usage(1);
  34. }
  35.  
  36. die "$patched_path already exists" if -e $patched_path;
  37.  
  38. my $original_digest = digest_file_base64($original_path, "SHA-1");
  39.  
  40. sub expect {
  41.     my ($fh, $offset, $expected) = @_;
  42.     $fh->seek($offset, 0);
  43.     my $original;
  44.     $fh->read($original, length($expected));
  45.     if ($original ne $expected) {
  46.         die <<ERROR;
  47. expected @{[unpack('H*', $expected)]}
  48. received @{[unpack('H*', $original)]}
  49. ERROR
  50.     }
  51. }
  52.  
  53. sub patch {
  54.     my ($fh, $offset, $expected, $patched) = @_;
  55.     printf("@%x\n", $offset);
  56.     say unpack('H*', $expected);
  57.     say unpack('H*', $patched);
  58.     die "length mismatch" if length($expected) != length($patched);
  59.     expect($fh, $offset, $expected);
  60.     $fh->seek($offset, 0);
  61.     $fh->write($patched);
  62.     expect($fh, $offset, $patched);
  63. }
  64.  
  65. sub linux64_44_12 {
  66.     my ($fh) = @_;
  67.     #  (eax = age difference) add $9, %eax; cmp $18, %eax; ja
  68.     my $original = pack('H*', '83c00983f8120f87');
  69.     die "range must not be zero" if !$range;
  70.     die "range must be less than 128" if 2 * $range > 255;
  71.     my $patched = '83c0' . sprintf('%02x', $range);
  72.     $patched .= '83f8' . sprintf('%02x', 2 * $range);
  73.     if ($invert) {
  74.         $patched .= '0f86'; # jbe
  75.     } else {
  76.         $patched .= '0f87';
  77.     }
  78.     for my $offset (0x0c4ed67, 0x0c7d82f) {
  79.         patch($fh, $offset, $original, pack('H*', $patched));
  80.     }
  81. }
  82.  
  83. my %digests = (hTVmt1eReW9h36t2uKQv4nTjoEA => \&linux64_44_12);
  84.  
  85. unless (exists $digests{$original_digest}) {
  86.     die "$original_path ($original_digest) not a supported version";
  87. }
  88.  
  89. my ($tmp_file, $tmp_path) = File::Temp::tempfile;
  90. File::Copy::copy($original_path, $tmp_path);
  91.  
  92. $digests{$original_digest}->($tmp_file);
  93.  
  94. File::Copy::move($tmp_path, $patched_path);
  95.  
  96. say "wrote $patched_path";
  97.  
  98. __END__
  99.  
  100. =head1 patchmarriage.pl
  101.  
  102. patchmarriage.pl - manipulate Dwarf Fortress marriageability
  103.  
  104. =head1 SYNOPSIS
  105.  
  106. patchmarriage.pl [options] --original <infile-DF-binary> --patched <outfile>
  107.  
  108. =head1 OPTIONS
  109.  
  110. =item B<--range=<years>>
  111.  
  112. Require being within <years> of age to marry (default: 15). Can't be 0
  113. presently
  114.  
  115. =item B<--[no-]invert>
  116.  
  117. Invert marriageability requirements (default: --invert)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement