ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/lib/cf/match.pm
(Generate patch)

Comparing deliantra/server/lib/cf/match.pm (file contents):
Revision 1.20 by root, Tue Oct 20 05:57:08 2009 UTC vs.
Revision 1.33 by root, Tue Oct 12 20:15:48 2010 UTC

1#
2# This file is part of Deliantra, the Roguelike Realtime MMORPG.
3#
4# Copyright (©) 2009,2010 Marc Alexander Lehmann / Robin Redeker / the Deliantra team
5#
6# Deliantra is free software: you can redistribute it and/or modify it under
7# the terms of the Affero GNU General Public License as published by the
8# Free Software Foundation, either version 3 of the License, or (at your
9# option) any later version.
10#
11# This program is distributed in the hope that it will be useful,
12# but WITHOUT ANY WARRANTY; without even the implied warranty of
13# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14# GNU General Public License for more details.
15#
16# You should have received a copy of the Affero GNU General Public License
17# and the GNU General Public License along with this program. If not, see
18# <http://www.gnu.org/licenses/>.
19#
20# The authors can be reached via e-mail to <support@deliantra.net>
21#
22
1=head1 NAME 23=head1 NAME
2 24
3cf::match - object matching language 25cf::match - object matching language
4 26
5=head1 DESCRIPTION 27=head1 DESCRIPTION
92Not that C<not> only negates a condition and not the whole match 114Not that C<not> only negates a condition and not the whole match
93expressions, thus 115expressions, thus
94 116
95 not applied in inv 117 not applied in inv
96 118
97is true if there is I<any> non-object in the inventory. To negate a whole 119is true if there is I<any> non-applied object in the inventory. To negate
98match, you have to use a sub-match. To check whether there is I<no> 120a whole match, you have to use a sub-match: To check whether there is
99applied object in someones inventory, write this: 121I<no> applied object in someones inventory, write this:
100 122
101 not (applied in inv) 123 not (applied in inv)
102 124
103Example: match applied weapons. 125Example: match applied weapons.
104 126
105 applied type=WEAPON 127 applied type=WEAPON
106 128
107Example: match horns or rods. 129Example: match horns or rods.
108 130
109 type=HORN or type=ROD 131 type=HORN or type=ROD
132
133Example: see if the originator is a player.
134
135 type=PLAYER of originator
110 136
111=item in ... 137=item in ...
112 138
113The in operator takes the context set and modifies it in various ways. As 139The in operator takes the context set and modifies it in various ways. As
114a less technical description, think of the C<in> as being a I<look into> 140a less technical description, think of the C<in> as being a I<look into>
136 162
137=item in map 163=item in map
138 164
139Replaces all objects by the objects that are on the same mapspace as them. 165Replaces all objects by the objects that are on the same mapspace as them.
140 166
167=item in head
168
169Replaces all objects by their head objects.
170
141=item in <condition> 171=item in <condition>
142 172
143Finds all context objects matching the condition, and then puts their 173Finds all context objects matching the condition, and then puts their
144inventories into the context set. 174inventories into the context set.
145 175
199Starts with the default object - this is the object passed to the match to 229Starts with the default object - this is the object passed to the match to
200match against by default. Matches have an explicit C<of object> appended, 230match against by default. Matches have an explicit C<of object> appended,
201but submatches start at the current object, and in this case C<of object> 231but submatches start at the current object, and in this case C<of object>
202can be used to start at the original object once more. 232can be used to start at the original object once more.
203 233
234=item of self
235
236Starts with the object initiating/asking for the match - this is basically
237always the object that the match expression is attached to.
238
204=item of source 239=item of source
205 240
206Starts with the I<source> object - this object is sometimes passed to 241Starts with the I<source> object - this object is sometimes passed to
207matches and represents the object that is the source of the action, such 242matches and represents the object that is the source of the action, such
208as a rod or a potion when it is applied. Often, the I<source> is the same 243as a rod or a potion when it is applied. Often, the I<source> is the same
215the original initiator of an action, most commonly a player or monster. 250the original initiator of an action, most commonly a player or monster.
216 251
217This object is often identical to the I<source> (e.g. when a player casts 252This object is often identical to the I<source> (e.g. when a player casts
218a spell, the player is both source and originator). 253a spell, the player is both source and originator).
219 254
220=item of self
221
222Starts with the object initiating/asking for the match - this is basically
223always the object that the match expression is attached to.
224
225=back 255=back
226 256
227=head2 EXPRESSIONS 257=head2 EXPRESSIONS
228 258
229Expressions used in conditions usually consist of simple boolean checks 259Expressions used in conditions usually consist of simple boolean checks
238 268
239=item scalar object attributes 269=item scalar object attributes
240 270
241Object attributes that consist of a single value (C<name>, C<title>, 271Object attributes that consist of a single value (C<name>, C<title>,
242C<value> and so on) can be specified by simply using their name, in which 272C<value> and so on) can be specified by simply using their name, in which
243acse their corresponding value is used. 273case their corresponding value is used.
244 274
245=item array objects attributes 275=item array objects attributes
246 276
247The C<resist> array can be accessed by specifying C<< resist [ ATNR_type ] 277The C<resist> array can be accessed by specifying C<< resist [ ATNR_type ]
248>>. 278>>.
252 resist[ATNR_ACID] > 30 282 resist[ATNR_ACID] > 30
253 283
254=item functions 284=item functions
255 285
256Some additional functions with or without arguments in parentheses are 286Some additional functions with or without arguments in parentheses are
257available. 287available. They are documented in their own section, below.
258 288
259=item { BLOCK } 289=item { BLOCK }
260 290
261You can specify perl code to execute by putting it inside curly 291You can specify perl code to execute by putting it inside curly
262braces. The last expression evaluated inside will become the result. 292braces. The last expression evaluated inside will become the result.
296 326
297=item any 327=item any
298 328
299This simply evaluates to true, and simply makes matching I<any> object a 329This simply evaluates to true, and simply makes matching I<any> object a
300bit easier to read. 330bit easier to read.
331
332=item none
333
334This simply evaluates to false, and simply makes matching I<never> a bit
335easier to read.
336
337=item archname
338
339The same as C<< { $_->arch->archname } >> - the archetype name is commonly
340used to match items, so this shortcut is provided.
341
342=item resist_xxx
343
344Resistancy values such as C<resist_physical>, C<resist_magic>,
345C<resists_fire> etc. are directly available (but can also be accessed via
346array syntax, i.e. C<resists[ATNR_FIRE]>).
347
348=item body_xxx_info and body_xxx_used
349
350Every body location (e.g. C<body_neck_info>, C<body_arm_used> etc.) can
351be accessed via these functions (these are aliases to more cumbersome C<< {
352$_->slot_info (body_xxx) } >> and C<slot_used> method calls).
353
354Example: (e.g. on a door) match only players that have no arms.
355
356 match type=PLAYER and body_arm_info=0
301 357
302=item has(condition) 358=item has(condition)
303 359
304True iff the object has a matching inventory object. 360True iff the object has a matching inventory object.
305 361
330 386
331 match = chain 387 match = chain
332 | chain 'of' root 388 | chain 'of' root
333 root = 'object' | 'self' | 'source' | 'originator' 389 root = 'object' | 'self' | 'source' | 'originator'
334 chain = condition 390 chain = condition
335 | chain also deep 'in' set 391 | chain also deep 'in' modifier
336 also = nothing | 'also' 392 also = nothing | 'also'
337 deep = nothing | 'deep' 393 deep = nothing | 'deep'
338 set = 'inv' | 'env' | 'arch' | 'map' 394 modifier ='inv' | 'env' | 'arch' | 'map' | 'head'
339 395
340 empty = 396 nothing =
341 397
342 # boolean matching condition 398 # boolean matching condition
343 399
344 condition = factor 400 condition = factor
345 | factor 'and'? condition 401 | factor 'and'? condition
353 operator = '=' | '==' | '!=' | '<' | '<=' | '>' | '>=' 409 operator = '=' | '==' | '!=' | '<' | '<=' | '>' | '>='
354 410
355 expr = flag 411 expr = flag
356 | sattr 412 | sattr
357 | aattr '[' <constant> ']' 413 | aattr '[' <constant> ']'
414 | 'stat.' statattr
358 | special 415 | special
359 | func '(' args ')' 416 | func '(' args ')'
360 | '{' perl code block '}' 417 | '{' perl code block '}'
361 418
362 func = <any function name> 419 func = <any function name>
363 sattr = <any scalar object attribute> 420 sattr = <any scalar object attribute>
364 aattr = <any array object attribute> 421 aattr = <any array object attribute>
365 flag = <any object flag> 422 flag = <any object flag>
423 statattr = <any stat attribute: exp, food, str, dex, hp, maxhp...>
366 special = <any ()-less "function"> 424 special = <any ()-less "function">
367 425
368 constant = <number> | '"' <string> '"' | <uppercase cf::XXX name> 426 constant = <number> | '"' <string> '"' | <uppercase cf::XXX name>
369 args = <depends on function> 427 args = <depends on function>
370 428
419 477
420 our %special = ( 478 our %special = (
421 any => sub { 479 any => sub {
422 1 480 1
423 }, 481 },
482 none => sub {
483 0
484 },
485 archname => sub {
486 '$_->arch->archname'
487 },
424 ); 488 );
489
490 # resist_xxx
491 for my $atnr (0 .. cf::NROFATTACKS - 1) {
492 $special{"resist_" . cf::attacktype_name ($atnr)} = sub { "\$_->resist ($atnr)" };
493 }
494
495 # body_xxx_info and _used
496 for my $slot (0 .. cf::NUM_BODY_LOCATIONS - 1) {
497 my $name = cf::object::slot_name $slot;
498
499 $special{"body_$name\_info"} = sub { "\$_->slot_info ($slot)" };
500 $special{"body_$name\_used"} = sub { "\$_->slot_used ($slot)" };
501 }
425 502
426 sub constant { 503 sub constant {
427 ws; 504 ws;
428 505
429 return $1 if /\G([\-\+0-9\.]+)/gc; 506 return $1 if /\G([\-\+0-9\.]+)/gc;
436 } 513 }
437 514
438 our $flag = $cf::REFLECT{object}{flags}; 515 our $flag = $cf::REFLECT{object}{flags};
439 our $sattr = $cf::REFLECT{object}{scalars}; 516 our $sattr = $cf::REFLECT{object}{scalars};
440 our $aattr = $cf::REFLECT{object}{arrays}; 517 our $aattr = $cf::REFLECT{object}{arrays};
518 our $lattr = $cf::REFLECT{living}{scalars};
441 519
442 sub expr { 520 sub expr {
443 # ws done by factor 521 # ws done by factor
444 my $res; 522 my $res;
445 523
447 # perl 525 # perl
448 526
449 my $expr = $1; 527 my $expr = $1;
450 528
451 $res .= $expr =~ /\{([^;]+)\}/ ? $1 : "do $expr"; 529 $res .= $expr =~ /\{([^;]+)\}/ ? $1 : "do $expr";
530
531 } elsif (/\Gstats\.([A-Za-z0-9_]+)/gc) {
532
533 if (exists $lattr->{$1}) {
534 $res .= "\$_->stats->$1";
535 } elsif (exists $lattr->{"\u$1"}) {
536 $res .= "\$_->stats->\u$1";
537 } else {
538 die "living statistic name expected (str, pow, hp, sp...)\n";
539 }
452 540
453 } elsif (/\G([A-Za-z0-9_]+)/gc) { 541 } elsif (/\G([A-Za-z0-9_]+)/gc) {
454 542
455 if (my $func = $func{$1}) { 543 if (my $func = $func{$1}) {
456 /\G\s*\(/gc 544 /\G\s*\(/gc
568 my $res = condition; 656 my $res = condition;
569 657
570 # if nothing follows, we have a simple condition, so 658 # if nothing follows, we have a simple condition, so
571 # optimise a comon case. 659 # optimise a comon case.
572 if ($defctx eq '$_' and /\G\s*(?=\)|$)/gc) { 660 if ($defctx eq '$_' and /\G\s*(?=\)|$)/gc) {
573 warn "shortcut<$res>$wantarray\n";#d#
574 return $wantarray 661 return $wantarray
575 ? "$res ? \$_ : ()" 662 ? "$res ? \$_ : ()"
576 : $res; 663 : $res;
577 } 664 }
578 665
585 my $deep = /\Gdeep\s+/gc + 0; 672 my $deep = /\Gdeep\s+/gc + 0;
586 673
587 if (/\Gin\s+/gc) { 674 if (/\Gin\s+/gc) {
588 my $expand; 675 my $expand;
589 676
590 if (/\G(inv|env|map|arch)\b/gc) { 677 if (/\G(inv|env|map|arch|head)\b/gc) {
591 if ($1 eq "inv") { 678 if ($1 eq "inv") {
592 $expand = "map \$_->inv,"; 679 $expand = "map \$_->inv,";
593 } elsif ($1 eq "env") { 680 } elsif ($1 eq "env") {
594 $expand = "map \$_->env // (),"; 681 $expand = "map \$_->env // (),";
682 } elsif ($1 eq "head") {
683 $expand = "map \$_->head,";
684 $deep = 0; # infinite loop otherwise
595 } elsif ($1 eq "arch") { 685 } elsif ($1 eq "arch") {
596 $expand = "map \$_->arch,"; 686 $expand = "map \$_->arch,";
597 $deep = 0; # infinite loop otherwise 687 $deep = 0; # infinite loop otherwise
598 } elsif ($1 eq "map") { 688 } elsif ($1 eq "map") {
599 $expand = "map \$_->map->at (\$_->x, \$_->y),"; 689 $expand = "map \$_->map->at (\$_->x, \$_->y),";
661 751
662 $res 752 $res
663} 753}
664 754
665if (0) {#d# 755if (0) {#d#
666 die parse 1, 'applied in inv'; 756 die parse 1, 'type=PLAYER and body_arm_info=0';
667 exit 0; 757 exit 0;
668} 758}
669 759
670our %CACHE; 760our %CACHE;
671 761
672sub compile($$) { 762sub compile($$) {
673 my ($wantarray, $match) = @_; 763 my ($wantarray, $match) = @_;
674 my $expr = parse $wantarray, $match; 764 my $expr = parse $wantarray, $match;
675 warn "MATCH DEBUG $match,$wantarray => $expr\n";#d# 765# warn "MATCH DEBUG $match,$wantarray => $expr\n";#d#
676 $expr = eval " 766 $expr = eval "
677 package cf::match::exec; 767 package cf::match::exec;
678 sub { 768 sub {
679 my (\$object, \$self, \$source, \$originator) = \@_; 769 my (\$object, \$self, \$source, \$originator) = \@_;
680 $expr 770 $expr

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines