File Coverage

blib/lib/Game/CharacterSheetGenerator/ElfNames.pm
Criterion Covered Total %
statement 48 54 88.8
branch 11 16 68.7
condition n/a
subroutine 8 8 100.0
pod 0 5 0.0
total 67 83 80.7


line stmt bran cond sub pod time code
1             #!/usr/bin/env perl
2             # Copyright (C) 2012-2022 Alex Schroeder
3              
4             # This program is free software: you can redistribute it and/or modify it under
5             # the terms of the GNU General Public License as published by the Free Software
6             # Foundation, either version 3 of the License, or (at your option) any later
7             # version.
8             #
9             # This program is distributed in the hope that it will be useful, but WITHOUT
10             # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11             # FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
12             #
13             # You should have received a copy of the GNU General Public License along with
14             # this program. If not, see .
15              
16             =encoding utf8
17              
18             =head1 NAME
19              
20             Game::CharacterSheetGenerator::ElfName - return a elf name
21              
22             =head1 SYNOPSIS
23              
24             use Game::CharacterSheetGenerator::ElfName qw(elf_name);
25             # returns both $name and $gender (F, M, or ?)
26             my ($name, $gender) = elf_name();
27             # returns the same name and its gender
28             ($name, $gender) = elf_name("Alex");
29              
30             =head1 DESCRIPTION
31              
32             This package has one function that returns a elf name and a gender. The gender
33             returned is "M", "F", or "?".
34              
35             If a name is provided, the gender is returned.
36              
37             =cut
38              
39             package Game::CharacterSheetGenerator::ElfNames;
40 9     9   59 use Modern::Perl;
  9         27  
  9         45  
41 9     9   1515 use utf8;
  9         30  
  9         51  
42              
43             require Exporter;
44             our @ISA = qw(Exporter);
45             our @EXPORT_OK = qw(elf_name);
46              
47             sub one {
48 92     92 0 190 my $i = int(rand(scalar @_));
49 92         478 return $_[$i];
50             }
51              
52             # Sindarin-English & English-Sindarin Dictionary, J-M Carpenter (2017)
53             # https://realelvish.net/names/sindarin/woodelf/all/
54             # https://sindarinlessons.weebly.com/36---how-to-make-names-1.html
55             # https://sindarinlessons.weebly.com/37---how-to-make-names-2.html
56              
57             my @prefix =
58             qw(achar adertha adleg al amartha aníra aphada ar ava awartha badh batha
59             beria blab brenia brona buia cab can car carpha cen critha dartha delia
60             dew díhena doltha drava drega dringa echad edledhia egleria eitha elia
61             ercha ertha fantha fara feira feria fuia gad gala gir gladh glavra
62             glintha glir gohena gonod gor gosta groga gruitha gwatha gwathra gweria
63             gwesta had hal haltha hamma harna hasta henia hwinia ialla ídha ídhra
64             ista iuitha laba lala lamma lasta lathra linna luitha mel metha mista nag
65             nalla nara narcha ndag ndagra ndamma nde nedia negra neitha nella nesta
66             ngal nganna nod nor northa orthel orthor osgar pad padra ped pel per puia
67             rada ran reda redh reitha reth rhib rista ritha rosta ruthra síla sog
68             suila teilia teitha telia theria thilia thora thosta tintha tir toba
69             toltha tortha trasta trevad tuia);
70              
71             my @word =
72             qw(abonthen achad adan agar agarwen aglar aglareb agor aith alag alagos alph
73             alu alwed amar amarth amarthan amath amdir amlug amon amrûn anc and
74             andreth ang angol angren annui annûn anor anu anwar apharch ar aran aras
75             arn arod arth asgar ast astor athe aur avorn awarth bain balch bara baran
76             beleg belt belthas beren bereth bor born bragol braig brand brassen
77             bregol brog bronadui brui brûn bŷr cadu cadwar cal calar calen callon cam
78             canad cand caran carch carweg caun celair celeb celebren celeg celevon
79             cem cidinn cinnog cîw coll com conui corch cordof corn coru coth craban
80             crann crist crumui cû cugu cuin cûn cund curu cŷr dail de del deleb delu
81             dem der dern dîn dínen dîr dol dolen doll dom donn dorn dram draug dring
82             dû dûr dŷr ech ecthel eden edhel edhellen edlenn eg egas eglan eglir
83             eglos eiliant einior el elanor ell elloth elu en er ereb eredh ereg eru
84             erui esgal estel estent ethir ew ewen fain fair falas falf fanui far faug
85             faun fe feg fel fela fen fer fern ferui filig fim find fíreb firen forgam
86             forn forod forodren fuin gail galadh galas galenas gamp gaud gear gearon
87             gel gell gellam gellui gem ger gern geruil glad glam glamor glamren glan
88             glass glaur glaw gler glîr glórin gloss goeol golass gondren gordh gorn
89             gost graw gronn gruin gûr gwache gwain gwann gwarth gwath gwathren
90             gwathui gwaun gwaur gwe gwen gweren gwest gwew gwilwileth gwîn hadhod hal
91             hall hallas hand hannas harad haradren hargam harn harvo hast hathel he
92             helch heledir hell hen heneb her hethu hîl him hîr hiril hith hithren
93             hithui hîw horn hû hûr hwand hwîn iand iar iaun iaur îdh idhor idhren ind
94             ingem inu iphant írui ist istui ithil ivren lagor laich lain lalaith lalf
95             lam lanc land lang lass laug lavan leb leg lend ler lew leweg lhain lhew
96             lhind lhûg lim limp lind lithui loen lom lorn lossen lost loth luin lum
97             lung lŷg madweg maelui magor maidh malt malthen malthorn malu man mbar
98             mbarad mecheneb med medli medlin medui meg megil melch meldir meldis
99             meleth mell mellon melui men mer meren meron mesg methen mew milui min
100             minai mîr mith mithren mîw morgul morn muil muin mûl mund mŷl naith nar
101             narch naru nathal naud naug naugla naur nauth naw nawag ndam nder ndîr
102             ndîs negen neledh nen nend nenui ner nestadren ngail ngalad ngannel
103             ngaraf ngaur ngawad ngilith ngoll ngollor ngolodh ngolu ngolwen ngor
104             ngorgor ngorn ngorth ngorthad ngûl ngurth nguru nguruthos niben nîd nîf
105             nimp nîn nind nîr noen norn noroth nórui nûr oel oer ogol ol onod orch
106             orchall orod oron othol ovor pant paran parch path paur pedweg pegui
107             pelin pen peng periand peth pigen pîn puig rain raud raudh raug raun raw
108             reg rem ren rend reth rhanc rhaw rhosg rhoss rhudol rhúnen rî rîn ring
109             rîs riss roch rosc ross rost rûdh ruin rustui rûth rŷn sadar sador said
110             sain sammar sarch sel ser sereg sîdh silef silivren sîr sûl tad taid tal
111             talagand talt tan tanc tang tara tarch tarlanc tathren taug taur tavor
112             taw tawar tawaren tawen tegil ten ter tes thala thanc thand tharan tharn
113             thaur thavor thaw thend thent thîr thon thorn thoron thûl thurin tinnu
114             tint tinu tîr tirn tithen tolog tond tong torn torog trîw tû tûg tuilind
115             tulus tûr uanui uilos uireb ûl ulund ûn ungol ûr urug urui);
116              
117             my @neutral_suffix =
118             qw(ben dil ndil or wi);
119             my @female_suffix = (@neutral_suffix, @neutral_suffix,
120             qw(iel iell ien il eth el wen));
121             my @male_suffix = (@neutral_suffix, @neutral_suffix,
122             qw(dir ion on));
123              
124             sub female_name {
125 24     24 0 41 my $r = rand();
126 24 100       109 if ($r < 0.6) { return one(@word) . one(@female_suffix) }
  14 100       137  
127 6         84 elsif ($r < 0.8) { return one(@prefix) . one(@female_suffix) }
128 4         37 else { return one(@prefix) . return one(@word) }
129             }
130              
131             sub male_name {
132 22     22 0 42 my $r = rand();
133 22 100       98 if ($r < 0.6) { return one(@word) . one(@male_suffix) }
  14 100       193  
134 4         32 elsif ($r < 0.8) { return one(@prefix) . one(@male_suffix) }
135 4         36 else { return one(@prefix) . return one(@word) }
136             }
137              
138             # We do some post-processing of words, inspired by these two web pages, but using
139             # our own replacements.
140             # https://sindarinlessons.weebly.com/36---how-to-make-names-1.html
141             # https://sindarinlessons.weebly.com/37---how-to-make-names-2.html
142              
143             sub normalize {
144 46     46 0 91 my $name = shift;
145              
146 46         229 $name =~ s/(.) \1/$1/g;
147 46         103 $name =~ s/d t/d/g;
148 46         105 $name =~ s/a ui/au/g;
149 46         87 $name =~ s/nd m/dhm/g;
150 46         95 $name =~ s/n?d w/dhw/g;
151 46         89 $name =~ s/r gw/rw/g;
152 46         91 $name =~ s/^nd/d/;
153 46         109 $name =~ s/^ng/g/;
154 46         120 $name =~ s/th n?d/d/g;
155 46         86 $name =~ s/dh dr/dhr/g;
156 46         92 $name =~ s/ //g;
157              
158 46     1   301 $name =~ tr/âêîôûŷ/aeioúi/;
  1         835  
  1         1  
  1         11  
159 46         119 $name =~ s/ll$/l/;
160 46         142 $name =~ s/ben$/wen/g;
161 46         88 $name =~ s/bwi$/wi/;
162 46         202 $name =~ s/[^aeiouúi]ndil$/dil/g;
163 46         106 $name =~ s/ae/aë/g;
164 46         95 $name =~ s/ea/ëa/g;
165 46         96 $name =~ s/ii/ï/g;
166              
167 46         163 $name = ucfirst($name);
168              
169 46         231 return $name;
170             }
171              
172             sub elf_name {
173 46     46 0 89 my $name = shift;
174 46 50       115 if ($name) {
175 0         0 my $gender;
176 0         0 for (@female_suffix) {
177 0 0       0 return ($name, 'F') if $name =~ /$_$/;
178             }
179 0         0 for (@male_suffix) {
180 0 0       0 return ($name, 'M') if $name =~ /$_$/;
181             }
182 0         0 return ($name, '?');
183             } else {
184 46 100       151 if (rand() < 0.5) { return (normalize(female_name()), 'F') }
  24         112  
185 22         116 else { return (normalize(male_name()), 'M') }
186             }
187             }
188              
189             1;