ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/server/cfperl.xs
Revision: 1.258
Committed: Sun Sep 30 20:22:24 2007 UTC (16 years, 8 months ago) by root
Branch: MAIN
Changes since 1.257: +13 -3 lines
Log Message:
- clean up message system, combine all boxes into one.
- suppress too long messages (we need a more robust solution to this problem).
- get rid of INS_MAP_LOAD, leading to slightly cleaner/faster code
  and certainly one special case less.
- insert objects manually at load time, this is both faster and also more
  correct, as loading a map is never supposed to trigger anything (and
  also for symmetry to the save code).

File Contents

# User Rev Content
1 root 1.1 /*
2 root 1.216 * This file is part of Crossfire TRT, the Roguelike Realtime MORPG.
3     *
4     * Copyright (©) 2006,2007 Marc Alexander Lehmann / Robin Redeker / the Crossfire TRT team
5     * Copyright (©) 2001-2005,2007 by Chachkoff Yann
6     * Copyright (©) 2006,2007 by Marc Lehmann <cf@schmorp.de>
7     *
8 root 1.226 * Crossfire TRT is free software: you can redistribute it and/or modify
9     * it under the terms of the GNU General Public License as published by
10     * the Free Software Foundation, either version 3 of the License, or
11     * (at your option) any later version.
12 root 1.216 *
13 root 1.226 * This program is distributed in the hope that it will be useful,
14     * but WITHOUT ANY WARRANTY; without even the implied warranty of
15     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16     * GNU General Public License for more details.
17 root 1.216 *
18 root 1.226 * You should have received a copy of the GNU General Public License
19     * along with this program. If not, see <http://www.gnu.org/licenses/>.
20 root 1.216 *
21     * The authors can be reached via e-mail to <crossfire@schmorp.de>
22 root 1.106 */
23 root 1.1
24 root 1.198 #include "autoconf.h"
25    
26 root 1.1 #define PLUGIN_NAME "perl"
27 root 1.13 #define PLUGIN_VERSION "cfperl 0.5"
28 root 1.1
29 root 1.189 #define CEDES_PER_TICK 5
30    
31 root 1.198 #if HAVE_EXECINFO_H
32     # include <execinfo.h>
33     #endif
34    
35 root 1.6 #include <cstdarg>
36 root 1.1
37 root 1.257 #include "global.h"
38 root 1.162 #include "loader.h"
39 root 1.257 #include "../random_maps/random_map.h"
40     #include <sproto.h>
41 root 1.1
42 root 1.125 #include <unistd.h>
43     #if _POSIX_MEMLOCK
44     # include <sys/mman.h>
45     #endif
46    
47 root 1.32 #include <EXTERN.h>
48     #include <perl.h>
49     #include <XSUB.h>
50    
51 root 1.107 #include "CoroAPI.h"
52 root 1.1 #include "perlxsi.c"
53    
54     extern sint64 *levels; // the experience table
55    
56 root 1.247 typedef object_thawer &object_thawer_ref;
57     typedef object_freezer &object_freezer_ref;
58 root 1.183
59 root 1.194 typedef std::string std__string;
60    
61 root 1.71 #if IVSIZE >= 8
62     typedef IV val64;
63     # define newSVval64 newSViv
64     # define SvVAL64 SvIV
65     #else
66     typedef double val64;
67     # define newSVval64 newSVnv
68     # define SvVAL64 SvNV
69     #endif
70 root 1.1
71     static PerlInterpreter *perl;
72    
73 root 1.220 tstamp NOW, runtime;
74 root 1.116
75 root 1.109 global gbl_ev;
76     static AV *cb_global, *cb_attachable, *cb_object, *cb_player, *cb_client, *cb_type, *cb_map;
77 root 1.189 static SV *sv_runtime, *sv_next_tick;
78 root 1.109
79 root 1.210 bitset<NUM_EVENT_TYPES> ev_want_event;
80     bitset<NUM_TYPES> ev_want_type;
81    
82 root 1.109 static HV
83     *stash_cf,
84     *stash_cf_object_wrap,
85     *stash_cf_object_player_wrap,
86     *stash_cf_player_wrap,
87     *stash_cf_map_wrap,
88     *stash_cf_client_wrap,
89     *stash_cf_arch_wrap,
90     *stash_cf_party_wrap,
91     *stash_cf_region_wrap,
92     *stash_cf_living_wrap;
93    
94 root 1.246 static inline SV *
95     newSVpv_utf8 (const char *s)
96     {
97 root 1.252 if (!s)
98     return newSV (0);
99    
100 root 1.246 SV *sv = newSVpv (s, 0);
101     SvUTF8_on (sv);
102     return sv;
103     }
104    
105     static inline SV *
106     newSVpvn_utf8 (const char *s, STRLEN l)
107     {
108 root 1.252 if (!s)
109     return newSV (0);
110    
111 root 1.246 SV *sv = newSVpvn (s, l);
112     SvUTF8_on (sv);
113     return sv;
114     }
115    
116 root 1.109 // helper cast function, returns super class * or 0
117     template<class super>
118     static super *
119     is_a (attachable *at)
120     {
121     //return dynamic_cast<super *>(at); // slower, safer
122     if (typeid (*at) == typeid (super))
123     return static_cast<super *>(at);
124     else
125     return 0;
126     }
127    
128     //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
129    
130     unordered_vector<attachable *> attachable::mortals;
131    
132 root 1.129 attachable::~attachable ()
133 root 1.109 {
134 root 1.133 assert (!self);
135 root 1.153 assert (!cb);
136 root 1.109 }
137    
138 root 1.130 int
139     attachable::refcnt_cnt () const
140     {
141 root 1.152 return refcnt + (self ? SvREFCNT (self) - 1 : 0);
142 root 1.130 }
143    
144     void
145 root 1.155 attachable::sever_self ()
146 root 1.109 {
147 root 1.164 if (HV *self = this->self)
148 root 1.129 {
149 root 1.155 // keep a refcount because sv_unmagic might call attachable_free,
150     // which might clear self, causing sv_unmagic to crash on a now
151     // invalid object.
152 root 1.154 SvREFCNT_inc (self);
153 root 1.155 hv_clear (self);
154     sv_unmagic ((SV *)self, PERL_MAGIC_ext);
155 root 1.154 SvREFCNT_dec (self);
156 root 1.155
157     // self *must* be null now because thats sv_unmagic's job.
158 root 1.164 assert (!this->self);
159 root 1.129 }
160 root 1.109 }
161    
162 root 1.155 void
163     attachable::optimise ()
164     {
165     if (self
166     && SvREFCNT (self) == 1
167     && !HvTOTALKEYS (self))
168     sever_self ();
169     }
170    
171 root 1.109 // check wether the object really is dead
172     void
173     attachable::do_check ()
174     {
175 root 1.152 if (refcnt_cnt () > 0)
176 root 1.109 return;
177    
178 root 1.133 destroy ();
179 root 1.109 }
180    
181     void
182     attachable::do_destroy ()
183     {
184 root 1.214 INVOKE_ATTACHABLE (DESTROY, this);
185 root 1.109
186 root 1.153 if (cb)
187     {
188     SvREFCNT_dec (cb);
189     cb = 0;
190     }
191    
192 root 1.109 mortals.push_back (this);
193     }
194    
195     void
196     attachable::destroy ()
197     {
198     if (destroyed ())
199     return;
200    
201     flags |= F_DESTROYED;
202     do_destroy ();
203 root 1.198 sever_self ();
204 root 1.109 }
205    
206 root 1.130 void
207     attachable::check_mortals ()
208 root 1.109 {
209 root 1.150 static int i = 0;
210    
211     for (;;)
212 root 1.109 {
213 root 1.150 if (i >= mortals.size ())
214     {
215     i = 0;
216    
217 root 1.221 if (mortals.size () >= 512)
218     {
219     static int last_mortalcount;
220     if (mortals.size () != last_mortalcount)
221     {
222     last_mortalcount = mortals.size ();
223     LOG (llevInfo, "%d mortals.\n", (int)mortals.size ());
224    
225     if (0)
226     {
227     for (int j = 0; j < mortals.size (); ++j)//D
228     fprintf (stderr, "%d:%s %p ", j, &((object *)mortals[j])->name, mortals[j]);//D
229     fprintf (stderr, "\n");//D
230     }
231     }
232     }
233 root 1.150
234     break;
235     }
236    
237 root 1.109 attachable *obj = mortals [i];
238    
239 root 1.197 #if 0
240     if (obj->self)//D make this an assert later
241     {
242     LOG (llevError, "check_mortals: object '%s' still has self\n", typeid (obj).name ());
243     obj->sever_self ();
244     }
245     #endif
246 root 1.109
247 root 1.198 if (obj->refcnt)
248 root 1.109 {
249 root 1.150 ++i; // further delay freeing
250 root 1.109
251 root 1.150 if (!(i & 0x3ff))
252     break;
253     }
254 root 1.109 else
255     {
256 root 1.112 mortals.erase (i);
257 root 1.197 obj->sever_self ();
258 root 1.109 delete obj;
259     }
260     }
261     }
262    
263 root 1.228 void
264 root 1.246 attachable::set_key (const char *key, const char *value, bool is_utf8)
265 root 1.228 {
266     if (!self)
267     self = newHV ();
268    
269     if (value)
270 root 1.246 hv_store (self, key, strlen (key), is_utf8 ? newSVpv_utf8 (value) : newSVpv (value, 0), 0);
271 root 1.228 else
272     hv_delete (self, key, strlen (key), G_DISCARD);
273     }
274    
275 root 1.109 attachable &
276     attachable::operator =(const attachable &src)
277     {
278     //if (self || cb)
279     //INVOKE_OBJECT (CLONE, this, ARG_OBJECT (dst));
280    
281     attach = src.attach;
282     return *this;
283     }
284 root 1.8
285 root 1.221 template<typename T>
286     static bool
287     find_backref (void *ptr, T *obj)
288     {
289     char *s = (char *)obj;
290     while (s < (char *)obj + sizeof (T))
291     {
292     if (ptr == *(void **)s)
293     return true;
294    
295     s += sizeof (void *); // assume natural alignment
296     }
297    
298     return false;
299     }
300    
301     // for debugging, find "live" objects containing this ptr
302     void
303     find_backref (void *ptr)
304     {
305     for_all_objects (op)
306     if (find_backref (ptr, op))
307     fprintf (stderr, "O %p %d:'%s'\n", op, op->count, &op->name);
308    
309     for_all_players (pl)
310     if (find_backref (ptr, pl))
311     fprintf (stderr, "P %p\n", pl);
312    
313     for_all_clients (ns)
314     if (find_backref (ptr, ns))
315     fprintf (stderr, "C %p\n", ns);
316    
317     }
318    
319 root 1.1 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
320    
321     static SV *
322 root 1.109 newSVptr (void *ptr, HV *stash, HV *hv = newHV ())
323 root 1.1 {
324     SV *sv;
325    
326     if (!ptr)
327 root 1.252 return newSV (0);
328 root 1.1
329 root 1.109 sv_magicext ((SV *)hv, 0, PERL_MAGIC_ext, 0, (char *)ptr, 0);
330     return sv_bless (newRV_noinc ((SV *)hv), stash);
331     }
332    
333     static int
334     attachable_free (pTHX_ SV *sv, MAGIC *mg)
335     {
336     attachable *at = (attachable *)mg->mg_ptr;
337 root 1.153
338     //TODO: check if transaction behaviour is really required here
339     if (SV *self = (SV *)at->self)
340     {
341     at->self = 0;
342     SvREFCNT_dec (self);
343     }
344    
345 root 1.111 // next line makes sense, but most objects still have refcnt 0 by default
346     //at->refcnt_chk ();
347 root 1.109 return 0;
348 root 1.1 }
349    
350 root 1.116 MGVTBL attachable::vtbl = {0, 0, 0, 0, attachable_free};
351 root 1.109
352 root 1.116 static SV *
353 root 1.109 newSVattachable (attachable *obj, HV *stash)
354 root 1.11 {
355     if (!obj)
356 root 1.252 return newSV (0);
357 root 1.11
358     if (!obj->self)
359 root 1.228 obj->self = newHV ();
360    
361     if (!SvOBJECT (obj->self))
362 root 1.109 {
363 root 1.116 sv_magicext ((SV *)obj->self, 0, PERL_MAGIC_ext, &attachable::vtbl, (char *)obj, 0);
364 root 1.11
365 root 1.129 // now bless the object _once_
366 root 1.228 //TODO: create a class registry with c++ type<=>perl name<=>stash and use it here and elsewhere
367 root 1.129 return sv_bless (newRV_inc ((SV *)obj->self), stash);
368 root 1.109 }
369 root 1.129 else
370 root 1.140 {
371     SV *sv = newRV_inc ((SV *)obj->self);
372    
373     if (Gv_AMG (stash)) // handle overload correctly, as the perl core does not
374     SvAMAGIC_on (sv);
375    
376     return sv;
377     }
378 root 1.11 }
379    
380 root 1.1 static void
381     clearSVptr (SV *sv)
382     {
383     if (SvROK (sv))
384     sv = SvRV (sv);
385    
386     hv_clear ((HV *)sv);
387     sv_unmagic (sv, PERL_MAGIC_ext);
388     }
389    
390     static long
391     SvPTR (SV *sv, const char *klass)
392     {
393     if (!sv_derived_from (sv, klass))
394     croak ("object of type %s expected", klass);
395    
396     MAGIC *mg = mg_find (SvRV (sv), PERL_MAGIC_ext);
397    
398     if (!mg)
399     croak ("perl code used %s object, but C object is already destroyed, caught", klass);
400    
401     return (long)mg->mg_ptr;
402     }
403    
404     static long
405     SvPTR_ornull (SV *sv, const char *klass)
406     {
407     if (SvOK (sv))
408     return SvPTR (sv, klass);
409     else
410     return 0;
411     }
412    
413 root 1.252 inline SV *to_sv (const shstr & v) { return newSVpvn_utf8 ((const char *)v, v.length ()); }
414     inline SV *to_sv (const char * v) { return v ? newSVpv (v, 0) : newSV (0); }
415 root 1.45 inline SV *to_sv (bool v) { return newSViv (v); }
416     inline SV *to_sv ( signed char v) { return newSViv (v); }
417     inline SV *to_sv (unsigned char v) { return newSViv (v); }
418     inline SV *to_sv ( signed short v) { return newSViv (v); }
419     inline SV *to_sv (unsigned short v) { return newSVuv (v); }
420     inline SV *to_sv ( signed int v) { return newSViv (v); }
421     inline SV *to_sv (unsigned int v) { return newSVuv (v); }
422     inline SV *to_sv ( signed long v) { return newSViv (v); }
423     inline SV *to_sv (unsigned long v) { return newSVuv (v); }
424 root 1.48 inline SV *to_sv ( signed long long v) { return newSVval64 (v); }
425     inline SV *to_sv (unsigned long long v) { return newSVval64 (v); }
426 root 1.45 inline SV *to_sv (float v) { return newSVnv (v); }
427     inline SV *to_sv (double v) { return newSVnv (v); }
428 root 1.109 inline SV *to_sv (client * v) { return newSVattachable (v, stash_cf_client_wrap); }
429     inline SV *to_sv (player * v) { return newSVattachable (v, stash_cf_player_wrap); }
430     inline SV *to_sv (object * v) { return newSVattachable (v, v && v->type == PLAYER ? stash_cf_object_player_wrap : stash_cf_object_wrap); }
431     inline SV *to_sv (maptile * v) { return newSVattachable (v, stash_cf_map_wrap); }
432     inline SV *to_sv (archetype * v) { return newSVattachable (v, stash_cf_arch_wrap); }
433 root 1.228 inline SV *to_sv (region * v) { return newSVattachable (v, stash_cf_region_wrap); }
434 root 1.109 inline SV *to_sv (partylist * v) { return newSVptr (v, stash_cf_party_wrap); }
435     inline SV *to_sv (living * v) { return newSVptr (v, stash_cf_living_wrap); }
436 root 1.45
437     inline SV *to_sv (object & v) { return to_sv (&v); }
438     inline SV *to_sv (living & v) { return to_sv (&v); }
439    
440 root 1.194 inline SV *to_sv (const std::string & v) { return newSVpvn (v.data (), v.size ()); }
441     inline SV *to_sv (const treasurelist *v) { return to_sv (v->name); }
442 root 1.45
443 root 1.69 inline SV *to_sv (UUID v)
444     {
445 elmex 1.68 char buf[128];
446 root 1.159 snprintf (buf, 128, "<1.%" PRIx64 ">", v.seq);
447 elmex 1.68 return newSVpv (buf, 0);
448     }
449    
450 root 1.247 inline void sv_to (SV *sv, shstr &v) { v = SvOK (sv) ? SvPVutf8_nolen (sv) : 0; }
451     inline void sv_to (SV *sv, char * &v) { free (v); v = SvOK (sv) ? strdup (SvPV_nolen (sv)) : 0; }
452     inline void sv_to (SV *sv, bool &v) { v = SvIV (sv); }
453     inline void sv_to (SV *sv, signed char &v) { v = SvIV (sv); }
454     inline void sv_to (SV *sv, unsigned char &v) { v = SvIV (sv); }
455     inline void sv_to (SV *sv, signed short &v) { v = SvIV (sv); }
456     inline void sv_to (SV *sv, unsigned short &v) { v = SvIV (sv); }
457     inline void sv_to (SV *sv, signed int &v) { v = SvIV (sv); }
458     inline void sv_to (SV *sv, unsigned int &v) { v = SvUV (sv); }
459     inline void sv_to (SV *sv, signed long &v) { v = SvIV (sv); }
460     inline void sv_to (SV *sv, unsigned long &v) { v = SvUV (sv); }
461 root 1.53 inline void sv_to (SV *sv, signed long long &v) { v = ( signed long long)SvVAL64 (sv); }
462     inline void sv_to (SV *sv, unsigned long long &v) { v = (unsigned long long)SvVAL64 (sv); }
463 root 1.247 inline void sv_to (SV *sv, float &v) { v = SvNV (sv); }
464     inline void sv_to (SV *sv, double &v) { v = SvNV (sv); }
465     inline void sv_to (SV *sv, client * &v) { v = (client *)(attachable *)SvPTR_ornull (sv, "cf::client"); }
466     inline void sv_to (SV *sv, player * &v) { v = (player *)(attachable *)SvPTR_ornull (sv, "cf::player"); }
467     inline void sv_to (SV *sv, object * &v) { v = (object *)(attachable *)SvPTR_ornull (sv, "cf::object"); }
468     inline void sv_to (SV *sv, archetype * &v) { v = (archetype *)(attachable *)SvPTR_ornull (sv, "cf::arch"); }
469     inline void sv_to (SV *sv, maptile * &v) { v = (maptile *)(attachable *)SvPTR_ornull (sv, "cf::map"); }
470     inline void sv_to (SV *sv, region * &v) { v = (region *)(attachable *)SvPTR_ornull (sv, "cf::region"); }
471     inline void sv_to (SV *sv, attachable * &v) { v = (attachable *)SvPTR_ornull (sv, "cf::attachable"); }
472     inline void sv_to (SV *sv, partylist * &v) { v = (partylist *)SvPTR_ornull (sv, "cf::party"); }
473     inline void sv_to (SV *sv, living * &v) { v = (living *)SvPTR_ornull (sv, "cf::living"); }
474     inline void sv_to (SV *sv, object_freezer * &v) { v = (object_freezer *)SvPTR_ornull (sv, "cf::object::freezer"); }
475     inline void sv_to (SV *sv, object_thawer * &v) { v = (object_thawer *)SvPTR_ornull (sv, "cf::object::thawer" ); }
476 root 1.45
477 root 1.247 //inline void sv_to (SV *sv, faceinfo * &v) { v = &faces [face_find (SvPV_nolen (sv), 0)]; }
478     inline void sv_to (SV *sv, treasurelist * &v) { v = treasurelist::find (SvPV_nolen (sv)); }
479 root 1.45
480 root 1.52 template<class T>
481 root 1.247 inline void sv_to (SV *sv, refptr<T> &v) { T *tmp; sv_to (sv, tmp); v = tmp; }
482 root 1.52
483 root 1.45 template<int N>
484 root 1.55 inline void sv_to (SV *sv, char (&v)[N]) { assign (v, SvPV_nolen (sv)); }
485 root 1.45
486 root 1.247 inline void sv_to (SV *sv, bowtype_t &v) { v = (bowtype_t) SvIV (sv); }
487     inline void sv_to (SV *sv, petmode_t &v) { v = (petmode_t) SvIV (sv); }
488     inline void sv_to (SV *sv, usekeytype &v) { v = (usekeytype) SvIV (sv); }
489     inline void sv_to (SV *sv, unapplymode &v) { v = (unapplymode) SvIV (sv); }
490 root 1.106
491 root 1.247 inline void sv_to (SV *sv, std::string &v)
492 root 1.176 {
493     STRLEN len;
494     char *data = SvPVbyte (sv, len);
495     v.assign (data, len);
496     }
497    
498 root 1.247 inline void sv_to (SV *sv, UUID &v)
499 root 1.69 {
500     unsigned int version;
501 elmex 1.68
502 root 1.71 if (2 != sscanf (SvPV_nolen (sv), "<%d.%" SCNx64 ">", &version, &v.seq) || 1 != version)
503 root 1.69 croak ("unparsable uuid: %s", SvPV_nolen (sv));
504 elmex 1.68 }
505    
506 root 1.109 inline void sv_to (SV *sv, object::flags_t::reference v) { v = SvTRUE (sv); }
507 root 1.106
508 root 1.1 static SV *
509 root 1.6 newSVdt_va (va_list &ap, data_type type)
510 root 1.1 {
511     SV *sv;
512    
513     switch (type)
514     {
515 root 1.10 case DT_INT:
516     sv = newSViv (va_arg (ap, int));
517     break;
518    
519     case DT_INT64:
520     sv = newSVval64 ((val64)va_arg (ap, sint64));
521     break;
522    
523 root 1.6 case DT_DOUBLE:
524 root 1.10 sv = newSVnv (va_arg (ap, double));
525 root 1.1 break;
526    
527 root 1.6 case DT_STRING:
528     {
529 root 1.10 char *str = (char *)va_arg (ap, const char *);
530 root 1.252 sv = str ? newSVpv (str, 0) : newSV (0);
531 root 1.6 }
532 root 1.1 break;
533    
534 root 1.6 case DT_DATA:
535 root 1.1 {
536 root 1.10 char *str = (char *)va_arg (ap, const void *);
537 root 1.6 int len = va_arg (ap, int);
538 root 1.252 sv = str ? newSVpv (str, len) : newSV (0);
539 root 1.1 }
540     break;
541    
542 root 1.6 case DT_OBJECT:
543 root 1.45 sv = to_sv (va_arg (ap, object *));
544 root 1.1 break;
545    
546 root 1.6 case DT_MAP:
547 root 1.11 // va_arg (object *) when void * is passed is an XSI extension
548 root 1.61 sv = to_sv (va_arg (ap, maptile *));
549 root 1.1 break;
550    
551 root 1.88 case DT_CLIENT:
552 root 1.84 sv = to_sv (va_arg (ap, client *));
553 root 1.79 break;
554    
555 root 1.6 case DT_PLAYER:
556 root 1.45 sv = to_sv (va_arg (ap, player *));
557 root 1.1 break;
558    
559 root 1.6 case DT_ARCH:
560 root 1.45 sv = to_sv (va_arg (ap, archetype *));
561 root 1.1 break;
562    
563 root 1.6 case DT_PARTY:
564 root 1.45 sv = to_sv (va_arg (ap, partylist *));
565 root 1.1 break;
566    
567 root 1.6 case DT_REGION:
568 root 1.45 sv = to_sv (va_arg (ap, region *));
569 root 1.1 break;
570    
571     default:
572 root 1.6 assert (("unhandled type in newSVdt_va", 0));
573     }
574    
575     return sv;
576     }
577    
578     static SV *
579     newSVdt (data_type type, ...)
580     {
581     va_list ap;
582    
583     va_start (ap, type);
584     SV *sv = newSVdt_va (ap, type);
585     va_end (ap);
586    
587     return sv;
588     }
589    
590 root 1.11 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
591    
592 root 1.12 SV *
593 root 1.109 registry (attachable *ext)
594 root 1.12 {
595 root 1.13 if (!ext->cb)
596     ext->cb = newAV ();
597 root 1.12
598 root 1.13 return newRV_inc ((SV *)ext->cb);
599 root 1.12 }
600    
601 root 1.13 /////////////////////////////////////////////////////////////////////////////
602    
603 root 1.7 void
604     cfperl_init ()
605     {
606 root 1.32 PERL_SYS_INIT3 (&settings.argc, &settings.argv, 0);
607     perl = perl_alloc ();
608     perl_construct (perl);
609    
610     PL_exit_flags |= PERL_EXIT_DESTRUCT_END;
611    
612 root 1.179 const char *argv[] = {
613 root 1.198 settings.argv [0],
614 root 1.7 "-e"
615 root 1.107 "use Event; use Coro;" // required for bootstrap
616     "cf->bootstrap;" // required for datadir :*>
617 root 1.32 "unshift @INC, cf::datadir ();"
618 root 1.41 "require cf;"
619 root 1.7 };
620    
621 root 1.179 if (perl_parse (perl, xs_init, 2, (char **)argv, (char **)NULL)
622     || perl_run (perl))
623 root 1.7 {
624     printf ("unable to initialize perl-interpreter, aborting.\n");
625     exit (EXIT_FAILURE);
626     }
627 root 1.162
628     {
629     dSP;
630    
631     PUSHMARK (SP);
632     PUTBACK;
633     call_pv ("cf::init", G_DISCARD | G_VOID);
634     }
635 root 1.7 }
636    
637 root 1.5 void cfperl_main ()
638 root 1.2 {
639     dSP;
640    
641     PUSHMARK (SP);
642     PUTBACK;
643 root 1.7 call_pv ("cf::main", G_DISCARD | G_VOID);
644     }
645    
646 root 1.109 void
647     attachable::instantiate ()
648     {
649     if (attach)
650     {
651 root 1.214 INVOKE_ATTACHABLE (INSTANTIATE, this, ARG_STRING (attach));
652 root 1.109 attach = 0;
653     }
654     }
655    
656     void
657     attachable::reattach ()
658     {
659     optimise ();
660     //TODO: check for _attachment's, very important for restarts
661 root 1.214 INVOKE_ATTACHABLE (REATTACH, this);
662 root 1.109 }
663    
664 root 1.8 static event_klass klass_of[NUM_EVENT_TYPES] = {
665     # define def(type,name) KLASS_ ## type,
666     # include "eventinc.h"
667     # undef def
668     };
669    
670 root 1.18 #define KLASS_OF(event) (((unsigned int)event) < NUM_EVENT_TYPES ? klass_of [event] : KLASS_NONE)
671    
672 root 1.8 static void
673     gather_callbacks (AV *&callbacks, AV *registry, event_type event)
674     {
675     // event must be in array
676     if (event >= 0 && event <= AvFILLp (registry))
677     {
678     SV *cbs_ = AvARRAY (registry)[event];
679    
680     // element must be list of callback entries
681     if (cbs_ && SvROK (cbs_) && SvTYPE (SvRV (cbs_)) == SVt_PVAV)
682     {
683     AV *cbs = (AV *)SvRV (cbs_);
684    
685     // no callback entries, no callbacks to call
686     if (AvFILLp (cbs) >= 0)
687     {
688     if (!callbacks)
689     {
690     callbacks = newAV ();
691     av_extend (callbacks, 16);
692     }
693    
694     // never use SvREFCNT_inc to copy values, but its ok here :)
695     for (int i = 0; i <= AvFILLp (cbs); ++i)
696     av_push (callbacks, SvREFCNT_inc (AvARRAY (cbs)[i]));
697     }
698     }
699     }
700     }
701    
702 root 1.109 void
703     attachable::gather_callbacks (AV *&callbacks, event_type event) const
704 root 1.6 {
705 root 1.109 ::gather_callbacks (callbacks, cb_attachable, event);
706 root 1.6
707 root 1.109 if (cb)
708     ::gather_callbacks (callbacks, cb, event);
709     }
710 root 1.8
711 root 1.109 void
712     global::gather_callbacks (AV *&callbacks, event_type event) const
713     {
714 root 1.210 ::gather_callbacks (callbacks, cb_global, event);
715 root 1.109 }
716 root 1.8
717 root 1.109 void
718     object::gather_callbacks (AV *&callbacks, event_type event) const
719     {
720 root 1.210 if (subtype && type + subtype * NUM_TYPES <= AvFILLp (cb_type))
721 root 1.109 {
722 root 1.210 SV *registry = AvARRAY (cb_type)[type + subtype * NUM_TYPES];
723 root 1.8
724 root 1.109 if (registry && SvROK (registry) && SvTYPE (SvRV (registry)) == SVt_PVAV)
725     ::gather_callbacks (callbacks, (AV *)SvRV (registry), event);
726     }
727 root 1.8
728 root 1.109 if (type <= AvFILLp (cb_type))
729 root 1.8 {
730 root 1.109 SV *registry = AvARRAY (cb_type)[type];
731 root 1.8
732 root 1.109 if (registry && SvROK (registry) && SvTYPE (SvRV (registry)) == SVt_PVAV)
733     ::gather_callbacks (callbacks, (AV *)SvRV (registry), event);
734     }
735 root 1.8
736 root 1.109 attachable::gather_callbacks (callbacks, event);
737     ::gather_callbacks (callbacks, cb_object, event);
738     }
739 root 1.8
740 root 1.109 void
741     archetype::gather_callbacks (AV *&callbacks, event_type event) const
742     {
743     attachable::gather_callbacks (callbacks, event);
744     //TODO//::gather_callbacks (callbacks, cb_archetype, event);
745     }
746 root 1.14
747 root 1.109 void
748     client::gather_callbacks (AV *&callbacks, event_type event) const
749     {
750     attachable::gather_callbacks (callbacks, event);
751     ::gather_callbacks (callbacks, cb_client, event);
752     }
753 root 1.8
754 root 1.109 void
755     player::gather_callbacks (AV *&callbacks, event_type event) const
756     {
757     attachable::gather_callbacks (callbacks, event);
758     ::gather_callbacks (callbacks, cb_player, event);
759     }
760 root 1.8
761 root 1.109 void
762     maptile::gather_callbacks (AV *&callbacks, event_type event) const
763     {
764     attachable::gather_callbacks (callbacks, event);
765     ::gather_callbacks (callbacks, cb_map, event);
766     }
767 root 1.8
768 root 1.210 void
769     _recalc_want (bitset<NUM_EVENT_TYPES> &set, AV *registry)
770     {
771     for (int event = 0; event <= AvFILLp (registry); ++event)
772     {
773     SV *cbs_ = AvARRAY (registry)[event];
774    
775     // element must be list of callback entries
776     if (cbs_ && SvROK (cbs_) && SvTYPE (SvRV (cbs_)) == SVt_PVAV)
777     {
778     AV *cbs = (AV *)SvRV (cbs_);
779    
780     // no callback entries, no callbacks to call
781     if (AvFILLp (cbs) >= 0)
782     set.set (event);
783     }
784     }
785     }
786    
787     // very slow and inefficient way to recalculate the global want bitsets
788     void
789     _recalc_want ()
790     {
791     ev_want_event.reset ();
792    
793     _recalc_want (ev_want_event, cb_global);
794     _recalc_want (ev_want_event, cb_attachable);
795     _recalc_want (ev_want_event, cb_object);
796     _recalc_want (ev_want_event, cb_client);
797     _recalc_want (ev_want_event, cb_player);
798     _recalc_want (ev_want_event, cb_map);
799    
800     ev_want_type.reset ();
801    
802     for (int type = 0; type <= AvFILLp (cb_type); ++type)
803     {
804     SV *cbs_ = AvARRAY (cb_type)[type];
805    
806     // element must be list of callback entries
807     if (cbs_ && SvROK (cbs_) && SvTYPE (SvRV (cbs_)) == SVt_PVAV)
808     {
809     AV *cbs = (AV *)SvRV (cbs_);
810    
811     // no callback entries, no callbacks to call
812     if (AvFILLp (cbs) >= 0)
813     ev_want_type.set (type % NUM_TYPES);
814     }
815     }
816     }
817    
818 root 1.109 bool
819 root 1.214 attachable::invoke (event_type event, ...)
820 root 1.109 {
821     data_type dt;
822 root 1.8
823 root 1.109 // callback call ordering should be:
824     // 1. per-object callback
825     // 2. per-class object
826     // 3. per-type callback
827     // 4. global callbacks
828 root 1.12
829 root 1.109 AV *callbacks = 0;
830     gather_callbacks (callbacks, event);
831 root 1.8
832     // short-circuit processing if no callbacks found/defined
833     if (!callbacks)
834     return 0;
835    
836 root 1.214 va_list ap;
837     va_start (ap, event);
838    
839 root 1.116 CALL_BEGIN (3);
840     CALL_ARG_SV (newSViv (event)); // only used for debugging nowadays
841     CALL_ARG_SV (newRV_noinc ((SV *)callbacks));
842 root 1.8
843 root 1.109 //TODO: unhack
844 root 1.116 if (object *op = is_a<object>(this)) CALL_ARG_SV (newSVdt (DT_OBJECT, op));
845     else if (player *pl = is_a<player>(this)) CALL_ARG_SV (newSVdt (DT_PLAYER, pl));
846     else if (client *ns = is_a<client>(this)) CALL_ARG_SV (newSVdt (DT_CLIENT, ns));
847     else if (maptile *m = is_a<maptile>(this)) CALL_ARG_SV (newSVdt (DT_MAP, m));
848 root 1.109 else if (global *gl = is_a<global>(this)) /*nop*/;
849     else
850     abort (); //TODO
851 root 1.7
852 root 1.6 for (;;)
853     {
854 root 1.8 dt = (data_type) va_arg (ap, int);
855 root 1.6
856     if (dt == DT_END)
857     break;
858 root 1.109 else if (dt == DT_AV)
859 root 1.12 {
860     AV *av = va_arg (ap, AV *);
861    
862     for (int i = 0; i <= av_len (av); ++i)
863     XPUSHs (*av_fetch (av, i, 1));
864     }
865     else
866     XPUSHs (sv_2mortal (newSVdt_va (ap, dt)));
867 root 1.6 }
868    
869     va_end (ap);
870    
871 root 1.116 CALL_CALL ("cf::do_invoke", G_SCALAR);
872 root 1.6 count = count > 0 ? POPi : 0;
873    
874 root 1.116 CALL_END;
875 root 1.6
876     return count;
877 root 1.2 }
878    
879 root 1.12 SV *
880     cfperl_result (int idx)
881     {
882 elmex 1.233 AV *av = get_av ("cf::INVOKE_RESULTS", 0);
883 root 1.12 if (!av)
884     return &PL_sv_undef;
885    
886     SV **sv = av_fetch (av, idx, 0);
887     if (!sv)
888     return &PL_sv_undef;
889    
890     return *sv;
891     }
892    
893     int
894     cfperl_result_INT (int idx)
895     {
896     return SvIV (cfperl_result (idx));
897     }
898    
899 root 1.74 double
900 root 1.73 cfperl_result_DOUBLE (int idx)
901     {
902     return SvNV (cfperl_result (idx));
903     }
904    
905 root 1.80 /////////////////////////////////////////////////////////////////////////////
906 root 1.247 // various c++ => perl glue functions
907 root 1.80
908 root 1.116 void
909 root 1.134 cfperl_emergency_save ()
910 root 1.116 {
911     CALL_BEGIN (0);
912 root 1.134 CALL_CALL ("cf::emergency_save", G_VOID);
913 root 1.116 CALL_END;
914     }
915    
916 root 1.165 void
917     cfperl_cleanup (int make_core)
918     {
919     CALL_BEGIN (1);
920     CALL_ARG (make_core);
921     CALL_CALL ("cf::post_cleanup", G_VOID);
922     CALL_END;
923     }
924    
925 root 1.213 void
926     cfperl_make_book (object *book, int level)
927     {
928     CALL_BEGIN (2);
929     CALL_ARG (book);
930     CALL_ARG (level);
931     CALL_CALL ("ext::books::make_book", G_VOID);
932     CALL_END;
933     }
934    
935 root 1.222 void
936     cfperl_send_msg (client *ns, int color, const char *type, const char *msg)
937     {
938     CALL_BEGIN (4);
939     CALL_ARG (ns);
940     CALL_ARG (type);
941 root 1.224 CALL_ARG_SV (newSVpv_utf8 (msg));
942 root 1.235 CALL_ARG (color);
943 root 1.222 CALL_CALL ("cf::client::send_msg", G_VOID);
944     CALL_END;
945     }
946    
947 root 1.234 int
948     cfperl_can_merge (object *ob1, object *ob2)
949     {
950     int can;
951    
952     CALL_BEGIN (2);
953     CALL_ARG (ob1);
954     CALL_ARG (ob2);
955     CALL_CALL ("cf::_can_merge", G_SCALAR);
956     can = count && SvTRUE (TOPs);
957     CALL_END;
958    
959     return can;
960     }
961    
962 root 1.244 player *
963     player::find (const char *name)
964     {
965     CALL_BEGIN (1);
966     CALL_ARG (name);
967     CALL_CALL ("cf::player::find", G_SCALAR);
968    
969     player *retval;
970    
971     if (count)
972     sv_to (POPs, retval);
973     else
974     retval = 0;
975    
976     CALL_END;
977    
978     return retval;
979     }
980    
981 root 1.116 maptile *
982 root 1.126 maptile::find_sync (const char *path, maptile *origin)
983 root 1.116 {
984     CALL_BEGIN (2);
985     CALL_ARG (path);
986     CALL_ARG (origin);
987 root 1.126 CALL_CALL ("cf::map::find_sync", G_SCALAR);
988 root 1.116
989     maptile *retval;
990    
991     if (count)
992     sv_to (POPs, retval);
993     else
994     retval = 0;
995    
996     CALL_END;
997    
998     return retval;
999     }
1000    
1001 root 1.135 maptile *
1002 root 1.243 maptile::find_async (const char *path, maptile *origin, bool load)
1003 root 1.135 {
1004 root 1.243 CALL_BEGIN (3);
1005 root 1.135 CALL_ARG (path);
1006     CALL_ARG (origin);
1007 root 1.243 CALL_ARG (load);
1008 root 1.135 CALL_CALL ("cf::map::find_async", G_SCALAR);
1009    
1010     maptile *retval;
1011    
1012     if (count)
1013     sv_to (POPs, retval);
1014     else
1015     retval = 0;
1016    
1017     CALL_END;
1018    
1019     return retval;
1020     }
1021    
1022 root 1.116 void
1023 root 1.126 maptile::do_load_sync ()
1024     {
1025     CALL_BEGIN (1);
1026     CALL_ARG (this);
1027     CALL_CALL ("cf::map::do_load_sync", G_SCALAR);
1028     CALL_END;
1029     }
1030    
1031     void
1032 root 1.116 maptile::change_all_map_light (int change)
1033     {
1034     CALL_BEGIN (1);
1035     CALL_ARG (change);
1036     CALL_CALL ("cf::map::change_all_map_light", G_VOID);
1037     CALL_END;
1038     }
1039    
1040     void
1041     object::enter_exit (object *exit)
1042     {
1043     if (type != PLAYER)
1044     return;
1045    
1046     CALL_BEGIN (2);
1047     CALL_ARG (this);
1048     CALL_ARG (exit);
1049     CALL_CALL ("cf::object::player::enter_exit", G_VOID);
1050     CALL_END;
1051     }
1052    
1053 root 1.247 const char *
1054     object::ref () const
1055     {
1056     if (type == PLAYER)
1057     return format ("player/<1.%llx>/%s", (unsigned long long)uuid.seq, &name);
1058     else
1059     return 0;
1060     }
1061    
1062     object *
1063     object::deref (const char *ref)
1064     {
1065 root 1.249 object *retval = 0;
1066 root 1.247
1067 root 1.249 if (ref)
1068     {
1069     CALL_BEGIN (1);
1070     CALL_ARG (ref);
1071     CALL_CALL ("cf::object::deref", G_SCALAR);
1072    
1073     if (count)
1074     sv_to (POPs, retval);
1075 root 1.247
1076 root 1.249 CALL_END;
1077     }
1078 root 1.247
1079     return retval;
1080     }
1081    
1082 root 1.198 void
1083     log_backtrace (const char *msg)
1084     {
1085     #if HAVE_BACKTRACE
1086     void *addr [20];
1087     int size = backtrace (addr, 20);
1088    
1089     CALL_BEGIN (size);
1090     CALL_ARG (msg);
1091     for (int i = 0; i < size; ++i)
1092     CALL_ARG ((IV)addr [i]);
1093     CALL_CALL ("cf::_log_backtrace", G_VOID);
1094     CALL_END;
1095     #endif
1096     }
1097    
1098 root 1.116 /////////////////////////////////////////////////////////////////////////////
1099    
1100 root 1.80 struct EventAPI *watcher_base::GEventAPI;
1101 root 1.116 struct CoroAPI *coroapi::GCoroAPI;
1102 root 1.80
1103 root 1.124 int coroapi::cede_counter;
1104 root 1.220 tstamp coroapi::next_cede;
1105 root 1.189
1106     void coroapi::do_cede_to_tick ()
1107     {
1108     cede_counter = 0;
1109    
1110     cede ();
1111    
1112     next_cede += (TICK / CEDES_PER_TICK) * 0.99;
1113     if (next_cede > SvNV (sv_next_tick) - 0.02)
1114     next_cede = SvNV (sv_next_tick);
1115     }
1116    
1117     void coroapi::do_cede_every ()
1118     {
1119     cede_counter = 0;
1120    
1121     if (coroapi::nready ())
1122     coroapi::cede ();
1123     }
1124    
1125     void coroapi::do_cede_to_tick_every ()
1126     {
1127     cede_counter = 0;
1128    
1129     cede_to_tick ();
1130     }
1131 root 1.124
1132 root 1.188 void
1133     coroapi::wait_for_tick ()
1134     {
1135     CALL_BEGIN (0);
1136     CALL_CALL ("cf::wait_for_tick", G_DISCARD);
1137     CALL_END;
1138     }
1139    
1140     void
1141     coroapi::wait_for_tick_begin ()
1142     {
1143     CALL_BEGIN (0);
1144     CALL_CALL ("cf::wait_for_tick_begin", G_DISCARD);
1145     CALL_END;
1146     }
1147    
1148     static void
1149     iw_dispatch (pe_event *ev)
1150 root 1.85 {
1151     iw *w = (iw *)ev->ext_data;
1152     w->call (*w);
1153     }
1154    
1155     void
1156     iw::alloc ()
1157     {
1158     pe = GEventAPI->new_idle (0, 0);
1159    
1160 root 1.150 WaREENTRANT_off (pe);
1161 root 1.85 pe->base.callback = (void *)iw_dispatch;
1162     pe->base.ext_data = (void *)this;
1163     }
1164    
1165 root 1.80 static void iow_dispatch (pe_event *ev)
1166     {
1167     iow *w = (iow *)ev->ext_data;
1168     w->call (*w, ((pe_ioevent *)ev)->got);
1169     }
1170    
1171     void
1172     iow::alloc ()
1173     {
1174     pe = GEventAPI->new_io (0, 0);
1175    
1176 root 1.150 WaREENTRANT_off (pe);
1177 root 1.80 pe->base.callback = (void *)iow_dispatch;
1178     pe->base.ext_data = (void *)this;
1179    
1180 root 1.81 pe->fd = -1;
1181     pe->poll = 0;
1182 root 1.80 }
1183    
1184 root 1.85 void
1185 root 1.80 iow::fd (int fd)
1186     {
1187     pe->fd = fd;
1188     }
1189    
1190     int
1191     iow::poll ()
1192     {
1193     return pe->poll;
1194     }
1195    
1196 root 1.85 void
1197 root 1.80 iow::poll (int events)
1198     {
1199 root 1.81 if (pe->poll != events)
1200     {
1201     if (pe->poll) stop ();
1202     pe->poll = events;
1203     if (pe->poll) start ();
1204     }
1205 root 1.80 }
1206    
1207 root 1.109 void
1208     _connect_to_perl ()
1209     {
1210     stash_cf = gv_stashpv ("cf" , 1);
1211    
1212     stash_cf_object_wrap = gv_stashpv ("cf::object::wrap", 1);
1213     stash_cf_object_player_wrap = gv_stashpv ("cf::object::player::wrap", 1);
1214     stash_cf_player_wrap = gv_stashpv ("cf::player::wrap", 1);
1215     stash_cf_map_wrap = gv_stashpv ("cf::map::wrap" , 1);
1216     stash_cf_client_wrap = gv_stashpv ("cf::client::wrap", 1);
1217     stash_cf_arch_wrap = gv_stashpv ("cf::arch::wrap" , 1);
1218     stash_cf_party_wrap = gv_stashpv ("cf::party::wrap" , 1);
1219     stash_cf_region_wrap = gv_stashpv ("cf::region::wrap", 1);
1220     stash_cf_living_wrap = gv_stashpv ("cf::living::wrap", 1);
1221    
1222 root 1.189 sv_runtime = get_sv ("cf::RUNTIME" , 1); sv_upgrade (sv_runtime , SVt_NV);
1223     sv_next_tick = get_sv ("cf::NEXT_TICK", 1); sv_upgrade (sv_next_tick, SVt_NV);
1224 root 1.116
1225 root 1.109 cb_global = get_av ("cf::CB_GLOBAL", 1);
1226     cb_attachable = get_av ("cf::CB_ATTACHABLE", 1);
1227     cb_object = get_av ("cf::CB_OBJECT", 1);
1228     cb_player = get_av ("cf::CB_PLAYER", 1);
1229     cb_client = get_av ("cf::CB_CLIENT", 1);
1230     cb_type = get_av ("cf::CB_TYPE" , 1);
1231     cb_map = get_av ("cf::CB_MAP" , 1);
1232     }
1233    
1234 root 1.1 MODULE = cf PACKAGE = cf PREFIX = cf_
1235    
1236     BOOT:
1237     {
1238 root 1.116 I_EVENT_API (PACKAGE); watcher_base::GEventAPI = GEventAPI;
1239     I_CORO_API (PACKAGE); coroapi::GCoroAPI = GCoroAPI;
1240 root 1.80
1241 root 1.189 _connect_to_perl ();
1242    
1243 root 1.109 newCONSTSUB (stash_cf, "VERSION", newSVpv (VERSION, sizeof (VERSION) - 1));
1244 root 1.63
1245 root 1.220 //{
1246     // require_pv ("Time::HiRes");
1247     //
1248     // SV **svp = hv_fetch (PL_modglobal, "Time::NVtime", 12, 0);
1249     // if (!svp) croak ("Time::HiRes is required");
1250     // if (!SvIOK(*svp)) croak ("Time::NVtime isn’t a function pointer");
1251     // coroapi::time = INT2PTR (double(*)(), SvIV(*svp));
1252     //}
1253 root 1.189
1254 root 1.1 static const struct {
1255     const char *name;
1256     IV iv;
1257     } *civ, const_iv[] = {
1258     # define const_iv(name) { # name, (IV)name },
1259 root 1.189 const_iv (llevError) const_iv (llevInfo) const_iv (llevDebug) const_iv (llevMonster)
1260 root 1.198 const_iv (logBacktrace)
1261 root 1.180
1262 root 1.189 const_iv (Map0Cmd) const_iv (Map1Cmd) const_iv (Map1aCmd)
1263    
1264     const_iv (MAP_CLIENT_X) const_iv (MAP_CLIENT_Y)
1265 root 1.180
1266 root 1.5 const_iv (MAX_TIME)
1267 root 1.258 const_iv (MAXSOCKBUF)
1268 root 1.189
1269 root 1.206 const_iv (NUM_BODY_LOCATIONS)
1270     const_iv (body_range) const_iv (body_shield) const_iv (body_combat)
1271     const_iv (body_arm) const_iv (body_torso) const_iv (body_head)
1272     const_iv (body_neck) const_iv (body_skill) const_iv (body_finger)
1273     const_iv (body_shoulder) const_iv (body_foot) const_iv (body_hand)
1274     const_iv (body_wrist) const_iv (body_waist)
1275 root 1.205
1276 root 1.189 const_iv (PLAYER) const_iv (TRANSPORT) const_iv (ROD) const_iv (TREASURE)
1277     const_iv (POTION) const_iv (FOOD) const_iv (POISON) const_iv (BOOK)
1278     const_iv (CLOCK) const_iv (ARROW) const_iv (BOW) const_iv (WEAPON)
1279     const_iv (ARMOUR) const_iv (PEDESTAL) const_iv (ALTAR) const_iv (LOCKED_DOOR)
1280     const_iv (SPECIAL_KEY) const_iv (MAP) const_iv (DOOR) const_iv (KEY)
1281     const_iv (TIMED_GATE) const_iv (TRIGGER) const_iv (GRIMREAPER) const_iv (MAGIC_EAR)
1282     const_iv (TRIGGER_BUTTON) const_iv (TRIGGER_ALTAR) const_iv (TRIGGER_PEDESTAL) const_iv (SHIELD)
1283     const_iv (HELMET) const_iv (HORN) const_iv (MONEY) const_iv (CLASS)
1284     const_iv (GRAVESTONE) const_iv (AMULET) const_iv (PLAYERMOVER) const_iv (TELEPORTER)
1285     const_iv (CREATOR) const_iv (SKILL) const_iv (EARTHWALL) const_iv (GOLEM)
1286     const_iv (THROWN_OBJ) const_iv (BLINDNESS) const_iv (GOD) const_iv (DETECTOR)
1287     const_iv (TRIGGER_MARKER) const_iv (DEAD_OBJECT) const_iv (DRINK) const_iv (MARKER)
1288     const_iv (HOLY_ALTAR) const_iv (PLAYER_CHANGER) const_iv (BATTLEGROUND) const_iv (PEACEMAKER)
1289     const_iv (GEM) const_iv (FIREWALL) const_iv (ANVIL) const_iv (CHECK_INV)
1290     const_iv (MOOD_FLOOR) const_iv (EXIT) const_iv (ENCOUNTER) const_iv (SHOP_FLOOR)
1291     const_iv (SHOP_MAT) const_iv (RING) const_iv (FLOOR) const_iv (FLESH)
1292     const_iv (INORGANIC) const_iv (SKILL_TOOL) const_iv (LIGHTER) const_iv (BUILDABLE_WALL)
1293     const_iv (MISC_OBJECT) const_iv (LAMP) const_iv (DUPLICATOR) const_iv (SPELLBOOK)
1294     const_iv (CLOAK) const_iv (SPINNER) const_iv (GATE) const_iv (BUTTON)
1295     const_iv (CF_HANDLE) const_iv (HOLE) const_iv (TRAPDOOR) const_iv (SIGN)
1296     const_iv (BOOTS) const_iv (GLOVES) const_iv (SPELL) const_iv (SPELL_EFFECT)
1297     const_iv (CONVERTER) const_iv (BRACERS) const_iv (POISONING) const_iv (SAVEBED)
1298     const_iv (WAND) const_iv (SCROLL) const_iv (DIRECTOR) const_iv (GIRDLE)
1299     const_iv (FORCE) const_iv (POTION_EFFECT) const_iv (EVENT_CONNECTOR) const_iv (CLOSE_CON)
1300     const_iv (CONTAINER) const_iv (ARMOUR_IMPROVER) const_iv (WEAPON_IMPROVER) const_iv (SKILLSCROLL)
1301     const_iv (DEEP_SWAMP) const_iv (IDENTIFY_ALTAR) const_iv (MENU) const_iv (RUNE)
1302     const_iv (TRAP) const_iv (POWER_CRYSTAL) const_iv (CORPSE) const_iv (DISEASE)
1303     const_iv (SYMPTOM) const_iv (BUILDER) const_iv (MATERIAL) const_iv (ITEM_TRANSFORMER)
1304 root 1.1
1305 root 1.210 const_iv (NUM_TYPES) const_iv (NUM_SUBTYPES)
1306 root 1.14
1307 root 1.189 const_iv (ST_BD_BUILD) const_iv (ST_BD_REMOVE)
1308     const_iv (ST_MAT_FLOOR) const_iv (ST_MAT_WALL) const_iv (ST_MAT_ITEM)
1309 root 1.1
1310 root 1.189 const_iv (AT_PHYSICAL) const_iv (AT_MAGIC) const_iv (AT_FIRE) const_iv (AT_ELECTRICITY)
1311     const_iv (AT_COLD) const_iv (AT_CONFUSION) const_iv (AT_ACID) const_iv (AT_DRAIN)
1312     const_iv (AT_WEAPONMAGIC) const_iv (AT_GHOSTHIT) const_iv (AT_POISON) const_iv (AT_SLOW)
1313     const_iv (AT_PARALYZE) const_iv (AT_TURN_UNDEAD) const_iv (AT_FEAR) const_iv (AT_CANCELLATION)
1314     const_iv (AT_DEPLETE) const_iv (AT_DEATH) const_iv (AT_CHAOS) const_iv (AT_COUNTERSPELL)
1315     const_iv (AT_GODPOWER) const_iv (AT_HOLYWORD) const_iv (AT_BLIND) const_iv (AT_INTERNAL)
1316     const_iv (AT_LIFE_STEALING) const_iv (AT_DISEASE)
1317    
1318     const_iv (WEAP_HIT) const_iv (WEAP_SLASH) const_iv (WEAP_PIERCE) const_iv (WEAP_CLEAVE)
1319     const_iv (WEAP_SLICE) const_iv (WEAP_STAB) const_iv (WEAP_WHIP) const_iv (WEAP_CRUSH)
1320 root 1.1 const_iv (WEAP_BLUD)
1321    
1322 root 1.189 const_iv (FLAG_ALIVE) const_iv (FLAG_WIZ) const_iv (FLAG_REMOVED) const_iv (FLAG_FREED)
1323 root 1.209 const_iv (FLAG_APPLIED) const_iv (FLAG_UNPAID) const_iv (FLAG_USE_SHIELD)
1324 root 1.189 const_iv (FLAG_NO_PICK) const_iv (FLAG_ANIMATE) const_iv (FLAG_MONSTER) const_iv (FLAG_FRIENDLY)
1325     const_iv (FLAG_GENERATOR) const_iv (FLAG_IS_THROWN) const_iv (FLAG_AUTO_APPLY) const_iv (FLAG_PLAYER_SOLD)
1326     const_iv (FLAG_SEE_INVISIBLE) const_iv (FLAG_CAN_ROLL) const_iv (FLAG_OVERLAY_FLOOR) const_iv (FLAG_IS_TURNABLE)
1327     const_iv (FLAG_IS_USED_UP) const_iv (FLAG_IDENTIFIED) const_iv (FLAG_REFLECTING) const_iv (FLAG_CHANGING)
1328     const_iv (FLAG_SPLITTING) const_iv (FLAG_HITBACK) const_iv (FLAG_STARTEQUIP) const_iv (FLAG_BLOCKSVIEW)
1329     const_iv (FLAG_UNDEAD) const_iv (FLAG_SCARED) const_iv (FLAG_UNAGGRESSIVE) const_iv (FLAG_REFL_MISSILE)
1330     const_iv (FLAG_REFL_SPELL) const_iv (FLAG_NO_MAGIC) const_iv (FLAG_NO_FIX_PLAYER) const_iv (FLAG_IS_LIGHTABLE)
1331     const_iv (FLAG_TEAR_DOWN) const_iv (FLAG_RUN_AWAY) const_iv (FLAG_PICK_UP) const_iv (FLAG_UNIQUE)
1332     const_iv (FLAG_NO_DROP) const_iv (FLAG_WIZCAST) const_iv (FLAG_CAST_SPELL) const_iv (FLAG_USE_SCROLL)
1333     const_iv (FLAG_USE_RANGE) const_iv (FLAG_USE_BOW) const_iv (FLAG_USE_ARMOUR) const_iv (FLAG_USE_WEAPON)
1334     const_iv (FLAG_USE_RING) const_iv (FLAG_READY_RANGE) const_iv (FLAG_READY_BOW) const_iv (FLAG_XRAYS)
1335     const_iv (FLAG_NO_APPLY) const_iv (FLAG_IS_FLOOR) const_iv (FLAG_LIFESAVE) const_iv (FLAG_NO_STRENGTH)
1336     const_iv (FLAG_SLEEP) const_iv (FLAG_STAND_STILL) const_iv (FLAG_RANDOM_MOVE) const_iv (FLAG_ONLY_ATTACK)
1337     const_iv (FLAG_CONFUSED) const_iv (FLAG_STEALTH) const_iv (FLAG_WIZPASS) const_iv (FLAG_IS_LINKED)
1338     const_iv (FLAG_CURSED) const_iv (FLAG_DAMNED) const_iv (FLAG_SEE_ANYWHERE) const_iv (FLAG_KNOWN_MAGICAL)
1339     const_iv (FLAG_KNOWN_CURSED) const_iv (FLAG_CAN_USE_SKILL) const_iv (FLAG_BEEN_APPLIED) const_iv (FLAG_READY_SCROLL)
1340     const_iv (FLAG_USE_ROD) const_iv (FLAG_USE_HORN) const_iv (FLAG_MAKE_INVIS) const_iv (FLAG_INV_LOCKED)
1341     const_iv (FLAG_IS_WOODED) const_iv (FLAG_IS_HILLY) const_iv (FLAG_READY_SKILL) const_iv (FLAG_READY_WEAPON)
1342     const_iv (FLAG_NO_SKILL_IDENT) const_iv (FLAG_BLIND) const_iv (FLAG_SEE_IN_DARK) const_iv (FLAG_IS_CAULDRON)
1343     const_iv (FLAG_NO_STEAL) const_iv (FLAG_ONE_HIT) const_iv (FLAG_CLIENT_SENT) const_iv (FLAG_BERSERK)
1344     const_iv (FLAG_NEUTRAL) const_iv (FLAG_NO_ATTACK) const_iv (FLAG_NO_DAMAGE) const_iv (FLAG_OBJ_ORIGINAL)
1345 root 1.245 const_iv (FLAG_ACTIVATE_ON_PUSH) const_iv (FLAG_ACTIVATE_ON_RELEASE) const_iv (FLAG_IS_WATER)
1346 root 1.189 const_iv (FLAG_CONTENT_ON_GEN) const_iv (FLAG_IS_A_TEMPLATE) const_iv (FLAG_IS_BUILDABLE)
1347     const_iv (FLAG_DESTROY_ON_DEATH) const_iv (FLAG_NO_MAP_SAVE)
1348    
1349     const_iv (NDI_BLACK) const_iv (NDI_WHITE) const_iv (NDI_NAVY) const_iv (NDI_RED)
1350     const_iv (NDI_ORANGE) const_iv (NDI_BLUE) const_iv (NDI_DK_ORANGE) const_iv (NDI_GREEN)
1351     const_iv (NDI_LT_GREEN) const_iv (NDI_GREY) const_iv (NDI_BROWN) const_iv (NDI_GOLD)
1352     const_iv (NDI_TAN) const_iv (NDI_MAX_COLOR) const_iv (NDI_COLOR_MASK) const_iv (NDI_UNIQUE)
1353 root 1.241 const_iv (NDI_ALL) const_iv (NDI_DEF) const_iv (NDI_REPLY) const_iv (NDI_CLIENT_MASK)
1354 root 1.250 const_iv (NDI_NOCREATE) const_iv (NDI_CLEAR)
1355 root 1.1
1356 root 1.189 const_iv (UPD_LOCATION) const_iv (UPD_FLAGS) const_iv (UPD_WEIGHT) const_iv (UPD_FACE)
1357     const_iv (UPD_NAME) const_iv (UPD_ANIM) const_iv (UPD_ANIMSPEED) const_iv (UPD_NROF)
1358    
1359     const_iv (UPD_SP_MANA) const_iv (UPD_SP_GRACE) const_iv (UPD_SP_DAMAGE)
1360    
1361 root 1.212 const_iv (SP_RAISE_DEAD)
1362     const_iv (SP_RUNE)
1363     const_iv (SP_MAKE_MARK)
1364     const_iv (SP_BOLT)
1365     const_iv (SP_BULLET)
1366     const_iv (SP_EXPLOSION)
1367     const_iv (SP_CONE)
1368     const_iv (SP_BOMB)
1369     const_iv (SP_WONDER)
1370     const_iv (SP_SMITE)
1371     const_iv (SP_MAGIC_MISSILE)
1372     const_iv (SP_SUMMON_GOLEM)
1373     const_iv (SP_DIMENSION_DOOR)
1374     const_iv (SP_MAGIC_MAPPING)
1375     const_iv (SP_MAGIC_WALL)
1376     const_iv (SP_DESTRUCTION)
1377     const_iv (SP_PERCEIVE_SELF)
1378     const_iv (SP_WORD_OF_RECALL)
1379     const_iv (SP_INVISIBLE)
1380     const_iv (SP_PROBE)
1381     const_iv (SP_HEALING)
1382     const_iv (SP_CREATE_FOOD)
1383     const_iv (SP_EARTH_TO_DUST)
1384     const_iv (SP_CHANGE_ABILITY)
1385     const_iv (SP_BLESS)
1386     const_iv (SP_CURSE)
1387     const_iv (SP_SUMMON_MONSTER)
1388     const_iv (SP_CHARGING)
1389     const_iv (SP_POLYMORPH)
1390     const_iv (SP_ALCHEMY)
1391     const_iv (SP_REMOVE_CURSE)
1392     const_iv (SP_IDENTIFY)
1393     const_iv (SP_DETECTION)
1394     const_iv (SP_MOOD_CHANGE)
1395     const_iv (SP_MOVING_BALL)
1396     const_iv (SP_SWARM)
1397     const_iv (SP_CHANGE_MANA)
1398     const_iv (SP_DISPEL_RUNE)
1399     const_iv (SP_CREATE_MISSILE)
1400     const_iv (SP_CONSECRATE)
1401     const_iv (SP_ANIMATE_WEAPON)
1402     const_iv (SP_LIGHT)
1403     const_iv (SP_CHANGE_MAP_LIGHT)
1404     const_iv (SP_FAERY_FIRE)
1405     const_iv (SP_CAUSE_DISEASE)
1406     const_iv (SP_AURA)
1407     const_iv (SP_TOWN_PORTAL)
1408     const_iv (SP_PARTY_SPELL)
1409    
1410 root 1.189 const_iv (F_APPLIED) const_iv (F_LOCATION) const_iv (F_UNPAID) const_iv (F_MAGIC)
1411     const_iv (F_CURSED) const_iv (F_DAMNED) const_iv (F_OPEN) const_iv (F_NOPICK)
1412 root 1.1 const_iv (F_LOCKED)
1413    
1414 root 1.189 const_iv (F_BUY) const_iv (F_SHOP) const_iv (F_SELL)
1415    
1416     const_iv (P_BLOCKSVIEW) const_iv (P_PLAYER) const_iv (P_NO_MAGIC) const_iv (P_IS_ALIVE)
1417     const_iv (P_NO_CLERIC) const_iv (P_OUT_OF_MAP) const_iv (P_NEW_MAP) const_iv (P_UPTODATE)
1418    
1419     const_iv (UP_OBJ_INSERT) const_iv (UP_OBJ_REMOVE) const_iv (UP_OBJ_CHANGE) const_iv (UP_OBJ_FACE)
1420    
1421     const_iv (INS_NO_MERGE) const_iv (INS_ABOVE_FLOOR_ONLY) const_iv (INS_NO_WALK_ON)
1422 root 1.258 const_iv (INS_ON_TOP) const_iv (INS_BELOW_ORIGINATOR)
1423 root 1.189
1424     const_iv (WILL_APPLY_HANDLE) const_iv (WILL_APPLY_TREASURE) const_iv (WILL_APPLY_EARTHWALL)
1425     const_iv (WILL_APPLY_DOOR) const_iv (WILL_APPLY_FOOD)
1426    
1427     const_iv (SAVE_MODE) const_iv (SAVE_DIR_MODE)
1428    
1429     const_iv (M_PAPER) const_iv (M_IRON) const_iv (M_GLASS) const_iv (M_LEATHER)
1430     const_iv (M_WOOD) const_iv (M_ORGANIC) const_iv (M_STONE) const_iv (M_CLOTH)
1431     const_iv (M_ADAMANT) const_iv (M_LIQUID) const_iv (M_SOFT_METAL) const_iv (M_BONE)
1432     const_iv (M_ICE) const_iv (M_SPECIAL)
1433    
1434     const_iv (SK_EXP_ADD_SKILL) const_iv (SK_EXP_TOTAL) const_iv (SK_EXP_NONE)
1435     const_iv (SK_SUBTRACT_SKILL_EXP) const_iv (SK_EXP_SKILL_ONLY)
1436    
1437     const_iv (SK_LOCKPICKING) const_iv (SK_HIDING) const_iv (SK_SMITHERY) const_iv (SK_BOWYER)
1438     const_iv (SK_JEWELER) const_iv (SK_ALCHEMY) const_iv (SK_STEALING) const_iv (SK_LITERACY)
1439     const_iv (SK_BARGAINING) const_iv (SK_JUMPING) const_iv (SK_DET_MAGIC) const_iv (SK_ORATORY)
1440     const_iv (SK_SINGING) const_iv (SK_DET_CURSE) const_iv (SK_FIND_TRAPS) const_iv (SK_MEDITATION)
1441     const_iv (SK_PUNCHING) const_iv (SK_FLAME_TOUCH) const_iv (SK_KARATE) const_iv (SK_CLIMBING)
1442     const_iv (SK_WOODSMAN) const_iv (SK_INSCRIPTION) const_iv (SK_ONE_HANDED_WEAPON) const_iv (SK_MISSILE_WEAPON)
1443     const_iv (SK_THROWING) const_iv (SK_USE_MAGIC_ITEM) const_iv (SK_DISARM_TRAPS) const_iv (SK_SET_TRAP)
1444     const_iv (SK_THAUMATURGY) const_iv (SK_PRAYING) const_iv (SK_CLAWING) const_iv (SK_LEVITATION)
1445     const_iv (SK_SUMMONING) const_iv (SK_PYROMANCY) const_iv (SK_EVOCATION) const_iv (SK_SORCERY)
1446     const_iv (SK_TWO_HANDED_WEAPON) const_iv (SK_SPARK_TOUCH) const_iv (SK_SHIVER) const_iv (SK_ACID_SPLASH)
1447 root 1.1 const_iv (SK_POISON_NAIL)
1448    
1449 root 1.189 const_iv (SOUND_NEW_PLAYER) const_iv (SOUND_FIRE_ARROW) const_iv (SOUND_LEARN_SPELL) const_iv (SOUND_FUMBLE_SPELL)
1450     const_iv (SOUND_WAND_POOF) const_iv (SOUND_OPEN_DOOR) const_iv (SOUND_PUSH_PLAYER) const_iv (SOUND_PLAYER_HITS1)
1451     const_iv (SOUND_PLAYER_HITS2) const_iv (SOUND_PLAYER_HITS3) const_iv (SOUND_PLAYER_HITS4) const_iv (SOUND_PLAYER_IS_HIT1)
1452     const_iv (SOUND_PLAYER_IS_HIT2) const_iv (SOUND_PLAYER_IS_HIT3) const_iv (SOUND_PLAYER_KILLS) const_iv (SOUND_PET_IS_KILLED)
1453     const_iv (SOUND_PLAYER_DIES) const_iv (SOUND_OB_EVAPORATE) const_iv (SOUND_OB_EXPLODE) const_iv (SOUND_CLOCK)
1454     const_iv (SOUND_TURN_HANDLE) const_iv (SOUND_FALL_HOLE) const_iv (SOUND_DRINK_POISON) const_iv (SOUND_CAST_SPELL_0)
1455    
1456     const_iv (PREFER_LOW) const_iv (PREFER_HIGH)
1457    
1458     const_iv (ATNR_PHYSICAL) const_iv (ATNR_MAGIC) const_iv (ATNR_FIRE) const_iv (ATNR_ELECTRICITY)
1459     const_iv (ATNR_COLD) const_iv (ATNR_CONFUSION) const_iv (ATNR_ACID) const_iv (ATNR_DRAIN)
1460     const_iv (ATNR_WEAPONMAGIC) const_iv (ATNR_GHOSTHIT) const_iv (ATNR_POISON) const_iv (ATNR_SLOW)
1461     const_iv (ATNR_PARALYZE) const_iv (ATNR_TURN_UNDEAD) const_iv (ATNR_FEAR) const_iv (ATNR_CANCELLATION)
1462     const_iv (ATNR_DEPLETE) const_iv (ATNR_DEATH) const_iv (ATNR_CHAOS) const_iv (ATNR_COUNTERSPELL)
1463     const_iv (ATNR_GODPOWER) const_iv (ATNR_HOLYWORD) const_iv (ATNR_BLIND) const_iv (ATNR_INTERNAL)
1464     const_iv (ATNR_LIFE_STEALING) const_iv (ATNR_DISEASE)
1465    
1466     const_iv (MAP_IN_MEMORY) const_iv (MAP_SWAPPED) const_iv (MAP_LOADING) const_iv (MAP_SAVING)
1467    
1468     const_iv (KLASS_ATTACHABLE) const_iv (KLASS_GLOBAL) const_iv (KLASS_OBJECT)
1469     const_iv (KLASS_CLIENT) const_iv (KLASS_PLAYER) const_iv (KLASS_MAP)
1470    
1471 root 1.251 const_iv (VERSION_CS) const_iv (VERSION_SC)
1472    
1473 root 1.189 const_iv (CS_QUERY_YESNO) const_iv (CS_QUERY_SINGLECHAR) const_iv (CS_QUERY_HIDEINPUT)
1474    
1475     const_iv (ST_DEAD) const_iv (ST_SETUP) const_iv (ST_PLAYING) const_iv (ST_CUSTOM)
1476 root 1.99
1477 root 1.189 const_iv (IO_HEADER) const_iv (IO_OBJECTS) const_iv (IO_UNIQUES)
1478 root 1.117
1479     // random map generator
1480 root 1.189 const_iv (LAYOUT_NONE) const_iv (LAYOUT_ONION) const_iv (LAYOUT_MAZE) const_iv (LAYOUT_SPIRAL)
1481     const_iv (LAYOUT_ROGUELIKE) const_iv (LAYOUT_SNAKE) const_iv (LAYOUT_SQUARE_SPIRAL)
1482    
1483     const_iv (RMOPT_RANDOM) const_iv (RMOPT_CENTERED) const_iv (RMOPT_LINEAR)
1484     const_iv (RMOPT_BOTTOM_C) const_iv (RMOPT_BOTTOM_R) const_iv (RMOPT_IRR_SPACE)
1485     const_iv (RMOPT_WALL_OFF) const_iv (RMOPT_WALLS_ONLY) const_iv (RMOPT_NO_DOORS)
1486    
1487     const_iv (SYMMETRY_RANDOM) const_iv (SYMMETRY_NONE) const_iv (SYMMETRY_X)
1488     const_iv (SYMMETRY_Y) const_iv (SYMMETRY_XY)
1489 root 1.195
1490     const_iv (GT_ENVIRONMENT) const_iv (GT_INVISIBLE) const_iv (GT_STARTEQUIP)
1491     const_iv (GT_APPLY) const_iv (GT_ONLY_GOOD) const_iv (GT_UPDATE_INV)
1492     const_iv (GT_MINIMAL)
1493 root 1.238
1494     const_iv (FT_FACE) const_iv (FT_MUSIC) const_iv (FT_SOUND)
1495     const_iv (FT_RSRC) const_iv (FT_NUM)
1496 root 1.1 };
1497    
1498     for (civ = const_iv + sizeof (const_iv) / sizeof (const_iv [0]); civ-- > const_iv; )
1499 root 1.109 newCONSTSUB (stash_cf, (char *)civ->name, newSViv (civ->iv));
1500 root 1.1
1501     static const struct {
1502     const char *name;
1503 root 1.14 int skip;
1504 root 1.7 IV klass;
1505 root 1.1 IV iv;
1506 root 1.6 } *eiv, event_iv[] = {
1507 root 1.14 # define def(klass,name) { "EVENT_" # klass "_" # name, sizeof ("EVENT_" # klass), (IV)KLASS_ ## klass, (IV)EVENT_ ## klass ## _ ## name },
1508 root 1.6 # include "eventinc.h"
1509     # undef def
1510     };
1511    
1512     AV *av = get_av ("cf::EVENT", 1);
1513    
1514     for (eiv = event_iv + sizeof (event_iv) / sizeof (event_iv [0]); eiv-- > event_iv; )
1515 root 1.7 {
1516     AV *event = newAV ();
1517 root 1.14 av_push (event, newSVpv ((char *)eiv->name + eiv->skip, 0));
1518 root 1.7 av_push (event, newSViv (eiv->klass));
1519     av_store (av, eiv->iv, newRV_noinc ((SV *)event));
1520 root 1.109 newCONSTSUB (stash_cf, (char *)eiv->name, newSViv (eiv->iv));
1521 root 1.7 }
1522 root 1.14 }
1523    
1524 root 1.109 void _connect_to_perl ()
1525 root 1.14
1526 root 1.210 void _recalc_want ()
1527    
1528 root 1.47 void _global_reattach ()
1529 root 1.14 CODE:
1530     {
1531     // reattach to all attachable objects in the game.
1532 root 1.128 for_all_clients (ns)
1533     ns->reattach ();
1534 root 1.96
1535 root 1.128 for_all_objects (op)
1536 root 1.109 op->reattach ();
1537 root 1.1 }
1538    
1539 root 1.192 # support function for map-world.ext
1540     void _quantise (SV *data_sv, SV *plt_sv)
1541     CODE:
1542     {
1543     if (!SvROK (plt_sv) || SvTYPE (SvRV (plt_sv)) != SVt_PVAV)
1544     croak ("_quantise called with invalid agruments");
1545    
1546     plt_sv = SvRV (plt_sv);
1547     SV **plt = AvARRAY (plt_sv);
1548     int plt_count = AvFILL (plt_sv) + 1;
1549    
1550     STRLEN len;
1551     char *data = SvPVbyte (data_sv, len);
1552     char *dst = data;
1553    
1554     while (len >= 3)
1555     {
1556     for (SV **val_sv = plt + plt_count; val_sv-- > plt; )
1557     {
1558     char *val = SvPVX (*val_sv);
1559    
1560     if (val [0] == data [0]
1561     && val [1] == data [1]
1562     && val [2] == data [2])
1563     {
1564     *dst++ = val [3];
1565     goto next;
1566     }
1567     }
1568    
1569     croak ("_quantise: color not found in palette: #%02x%02x%02x, at offset %d %d",
1570     (uint8_t)data [0], (uint8_t)data [1], (uint8_t)data [2],
1571     dst - SvPVX (data_sv), len);
1572    
1573     next:
1574     data += 3;
1575     len -= 3;
1576     }
1577    
1578     SvCUR_set (data_sv, dst - SvPVX (data_sv));
1579     }
1580    
1581 root 1.236 void _post_tick ()
1582     CODE:
1583     coroapi::next_cede = SvNV (sv_next_tick) - TICK * (1. - 1. / CEDES_PER_TICK);
1584    
1585     NV till_cede ()
1586     CODE:
1587     RETVAL = coroapi::next_cede - now ();
1588     OUTPUT:
1589     RETVAL
1590    
1591     NV till_tick ()
1592     CODE:
1593     RETVAL = SvNV (sv_next_tick) - now ();
1594     OUTPUT:
1595     RETVAL
1596    
1597 root 1.1 NV floor (NV x)
1598    
1599     NV ceil (NV x)
1600    
1601 root 1.143 NV rndm (...)
1602     CODE:
1603     switch (items)
1604     {
1605     case 0: RETVAL = rndm (); break;
1606     case 1: RETVAL = rndm (SvUV (ST (0))); break;
1607     case 2: RETVAL = rndm (SvIV (ST (0)), SvIV (ST (1))); break;
1608     default: croak ("cf::rndm requires none, one or two parameters."); break;
1609     }
1610     OUTPUT:
1611     RETVAL
1612    
1613 root 1.207 NV clamp (NV value, NV min_value, NV max_value)
1614     CODE:
1615     RETVAL = clamp (value, min_value, max_value);
1616     OUTPUT:
1617     RETVAL
1618    
1619     NV lerp (NV value, NV min_in, NV max_in, NV min_out, NV max_out)
1620     CODE:
1621     RETVAL = lerp (value, min_in, max_in, min_out, max_out);
1622     OUTPUT:
1623     RETVAL
1624    
1625     void cede_to_tick ()
1626     CODE:
1627     coroapi::cede_to_tick ();
1628    
1629 root 1.5 void server_tick ()
1630 root 1.116 CODE:
1631 root 1.220 NOW = now ();
1632 root 1.116 runtime = SvNVx (sv_runtime);
1633     server_tick ();
1634 root 1.5
1635 root 1.1 void
1636 root 1.198 log_backtrace (utf8_string msg)
1637    
1638     void
1639     LOG (int flags, utf8_string msg)
1640 root 1.1 PROTOTYPE: $$
1641 root 1.198 C_ARGS: flags, "%s", msg
1642 root 1.1
1643 root 1.183 octet_string path_combine (octet_string base, octet_string path)
1644 root 1.1 PROTOTYPE: $$
1645    
1646 root 1.183 octet_string path_combine_and_normalize (octet_string base, octet_string path)
1647 root 1.1 PROTOTYPE: $$
1648    
1649     void
1650     sub_generation_inc ()
1651     CODE:
1652     PL_sub_generation++;
1653    
1654 root 1.183 const_octet_string
1655 root 1.1 mapdir ()
1656     PROTOTYPE:
1657     ALIAS:
1658     mapdir = 0
1659     uniquedir = 1
1660     tmpdir = 2
1661     confdir = 3
1662     localdir = 4
1663     playerdir = 5
1664     datadir = 6
1665     CODE:
1666 root 1.19 switch (ix)
1667     {
1668     case 0: RETVAL = settings.mapdir ; break;
1669     case 1: RETVAL = settings.uniquedir; break;
1670     case 2: RETVAL = settings.tmpdir ; break;
1671     case 3: RETVAL = settings.confdir ; break;
1672     case 4: RETVAL = settings.localdir ; break;
1673     case 5: RETVAL = settings.playerdir; break;
1674     case 6: RETVAL = settings.datadir ; break;
1675     }
1676 root 1.1 OUTPUT: RETVAL
1677    
1678 root 1.120 void abort ()
1679    
1680 root 1.199 void reset_signals ()
1681    
1682 root 1.183 void fork_abort (octet_string cause = "cf::fork_abort")
1683 root 1.144
1684 root 1.183 void cleanup (octet_string cause, bool make_core = false)
1685 root 1.134
1686 root 1.116 void emergency_save ()
1687    
1688 root 1.156 void _exit (int status = EXIT_SUCCESS)
1689    
1690 root 1.149 UV sv_2watcher (SV *w)
1691     CODE:
1692     RETVAL = (UV)GEventAPI->sv_2watcher (w);
1693     OUTPUT:
1694     RETVAL
1695    
1696 root 1.125 #if _POSIX_MEMLOCK
1697    
1698     int mlockall (int flags = MCL_CURRENT | MCL_FUTURE)
1699    
1700     int munlockall ()
1701    
1702     #endif
1703    
1704 root 1.183 int find_animation (utf8_string text)
1705 root 1.1 PROTOTYPE: $
1706    
1707 root 1.74 int random_roll (int min, int max, object *op, int goodbad);
1708 root 1.1
1709 root 1.183 const_utf8_string cost_string_from_value(uint64 cost, int approx = 0)
1710 root 1.1
1711     int
1712     exp_to_level (val64 exp)
1713     CODE:
1714     {
1715     int i = 0;
1716    
1717     RETVAL = settings.max_level;
1718    
1719     for (i = 1; i <= settings.max_level; i++)
1720     {
1721     if (levels[i] > exp)
1722     {
1723     RETVAL = i - 1;
1724     break;
1725     }
1726     }
1727     }
1728     OUTPUT: RETVAL
1729    
1730     val64
1731     level_to_min_exp (int level)
1732     CODE:
1733     if (level > settings.max_level)
1734     RETVAL = levels[settings.max_level];
1735     else if (level < 1)
1736     RETVAL = 0;
1737     else
1738     RETVAL = levels[level];
1739     OUTPUT: RETVAL
1740    
1741     SV *
1742     resistance_to_string (int atnr)
1743     CODE:
1744     if (atnr >= 0 && atnr < NROFATTACKS)
1745     RETVAL = newSVpv (resist_plus[atnr], 0);
1746     else
1747     XSRETURN_UNDEF;
1748     OUTPUT: RETVAL
1749    
1750 root 1.162 bool
1751 root 1.183 load_resource_file (octet_string filename)
1752 root 1.162
1753 root 1.97 MODULE = cf PACKAGE = cf::attachable
1754    
1755 root 1.27 int
1756 root 1.97 valid (SV *obj)
1757 root 1.27 CODE:
1758     RETVAL = SvROK (obj) && mg_find (SvRV (obj), PERL_MAGIC_ext);
1759     OUTPUT:
1760     RETVAL
1761    
1762 root 1.164 void
1763     debug_trace (attachable *obj, bool on = true)
1764     CODE:
1765     obj->flags &= ~attachable::F_DEBUG_TRACE;
1766     if (on)
1767     obj->flags |= attachable::F_DEBUG_TRACE;
1768    
1769 root 1.153 int mortals_size ()
1770     CODE:
1771     RETVAL = attachable::mortals.size ();
1772     OUTPUT: RETVAL
1773    
1774     #object *mortals (U32 index)
1775     # CODE:
1776     # RETVAL = index < attachable::mortals.size () ? attachable::mortals [index] : 0;
1777     # OUTPUT: RETVAL
1778    
1779 root 1.242 INCLUDE: $PERL $srcdir/genacc attachable ../include/util.h ../include/cfperl.h |
1780 root 1.115
1781 root 1.101 MODULE = cf PACKAGE = cf::global
1782    
1783     int invoke (SV *klass, int event, ...)
1784     CODE:
1785     if (KLASS_OF (event) != KLASS_GLOBAL) croak ("event class must be GLOBAL");
1786     AV *av = (AV *)sv_2mortal ((SV *)newAV ());
1787     for (int i = 1; i < items; i++) av_push (av, SvREFCNT_inc (ST (i)));
1788 root 1.109 RETVAL = gbl_ev.invoke ((event_type)event, ARG_AV (av), DT_END);
1789 root 1.101 OUTPUT: RETVAL
1790    
1791 root 1.1 MODULE = cf PACKAGE = cf::object PREFIX = cf_object_
1792    
1793 root 1.173 INCLUDE: $PERL $srcdir/genacc object ../include/object.h |
1794 root 1.62
1795 root 1.18 int invoke (object *op, int event, ...)
1796     CODE:
1797     if (KLASS_OF (event) != KLASS_OBJECT) croak ("event class must be OBJECT");
1798 root 1.24 AV *av = (AV *)sv_2mortal ((SV *)newAV ());
1799     for (int i = 2; i < items; i++) av_push (av, SvREFCNT_inc (ST (i)));
1800 root 1.109 RETVAL = op->invoke ((event_type)event, ARG_AV (av), DT_END);
1801 root 1.18 OUTPUT: RETVAL
1802    
1803     SV *registry (object *op)
1804    
1805 root 1.134 int objects_size ()
1806     CODE:
1807     RETVAL = objects.size ();
1808     OUTPUT: RETVAL
1809    
1810     object *objects (U32 index)
1811     CODE:
1812     RETVAL = index < objects.size () ? objects [index] : 0;
1813     OUTPUT: RETVAL
1814    
1815     int actives_size ()
1816     CODE:
1817     RETVAL = actives.size ();
1818     OUTPUT: RETVAL
1819    
1820     object *actives (U32 index)
1821 root 1.57 CODE:
1822 root 1.134 RETVAL = index < actives.size () ? actives [index] : 0;
1823 root 1.57 OUTPUT: RETVAL
1824    
1825 root 1.215 const char *slot_use_name (U32 slot)
1826 root 1.205 ALIAS:
1827 root 1.215 slot_nonuse_name = 1
1828 root 1.205 CODE:
1829     {
1830     if (slot >= NUM_BODY_LOCATIONS)
1831     croak ("body slot index out of range");
1832    
1833     switch (ix)
1834     {
1835 root 1.215 case 0: RETVAL = body_locations[slot].use_name; break;
1836     case 1: RETVAL = body_locations[slot].nonuse_name; break;
1837 root 1.205 }
1838     }
1839     OUTPUT:
1840     RETVAL
1841    
1842 root 1.1 # missing properties
1843    
1844 root 1.54 object *head (object *op)
1845     PROTOTYPE: $
1846     CODE:
1847 root 1.134 RETVAL = op->head_ ();
1848 root 1.54 OUTPUT: RETVAL
1849    
1850 root 1.1 void
1851     inv (object *obj)
1852     PROTOTYPE: $
1853     PPCODE:
1854     {
1855 root 1.254 for (object *o = obj->inv; o; o = o->below)
1856 root 1.100 XPUSHs (sv_2mortal (to_sv (o)));
1857 root 1.1 }
1858    
1859 root 1.102 void
1860     set_animation (object *op, int idx)
1861     CODE:
1862     SET_ANIMATION (op, idx);
1863    
1864 elmex 1.160 int
1865     num_animations (object *op)
1866     CODE:
1867     RETVAL = NUM_ANIMATIONS (op);
1868     OUTPUT: RETVAL
1869    
1870 root 1.205 int slot_info (object *op, UV slot, int value = 0)
1871     ALIAS:
1872     slot_used = 1
1873     CODE:
1874     {
1875     if (slot >= NUM_BODY_LOCATIONS)
1876     croak ("body slot index out of range");
1877    
1878 root 1.208 RETVAL = ix ? op->slot[slot].used : op->slot[slot].info;
1879 root 1.205
1880     if (items > 2)
1881     if (ix)
1882 root 1.208 op->slot[slot].used = value;
1883     else
1884 root 1.205 op->slot[slot].info = value;
1885     }
1886     OUTPUT:
1887     RETVAL
1888    
1889 root 1.183 object *find_best_object_match (object *op, utf8_string match)
1890 root 1.58
1891     object *find_marked_object (object *op)
1892    
1893 root 1.109 int need_identify (object *obj);
1894 root 1.1
1895     int apply_shop_mat (object *shop_mat, object *op);
1896    
1897 root 1.27 int move (object *op, int dir, object *originator = op)
1898     CODE:
1899     RETVAL = move_ob (op, dir, originator);
1900     OUTPUT:
1901     RETVAL
1902 root 1.1
1903 root 1.74 void apply (object *applier, object *applied, int flags = 0)
1904     CODE:
1905     manual_apply (applied, applier, flags);
1906 root 1.1
1907 root 1.74 void apply_below (object *op)
1908     CODE:
1909     player_apply_below (op);
1910 root 1.1
1911 root 1.167 int cast_heal (object *op, object *caster, object *spell, int dir = 0)
1912    
1913 root 1.116 #//TODO
1914     object *clone_ (object *op, int recursive = 0)
1915 root 1.74 CODE:
1916     if (recursive)
1917     RETVAL = object_create_clone (op);
1918     else
1919     {
1920     RETVAL = object::create ();
1921 root 1.75 op->copy_to (RETVAL);
1922 root 1.74 }
1923     OUTPUT: RETVAL
1924 root 1.1
1925 root 1.74 int pay_item (object *op, object *buyer)
1926     CODE:
1927     RETVAL = pay_for_item (op, buyer);
1928     OUTPUT: RETVAL
1929 root 1.1
1930 root 1.74 int pay_amount (object *op, uint64 amount)
1931     CODE:
1932     RETVAL = pay_for_amount (amount, op);
1933     OUTPUT: RETVAL
1934 root 1.1
1935     void pay_player (object *op, uint64 amount)
1936    
1937 root 1.183 val64 pay_player_arch (object *op, utf8_string arch, uint64 amount)
1938 root 1.1
1939 root 1.183 int cast_spell (object *op, object *caster, int dir, object *spell_ob, utf8_string stringarg = 0)
1940 root 1.1
1941 root 1.74 void learn_spell (object *op, object *sp, int special_prayer = 0)
1942     CODE:
1943     do_learn_spell (op, sp, special_prayer);
1944 root 1.1
1945 root 1.74 void forget_spell (object *op, object *sp)
1946     CODE:
1947     do_forget_spell (op, query_name (sp));
1948 root 1.1
1949 root 1.183 object *check_for_spell (object *op, utf8_string spellname)
1950 root 1.74 CODE:
1951     RETVAL = check_spell_known (op, spellname);
1952     OUTPUT: RETVAL
1953 root 1.1
1954 root 1.74 int query_money (object *op)
1955 root 1.1 ALIAS: money = 0
1956    
1957 elmex 1.108 val64 query_cost (object *op, object *who, int flags)
1958 root 1.1 ALIAS: cost = 0
1959    
1960 root 1.74 void spring_trap (object *op, object *victim)
1961 root 1.1
1962 root 1.74 int check_trigger (object *op, object *cause)
1963 root 1.1
1964 root 1.74 void drop (object *who, object *op)
1965 root 1.1
1966 root 1.74 void pick_up (object *who, object *op)
1967 root 1.1
1968 root 1.102 void update_object (object *op, int action)
1969 root 1.1
1970 root 1.183 void change_exp (object *op, uint64 exp, utf8_string skill_name = 0, int flag = 0)
1971 root 1.1
1972     void player_lvl_adj (object *who, object *skill = 0)
1973    
1974     int kill_object (object *op, int dam = 0, object *hitter = 0, int type = AT_PHYSICAL)
1975    
1976     int calc_skill_exp (object *who, object *op, object *skill);
1977    
1978     void push_button (object *op);
1979    
1980     void use_trigger (object *op);
1981    
1982 root 1.61 void add_button_link (object *button, maptile *map, int connected);
1983 root 1.1
1984     void remove_button_link (object *op);
1985    
1986 elmex 1.232 void handle_apply_yield (object *op);
1987    
1988 root 1.1
1989     MODULE = cf PACKAGE = cf::object PREFIX = cf_
1990    
1991     # no clean way to get an object from an archetype - stupid idiotic
1992     # dumb kludgy misdesigned plug-in api slowly gets on my nerves.
1993    
1994 root 1.183 object *new (utf8_string archetype = 0)
1995 root 1.1 PROTOTYPE: ;$
1996     CODE:
1997 elmex 1.219 RETVAL = archetype ? get_archetype (archetype) : object::create ();
1998 root 1.1 OUTPUT:
1999     RETVAL
2000    
2001 root 1.225 object *find_object (U32 tag)
2002    
2003 root 1.218 # TODO: nuke
2004 root 1.61 object *insert_ob_in_map_at (object *ob, maptile *where, object_ornull *orig, int flag, int x, int y)
2005 root 1.1 PROTOTYPE: $$$$$$
2006     CODE:
2007     {
2008 root 1.257 RETVAL = insert_ob_in_map_at (ob, where, orig, flag, x, y);
2009 root 1.1 }
2010    
2011 root 1.183 const_utf8_string get_ob_key_value (object *op, utf8_string key)
2012 root 1.1
2013 root 1.183 bool set_ob_key_value (object *op, utf8_string key, utf8_string value = 0, int add_key = 1)
2014 root 1.1
2015     object *get_nearest_player (object *ob)
2016     ALIAS: nearest_player = 0
2017     PREINIT:
2018     extern object *get_nearest_player (object *);
2019    
2020     void rangevector (object *ob, object *other, int flags = 0)
2021     PROTOTYPE: $$;$
2022     PPCODE:
2023     {
2024     rv_vector rv;
2025     get_rangevector (ob, other, &rv, flags);
2026     EXTEND (SP, 5);
2027     PUSHs (newSVuv (rv.distance));
2028     PUSHs (newSViv (rv.distance_x));
2029     PUSHs (newSViv (rv.distance_y));
2030     PUSHs (newSViv (rv.direction));
2031 root 1.257 PUSHs (to_sv (rv.part));
2032 root 1.1 }
2033    
2034     bool on_same_map_as (object *ob, object *other)
2035     CODE:
2036     RETVAL = on_same_map (ob, other);
2037     OUTPUT: RETVAL
2038    
2039 root 1.183 const_utf8_string
2040 root 1.58 base_name (object *op, int plural = op->nrof > 1)
2041 root 1.1 CODE:
2042 root 1.58 RETVAL = query_base_name (op, plural);
2043 root 1.1 OUTPUT: RETVAL
2044    
2045 elmex 1.86 object *decrease_ob_nr (object *op, unsigned long i)
2046    
2047 root 1.256 # return the tail of an object, excluding itself
2048     void
2049     tail (object *op)
2050     PPCODE:
2051     while ((op = op->more))
2052     XPUSHs (sv_2mortal (to_sv (op)));
2053    
2054 root 1.1 MODULE = cf PACKAGE = cf::object::player PREFIX = cf_player_
2055    
2056     player *player (object *op)
2057     CODE:
2058     RETVAL = op->contr;
2059     OUTPUT: RETVAL
2060    
2061 root 1.257 bool move_player (object *op, int dir)
2062    
2063 root 1.105 void check_score (object *op)
2064    
2065 root 1.183 void message (object *op, utf8_string txt, int flags = NDI_ORANGE | NDI_UNIQUE)
2066 root 1.120 CODE:
2067     new_draw_info (flags, 0, op, txt);
2068 root 1.1
2069     void kill_player (object *op)
2070    
2071 root 1.257 void esrv_send_item (object *pl, object *item)
2072    
2073     void esrv_update_item (object *pl, int what, object *item)
2074     C_ARGS: what, pl, item
2075    
2076     void esrv_del_item (object *pl, int tag)
2077     C_ARGS: pl->contr, tag
2078 root 1.58
2079 root 1.183 int command_summon (object *op, utf8_string params)
2080 root 1.67
2081 root 1.183 int command_arrest (object *op, utf8_string params)
2082 root 1.67
2083 root 1.66
2084 root 1.12 MODULE = cf PACKAGE = cf::player PREFIX = cf_player_
2085 root 1.1
2086 root 1.173 INCLUDE: $PERL $srcdir/genacc player ../include/player.h |
2087 root 1.62
2088 root 1.18 int invoke (player *pl, int event, ...)
2089     CODE:
2090     if (KLASS_OF (event) != KLASS_PLAYER) croak ("event class must be PLAYER");
2091 root 1.24 AV *av = (AV *)sv_2mortal ((SV *)newAV ());
2092     for (int i = 2; i < items; i++) av_push (av, SvREFCNT_inc (ST (i)));
2093 root 1.109 RETVAL = pl->invoke ((event_type)event, ARG_AV (av), DT_END);
2094 root 1.18 OUTPUT: RETVAL
2095    
2096 root 1.12 SV *registry (player *pl)
2097 root 1.1
2098 root 1.102 void
2099     save_stats (player *pl)
2100     CODE:
2101     pl->ob->stats.hp = pl->ob->stats.maxhp;
2102     pl->ob->stats.sp = pl->ob->stats.maxsp;
2103     pl->ob->stats.grace = pl->ob->stats.maxgrace;
2104     pl->orig_stats = pl->ob->stats;
2105    
2106 root 1.217 void clear_los (player *pl)
2107    
2108 root 1.1 bool
2109     cell_visible (player *pl, int dx, int dy)
2110     CODE:
2111 root 1.98 RETVAL = FABS (dx) <= pl->ns->mapx / 2 && FABS (dy) <= pl->ns->mapy / 2
2112     && !pl->blocked_los [dx + pl->ns->mapx / 2][dy + pl->ns->mapy / 2];
2113 root 1.1 OUTPUT:
2114     RETVAL
2115    
2116 root 1.4 void
2117 root 1.1 send (player *pl, SV *packet)
2118     CODE:
2119     {
2120     STRLEN len;
2121     char *buf = SvPVbyte (packet, len);
2122    
2123 root 1.258 if (len > MAXSOCKBUF)
2124     pl->failmsg ("[packet too long for client]");
2125     else if (pl->ns)
2126 root 1.100 pl->ns->send_packet (buf, len);
2127 root 1.1 }
2128    
2129     int
2130     listening (player *pl, int new_value = -1)
2131     CODE:
2132     RETVAL = pl->listening;
2133     if (new_value >= 0)
2134     pl->listening = new_value;
2135     OUTPUT:
2136     RETVAL
2137    
2138 root 1.46 void savebed (player *pl, SV *map_path = 0, SV *x = 0, SV *y = 0)
2139 root 1.45 PROTOTYPE: $;$$$
2140 root 1.1 PPCODE:
2141 root 1.45 if (GIMME_V != G_VOID)
2142     {
2143     EXTEND (SP, 3);
2144     PUSHs (sv_2mortal (newSVpv (pl->savebed_map, 0)));
2145     PUSHs (sv_2mortal (newSViv (pl->bed_x)));
2146     PUSHs (sv_2mortal (newSViv (pl->bed_y)));
2147     }
2148 root 1.46 if (map_path) sv_to (map_path, pl->savebed_map);
2149     if (x) sv_to (x, pl->bed_x);
2150     if (y) sv_to (y, pl->bed_y);
2151 root 1.1
2152     void
2153     list ()
2154     PPCODE:
2155 root 1.128 for_all_players (pl)
2156 root 1.100 XPUSHs (sv_2mortal (to_sv (pl)));
2157 root 1.1
2158    
2159     MODULE = cf PACKAGE = cf::map PREFIX = cf_map_
2160    
2161 root 1.61 int invoke (maptile *map, int event, ...)
2162 root 1.18 CODE:
2163     if (KLASS_OF (event) != KLASS_MAP) croak ("event class must be MAP");
2164 root 1.24 AV *av = (AV *)sv_2mortal ((SV *)newAV ());
2165     for (int i = 2; i < items; i++) av_push (av, SvREFCNT_inc (ST (i)));
2166 root 1.109 RETVAL = map->invoke ((event_type)event, ARG_AV (av), DT_END);
2167 root 1.25 OUTPUT: RETVAL
2168 root 1.18
2169 root 1.61 SV *registry (maptile *map)
2170 root 1.12
2171 root 1.255 void
2172     find_tagged_objects (maptile *map, utf8_string tag = 0)
2173     PPCODE:
2174     {
2175     if (!map->spaces)
2176     XSRETURN_EMPTY;
2177    
2178     if (tag)
2179     {
2180     shstr_cmp tag_ (tag);
2181    
2182     for (mapspace *ms = map->spaces + map->size (); ms-- > map->spaces; )
2183     for (object *op = ms->bot; op; op = op->above)
2184     if (op->tag == tag_)
2185     XPUSHs (sv_2mortal (to_sv (op)));
2186     }
2187     else
2188     {
2189     for (mapspace *ms = map->spaces + map->size (); ms-- > map->spaces; )
2190     for (object *op = ms->bot; op; op = op->above)
2191     if (op->tag)
2192     XPUSHs (sv_2mortal (to_sv (op)));
2193     }
2194     }
2195    
2196 root 1.173 INCLUDE: $PERL $srcdir/genacc maptile ../include/map.h |
2197 root 1.1
2198 root 1.116 void
2199     maptile::instantiate ()
2200    
2201     maptile *new ()
2202 root 1.1 PROTOTYPE:
2203     CODE:
2204 root 1.116 RETVAL = new maptile;
2205 root 1.1 OUTPUT:
2206     RETVAL
2207    
2208 root 1.116 void
2209 root 1.117 maptile::players ()
2210     PPCODE:
2211     if (GIMME_V == G_SCALAR)
2212 root 1.118 XPUSHs (sv_2mortal (to_sv (THIS->players)));
2213 root 1.117 else if (GIMME_V == G_ARRAY)
2214     {
2215     EXTEND (SP, THIS->players);
2216     for_all_players (pl)
2217     if (pl->ob && pl->ob->map == THIS)
2218 root 1.118 PUSHs (sv_2mortal (to_sv (pl->ob)));
2219 root 1.117 }
2220    
2221 root 1.156 void
2222 root 1.168 maptile::add_underlay (SV *data, int offset, int stride, SV *palette)
2223 root 1.156 CODE:
2224     {
2225 root 1.168 if (!SvROK (palette) || SvTYPE (SvRV (palette)) != SVt_PVAV)
2226     croak ("maptile::add_underlay: palette must be arrayref");
2227 root 1.156
2228 root 1.168 palette = SvRV (palette);
2229 root 1.156
2230 root 1.168 STRLEN idxlen;
2231     const uint8_t *idx = (const uint8_t *)SvPVbyte (data, idxlen);
2232 root 1.156
2233 root 1.168 for (int x = 0; x < THIS->width; ++x)
2234     for (int y = 0; y < THIS->height; ++y)
2235     {
2236     for (object *op = THIS->at (x, y).bot; op; op = op->above)
2237     if (op->flag [FLAG_IS_FLOOR])
2238     goto skip_space;
2239    
2240     {
2241     int offs = offset + y * stride + x;
2242     if (IN_RANGE_EXC (offs, 0, idxlen))
2243     {
2244     if (SV **elem = av_fetch ((AV *)palette, idx [offs], 0))
2245     {
2246     object *ob = get_archetype (SvPVutf8_nolen (*elem));
2247     ob->flag [FLAG_NO_MAP_SAVE] = true;
2248     THIS->insert (ob, x, y, 0, INS_ABOVE_FLOOR_ONLY);
2249 root 1.200
2250     if (ob->randomitems)
2251     {
2252 root 1.203 if (!ob->above)
2253     {
2254     ob->create_treasure (ob->randomitems);
2255    
2256     for (object *op = ob->above; op; op = op->above)
2257     op->flag [FLAG_NO_MAP_SAVE] = true;
2258     }
2259    
2260 root 1.200 ob->randomitems = 0;
2261     }
2262 root 1.168 }
2263     }
2264     }
2265 root 1.156
2266 root 1.168 skip_space: ;
2267     }
2268     }
2269    
2270     void
2271     maptile::set_regiondata (SV *data, int offset, int stride, SV *palette)
2272     CODE:
2273     {
2274     if (!SvROK (palette) || SvTYPE (SvRV (palette)) != SVt_PVAV)
2275     croak ("maptile::set_regiondata: palette must be arrayref");
2276    
2277     palette = SvRV (palette);
2278    
2279     STRLEN idxlen;
2280     const uint8_t *idx = (const uint8_t *)SvPVbyte (data, idxlen);
2281    
2282 root 1.230 region_ptr *regionmap = new region_ptr [av_len ((AV *)palette) + 1];
2283 root 1.168 uint8_t *regions = salloc<uint8_t> (THIS->size ());
2284    
2285     for (int i = av_len ((AV *)palette) + 1; i--; )
2286 root 1.230 regionmap [i] = region::find (SvPVutf8_nolen (*av_fetch ((AV *)palette, i, 1)));
2287 root 1.168
2288     for (int y = 0; y < THIS->height; ++y)
2289     memcpy (regions + y * THIS->width, idx + offset + y * stride, THIS->width);
2290    
2291     sfree (THIS->regions, THIS->size ());
2292 root 1.230 delete [] THIS->regionmap;
2293 root 1.168
2294     THIS->regions = regions;
2295 root 1.156 THIS->regionmap = regionmap;
2296     }
2297    
2298 root 1.193 void
2299     maptile::create_region_treasure ()
2300     CODE:
2301     {
2302     object *op = object::create ();
2303     op->type = FLOOR;
2304     op->map = THIS;
2305    
2306     for (int x = 0; x < THIS->width; ++x)
2307     for (int y = 0; y < THIS->height; ++y)
2308     {
2309     region *rgn = THIS->region (x, y);
2310    
2311     //fprintf (stderr, "%d,%d %f %p\n", x, y, rgn->treasure_density,rgn->treasure);//D
2312     if (rgn->treasure && rndm () < rgn->treasure_density)
2313     {
2314     op->x = x;
2315     op->y = y;
2316     create_treasure (rgn->treasure, op, GT_ENVIRONMENT, THIS->difficulty);
2317     }
2318     }
2319    
2320     op->destroy ();
2321     }
2322    
2323 root 1.74 int out_of_map (maptile *map, int x, int y)
2324    
2325 root 1.29 void
2326 root 1.61 trigger (maptile *map, long connection, bool state = true)
2327 root 1.29 CODE:
2328     activate_connection (map, connection, state);
2329    
2330     void
2331 root 1.61 get_connection (maptile *map, long connection)
2332 root 1.29 PPCODE:
2333     oblinkpt *obp = get_connection_links (map, connection);
2334     if (obp)
2335     for (objectlink *ol = obp->link; ol; ol = ol->next)
2336 root 1.257 XPUSHs (sv_2mortal (to_sv ((object *)ol->ob)));
2337 root 1.1
2338     void
2339 root 1.140 get_map_flags (maptile *map, int x, int y)
2340 root 1.1 PPCODE:
2341     {
2342 root 1.61 maptile *nmap = 0;
2343 root 1.1 I16 nx = 0, ny = 0;
2344 root 1.19 int flags = get_map_flags (map, &nmap, x, y, &nx, &ny);
2345 root 1.1
2346     EXTEND (SP, 4);
2347     PUSHs (sv_2mortal (newSViv (flags)));
2348    
2349     if (GIMME_V == G_ARRAY)
2350     {
2351 root 1.257 PUSHs (sv_2mortal (to_sv (nmap)));
2352 root 1.1 PUSHs (sv_2mortal (newSViv (nx)));
2353     PUSHs (sv_2mortal (newSViv (ny)));
2354     }
2355     }
2356    
2357     void
2358 root 1.61 at (maptile *map, unsigned int x, unsigned int y)
2359 root 1.1 PROTOTYPE: $$$
2360     PPCODE:
2361     {
2362     object *o;
2363 root 1.61 maptile *nmap = 0;
2364 root 1.1 I16 nx, ny;
2365    
2366 root 1.19 get_map_flags (map, &nmap, x, y, &nx, &ny);
2367 root 1.1
2368     if (nmap)
2369     for (o = GET_MAP_OB (nmap, nx, ny); o; o = o->above)
2370 root 1.257 XPUSHs (sv_2mortal (to_sv (o)));
2371 root 1.1 }
2372    
2373     SV *
2374 root 1.61 bot_at (maptile *obj, unsigned int x, unsigned int y)
2375 root 1.1 PROTOTYPE: $$$
2376     ALIAS:
2377     top_at = 1
2378     flags_at = 2
2379     light_at = 3
2380     move_block_at = 4
2381     move_slow_at = 5
2382     move_on_at = 6
2383     move_off_at = 7
2384     INIT:
2385 root 1.110 if (x >= obj->width || y >= obj->height) XSRETURN_UNDEF;
2386 root 1.1 CODE:
2387     switch (ix)
2388     {
2389 root 1.257 case 0: RETVAL = to_sv (GET_MAP_OB (obj, x, y)); break;
2390     case 1: RETVAL = to_sv (GET_MAP_TOP (obj, x, y)); break;
2391     case 2: RETVAL = newSVuv (GET_MAP_FLAGS (obj, x, y)); break;
2392     case 3: RETVAL = newSViv (GET_MAP_LIGHT (obj, x, y)); break;
2393     case 4: RETVAL = newSVuv (GET_MAP_MOVE_BLOCK (obj, x, y)); break;
2394     case 5: RETVAL = newSVuv (GET_MAP_MOVE_SLOW (obj, x, y)); break;
2395     case 6: RETVAL = newSVuv (GET_MAP_MOVE_ON (obj, x, y)); break;
2396     case 7: RETVAL = newSVuv (GET_MAP_MOVE_OFF (obj, x, y)); break;
2397 root 1.1 }
2398 root 1.122 OUTPUT: RETVAL
2399 root 1.1
2400 elmex 1.70 void fix_walls (maptile *map, int x, int y)
2401    
2402     void fix_walls_around (maptile *map, int x, int y)
2403 root 1.1
2404 root 1.117 # worst xs function of my life
2405 root 1.140 bool
2406 root 1.117 _create_random_map (\
2407 root 1.140 maptile *self,\
2408 root 1.183 utf8_string wallstyle,\
2409     utf8_string wall_name,\
2410     utf8_string floorstyle,\
2411     utf8_string monsterstyle,\
2412     utf8_string treasurestyle,\
2413     utf8_string layoutstyle,\
2414     utf8_string doorstyle,\
2415     utf8_string decorstyle,\
2416     utf8_string origin_map,\
2417     utf8_string final_map,\
2418     utf8_string exitstyle,\
2419     utf8_string this_map,\
2420     utf8_string exit_on_final_map,\
2421 root 1.146 int xsize,\
2422     int ysize,\
2423 root 1.117 int expand2x,\
2424     int layoutoptions1,\
2425     int layoutoptions2,\
2426     int layoutoptions3,\
2427     int symmetry,\
2428     int difficulty,\
2429     int difficulty_given,\
2430     float difficulty_increase,\
2431     int dungeon_level,\
2432     int dungeon_depth,\
2433     int decoroptions,\
2434     int orientation,\
2435     int origin_y,\
2436     int origin_x,\
2437 root 1.146 U32 random_seed,\
2438 root 1.117 val64 total_map_hp,\
2439     int map_layout_style,\
2440     int treasureoptions,\
2441     int symmetry_used,\
2442 root 1.137 region *region,\
2443 root 1.183 utf8_string custom\
2444 root 1.117 )
2445     CODE:
2446     {
2447     random_map_params rmp;
2448    
2449     assign (rmp.wallstyle , wallstyle);
2450     assign (rmp.wall_name , wall_name);
2451     assign (rmp.floorstyle , floorstyle);
2452     assign (rmp.monsterstyle , monsterstyle);
2453     assign (rmp.treasurestyle , treasurestyle);
2454     assign (rmp.layoutstyle , layoutstyle);
2455     assign (rmp.doorstyle , doorstyle);
2456     assign (rmp.decorstyle , decorstyle);
2457     assign (rmp.exitstyle , exitstyle);
2458     assign (rmp.exit_on_final_map, exit_on_final_map);
2459    
2460 root 1.122 rmp.origin_map = origin_map;
2461     rmp.final_map = final_map;
2462     rmp.this_map = this_map;
2463 root 1.146 rmp.xsize = xsize;
2464     rmp.ysize = ysize;
2465 root 1.117 rmp.expand2x = expand2x;
2466     rmp.layoutoptions1 = layoutoptions1;
2467     rmp.layoutoptions2 = layoutoptions2;
2468     rmp.layoutoptions3 = layoutoptions3;
2469     rmp.symmetry = symmetry;
2470     rmp.difficulty = difficulty;
2471     rmp.difficulty_given = difficulty_given;
2472     rmp.difficulty_increase = difficulty_increase;
2473     rmp.dungeon_level = dungeon_level;
2474     rmp.dungeon_depth = dungeon_depth;
2475     rmp.decoroptions = decoroptions;
2476     rmp.orientation = orientation;
2477     rmp.origin_y = origin_y;
2478     rmp.origin_x = origin_x;
2479     rmp.random_seed = random_seed;
2480 root 1.214 rmp.total_map_hp = (uint64_t) total_map_hp;
2481 root 1.117 rmp.map_layout_style = map_layout_style;
2482     rmp.treasureoptions = treasureoptions;
2483     rmp.symmetry_used = symmetry_used;
2484     rmp.region = region;
2485 root 1.137 rmp.custom = custom;
2486 root 1.117
2487 root 1.140 RETVAL = self->generate_random_map (&rmp);
2488 root 1.117 }
2489     OUTPUT:
2490     RETVAL
2491    
2492 root 1.19 MODULE = cf PACKAGE = cf::arch
2493 root 1.1
2494 root 1.218 int archetypes_size ()
2495     CODE:
2496     RETVAL = archetypes.size ();
2497     OUTPUT: RETVAL
2498    
2499     archetype *archetypes (U32 index)
2500     CODE:
2501     RETVAL = index < archetypes.size () ? archetypes [index] : 0;
2502     OUTPUT: RETVAL
2503 root 1.1
2504 root 1.212 object *instantiate (archetype *arch)
2505     CODE:
2506     RETVAL = arch_to_object (arch);
2507     OUTPUT:
2508     RETVAL
2509    
2510 root 1.173 INCLUDE: $PERL $srcdir/genacc archetype ../include/object.h |
2511 root 1.1
2512 root 1.19 MODULE = cf PACKAGE = cf::party
2513 root 1.1
2514 root 1.19 partylist *first ()
2515 root 1.1 PROTOTYPE:
2516 root 1.19 CODE:
2517     RETVAL = get_firstparty ();
2518     OUTPUT: RETVAL
2519 root 1.1
2520 root 1.173 INCLUDE: $PERL $srcdir/genacc partylist ../include/player.h |
2521 root 1.1
2522 root 1.19 MODULE = cf PACKAGE = cf::region
2523 root 1.1
2524 root 1.161 void
2525     list ()
2526     PPCODE:
2527     for_all_regions (rgn)
2528     XPUSHs (sv_2mortal (to_sv (rgn)));
2529    
2530 root 1.183 region *find (utf8_string name)
2531 root 1.161 PROTOTYPE: $
2532 root 1.19 CODE:
2533 root 1.161 RETVAL = region::find (name);
2534 root 1.19 OUTPUT: RETVAL
2535 root 1.1
2536 root 1.183 region *find_fuzzy (utf8_string name)
2537 root 1.122 PROTOTYPE: $
2538     CODE:
2539 root 1.161 RETVAL = region::find_fuzzy (name);
2540 root 1.122 OUTPUT: RETVAL
2541    
2542 root 1.186 int specificity (region *rgn)
2543     CODE:
2544     RETVAL = 0;
2545     while (rgn = rgn->parent)
2546     RETVAL++;
2547     OUTPUT: RETVAL
2548    
2549 root 1.193 INCLUDE: $PERL $srcdir/genacc region ../include/region.h |
2550 root 1.1
2551 root 1.19 MODULE = cf PACKAGE = cf::living
2552 root 1.1
2553 root 1.173 INCLUDE: $PERL $srcdir/genacc living ../include/living.h |
2554 root 1.1
2555 root 1.76 MODULE = cf PACKAGE = cf::settings
2556    
2557 root 1.173 INCLUDE: $PERL $srcdir/genacc Settings ../include/global.h |
2558 root 1.76
2559 root 1.84 MODULE = cf PACKAGE = cf::client
2560 root 1.79
2561 root 1.173 INCLUDE: $PERL $srcdir/genacc client ../include/client.h |
2562 root 1.79
2563 root 1.84 int invoke (client *ns, int event, ...)
2564 root 1.79 CODE:
2565 root 1.88 if (KLASS_OF (event) != KLASS_CLIENT) croak ("event class must be CLIENT");
2566 root 1.79 AV *av = (AV *)sv_2mortal ((SV *)newAV ());
2567     for (int i = 2; i < items; i++) av_push (av, SvREFCNT_inc (ST (i)));
2568 root 1.109 RETVAL = ns->invoke ((event_type)event, ARG_AV (av), DT_END);
2569 root 1.79 OUTPUT: RETVAL
2570    
2571 root 1.84 SV *registry (client *ns)
2572 root 1.79
2573 root 1.100 void
2574     list ()
2575     PPCODE:
2576     EXTEND (SP, clients.size ());
2577     for (sockvec::iterator i = clients.begin (); i != clients.end (); ++i)
2578     PUSHs (sv_2mortal (to_sv (*i)));
2579    
2580 root 1.88 void
2581 root 1.100 client::send_packet (SV *packet)
2582     CODE:
2583     {
2584     STRLEN len;
2585     char *buf = SvPVbyte (packet, len);
2586    
2587 root 1.258 if (len > MAXSOCKBUF)
2588     {
2589     // ugly
2590     if (THIS->pl)
2591     THIS->pl->failmsg ("[packet too long for client]");
2592     }
2593     else
2594     THIS->send_packet (buf, len);
2595 root 1.100 }
2596    
2597 root 1.237 faceidx
2598 root 1.238 client::need_face (utf8_string name, int pri = 0)
2599 root 1.237 CODE:
2600 root 1.238 RETVAL = face_find (name, 0);
2601     if (RETVAL)
2602     {
2603     THIS->send_face (RETVAL, pri);
2604     THIS->flush_fx ();
2605     }
2606     OUTPUT:
2607     RETVAL
2608    
2609     int
2610     client::fx_want (int idx, int value = -1)
2611     CODE:
2612     if (0 < idx && idx < FT_NUM)
2613     {
2614     RETVAL = THIS->fx_want [idx];
2615     if (items > 2)
2616     THIS->fx_want [idx] = value;
2617     }
2618     else
2619     RETVAL = 0;
2620 root 1.237 OUTPUT:
2621     RETVAL
2622    
2623 root 1.239 MODULE = cf PACKAGE = cf::sound PREFIX = sound_
2624    
2625     faceidx sound_find (utf8_string name)
2626    
2627 root 1.240 void sound_set (utf8_string str, faceidx face)
2628    
2629     # dire hack
2630     void old_sound_index (int idx, faceidx face)
2631     CODE:
2632     extern faceidx old_sound_index [SOUND_CAST_SPELL_0];
2633     old_sound_index [idx] = face;
2634    
2635 root 1.176 MODULE = cf PACKAGE = cf::face PREFIX = face_
2636    
2637 root 1.185 #INCLUDE: $PERL $srcdir/genacc faceset ../include/face.h |
2638 root 1.176
2639 root 1.183 faceidx face_find (utf8_string name, faceidx defidx = 0)
2640 root 1.176
2641 root 1.183 faceidx alloc (utf8_string name)
2642 root 1.176 CODE:
2643     {
2644     do
2645     {
2646     RETVAL = faces.size ();
2647 root 1.177 faces.resize (RETVAL + 1);
2648 root 1.176 }
2649     while (!RETVAL); // crude way to leave index 0
2650    
2651     faces [RETVAL].name = name;
2652     facehash.insert (std::make_pair (faces [RETVAL].name, RETVAL));
2653    
2654     if (!strcmp (name, BLANK_FACE_NAME)) blank_face = RETVAL;
2655     if (!strcmp (name, EMPTY_FACE_NAME)) empty_face = RETVAL;
2656     }
2657     OUTPUT: RETVAL
2658    
2659 root 1.227 void set_type (faceidx idx, int value)
2660     ALIAS:
2661     set_type = 0
2662     set_visibility = 1
2663     set_magicmap = 2
2664     set_smooth = 3
2665     set_smoothlevel = 4
2666 root 1.176 CODE:
2667 root 1.229 faceinfo *f = face_info (idx); assert (f);
2668 root 1.227 switch (ix)
2669     {
2670     case 0: f->type = value; break;
2671     case 1: f->visibility = value; break;
2672     case 2: f->magicmap = value; break;
2673     case 3: f->smooth = value; break;
2674     case 4: f->smoothlevel = value; break;
2675     }
2676 root 1.177
2677     void set_data (faceidx idx, int faceset, SV *data, SV *chksum)
2678 root 1.176 CODE:
2679 root 1.182 {
2680 root 1.231 faceinfo *f = face_info (idx); assert (f);
2681     facedata *d = &(faceset ? f->data64 : f->data32);
2682 root 1.181 sv_to (data, d->data);
2683     STRLEN clen;
2684     char *cdata = SvPVbyte (chksum, clen);
2685 root 1.182 clen = min (CHKSUM_SIZE, clen);
2686    
2687     if (memcmp (d->chksum, cdata, clen))
2688     {
2689     memcpy (d->chksum, cdata, clen);
2690    
2691     // invalidate existing client face info
2692     for_all_clients (ns)
2693     if (ns->faceset == faceset)
2694     {
2695     ns->faces_sent [idx] = false;
2696     ns->force_newmap = true;
2697     }
2698     }
2699     }
2700 root 1.176
2701 root 1.229 int get_data_size (faceidx idx, int faceset = 0)
2702     CODE:
2703     facedata *d = face_data (idx, faceset); assert (d);
2704     RETVAL = d->data.size ();
2705     OUTPUT:
2706     RETVAL
2707    
2708     SV *get_chksum (faceidx idx, int faceset = 0)
2709     CODE:
2710     facedata *d = face_data (idx, faceset); assert (d);
2711     RETVAL = newSVpvn ((char *)d->chksum, CHKSUM_SIZE);
2712     OUTPUT:
2713     RETVAL
2714    
2715 root 1.177 void invalidate (faceidx idx)
2716     CODE:
2717     for_all_clients (ns)
2718 root 1.182 {
2719     ns->faces_sent [idx] = false;
2720     ns->force_newmap = true;
2721     }
2722 root 1.177
2723     void invalidate_all ()
2724     CODE:
2725     for_all_clients (ns)
2726 root 1.182 {
2727     ns->faces_sent.reset ();
2728     ns->force_newmap = true;
2729     }
2730 root 1.177
2731 root 1.185 MODULE = cf PACKAGE = cf::anim PREFIX = anim_
2732    
2733     #INCLUDE: $PERL $srcdir/genacc faceset ../include/anim.h |
2734    
2735     animidx anim_find (utf8_string name)
2736     CODE:
2737     RETVAL = animation::find (name).number;
2738     OUTPUT: RETVAL
2739    
2740     animidx set (utf8_string name, SV *frames, int facings = 1)
2741     CODE:
2742     {
2743     if (!SvROK (frames) && SvTYPE (SvRV (frames)) != SVt_PVAV)
2744     croak ("frames must be an arrayref");
2745    
2746     AV *av = (AV *)SvRV (frames);
2747    
2748     animation *anim = &animation::find (name);
2749     if (anim->number)
2750     {
2751     anim->resize (av_len (av) + 1);
2752     anim->facings = facings;
2753     }
2754     else
2755     anim = &animation::create (name, av_len (av) + 1, facings);
2756    
2757     for (int i = 0; i < anim->num_animations; ++i)
2758     anim->faces [i] = face_find (SvPVutf8_nolen (*av_fetch (av, i, 1)));
2759     }
2760     OUTPUT: RETVAL
2761    
2762     void invalidate_all ()
2763     CODE:
2764     for_all_clients (ns)
2765     ns->anims_sent.reset ();
2766    
2767 root 1.247 MODULE = cf PACKAGE = cf::object::freezer
2768    
2769     INCLUDE: $PERL $srcdir/genacc object_freezer ../include/cfperl.h |
2770    
2771     SV *
2772     new (char *klass)
2773     CODE:
2774     RETVAL = newSVptr (new object_freezer, gv_stashpv ("cf::object::freezer", 1));
2775     OUTPUT: RETVAL
2776    
2777     void
2778     DESTROY (SV *sv)
2779     CODE:
2780     object_freezer *self;
2781     sv_to (sv, self);
2782     delete self;
2783    
2784     MODULE = cf PACKAGE = cf::object::thawer
2785    
2786     INCLUDE: $PERL $srcdir/genacc object_thawer ../include/cfperl.h |
2787    
2788     SV *
2789     new_from_file (char *klass, octet_string path)
2790     CODE:
2791     object_thawer *f = new object_thawer (path);
2792     if (!*f)
2793     {
2794     delete f;
2795     XSRETURN_UNDEF;
2796     }
2797     RETVAL = newSVptr (f, gv_stashpv ("cf::object::thawer", 1));
2798     OUTPUT: RETVAL
2799    
2800     void
2801     DESTROY (SV *sv)
2802     CODE:
2803     object_thawer *self;
2804     sv_to (sv, self);
2805     delete self;
2806    
2807 root 1.252 void
2808 root 1.253 extract_tags (object_thawer *self)
2809 root 1.254 PPCODE:
2810 root 1.252 while (self->kw != KW_EOF)
2811     {
2812 root 1.254 PUTBACK;
2813 root 1.253 coroapi::cede_to_tick_every (5000);
2814 root 1.254 SPAGAIN;
2815 root 1.253
2816 root 1.252 if (self->kw == KW_tag)
2817 root 1.254 XPUSHs (sv_2mortal (newSVpv_utf8 (self->get_str ())));
2818 root 1.252
2819     self->skip ();
2820     }
2821