1 | #! perl |
1 | #! perl |
2 | |
2 | |
3 | # archetype nekosan |
3 | # archetype nekosan |
4 | |
|
|
5 | use Data::Dumper; |
|
|
6 | |
4 | |
7 | sub teleport { |
5 | sub teleport { |
8 | my ($pl, $map, $x, $y) = @_; |
6 | my ($pl, $map, $x, $y) = @_; |
9 | |
7 | |
10 | my $portal = cf::object::new "exit"; |
8 | my $portal = cf::object::new "exit"; |
… | |
… | |
16 | $portal->apply ($pl); |
14 | $portal->apply ($pl); |
17 | |
15 | |
18 | $portal->free; |
16 | $portal->free; |
19 | } |
17 | } |
20 | |
18 | |
21 | sub on_move { |
19 | sub find_target_player { |
22 | my ($data) = @_; |
20 | my ($obj) = @_; |
23 | |
21 | |
24 | if (my $pl = $data->{who}->nearest_player) { |
22 | my ($time, $pl) = (time + 120, undef); |
|
|
23 | |
|
|
24 | for (map $_->ob, cf::player::list) { |
|
|
25 | next unless $obj->on_same_map_as ($_); |
|
|
26 | |
|
|
27 | my $ptime = List::Util::max $_->{neko_next_pester}, $_->{neko_next_cast}; |
|
|
28 | |
|
|
29 | ($time, $pl) = ($ptime, $_) |
|
|
30 | if $time > $ptime; |
|
|
31 | } |
|
|
32 | |
|
|
33 | $pl |
|
|
34 | } |
|
|
35 | |
|
|
36 | sub on_monster_move { |
|
|
37 | my ($self, $enemy) = @_; |
|
|
38 | |
|
|
39 | if (my $pl = find_target_player $self) { |
25 | my ($d, undef, undef, $dir, undef) = $data->{who}->rangevector ($pl); |
40 | my ($d, undef, undef, $dir, undef) = $self->rangevector ($pl); |
26 | |
41 | |
27 | if ($d < 1.5) { |
42 | if ($d < 1.5) { |
28 | if (grep $_->type == cf::FORCE && $_->slaying eq "schmorp-neko-gave-fish", $pl->inv) { |
43 | if (grep $_->type == cf::FORCE && $_->slaying eq "schmorp-neko-gave-fish", $pl->inv) { |
29 | # she likes us! |
44 | # she likes us! |
30 | if ($pl->{neko_fish} < time) { |
45 | if ($pl->{neko_next_pester} < time) { |
31 | $pl->{neko_fish} = time + 120 + rand 300; |
46 | $pl->{neko_next_pester} = time + 120 + rand 300; |
32 | $pl->message ("Purr. (Purr)"); |
47 | $pl->message ("Purr. (Purr)"); |
33 | } |
48 | } |
34 | |
49 | |
35 | # so heal her |
50 | if ($pl->{neko_next_cast} < time) { |
36 | my $spell = cf::object::new "spell_heal"; |
51 | $pl->{neko_next_cast} = time + 40 + rand 60; |
37 | |
52 | |
38 | $spell->set_hp (0); |
53 | # so heal her |
39 | $spell->set_dam (0); # normal hp heal (none to aovid message) |
54 | my $spell = cf::object::new "spell_heal"; |
40 | $spell->set_food (999); # fill food |
|
|
41 | $spell->set_last_sp (9999); # fill sp |
|
|
42 | $spell->set_last_grace (9999); # fill gr |
|
|
43 | $spell->set_attacktype (cf::AT_CONFUSION | cf::AT_POISON | cf::AT_BLIND | cf::AT_DISEASE); |
|
|
44 | |
55 | |
45 | if ($data->{who}->cast_spell ($data->{who}, $dir, $spell)) { |
56 | $spell->set_sp (0); # makes casting work |
|
|
57 | $spell->set_gp (0); # on unholy/nomagic ground |
|
|
58 | |
|
|
59 | $spell->set_hp (0); |
|
|
60 | $spell->set_dam (($pl->maxhp - $pl->hp) * 0.5); # normal hp heal |
|
|
61 | $spell->set_food (50); # fill food |
|
|
62 | $spell->set_last_sp (100); # fill sp |
|
|
63 | $spell->set_last_grace (100); # fill gr |
|
|
64 | $spell->set_attacktype (cf::AT_CONFUSION | cf::AT_POISON | cf::AT_BLIND | cf::AT_DISEASE); |
|
|
65 | |
46 | $pl->message ("... (Neko-san makes strange noises)"); |
66 | $pl->message ("(Neko-san makes strange noises)"); |
|
|
67 | $pl->cast_spell ($self, $dir, $spell); |
|
|
68 | |
|
|
69 | $spell->free; |
47 | } |
70 | } |
48 | |
|
|
49 | $spell->free; |
|
|
50 | |
71 | |
51 | } else { |
72 | } else { |
52 | # check for fish in his inv and steal it |
73 | # check for fish in his inv and steal it |
53 | if (my $fish = (grep $_->archetype->name eq "fishfood", $pl->inv)[0]) { |
74 | if (my $fish = (grep $_->archetype->name eq "fishfood", $pl->inv)[0]) { |
54 | # add force |
75 | # add force |
… | |
… | |
64 | # be nice |
85 | # be nice |
65 | $pl->message ("Meoww! (Thank you)"); |
86 | $pl->message ("Meoww! (Thank you)"); |
66 | |
87 | |
67 | } else { |
88 | } else { |
68 | # pester user |
89 | # pester user |
69 | if ($pl->{neko_fish} < time) { |
90 | if ($pl->{neko_next_pester} < time) { |
70 | $pl->{neko_fish} = time + 60 + rand 300; |
91 | $pl->{neko_next_pester} = time + 60 + rand 300; |
71 | $pl->message ("Meow. (Please bring me fish)"); |
92 | $pl->message ("Meow. (Please bring me fish)"); |
72 | } |
93 | } |
73 | } |
94 | } |
74 | } |
95 | } |
75 | |
96 | |
76 | # circular movement |
97 | # circular movement |
77 | $dir = $dir % 8 + 1 unless $d > 1.5; |
98 | $dir = $dir % 8 + 1 unless $d > 1.5; |
78 | } |
99 | } |
79 | |
100 | |
80 | $data->{who}->move ($dir); |
101 | $self->move ($dir); |
81 | } |
102 | } |
82 | |
103 | |
83 | 1 |
104 | cf::override; |
84 | } |
105 | } |
85 | |
106 | |
86 | sub on_attack { |
107 | sub on_attack { |
87 | my ($data) = @_; |
108 | my ($self, $hitter) = @_; |
88 | |
109 | |
89 | $data->{activator}{neko_attack}++ |
110 | if ($hitter->{neko_last_attack} < time - 300) { |
90 | or cf::LOG cf::llevDebug, sprintf "QBERT Neko-san was attacked by %s!\n", $data->{activator}->name; |
111 | $hitter->{neko_attack} = 0; |
91 | |
|
|
92 | $data->{activator}->message ("Meoow! (Please do not hurt me)") |
|
|
93 | if !($data->{activator}{neko_attack} & 15); |
|
|
94 | |
|
|
95 | if ($data->{activator}{neko_attack} > 512) { |
|
|
96 | $data->{activator}{neko_attack} -= 128; |
|
|
97 | $data->{activator}->message ("Neko-san is suddenly gone!"); |
|
|
98 | teleport $data->{activator}, "/scorn/misc/scorn_illusions", 15, 7; |
|
|
99 | $data->{activator}->message ("You hear strange noises all around you..."); |
|
|
100 | $data->{activator}->message ("You feel dumb."); |
|
|
101 | } |
112 | } |
102 | |
113 | |
|
|
114 | $hitter->{neko_last_attack} = time; |
|
|
115 | $hitter->{neko_attack}++ |
|
|
116 | or ext::schmorp_irc::do_notice "Neko-san was attacked by ". $hitter->name . "!\n"; |
|
|
117 | |
|
|
118 | $hitter->message ("Meoow! (Please do not hurt me)") |
|
|
119 | if !($hitter->{neko_attack} & 15); |
|
|
120 | |
|
|
121 | if ($hitter->{neko_attack} > 512) { |
|
|
122 | $hitter->{neko_attack} -= 128; |
|
|
123 | $hitter->message ("Neko-san is suddenly gone!"); |
|
|
124 | teleport $hitter, "/scorn/misc/scorn_illusions", 15, 7; |
|
|
125 | $hitter->message ("You hear strange noises all around you..."); |
|
|
126 | $hitter->message ("You feel dumb."); |
103 | 1 |
127 | } |
|
|
128 | |
|
|
129 | cf::override; |
104 | } |
130 | } |
105 | |
131 | |
106 | sub on_say { |
132 | sub on_listen { |
107 | my ($data) = @_; |
133 | my ($event, $ob, $who, $msg) = @_; |
108 | |
134 | |
109 | cf::LOG cf::llevDebug, sprintf "QBERT [Neko-fon] %s: %s\n", $data->{activator}->name, $data->{message}; |
135 | cf::LOG cf::llevDebug, sprintf "QBERT [Neko-fon] %s: %s\n", $who->name, $msg; |
110 | |
136 | ext::schmorp_irc::do_notice (sprintf "[Neko-fon] %s: %s\n", $who->name, $msg); |
111 | 0 |
|
|
112 | } |
137 | } |
113 | |
138 | |
|
|
139 | cf::register_attachment "Nekosan", package => __PACKAGE__; |
|
|
140 | |