File: collect

package info (click to toggle)
crossfire 1.75.0-9
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 24,168 kB
  • sloc: ansic: 83,169; sh: 4,659; perl: 1,736; lex: 1,443; makefile: 1,199; python: 43
file content (480 lines) | stat: -rw-r--r-- 13,872 bytes parent folder | download | duplicates (4)
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
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
#!/usr/bin/env perl

require "util.pl";

if ($#ARGV >= 0) {
    if ($ARGV[0] =~ m/^--?[hH](elp)?$/) {
	die ("\nUSAGE: perl collect.pl  ARCHDIR\n".
	     "\nWhere ARCHDIR is the directory where you stored the ".
	     "raw archetypes.\n".
	     "This script will then create these files:\n".
	     "archetypes,bmaps.paths,faces,treasures,animations.\n"
	)
    }
}

# mkdir is nice because it is an atomic operation - if 2 programs
# try to do it at the same time, one will fail.  Do a -e/create
# file check has a chance of race condition.
if (!mkdir("collect.lock",0)) {
    print "Collect is already running.  If you think this is an error,\n";
    print "rmdir collect.lock\n";
    # exit with a non zero code - in that way make errors out and
    # won't try to build the next target - the images.  If another
    # process is running on the archetypes, that will make a new bmaps.paths
    # requiring new images at that time.
    exit(1);
}


# archonly is used to only build the archetypes.  I find this
# very handy if I know I've only changed .arc files - I don't want
# to rebuild the other files, because now cvs tries to do diffs
# on them as well as commit them, even if there are no changes.
$archonly = 0;
if ($#ARGV >= 1) {
    if ($ARGV[1] eq "ARCHONLY") { $archonly = 1; }
    else {print "Ignoring unknown option: $ARGV[1]\n"; }
}


$root = $ARGV[0];
$archetypes = "archetypes";
$faces = "faces";
$treasures = "treasures";
$animations = "animations";
$paths = "bmaps.paths";
$faceExt = "\\.[a-zA-Z0-9][A-Z0-9][A-Z0-9]";
$smooths = "smooth";

### main
&info("looking ...");
&traverse($root);

$attacktype{ 'physical' } = ( 1 << 0 );
$attacktype{ 'magic' } = ( 1 << 1 );
$attacktype{ 'fire' } = ( 1 << 2 );
$attacktype{ 'electricity' } = ( 1 << 3 );
$attacktype{ 'cold' } = ( 1 << 4 );
$attacktype{ 'confusion' } = ( 1 << 5 );
$attacktype{ 'acid' } = ( 1 << 6 );
$attacktype{ 'drain' } = ( 1 << 7 );
$attacktype{ 'weaponmagic' } = ( 1 << 8 );
$attacktype{ 'ghosthit' } = ( 1 << 9 );
$attacktype{ 'poison' } = ( 1 << 10 );
$attacktype{ 'slow' } = ( 1 << 11 );
$attacktype{ 'paralyze' } = ( 1 << 12 );
$attacktype{ 'turnundead' } = ( 1 << 13 );
$attacktype{ 'fear' } = ( 1 << 14 );
$attacktype{ 'cancellation' } = ( 1 << 15 );
$attacktype{ 'deplete' } = ( 1 << 16 );
$attacktype{ 'death' } = ( 1 << 17 );
$attacktype{ 'chaos' } = ( 1 << 18 );
$attacktype{ 'counterspell' } = ( 1 << 19 );
$attacktype{ 'godpower' } = ( 1 << 20 );
$attacktype{ 'holyword' } = ( 1 << 21 );
$attacktype{ 'blind' } = ( 1 << 22 );
$attacktype{ 'internal' } = ( 1 << 23 );
$attacktype{ 'lifestealing' } = ( 1 << 24 );
$attacktype{ 'disease' } = ( 1 << 25 );

&info("writing ...$archetypes");
open(ARCH,">".$archetypes) || &my_die("cannot open ".$archetypes);

binmode(ARCH);
&archsOut($root);
close(ARCH);


if (!$archonly) {
    &info("$paths");
    open(BMAPS,">".$paths) || &my_die("cannot open ".$paths);
	binmode(BMAPS);
    &pathsOut;
    close(BMAPS);

    &info("$faces");
    open(FACES,">".$faces) || &my_die("cannot open ".$faces);
	binmode(FACES);
    &facesOut;
    close(FACES);

    &info("$smooths");
    open(SMOOTHS,">".$smooths) || &my_die("cannot open ".$smooths);
	binmode(SMOOTHS);
    &smoothOut;
    close(SMOOTHS);

    &info("$treasures");
    # We still support the old consolidated treasure information
    # so copy it over.
    open(TREASURES,">".$treasures) || &my_die("cannot open ".$treasures);
	binmode(TREASURES);
    print TREASURES "#
# Do not modify this file - any changes will get overwritten.
# instead, modify the .trs file in the arch directory.
#
";
    &treasuresOut;
    close(TREASURES);

    &info("$animations");
    open(ANIM,">".$animations) || &my_die("cannot open ".$animations);
	binmode(ANIM);
    &animOut;
    close(ANIM);
}


&stats;
rmdir("collect.lock");
exit 0;

sub traverse {
    local($dir) = shift;
    local($file,$name);
    local( $tfile);

    opendir(THISDIR, $dir) || my_die("couldn't open $dir");
    local(@allfiles) = readdir(THISDIR);
    closedir(THISDIR);

    foreach $tfile (sort @allfiles) {
	next if $tfile =~ /^\./;
	next if $tfile =~ /~$/;
	$file = $dir."/".$tfile;
	$name = &basename($file,""); # DIR

	if( -d $file && $name ne "dev" && $name ne "trashbin" && $name ne ".svn" ) {
	    &traverse($file);
	} elsif ( -d $file && ( $name eq "dev" || $name eq "trashbin" ) ) {
# Empty directive to prevent warnings below
	} elsif( $file =~ /.*\.arc$/) {	# ARCHETYPE
	    $archsNum++;
	    push(@archs,$file);n
	} elsif( $name =~ /(\S+)\.base($faceExt)\.png$/) { # FACE
	    $facesNum++;
	    $im_name = "$1$2";
	    &warn("duplicate face $im_name in ".$dir." and $faces{$im_name}")
		if $faces{$im_name};
	    $faces{$im_name} = $dir."/".$im_name;

	} elsif ( $file =~ /.*\.face$/) {	# Face information file
	    $facesFileNum++;
	    push(@face_files, $file);
	} elsif ( $file =~ /.*\.trs$/) {	# Treasure information file
	    push(@treasure_files, $file);
	}
	elsif ( $file =~ /\.png$/ || $file =~ /\.xpm$/ || $file =~ /\.xcf/ || $file =~ /\.doc$/ || $file =~ /\.txt$/ || $file =~ /$faceExt$/ || $file =~ /\.blend$/ ) {
	# we cover many files we probably shouldn't, but oh well.
	# we just don't want complaints about all of these.
	}
	# ignore a couple of the more common 'junk' files that are not
	# really junk.
	elsif (($name ne "README") && ($name ne "ChangeLog") && ($name ne "TODO") && ($name ne ".svn") && ($name ne "artifacts") && ($name ne "attackmess") && ($name ne "formulae") && ($name ne "image_info") && ($name ne "materials") && ($name ne "messages") && ($name ne "races")) {
	    $trashNum++;
	    print "Warning: $file might be a junk file\n";
	}
    }
}

sub storeFaceInfo {
    local($lface,@values) = @_;

    if ($values[0] ne "") {
#	blank.111 is a special case -
#	since no foreground pixels will actually be drawn, foreground colors is
#	not relevant.  Several monsters use blank.111 as part of their
#	animation to make them appear invisible, but have some other
#	foreground color set.
#	Same applies to empty also.
	if ($fg{$lface} && $fg{$lface} ne $values[0] && $lface ne "blank.111"
		&& $lface ne "empty.111") {
	    &warn($arch." duplicate fg color ".$fg{$lface}."/".$values[0]." face ".$lface);
	} else {
	    $fg{$lface} = $values[0];
	}
    }
    if ($values[1] ne "" && $lface ne "blank.111" && $lface ne "empty.111") {
#      blank.111 is a special case - see above explanation
#      Its visibility is always 0.
	if ($visibility{$lface} && $visibility{$lface} ne $values[1]) {
	    &warn($arch." duplicate visibilty ".$visibility{$lface}."/".$values[1]." face ".$lface);
	} else {
	    $visibility{$lface} = $values[1];
	}
    }
    if ($values[2] ne "" && lface ne "blank.111" && $lface ne "empty.111") {
	if ($magicmap{$lface} && $magicmap{$lface} ne $values[2]) {
	    &warn($arch." duplicate magicmap color ".$magicmap{$lface}."/".$values[2]." face ".$lface);
	} else {
	    $magicmap{$lface} = $values[2];
	}
    }
    if ($values[3] ne "") {
	if ($floor{$lface} && $floor{$lface} ne $values[3]) {
	    &warn($arch." duplicate floor information ".$floor{$lface}."/".$values[3]." face ".$lface);
	} else {
	    $floor{$lface} = $values[3];
	}
    }
}


sub archsOut {
    local($dir) = shift;

    foreach $arch (@archs) {
	# Assume the filename $arch begins with $dir. Assign all path name
	# components after $dir to $pathto.
	if($arch =~ /^\Q$dir\E\/(.*)\/[^\/]*[.]arc$/) {
	    $pathto = $1;
	} else {
	    &warn("cannot determine editor_folder from arch '$arch'");
	    $pathto = "";
	}
	open(ARC,$arch) || &my_die("cannot open ".$arch);
line:	while(<ARC>) {
	    chop;
	    ($var,@values) = split;
	    if ($var eq "#") {
		#developper comment, switch to next line
		$commentNum++;
		next line;
	    }
	    if ($var eq "Object") {
		$lface[0] = "";
		$#lface = 0;
		$lfg = "";
		$lvis = "";
		$mm = "";
		$floor = "";
		$moveon = 0;
		$nopick = 0;
		$arch = join "_", @values;
		$print_editor_folder = 1;
	    } else {
		$print_editor_folder = 0;
	    }
	    if ($var eq "end") {
		if ($#lface !=0) {
		    $#lface--;
		    foreach $face (@lface) {
			&storeFaceInfo($face, $lfg, $lvis,$mm,$floor);
		    }
	 	}
		if ($moveon && !$nopick) {
		    &warn("File $arch has an object with move_on set which can be picked up\n");
		}
	    }
	    # Process the color/face info now
	    if ($var eq "color_fg") {
		$lfg = $values[0];
		next line;
	    }
	    if ($var eq "visibility") {
		$lvis = $values[0];
		next line;
	    }
	    if ($var eq "magicmap") {
		$mm = $values[0];
		next line;
	    }
	    if ($var eq "attacktype") {
		$at = 0;
		foreach $t ( @values ) {
		    if ( $t =~ /^\d+$/ ) {
			$at |= $t;
		    } else {
			if ( defined( $attacktype{ $t } ) ) {
			    $at |= $attacktype{ $t };
			} else {
			    &warn($arch . " has invalid attacktype " . $t);
			}
		    }
		}
		$_ = $var . ' ' . $at;
	    }
	    if ($var eq "is_floor") {
		$floor = $values[0];
		# is_floor is also needed for archs, so let it pass
		# through
	    }
	    elsif ($var eq "no_pick") {
		$nopick = $values[0];
	    } elsif ($var eq "move_on") {
		$moveon = 1;
	    }
	    elsif ($var eq "face") {
		$lface[$#lface++] = $values[0]
	    }
	    if ($var eq "face" && ! $faces{$values[0]}) {
		&warn($arch." is missing face ".$values[0])
	    }
	    if ($var eq "smoothface") {
		if ($smoothing{$values[0]} && ($smoothing{$values[0]} ne $values[1])) {
		    &warn($arch." duplicate smoothface for ".$values[0].": ".$smoothing{$values[0]}." and ".$values[1]);
		} elsif ( ($values[0] eq "") || ($values[1] eq "")) {
		    &warn ($arch." incomplete smoothface entry found: ".$values[0]." ".$values[1]);
		} else {
		    $smoothing{$values[0]}=$values[1]
		}
		next line;  #smoothface must be excluded from archetype file
	    }
	    print ARCH $_,"\n";
	    if ($print_editor_folder) {
		print ARCH "editor_folder $pathto\n" if $pathto ne "";
	    }
	}
	close(ARC);
    }
}

sub pline {
    local($face) = shift;
    print BMAPS sprintf("%05d",$idx++)," ",$face,"\n";
}

sub opline {
    local($face) = shift;
    print BMAPS sprintf("\\%05d",$idx++),"\t",$face,"\n";
}

sub pheader {
    print BMAPS "# This file is generated by $0, do not edit\n";
}

sub pathsOut {
    &pheader;
    $idx = 0;
    &opline($root."/system/bug.111");
    foreach $face (sort(keys %faces)) {
	&opline($faces{$face}) if $faces{$face} !~ /bug\.111/;
    }
}

sub treasuresOut {
    foreach $treasure (@treasure_files) {
	open(TREAS, $treasure) || &my_die("cannot open ".$treasure);
	while(<TREAS>) {
	    if (! /^\s*$/) {
		print TREASURES $_;
	    }
	}
	close(FACE);
    }
}

sub facesOut {
    foreach $face (@face_files) {
	open(FACE, $face) || &my_die("cannot open ".$face);
	while(<FACE>) {
	    chop;
	    local ($var, @values) = split;
	    if ($var eq "face") {
		$lface = $values[0];
		$lfg = "";
		$lvis = "";
		$mm = "";
		$floor = "";
	    }
	    elsif ($var eq "color_fg") {
		$lfg = $values[0];
	    }
	    elsif ($var eq "visibility") {
		$lvis = $values[0];
	    }
	    elsif ($var eq "magicmap") {
		$mm = $values[0];
	    }
	    elsif ($var eq "is_floor") {
		$floor = $values[0];
	    }
	    elsif ($var eq "end") {
		&storeFaceInfo($lface, $lfg, $lvis, $mm, $floor);
	    }
	    elsif ($var eq "animation") {
		$animation=$values[0];
		if ($anim{$1}) {
		    &warn("$animation is a duplicate animation name");
		    $anim{$animation}="";
		}
		while (<FACE>) {
		    chomp;
		    $var = $_;
		    last if ($var =~ /^mina\s*$/);
		    if ($var !~ /^facings/ ) {
		    	if (! $faces{$var}) {
			    &warn($arch." is missing face ".$var);
			}
			else {
			    $lface[$#lface++] = $var;
			}
		    }
		    $anim{$animation} .= "$var\n";
		}
		next;	# don't want the mina
	    }
	}
	close(FACE);
    }
    print FACES "# This file is generated by $0, do not edit\n";
    foreach $face (sort(keys %faces)) {
	if ($fg{$face} ne "" || $bg{$face} ne "" || $visibility{$face} ne "" ||
	    $magicmap{$face} ne "" || $floor{$face} ne "") {
	    print FACES "face ".$face."\n";
	    print FACES "color_fg ".$fg{$face}."\n"
	    if $fg{$face} ne "";
		print FACES "visibility ".$visibility{$face}."\n"
	    if $visibility{$face} ne "";
		print FACES "magicmap ".$magicmap{$face}."\n"
	    if $magicmap{$face} ne "";
		print FACES "is_floor ".$floor{$face}."\n"
	    if $floor{$face} ne "";
		print FACES "end\n";
	}
    }
}

sub animOut {
    foreach $anim (sort keys %anim) {
	print ANIM "anim $anim\n$anim{$anim}mina\n";
	$animationsNum++;
    }
}
sub smoothOut {
    local ($sm);
    print SMOOTHS "##########################################################\n";
    print SMOOTHS "# Do not touch this file.                                #\n";
    print SMOOTHS "# It has been generated from the informations present    #\n";
    print SMOOTHS "# in the archetype files.                                #\n";
    print SMOOTHS "# To add new entries, simply add                         #\n";
    print SMOOTHS "#     smoothface xxx yyy                                 #\n";
    print SMOOTHS "# to an archetype and collect.pl will put below an entry #\n";
    print SMOOTHS "#      xxx yyy                                           #\n";
    print SMOOTHS "##########################################################\n\n";
    print SMOOTHS "\n# Data extracted from arch files\n";
    foreach $sm (sort (keys %smoothing)) {
	print SMOOTHS "$sm $smoothing{$sm}\n";
	$smoothNum++;
    }
}

### print out statical information
sub stats {
    &info(Archs.":\t".$archsNum);
    &info(Images.":\t".$facesNum);
    &info(Faces.":\t".$facesFileNum);
    &info(Animations.":\t".$animationsNum);
    &info(Treasures.":\t".($#treasure_files+1));
    &info(Trash.":\t".$trashNum);
    &info(Smooths.":\t".$smoothNum);
    &info("Comment lines:\t".$commentNum);
}

# This is a simple function to clean up the collect lock
# and then call die.
sub my_die {
    rmdir("collect.lock");
    die(@_);
}