… | |
… | |
20 | |
20 | |
21 | use strict; |
21 | use strict; |
22 | |
22 | |
23 | use AnyEvent; |
23 | use AnyEvent; |
24 | use IO::Socket::INET; |
24 | use IO::Socket::INET; |
|
|
25 | |
|
|
26 | my $TICK = 0.120; # one server tick, not exposed through the protocol of course |
25 | |
27 | |
26 | =item new Crossfire::Protocol host => ..., port => ... |
28 | =item new Crossfire::Protocol host => ..., port => ... |
27 | |
29 | |
28 | =cut |
30 | =cut |
29 | |
31 | |
… | |
… | |
68 | facecache => 1, |
70 | facecache => 1, |
69 | newmapcmd => 1, |
71 | newmapcmd => 1, |
70 | mapinfocmd => 1, |
72 | mapinfocmd => 1, |
71 | plugincmd => 1, |
73 | plugincmd => 1, |
72 | extendedTextInfos => 1, |
74 | extendedTextInfos => 1, |
|
|
75 | spellmon => 1, |
73 | }; |
76 | }; |
74 | |
77 | |
75 | $self->send ("version 1023 1027 perlclient"); |
78 | $self->send ("version 1023 1027 perlclient"); |
76 | $self->send_setup; |
79 | $self->send_setup; |
|
|
80 | $self->send ("requestinfo skill_info"); |
|
|
81 | $self->send ("requestinfo spell_paths"); |
77 | |
82 | |
78 | $self |
83 | $self |
79 | } |
84 | } |
80 | |
85 | |
81 | sub feed { |
86 | sub feed { |
… | |
… | |
131 | |
136 | |
132 | sub feed_face1 { |
137 | sub feed_face1 { |
133 | my ($self, $data) = @_; |
138 | my ($self, $data) = @_; |
134 | |
139 | |
135 | my ($num, $chksum, $name) = unpack "nNa*", $data; |
140 | my ($num, $chksum, $name) = unpack "nNa*", $data; |
|
|
141 | |
|
|
142 | $self->need_face ($num, $name, $chksum); |
|
|
143 | } |
|
|
144 | |
|
|
145 | sub need_face { |
|
|
146 | my ($self, $num, $name, $chksum) = @_; |
|
|
147 | |
|
|
148 | return if $self->{face}[$num]; |
136 | |
149 | |
137 | my $face = $self->{face}[$num] = { name => $name, chksum => $chksum }; |
150 | my $face = $self->{face}[$num] = { name => $name, chksum => $chksum }; |
138 | |
151 | |
139 | if (my $data = $self->face_find ($num, $face)) { |
152 | if (my $data = $self->face_find ($num, $face)) { |
140 | $face->{image} = $data; |
153 | $face->{image} = $data; |
… | |
… | |
319 | weight => $weight, |
332 | weight => $weight, |
320 | face => $face, |
333 | face => $face, |
321 | name => $name, |
334 | name => $name, |
322 | name_pl => $name_pl, |
335 | name_pl => $name_pl, |
323 | anim => $anim, |
336 | anim => $anim, |
324 | animspeed => $animspeed * 0.120, #??? |
337 | animspeed => $animspeed * $TICK, #??? |
325 | nrof => $nrof, |
338 | nrof => $nrof, |
326 | type => $type, |
339 | type => $type, |
327 | }; |
340 | }; |
328 | } |
341 | } |
329 | |
342 | |
… | |
… | |
336 | |
349 | |
337 | sub item_update { } |
350 | sub item_update { } |
338 | |
351 | |
339 | sub feed_upditem { |
352 | sub feed_upditem { |
340 | #todo |
353 | #todo |
|
|
354 | #define UPD_LOCATION 0x01 |
|
|
355 | #define UPD_FLAGS 0x02 |
|
|
356 | #define UPD_WEIGHT 0x04 |
|
|
357 | #define UPD_FACE 0x08 |
|
|
358 | #define UPD_NAME 0x10 |
|
|
359 | #define UPD_ANIM 0x20 |
|
|
360 | #define UPD_ANIMSPEED 0x40 |
|
|
361 | #define UPD_NROF 0x80 |
|
|
362 | } |
|
|
363 | |
|
|
364 | =item $conn->spell_add ($spell) |
|
|
365 | |
|
|
366 | $spell = { |
|
|
367 | tag => ..., |
|
|
368 | level => ..., |
|
|
369 | casting_time => ..., |
|
|
370 | mana => ..., |
|
|
371 | grace => ..., |
|
|
372 | damage => ..., |
|
|
373 | skill => ..., |
|
|
374 | path => ..., |
|
|
375 | face => ..., |
|
|
376 | name => ..., |
|
|
377 | message => ..., |
|
|
378 | }; |
|
|
379 | |
|
|
380 | =item $conn->spell_update ($spell) |
|
|
381 | |
|
|
382 | (the default implementation calls delete then add) |
|
|
383 | |
|
|
384 | =item $conn->spell_delete ($spell) |
|
|
385 | |
|
|
386 | =cut |
|
|
387 | |
|
|
388 | sub spell_add { } |
|
|
389 | |
|
|
390 | sub spell_update { |
|
|
391 | my ($self, $spell) = @_; |
|
|
392 | |
|
|
393 | $self->spell_delete ($spell); |
|
|
394 | $self->spell_add ($spell); |
|
|
395 | } |
|
|
396 | |
|
|
397 | sub spell_delete { } |
|
|
398 | |
|
|
399 | sub feed_addspell { |
|
|
400 | my ($self, $data) = @_; |
|
|
401 | |
|
|
402 | my @data = unpack "(NnnnnnCNN C/a n/a)*", $data; |
|
|
403 | |
|
|
404 | while (@data) { |
|
|
405 | my $spell = { |
|
|
406 | tag => (shift @data), |
|
|
407 | level => (shift @data), |
|
|
408 | casting_time => (shift @data), |
|
|
409 | mana => (shift @data), |
|
|
410 | grace => (shift @data), |
|
|
411 | damage => (shift @data), |
|
|
412 | skill => (shift @data), |
|
|
413 | path => (shift @data), |
|
|
414 | face => (shift @data), |
|
|
415 | name => (shift @data), |
|
|
416 | message => (shift @data), |
|
|
417 | }; |
|
|
418 | |
|
|
419 | $self->send ("requestinfo image_sums $spell->{face} $spell->{face}") |
|
|
420 | unless $self->{spell_face}[$spell->{face}]++; |
|
|
421 | |
|
|
422 | $self->spell_add ($self->{spell}{$spell->{tag}} = $spell); |
|
|
423 | } |
|
|
424 | } |
|
|
425 | |
|
|
426 | sub feed_updspell { |
|
|
427 | my ($self, $data) = @_; |
|
|
428 | |
|
|
429 | my ($flags, $tag) = unpack "CN", substr $data, 0, 5, ""; |
|
|
430 | |
|
|
431 | # only 1, 2, 4 supported |
|
|
432 | # completely untested |
|
|
433 | |
|
|
434 | my $spell = $self->{spell}{$tag}; |
|
|
435 | |
|
|
436 | $spell->{mana} = unpack "n", substr $data, 0, 2, "" if $flags & 1; |
|
|
437 | $spell->{grace} = unpack "n", substr $data, 0, 2, "" if $flags & 2; |
|
|
438 | $spell->{damage} = unpack "n", substr $data, 0, 2, "" if $flags & 4; |
|
|
439 | |
|
|
440 | $self->spell_update ($spell); |
|
|
441 | } |
|
|
442 | |
|
|
443 | sub feed_delspell { |
|
|
444 | my ($self, $data) = @_; |
|
|
445 | |
|
|
446 | $self->spell_delete (delete $self->{spell}{unpack "N", $data}); |
341 | } |
447 | } |
342 | |
448 | |
343 | sub feed_map1a { |
449 | sub feed_map1a { |
344 | my ($self, $data) = @_; |
450 | my ($self, $data) = @_; |
345 | |
451 | |
… | |
… | |
495 | } |
601 | } |
496 | |
602 | |
497 | $self->map_update (\@dirty); |
603 | $self->map_update (\@dirty); |
498 | } |
604 | } |
499 | |
605 | |
|
|
606 | sub feed_replyinfo { |
|
|
607 | my ($self, $data) = @_; |
|
|
608 | |
|
|
609 | if ($data =~ s/^image_sums \d+ \d+ //) { |
|
|
610 | my ($num, $chksum, $faceset, $name) = unpack "n N C C/Z*", $data; |
|
|
611 | |
|
|
612 | $self->need_face ($num, $name, $chksum); |
|
|
613 | } elsif ($data =~ s/^skill_info\s+//) { |
|
|
614 | for (split /\012/, $data) { |
|
|
615 | my ($id, $name) = split /:/, $_, 2; |
|
|
616 | $self->{skill_info}{$id} = $name; |
|
|
617 | } |
|
|
618 | } elsif ($data =~ s/^spell_paths\s+//) { |
|
|
619 | for (split /\012/, $data) { |
|
|
620 | my ($id, $name) = split /:/, $_, 2; |
|
|
621 | $self->{spell_paths}{$id} = $name; |
|
|
622 | } |
|
|
623 | } |
|
|
624 | } |
|
|
625 | |
500 | =item $conn->map_change ($mode, ...) [OVERWRITE] |
626 | =item $conn->map_change ($mode, ...) [OVERWRITE] |
501 | |
627 | |
502 | current <flags> <x> <y> <width> <height> <hashstring> |
628 | current <flags> <x> <y> <width> <height> <hashstring> |
503 | |
629 | |
504 | =cut |
630 | =cut |