summaryrefslogtreecommitdiffstats
path: root/bin/smt_fusion
blob: 9fb9da1cf3f3c9fbb31a4e7e8c0907203dab4000 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
#!/usr/bin/env perl
use strict;
use warnings;

use Getopt::Long;
use List::Util 'max';

use Games::SMTNocturne::Demons;

sub _demon       { Games::SMTNocturne::Demons::demon(@_) }
sub _fuse        { Games::SMTNocturne::Demons::fuse(@_) }
sub _fusions_for { Games::SMTNocturne::Demons::fusions_for(@_) }

my $command = shift @ARGV;

my ($max_level, $deathstones, $kagatsuchi, $bosses);
GetOptions(
    "max_level=i"   => \$max_level,
    "deathstones=i" => \$deathstones,
    "kagatsuchi=i"  => \$kagatsuchi,
    "boss=s@"       => \$bosses,
) or die "couldn't parse options";

my $options = {
    max_level  => $max_level,
    deathstone => $deathstones,
    kagatsuchi => $kagatsuchi,
    bosses     => $bosses,
};

if ($command !~ /^_/ && defined &$command) {
    { no strict 'refs'; &{ $command }(@ARGV) }
}
else {
    die "unknown command $command";
}

sub demon {
    my ($demon) = @_;
    print _demon($demon), "\n";
}

sub fuse {
    my ($demon1, $demon2) = @_;
    print _fuse($demon1, $demon2, $options), "\n";
}

sub fusions_for {
    my ($demon) = @_;
    print join("\n", _fusions_for($demon, $options)), "\n";
}

sub min_level_for {
    my ($demon) = @_;

    my @fusions = _fusions_for($demon, $options);
    my $min_level = 99;
    my @min_level_fusions;
    for my $fusion (@fusions) {
        my $max_level = max(map { $_->level } $fusion->all_demons);
        if ($max_level < $min_level) {
            @min_level_fusions = ($fusion);
            $min_level = $max_level;
        }
        elsif ($max_level == $min_level) {
            push @min_level_fusions, $fusion;
        }
    }
    print "Level $min_level:\n";
    print join("\n", @min_level_fusions), "\n";
}

sub party_fusion {
    my @demons = @_;

    my $seen = _party_fusion_recursive_fuse(
        {},
        $deathstones,
        map { _demon($_) } @demons
    );
    print join("\n",
        sort { $a->level <=> $b->level } map { _demon($_) } keys %$seen
    ), "\n";
}
sub _party_fusion_recursive_fuse {
    my ($seen, $deathstones, @demons) = @_;

    $seen->{$_} = 1 for map { $_->name } @demons;

    if (@demons > 1) {
        my $check_fusion = sub {
            my ($demon1, $demon2, $sacrifice, $phase) = @_;

            my $fused = _fuse(
                $demon1, $demon2,
                {
                    %$options,
                    sacrifice => $sacrifice,
                    deathstone => $deathstones,
                    kagatsuchi => $phase,
                },
            );
            return unless $fused;
            return if defined $max_level && $fused->level > $max_level;
            my @new_party = (
                $fused,
                grep {
                    $_ ne $demon1 && $_ ne $demon2
                    && (!$sacrifice || $_ ne $sacrifice)
                } @demons
            );
            _party_fusion_recursive_fuse(
                $seen,
                ($fused->type eq 'Fiend' ? $deathstones - 1 : $deathstones),
                @new_party
            );
        };

        for my $demon1 (@demons) {
            for my $demon2 (grep { $_ ne $demon1 } @demons) {
                if ($deathstones) {
                    for my $phase (0..8) {
                        $check_fusion->($demon1, $demon2, undef, $phase);
                    }
                }
                else {
                    $check_fusion->($demon1, $demon2);
                }
                for my $demon3 (grep { $_ ne $demon1 && $_ ne $demon2 } @demons) {
                    $check_fusion->($demon1, $demon2, $demon3);
                }
            }
        }
    }

    return $seen;
}