ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/ext/map_lib.ext
Revision: 1.10
Committed: Tue May 4 21:45:42 2010 UTC (14 years ago) by root
Branch: MAIN
CVS Tags: rel-3_1, rel-3_0, HEAD
Changes since 1.9: +1 -0 lines
Log Message:
*** empty log message ***

File Contents

# Content
1 #! perl
2
3 =head1 CF+ map maker library and utilities
4
5 =over 4
6
7 =cut
8 # This extension loads some nice functionality for map makers
9
10 sub rec_inv_by_slaying {
11 my ($ob, $slaying, $cb) = @_;
12 $cb->($ob) if $ob->slaying eq $slaying;
13 for my $iob ($ob->inv) { rec_inv_by_slaying ($iob, $slaying, $cb) }
14 }
15
16 =item count_linked ($map, $connected)
17
18 Counts the number of objects with the connected value C<$connected> on
19 the map C<$map>.
20
21 =cut
22
23 sub count_linked {
24 my ($map, $connected) = @_;
25 my (@a) = $map->find_link ($connected);
26 scalar @a
27 }
28
29 =item object attachment: 'check_inventory_on_apply'
30
31 This attachment checks on apply whether the applyer
32 has a specific item. Currently you can only match the slaying
33 field of the inventory item of the player.
34
35 On match the apply isn't inhibited.
36
37 Following configuration can be supplied to this attachment:
38
39 =over 4
40
41 =item key_string
42
43 This is the string that will be matched against the slaying field
44 of the inventory item of the player. The first found item will be
45 decreased by the amount that can be passed in the 'decrease_by_cnt'
46 option.
47
48 =item decrease_by_cnt
49
50 This is the amount the matching object will be decreased by from the inventory.
51 Default is 0 and means nothing will be removed.
52
53 =item message_on_match
54
55 This is the message that will printed to the player if a matching
56 object was found.
57
58 =item message_on_nomatch
59
60 This is the message that will printed to the player if NO matching
61 object was found.
62
63 =back
64
65 =cut
66
67 cf::object::attachment check_inventory_on_apply =>
68 on_apply => sub {
69 my ($self, $pl) = @_;
70 my $cfg = $self->{check_inventory_on_apply};
71 my $match;
72 rec_inv_by_slaying ($pl, $cfg->{key_string}, sub {
73 my ($ob) = @_;
74 $match = $ob;
75 });
76 if ($match) {
77 $match->decrease ($cfg->{decrease_by_cnt}) if $cfg->{decrease_by_cnt};
78 $pl->message ($cfg->{message_on_match}, cf::NDI_UNIQUE) if defined $cfg->{message_on_match};
79 } else {
80 $pl->message ($cfg->{message_on_nomatch}, cf::NDI_RED | cf::NDI_UNIQUE) if defined $cfg->{message_on_nomatch};
81 cf::override;
82 }
83 };
84
85
86 =item object attachment: 'trigger_on_dialog_flag'
87
88 This attachment checks whether the player has a specific
89 dialog flag set (the ones you can set with @setflag, see also
90 L<NPC_Dialogue>, and triggers a connection depending on that.
91
92 The attachment has following configuration:
93
94 =over 4
95
96 =item flag
97
98 This field should contain the name of the flag that you want to check
99 for.
100
101 =item connection
102
103 The connection ID of the connection you want to trigger.
104
105 =item state
106
107 The state of the connection: 0 for release, 1 for push.
108
109 =back
110
111 =cut
112
113 cf::object::attachment trigger_on_dialog_flag =>
114 on_move_trigger => sub {
115 my ($self, $who, $orig) = @_;
116 my $cfg = $self->{trigger_on_dialog_flag};
117 if (exists $who->{ob}{dialog_flag}{$cfg->{flag}}) {
118 if ($who->{ob}{dialog_flag}{$cfg->{flag}}) {
119 $self->map->trigger ($cfg->{connection}, $cfg->{state});
120 }
121 cf::override;
122 }
123 };
124
125
126 =item object attachment: 'ratelimit_converter'
127
128 This is an attachment that allows a converter to be ratelimited in terms of
129 items per hour.
130
131 The attachment has following configuration:
132
133 =over 4
134
135 =item match
136
137 This field should contain a L<cf::match> match string, that should match the
138 input object.
139
140 =item generate_arch
141
142 This field should contain the archetype name of the output.
143
144 =item items_per_hour
145
146 This field should contain the number of items to generate at maximum per hour.
147 Default is: 20
148
149 =item converter_tag
150
151 This is the tag of the converter, it should be unique per converter. You can
152 also use this to make the limit hit for multiple converters.
153
154 =item msg
155
156 This is the message when the player successfully converted.
157
158 =item failmsg
159
160 This is the failure message, which will be presented to the player when he hits
161 the rate limit.
162
163 =back
164
165 =cut
166
167 cf::object::attachment ratelimit_converter =>
168 on_drop_on => sub {
169 my ($self, $obj, $who) = @_;
170
171 my $cfg = $self->{ratelimit_converter};
172
173 my $output_arch = $cfg->{generate_arch};
174 my $match = $cfg->{match};
175 my $mitems = $cfg->{items_per_hour} || 20;
176 my $tag = 'ratelimit_converter_' . $cfg->{converter_tag};
177
178 return unless cf::match::match $match, $obj;
179
180 my $items = $mitems;
181
182 if (!$who->flag (cf::FLAG_WIZ) && defined $who->{$tag . '_ts'}) {
183 my $itemtime = time - $who->{$tag . '_ts'};
184 if ($itemtime < 3600) {
185 $items = int ($items * ($itemtime / 3600));
186 }
187 }
188
189 my $nr = $obj->nrof ? $obj->nrof : 1;
190 $nr = $items if $nr > $items;
191
192 if ($nr > 0) {
193 $obj->decrease ($nr);
194
195 my $out = cf::object::generate ($output_arch, $self);
196 $out->nrof ($nr);
197 $out->insert_at ($self, $self);
198
199 if ($nr >= $mitems) {
200 $who->{$tag . '_ts'} = time;
201 } else {
202 # give player credit for the unused refills.
203 $who->{$tag . '_ts'} =
204 time - int ((($items - $nr) * 3600) / $mitems);
205 }
206
207 $who->message ($cfg->{msg})
208 if $cfg->{msg} ne '';
209 } else {
210 if ($who->contr) {
211 $who->contr->failmsg ($cfg->{failmsg})
212 if $cfg->{failmsg} ne '';
213 }
214 }
215
216 if ($who->flag (cf::FLAG_WIZ)) {
217 delete $who->{$tag . '_ts'};
218 }
219 };
220
221
222 =item object attachment: 'display_info_window'
223
224 If you attach this attachment to a sign a window containing the
225 message will open in the client when the player applies it.
226
227 Use this feature with care, as popups usually are very noisy.
228 This is mostly thought for tutorial or other instructions.
229
230 =cut
231
232 cf::object::attachment display_info_window =>
233 on_apply => sub {
234 my ($self, $pl) = @_;
235
236 return unless $pl->contr->ns->{can_widget};
237
238 my $cfg = $self->{display_info_window};
239
240 if ($pl->contr->ns->{info_wins}->{$self->uuid}) {
241 $pl->contr->ns->{info_wins}->{$self->uuid}->destroy;
242 }
243
244 my $ws = $pl->contr->ns->new_widgetset;
245
246 my $w = $ws->{my_main} = $ws->new (Toplevel =>
247 force_w => 600,
248 force_h => 400,
249 x => 'center',
250 y => 'center',
251 title => 'Information Sign',
252 has_close_button => 1,
253 on_delete => sub { $ws->destroy },
254 );
255 $w->add ($ws->{txt_area} = $ws->new ('TextScroller'));
256 $ws->{txt_area}->add_paragraph ($self->msg);
257 $w->show;
258 $pl->contr->ns->{info_wins}->{$self->uuid} = $ws;
259
260 cf::override 1;
261 };
262
263 =back
264
265 =cut
266