| 1 |
=head1 CROSSFIRE+ EXTENSION INTRODUCTION |
| 2 |
|
| 3 |
In Crossfire+ the plugin/extension and event API was completly rewritten |
| 4 |
in Perl and C++. Here is a small guide or introduction on how to |
| 5 |
use it. |
| 6 |
|
| 7 |
If you have any questions don't hesitate to contact the developers, |
| 8 |
see: http://cf.schmorp.de/contact.shtml |
| 9 |
|
| 10 |
|
| 11 |
=head2 Extension to <thing> attachments |
| 12 |
|
| 13 |
You can "attach" extensions to global events, to type/subtypes, |
| 14 |
to specifix objects, to players and to maps. |
| 15 |
On top of that a extension can implement new user commands. |
| 16 |
|
| 17 |
If a extension for example wants to attach itself to all jeweler |
| 18 |
skills it has to attach itself like this: |
| 19 |
|
| 20 |
cf::attach_to_type cf::SKILL, cf::SK_JEWELER, |
| 21 |
on_use_skill => sub { |
| 22 |
... handling code here ... |
| 23 |
}; |
| 24 |
|
| 25 |
This function attaches itself to the type SKILL with the subtype |
| 26 |
SK_JEWELER. And everytime someone uses the skill the callback |
| 27 |
registered as 'on_use_skill' is called. |
| 28 |
Multiple extensions can attach themself to this type, and they |
| 29 |
can specify a priority with 'prio => -100' to be executed earlier. |
| 30 |
|
| 31 |
You can also attach a Perl package to the skill like this: |
| 32 |
|
| 33 |
cf::attach_to_type cf::SKILL, cf::SK_JEWELER, |
| 34 |
package => 'Crossfire::JewelerSkill'; |
| 35 |
|
| 36 |
cf::attach_to_objects will attach handlers for events on _all_ objects |
| 37 |
in the game, this is mainly for debugging purposes, as it will produce a |
| 38 |
high load. |
| 39 |
|
| 40 |
The map attachments work like this: |
| 41 |
|
| 42 |
If a extension wants to attach itself to the 'trigger' event (this is |
| 43 |
the event that is generated when a connection is activated (pushed or |
| 44 |
released)), it has to do this: |
| 45 |
|
| 46 |
cf::attach_to_maps |
| 47 |
on_trigger => sub { |
| 48 |
my ($map, $connection, $state) = @_; |
| 49 |
|
| 50 |
print "CONNECITON TRIGGERED: $connection : $state\n"; |
| 51 |
|
| 52 |
for ($map->get_connection ($connection)) { |
| 53 |
print "connected obj: " . $_->name . "\n"; |
| 54 |
} |
| 55 |
}; |
| 56 |
|
| 57 |
This small attachment dumps all connection activations and the connected |
| 58 |
objects. If this attachment now decides to overwrite connection 10, so that |
| 59 |
nothing happens if it is triggered, it has to do this: |
| 60 |
|
| 61 |
cf::attach_to_maps |
| 62 |
on_trigger => sub { |
| 63 |
my ($map, $connection, $state) = @_; |
| 64 |
|
| 65 |
if ($connection == 10) { |
| 66 |
cf::override; |
| 67 |
return; # the idiom 'return cf::override;' is quite common in our code |
| 68 |
# but i want to empasize that cf::override is just a functioncall |
| 69 |
} |
| 70 |
}; |
| 71 |
|
| 72 |
The call of cf::override sets a flag in the event system that will prevent any execution |
| 73 |
of further code that handles this event. This way all attachments with 'lower' priority |
| 74 |
and the C/C++ code is inhibited/overridden. |
| 75 |
|
| 76 |
=head2 <thing> to extension attachments |
| 77 |
|
| 78 |
The attachments are not limited to 'an extension attaches itself to <...>', a map or an |
| 79 |
objects itself can attach to a 'registered' attachment. For example our nice cat which runs |
| 80 |
around in scorn and heals people at random has following line in it's archetype: |
| 81 |
|
| 82 |
Object nekosan |
| 83 |
... |
| 84 |
attach [["Nekosan"]] |
| 85 |
end |
| 86 |
|
| 87 |
The value of the attach field is a 2 dimensional array in JSON (JavaScript Object Notation) |
| 88 |
is a array of arrays which contain following fields: |
| 89 |
[ <attachment name/key>, { <key value pairs of arguments for the attachment> }] |
| 90 |
|
| 91 |
The code side of this looks like this: |
| 92 |
|
| 93 |
cf::register_attachment "Nekosan", package => __PACKAGE__; |
| 94 |
|
| 95 |
This registeres an attachment under the name/key 'Nekosan' so that objects like our |
| 96 |
cat can attach itself. |
| 97 |
|
| 98 |
Where the package defines for example this function: |
| 99 |
sub on_monster_move { |
| 100 |
my ($self, $enemy) = @_; |
| 101 |
... |
| 102 |
} |
| 103 |
|
| 104 |
$self is a mostly empty object, the attachment object, which is initalized |
| 105 |
with the arguments that are given in the 'attach' value, if nekosan would have an |
| 106 |
attach field like this: |
| 107 |
|
| 108 |
attach [["Nekosan", {"foo":"bar"}]] |
| 109 |
|
| 110 |
The attached function can access the value of the key "foo" like this: |
| 111 |
|
| 112 |
$self->{Nekosan}->{foo} |
| 113 |
|
| 114 |
This way multiple different attachments have a seperate field for storing |
| 115 |
their arguments. |
| 116 |
|
| 117 |
=head2 Defining new user commands |
| 118 |
|
| 119 |
If a extension wants to redefine a user command it does it like this: |
| 120 |
|
| 121 |
cf::register_command invite => 10, sub { |
| 122 |
my ($who, $args) = @_; |
| 123 |
... |
| 124 |
} |
| 125 |
|
| 126 |
This registers the 'invite' command with the execution time of 10. The |
| 127 |
arguments to the function are ($who, $args), where $who is the player |
| 128 |
and $args the argument string to the command. |
| 129 |
|
| 130 |
=head2 Adding event invocations to the C++ code |
| 131 |
|
| 132 |
There are already a lot of events implemented, look in the L<events.pod> for |
| 133 |
a reference of existing events. But when you need a new event, here |
| 134 |
is how to do add it: |
| 135 |
|
| 136 |
Here an example for move_trigger in move_apply (): |
| 137 |
|
| 138 |
Add a line to doc/events.pod with documentation looking like this: |
| 139 |
|
| 140 |
=head3 move_trigger (object victim originator -- ) |
| 141 |
|
| 142 |
Invoked whenever a trap-like B<object> has been activated, usually by |
| 143 |
moving onto it. This includes not just traps, but also buttons, holes, |
| 144 |
signs and similar stuff. |
| 145 |
|
| 146 |
And put some lines like this to move_apply: |
| 147 |
|
| 148 |
if (INVOKE_OBJECT (MOVE_TRIGGER, trap, ARG_OBJECT (victim), ARG_OBJECT (originator))) |
| 149 |
goto leave; |
| 150 |
|
| 151 |
This invokes all attachments that are interested in the object event MOVE_TRIGGER, with |
| 152 |
the object being 'trap' and the arguments victim and originator. This is all C++ code |
| 153 |
that has to be added when one wants to add an event. 'make' will update include/eventinc.h |
| 154 |
from the events.pod automatically when building. |
| 155 |
|
| 156 |
=head2 Resources / See also |
| 157 |
|
| 158 |
Here is the documentation for all this, which is maybe partly unfinished. But there |
| 159 |
are also a lot of examples: |
| 160 |
|
| 161 |
=over 4 |
| 162 |
|
| 163 |
=item lib/cf.pm |
| 164 |
|
| 165 |
Has some documentation of the attachment API |
| 166 |
|
| 167 |
=item pod/events.pod |
| 168 |
|
| 169 |
A reference for all existing events |
| 170 |
|
| 171 |
=item Examples |
| 172 |
|
| 173 |
Examples can be found in http://cvs.schmorp.de/cf.schmorp.de/maps/perl/ |
| 174 |
|
| 175 |
=item NPC_Dialogue.pod in maps/perl/ |
| 176 |
|
| 177 |
The NPC dialogue system might also be interesting: http://cf.schmorp.de/doc/development/NPC_Dialogue.html |