summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rwxr-xr-xbin/smt117
-rw-r--r--dist.ini10
-rw-r--r--lib/Games/SMTNocturne/Demons.pm148
-rw-r--r--lib/Games/SMTNocturne/Demons/Demon.pm47
-rw-r--r--lib/Games/SMTNocturne/Demons/Fusion.pm44
5 files changed, 365 insertions, 1 deletions
diff --git a/bin/smt b/bin/smt
index ac901f6..4ea8746 100755
--- a/bin/smt
+++ b/bin/smt
@@ -1,12 +1,129 @@
#!/usr/bin/env perl
use strict;
use warnings;
+# PODNAME: smt
+# ABSTRACT: command line interface to Games::SMTNocturne::Demons
use Getopt::Long;
use List::Util 'max', 'sum0';
use Games::SMTNocturne::Demons;
+=head1 SYNOPSIS
+
+ smt <command> [args...]
+
+ Possible commands:
+
+ demon <name>
+
+ demons_of_type <type>
+
+ all_demons
+
+ fuse [--boss <boss1>[,<boss2>...] [--deathstones <n>]
+ [--kagutsuchi <phase>] <demon1> <demon2>
+
+ fusions_for [--boss <boss1>[,<boss2>...] [--max_level <n>] <demon>
+
+ min_level_for [--boss <boss1>[,<boss2>...] [--max_level <n>] <demon>
+
+ party_fusion [--boss <boss1>[,<boss2>...] [--max_level <n>]
+ [--deathstones <n>] <demon1> [<demon2> ...]
+
+=head1 DESCRIPTION
+
+This program exposes the functionality from L<Games::SMTNocturne::Demons> on
+the command line, as well as adding some useful functionality on top of it.
+
+=head1 COMMANDS
+
+=head2 demon
+
+ $ smt demon Pixie
+ <Fairy Pixie (2)>
+
+Displays the type, name, and base level for the given demon.
+
+=head2 demons_of_type
+
+ $ smt demons_of_type Wilder
+ <Wilder Zhen (6)>
+ <Wilder Bicorn (15)>
+ <Wilder Raiju (25)>
+ <Wilder Nue (31)>
+ <Wilder Mothman (43)>
+ <Wilder Hresvelgr (75)>
+
+Displays the type, name, and base level for all demons of a given type.
+
+=head2 all_demons
+
+ $ smt all_demons
+ <Foul Will o' Wisp (1)>
+ <Fairy Pixie (2)>
+ <Jirae Kodama (3)>
+ <Haunt Preta (4)>
+ <Brute Shikigami (4)>
+ <Jirae Hua Po (5)>
+ <Foul Slime (6)>
+ <Wilder Zhen (6)>
+ <Femme Datsue-Ba (7)>
+ <Element Erthys (7)>
+ [...]
+
+Displays the type, name, and base level for all demons.
+
+=head2 fuse
+
+ $ smt fuse Zhen Lilim
+ <Beast Inugami (13)>
+
+Displays the demon that would result from fusing C<demon1> with C<demon2>.
+
+=head2 fusions_for
+
+ $ smt fusions_for 'Jack Frost'
+ Fuse <Brute Shikigami (4)> with <Wilder Zhen (6)> resulting in <Fairy Jack Frost (7)>
+ Fuse <Jirae Kodama (3)> with <Brute Shikigami (4)> resulting in <Fairy Jack Frost (7)>
+ Fuse <Jirae Hua Po (5)> with <Brute Shikigami (4)> resulting in <Fairy Jack Frost (7)>
+ Fuse <Mitama Ara Mitama (25)> with <Fairy Jack Frost (7)> resulting in <Fairy Jack Frost (7)>
+ [...]
+
+Displays all possible ways to create C<demon> via fusion.
+
+=head2 min_level_for
+
+ $ smt min_level_for 'Jack Frost'
+ Level 4:
+ Fuse <Jirae Kodama (3)> with <Brute Shikigami (4)> resulting in <Fairy Jack Frost (7)>
+
+Calculates the "easiest" way to fuse a given demon, where "easiest" is defined
+as requiring the lowest leveled demons possible.
+
+=head2 party_fusion
+
+ $ smt party_fusion Pixie 'Hua Po' Zhen
+ <Fairy Pixie (2)>
+ <Jirae Hua Po (5)>
+ <Wilder Zhen (6)>
+ <Yoma Apsaras (8)>:
+ Fuse <Jirae Hua Po (5)> with <Fairy Pixie (2)> resulting in <Yoma Apsaras (8)>
+ <Beast Inugami (13)>:
+ Fuse <Jirae Hua Po (5)> with <Fairy Pixie (2)> resulting in <Yoma Apsaras (8)>
+ Fuse <Yoma Apsaras (8)> with <Wilder Zhen (6)> resulting in <Beast Inugami (13)>
+ <Night Fomor (18)>:
+ Fuse <Jirae Hua Po (5)> with <Wilder Zhen (6)> resulting in <Brute Momunofu (20)>
+ Fuse <Brute Momunofu (20)> with <Fairy Pixie (2)> resulting in <Night Fomor (18)>
+ <Brute Momunofu (20)>:
+ Fuse <Jirae Hua Po (5)> with <Wilder Zhen (6)> resulting in <Brute Momunofu (20)>
+
+
+Calculates all possible demons that can be fused from the given party, as well
+as an example path to take in order to create that demon.
+
+=cut
+
sub _demon { Games::SMTNocturne::Demons::demon(@_) }
sub _demons_of_type { Games::SMTNocturne::Demons::demons_of_type(@_) }
sub _all_demons { Games::SMTNocturne::Demons::all_demons(@_) }
diff --git a/dist.ini b/dist.ini
index 367805e..eaf6abc 100644
--- a/dist.ini
+++ b/dist.ini
@@ -3,11 +3,19 @@ author = Jesse Luehrs <doy@tozt.net>
license = MIT
copyright_holder = Jesse Luehrs
+[FileFinder::Filter / WeaverFiles]
+finder = :InstallModules
+finder = :ExecFiles
+skip = ^lib/Games/SMTNocturne/Demons/FusionChart.pm$
+
[@DOY]
:version = 0.14
dist = Games-SMTNocturne-Demons
repository = github
-bugtracker_web = https://github.com/doy/games-smtnocturne-demons/issues
+PodWeaver_finder = WeaverFiles
+
+[MetaNoIndex]
+package = Games::SMTNocturne::Demons::FusionChart
[AutoPrereqs]
diff --git a/lib/Games/SMTNocturne/Demons.pm b/lib/Games/SMTNocturne/Demons.pm
index 2725c8c..50e69f3 100644
--- a/lib/Games/SMTNocturne/Demons.pm
+++ b/lib/Games/SMTNocturne/Demons.pm
@@ -1,6 +1,7 @@
package Games::SMTNocturne::Demons;
use strict;
use warnings;
+# ABSTRACT: look up information about demon fusion in Shin Megami Tensei: Nocturne
use Exporter 'import';
our @EXPORT_OK = qw(demon demons_of_type all_demons fuse fusions_for);
@@ -9,22 +10,99 @@ use Games::SMTNocturne::Demons::Demon;
use Games::SMTNocturne::Demons::Fusion;
use Games::SMTNocturne::Demons::FusionChart;
+=head1 SYNOPSIS
+
+ use Games::SMTNocturne::Demons qw(fuse fusions_for);
+
+ say fuse('Rangda', 'Barong');
+ # <Fury Shiva (95)>
+
+ say for fusions_for('Shiva');
+ # Fuse <Mitama Ara Mitama (25)> with <Fury Shiva (95)> resulting in <Fury Shiva (95)>
+ # Fuse <Mitama Nigi Mitama (29)> with <Fury Shiva (95)> resulting in <Fury Shiva (95)>
+ # Fuse <Mitama Kusi Mitama (32)> with <Fury Shiva (95)> resulting in <Fury Shiva (95)>
+ # Fuse <Mitama Saki Mitama (35)> with <Fury Shiva (95)> resulting in <Fury Shiva (95)>
+ # Fuse <Avatar Barong (60)> with <Femme Rangda (72)> resulting in <Fury Shiva (95)>
+
+=head1 DESCRIPTION
+
+This module implements various routines for modeling demon fusion in the
+PlayStation 2 game Shin Megami Tensei: Nocturne. Note that it also comes with a
+command line script called C<smt> which implements some more useful commands on
+top of the basic functionality given here; see its documentation for more
+information. All of the functions listed below are exported on request.
+
+=cut
+
+=func demon($name)
+
+Returns an instance of L<Games::SMTNocturne::Demons::Demon> for the named
+demon. Throws an exception if no such demon exists.
+
+=cut
+
sub demon {
my ($demon) = @_;
return Games::SMTNocturne::Demons::Demon->from_name($demon);
}
+=func demons_of_type($name)
+
+Returns a list of all demons of a given type. Throws an exception if no such
+type exists.
+
+=cut
+
sub demons_of_type {
my ($type) = @_;
return Games::SMTNocturne::Demons::Demon->from_type($type);
}
+=func all_demons
+
+Returns a list of all demons in the game.
+
+=cut
+
sub all_demons {
return Games::SMTNocturne::Demons::Demon->all_demons;
}
+=func fuse($demon1, $demon2, $options)
+
+Returns the demon that will be created when fusing C<$demon1> with C<$demon2>.
+Possible options (all optional) are:
+
+=over 4
+
+=item sacrifice
+
+A third demon to be sacrificed (at full Kagutsuchi).
+
+=item max_level
+
+The level of your main character (so fusions that would result in a demon of a
+higher level than this will be ignored).
+
+=item bosses
+
+An arrayref of boss demons which have been defeated. Any boss demon not listed
+here will be unavailable for fusion.
+
+=item deathstone
+
+Whether or not you own any deathstones.
+
+=item kagutsuchi
+
+The current Kagutsuchi phase.
+
+=back
+
+=cut
+
sub fuse {
my ($demon1, $demon2, $options) = @_;
$options = { %{ $options || {} } };
@@ -77,6 +155,27 @@ sub fuse {
}
}
+=func fusions_for($demon, $options)
+
+Returns a list of all possible demons fusions which can result in the given
+demon. Possible options (all optional) are:
+
+=over 4
+
+=item max_level
+
+The level of your main character (so fusions that would result in a demon of a
+higher level than this will be ignored).
+
+=item bosses
+
+An arrayref of boss demons which have been defeated. Any boss demon not listed
+here will be unavailable for fusion.
+
+=back
+
+=cut
+
sub fusions_for {
my ($demon, $options) = @_;
@@ -277,4 +376,53 @@ sub _normal_fusion {
});
}
+=head1 BUGS
+
+Probably a lot, since I just wrote this on the fly as I was playing. It was
+reasonably accurate enough to get me through the game, but it probably needs a
+lot more cleaning around the edges. Failing tests welcome!
+
+One notable omission (that I would be interested in fixing) is that this module
+does not handle cursed fusions (mostly since taking advantage of cursed fusions
+is so difficult in the game to begin with).
+
+Please report any bugs to GitHub Issues at
+L<https://github.com/doy/games-smtnocturne-demons/issues>.
+
+=head1 SEE ALSO
+
+L<http://megamitensei.wikia.com/wiki/Shin_Megami_Tensei_III:_Nocturne>
+
+L<http://www.gamefaqs.com/ps2/582958-shin-megami-tensei-nocturne/faqs/35110>
+
+=head1 SUPPORT
+
+You can find this documentation for this module with the perldoc command.
+
+ perldoc Games::SMTNocturne::Demons
+
+You can also look for information at:
+
+=over 4
+
+=item * MetaCPAN
+
+L<https://metacpan.org/release/Games-SMTNocturne-Demons>
+
+=item * Github
+
+L<https://github.com/doy/games-smtnocturne-demons>
+
+=item * RT: CPAN's request tracker
+
+L<http://rt.cpan.org/NoAuth/Bugs.html?Dist=Games-SMTNocturne-Demons>
+
+=item * CPAN Ratings
+
+L<http://cpanratings.perl.org/d/Games-SMTNocturne-Demons>
+
+=back
+
+=cut
+
1;
diff --git a/lib/Games/SMTNocturne/Demons/Demon.pm b/lib/Games/SMTNocturne/Demons/Demon.pm
index bc1e958..dee3855 100644
--- a/lib/Games/SMTNocturne/Demons/Demon.pm
+++ b/lib/Games/SMTNocturne/Demons/Demon.pm
@@ -2,9 +2,29 @@ package Games::SMTNocturne::Demons::Demon;
use strict;
use warnings;
use overload '""' => 'to_string', fallback => 1;
+# ABSTRACT: an individual demon
use JSON::PP;
+=head1 SYNOPSIS
+
+ use Games::SMTNocturne::Demons 'demon';
+
+ my $pixie = demon('Pixie');
+ say $pixie->name # 'Pixie'
+ say $pixie->level # 2
+ say $pixie->type # 'Fairy'
+
+=head1 DESCRIPTION
+
+This class represents an individual demon. You typically create instances of
+this class via the functions in the L<Games::SMTNocturne::Demons> package, and
+you can then look up various data using the accessors here. This class also
+includes a stringification overload to display the information about the demon
+in a readable form.
+
+=cut
+
my %DEMONS_BY_NAME = %{ decode_json(do { local $/; <DATA> }) };
for my $name (keys %DEMONS_BY_NAME) {
$DEMONS_BY_NAME{$name}{name} = $name;
@@ -75,6 +95,33 @@ sub from_type {
return @{ $DEMONS_BY_TYPE{$type} };
}
+=method boss
+
+True if the demon is a boss (meaning that fusing it will not be possible until
+it has been defeated).
+
+=method fusion_type
+
+How this demon can be created. Can be C<normal> for demons that can be fused
+normally, C<evolve> for demons that must be evolved, C<special> for demons
+that require special fusions, and C<deathstone> for demons that require a
+deathstone in order to fuse.
+
+=method level
+
+The base level of the demon. This level is what is used in the fusion process,
+regardless of the experience level of the actual demon in your party.
+
+=method name
+
+The name of the demon.
+
+=method type
+
+The type of the demon (C<Fairy>, C<Yoma>, etc).
+
+=cut
+
sub boss { $_[0]->{boss} }
sub fusion_type { $_[0]->{fusion_type} }
sub level { $_[0]->{level} }
diff --git a/lib/Games/SMTNocturne/Demons/Fusion.pm b/lib/Games/SMTNocturne/Demons/Fusion.pm
index cdfdcd8..4c1c901 100644
--- a/lib/Games/SMTNocturne/Demons/Fusion.pm
+++ b/lib/Games/SMTNocturne/Demons/Fusion.pm
@@ -2,9 +2,30 @@ package Games::SMTNocturne::Demons::Fusion;
use strict;
use warnings;
use overload '""' => 'to_string';
+# ABSTRACT: represents the results of a fusion
use Games::SMTNocturne::Demons::Demon;
+=head1 SYNOPSIS
+
+ use Games::SMTNocturne::Demons 'fusions_for';
+
+ my @fusions = fusions_for('Jack Frost');
+
+ say $fusions[0]->demons->[0]; # <Divine Angel (11)>
+ say $fusions[0]->demons->[1]; # <Foul Will o' Wisp (1)>
+ say $fusions[0]->result; # <Fairy Jack Frost (7)>
+ say $fusions[0]; # Fuse <Divine Angel (11)> with <Foul Will o' Wisp (1)> resulting in <Fairy Jack Frost (7)>
+
+=head1 DESCRIPTION
+
+This class represents the result of a demon fusion which was calculated by the
+C<fusions_for> function in L<Games::SMTNocturne::Demons>. It includes various
+accessor methods to get information about the generated fusion, as well as a
+stringification overload to produce a readable summary.
+
+=cut
+
sub new {
my ($class, $options, $demon1, $demon2, $sacrifice, $kagutsuchi) = @_;
@@ -33,6 +54,29 @@ sub new {
return bless $attrs, $class;
}
+=method demons
+
+An arrayref containing the two demons to be fused.
+
+=method sacrifice
+
+An optional third demon to be sacrificed (at full Kagutsuchi).
+
+=method deathstone
+
+True if this fusion requires a deathstone.
+
+=method kagutsuchi
+
+An optional arrayref containing the Kagutsuchi phases during which this fusion
+may take place.
+
+=method result
+
+The demon that will be created by the fusion.
+
+=cut
+
sub options { $_[0]->{options} }
sub demons { $_[0]->{demons} }
sub sacrifice { $_[0]->{sacrifice} }