ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/server/cfperl.xs
Revision: 1.265
Committed: Wed Nov 14 08:09:46 2007 UTC (16 years, 7 months ago) by root
Branch: MAIN
CVS Tags: rel-2_32
Changes since 1.264: +11 -64 lines
Log Message:
switch from Event to EV

File Contents

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