$combatblock = "$name:$dex:$db:$mp:$hp";
I’m using Perl 5.36 on Debian Linux 12 and am writing a utility for a roleplaying game. This isn’t a work-related project, as I’m more of a hobbyist than a serious programmer, so I apologise if this isn’t really an appropriate request.
My input file looks like this:
Name: orc of power normal
mw_monsters normal
Stats: STR [14] CON [10] SIZ [10] INT [8] POW [8] DEX [15] APP [8] EDU [5]
SCB: Physical=7 Communication=4 Knowledge=4 Manipulation=8 Perception=5
Combat: Hit Points=10 Major Wound Level=5 Armour=
Initiative:
Stat Rolls: Effort 70% Stamina 50% Idea 40% Luck 40% Agility 75% Charisma 40% Know 25%
Derived: MP=8 XP=4 FP=24 SAN=40% DB=NONE MOV [10]
Skills: Scimitar 42% Composite Bow 42% Short Spear 42% Short Spear (thrown) 42% Spiked Shield 42% Climb 62% Dodge 47% Hide 42% Lore (Orc-lore) 39% Language (Human) 29% Language (Orcish) 64% Ride (warboar) 57% Sense 40% Search 50% Move Quietly 47% Track 35%
++ Distribute 40% to ONE skill and 20% to THREE skills
Powers:
This orc is not a sorcerer.
Possessions:
Notes:
I want to select certain parts of these lines and produce output like this:
Name:DEX:DB:MP:HP:Current:
orc:[15]:DB=NONE:MP=8:Points=10
This is my code so far:
#!/usr/bin/env perl
use strict;
use warnings;
my $line;
my $combatblock = "";
my $name = "";
my $dex = "";
my $db = "";
my $mp = "";
my $hp = "";
my @combatarray;
my @nameline;
my @statline;
my @hpline;
my @derivedline;
print "Name:DEX:DB:MP:HP:Current:n";
while ($line = <>) {
chomp $line;
if ($line =~ "Name") {
@nameline = split (/ /,$line);
$name=$nameline[1]; # Name
};
if ($line =~ "STR") {
@statline = split (/ /,$line);
$dex=$statline[12]; # DEX for initiative
};
if ($line =~ "Derived") {
@derivedline = split (/ /,$line);
$db=$derivedline[5]; # Damage Bonus
$mp=$derivedline[1]; # Magic Points
};
if ($line =~ "Hit Points") {
@hpline = split (/ /,$line);
$hp=$hpline[2]; # Hitpoints
};
$combatblock = "$name:$dex:$db:$mp:$hp";
print "$combatblockn"; # This can be commented out to get rid of unnecessary output
};
print "Result $combatblockn"; # Result can be taken out of this line
What it generates is this:
61 colin@kuu> combatstatblock.pl < orc.txt
Name:DEX:DB:MP:HP:Current:
orc::::
orc::::
orc:[15]:::
orc:[15]:::
orc:[15]:::Points=10
orc:[15]:::Points=10
orc:[15]:::Points=10
orc:[15]:DB=NONE:MP=8:Points=10
orc:[15]:DB=NONE:MP=8:Points=10
orc:[15]:DB=NONE:MP=8:Points=10
orc:[15]:DB=NONE:MP=8:Points=10
orc:[15]:DB=NONE:MP=8:Points=10
orc:[15]:DB=NONE:MP=8:Points=10
orc:[15]:DB=NONE:MP=8:Points=10
Result orc:[15]:DB=NONE:MP=8:Points=10
62 colin@kuu>
Now, I understand this is actually doing what it’s written to do. As noted in a comment string above, I can take out "print "$combatblockn";
" to get rid of all the other output and just leave the "Result" line.
This script is supposed to process many more "orc" stats and produce output like this:
Name:DEX:DB:MP:HP:Current:
orc:[15]:DB=NONE:MP=8:Points=10
orc:[19]:DB=NONE:MP=13:Points=10
orc:[12]:DB=+1D4:MP=10:Points=12
… and so on through the input file.
What’s happening is that only the last result (orc:[12]
in this case) is printed: the while loop overwrites the previous value of $combatblock
.
How can I break out of the while loop, print the "Result" line, then go back to the top of the while loop to process the next set of "orc" stats?
I’ve tried:
- Writing the $combatblock to a file so I can "cat" the output on the console
- Nesting the
"if ($line =~"
statements inside another foreach or while loop - Using an
@combatarray
structure to push the$combatblock
onto - Generating
$combatblock
inside the "if
" statements with lines like "$combatblock = "$combatblock:$db:$mp:""
(which are commented out in the script above)
Nothing seems to get past the "while overwrites the previous value" problem. I’m pretty sure the solution is quite simple but I simply can’t find a way forward.
Any help would be greatly appreciated.
2
Answers
you can achieve that by :
push
your variables to an array at eachif condition
and print at end of the all if conditions inside the while loop and reset thearray
.but you need to revisit your code for the how you are extracting the desired
strings
from input file.I’ve mentioned a lot of things in the comments, and basically what it all comes down to is that this is an XY-problem, by which I mean that your problem comes from choosing a bad design.
First of all, the save file for the orc npc feels very spontaneous and not very thought through. You have a number of inconsistencies that break the format, and it seems you allow for free style comments.
It is almost like this is a combination of a character sheet (e.g. 100% human readable) and a data sheet, which can be read by a program. The simplest solution is to pick a pre-existing storage format, such as XML or json. Then if you need to write to the file, or read it, you use a parser, or a program (e.g. excel). Then store the npc data as e.g "orc.xml" and just double click it.
Second, your main problem in the code you show is that you try to parse and print at the same time. And you are using global variables. My suggestions are:
Here is a small example of how you could handle your current save file format:
Output:
Note that this program completely skips comments. Comments like this inside a data file with a home made format tend to get lost. If you want to secure them, put them in a special field like
Comments:
.Note also the warnings for parsing errors. I have not attempted to parse your fields, because they are so inconsistent they would need their own parser. If you want to access the fields of this object, you just do
print $orc->{Combat}
for example. Or for a slice:print @{$orc}{qw(Combat Name Derived)};