ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/server/cfperl.xs
Revision: 1.260
Committed: Tue Oct 16 05:00:38 2007 UTC (16 years, 8 months ago) by root
Branch: MAIN
Changes since 1.259: +4 -1 lines
Log Message:
add support for mallinfo, just for me

File Contents

# User Rev Content
1 root 1.1 /*
2 root 1.216 * This file is part of Crossfire TRT, the Roguelike Realtime MORPG.
3     *
4     * Copyright (©) 2006,2007 Marc Alexander Lehmann / Robin Redeker / the Crossfire TRT team
5     * Copyright (©) 2001-2005,2007 by Chachkoff Yann
6     * Copyright (©) 2006,2007 by Marc Lehmann <cf@schmorp.de>
7     *
8 root 1.226 * Crossfire TRT is free software: you can redistribute it and/or modify
9     * it under the terms of the GNU General Public License as published by
10     * the Free Software Foundation, either version 3 of the License, or
11     * (at your option) any later version.
12 root 1.216 *
13 root 1.226 * This program is distributed in the hope that it will be useful,
14     * but WITHOUT ANY WARRANTY; without even the implied warranty of
15     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16     * GNU General Public License for more details.
17 root 1.216 *
18 root 1.226 * You should have received a copy of the GNU General Public License
19     * along with this program. If not, see <http://www.gnu.org/licenses/>.
20 root 1.216 *
21     * The authors can be reached via e-mail to <crossfire@schmorp.de>
22 root 1.106 */
23 root 1.1
24 root 1.198 #include "autoconf.h"
25    
26 root 1.1 #define PLUGIN_NAME "perl"
27 root 1.13 #define PLUGIN_VERSION "cfperl 0.5"
28 root 1.1
29 root 1.189 #define CEDES_PER_TICK 5
30    
31 root 1.198 #if HAVE_EXECINFO_H
32     # include <execinfo.h>
33     #endif
34    
35 root 1.6 #include <cstdarg>
36 root 1.1
37 root 1.257 #include "global.h"
38 root 1.162 #include "loader.h"
39 root 1.257 #include "../random_maps/random_map.h"
40     #include <sproto.h>
41 root 1.1
42 root 1.125 #include <unistd.h>
43     #if _POSIX_MEMLOCK
44     # include <sys/mman.h>
45     #endif
46    
47 root 1.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.107 "use Event; 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.80 struct EventAPI *watcher_base::GEventAPI;
1105 root 1.116 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     static void
1153     iw_dispatch (pe_event *ev)
1154 root 1.85 {
1155     iw *w = (iw *)ev->ext_data;
1156     w->call (*w);
1157     }
1158    
1159     void
1160     iw::alloc ()
1161     {
1162     pe = GEventAPI->new_idle (0, 0);
1163    
1164 root 1.150 WaREENTRANT_off (pe);
1165 root 1.85 pe->base.callback = (void *)iw_dispatch;
1166     pe->base.ext_data = (void *)this;
1167     }
1168    
1169 root 1.80 static void iow_dispatch (pe_event *ev)
1170     {
1171     iow *w = (iow *)ev->ext_data;
1172     w->call (*w, ((pe_ioevent *)ev)->got);
1173     }
1174    
1175     void
1176     iow::alloc ()
1177     {
1178     pe = GEventAPI->new_io (0, 0);
1179    
1180 root 1.150 WaREENTRANT_off (pe);
1181 root 1.80 pe->base.callback = (void *)iow_dispatch;
1182     pe->base.ext_data = (void *)this;
1183    
1184 root 1.81 pe->fd = -1;
1185     pe->poll = 0;
1186 root 1.80 }
1187    
1188 root 1.85 void
1189 root 1.80 iow::fd (int fd)
1190     {
1191     pe->fd = fd;
1192     }
1193    
1194     int
1195     iow::poll ()
1196     {
1197     return pe->poll;
1198     }
1199    
1200 root 1.85 void
1201 root 1.80 iow::poll (int events)
1202     {
1203 root 1.81 if (pe->poll != events)
1204     {
1205     if (pe->poll) stop ();
1206     pe->poll = events;
1207     if (pe->poll) start ();
1208     }
1209 root 1.80 }
1210    
1211 root 1.109 void
1212     _connect_to_perl ()
1213     {
1214     stash_cf = gv_stashpv ("cf" , 1);
1215    
1216     stash_cf_object_wrap = gv_stashpv ("cf::object::wrap", 1);
1217     stash_cf_object_player_wrap = gv_stashpv ("cf::object::player::wrap", 1);
1218     stash_cf_player_wrap = gv_stashpv ("cf::player::wrap", 1);
1219     stash_cf_map_wrap = gv_stashpv ("cf::map::wrap" , 1);
1220     stash_cf_client_wrap = gv_stashpv ("cf::client::wrap", 1);
1221     stash_cf_arch_wrap = gv_stashpv ("cf::arch::wrap" , 1);
1222     stash_cf_party_wrap = gv_stashpv ("cf::party::wrap" , 1);
1223     stash_cf_region_wrap = gv_stashpv ("cf::region::wrap", 1);
1224     stash_cf_living_wrap = gv_stashpv ("cf::living::wrap", 1);
1225    
1226 root 1.189 sv_runtime = get_sv ("cf::RUNTIME" , 1); sv_upgrade (sv_runtime , SVt_NV);
1227     sv_next_tick = get_sv ("cf::NEXT_TICK", 1); sv_upgrade (sv_next_tick, SVt_NV);
1228 root 1.116
1229 root 1.109 cb_global = get_av ("cf::CB_GLOBAL", 1);
1230     cb_attachable = get_av ("cf::CB_ATTACHABLE", 1);
1231     cb_object = get_av ("cf::CB_OBJECT", 1);
1232     cb_player = get_av ("cf::CB_PLAYER", 1);
1233     cb_client = get_av ("cf::CB_CLIENT", 1);
1234     cb_type = get_av ("cf::CB_TYPE" , 1);
1235     cb_map = get_av ("cf::CB_MAP" , 1);
1236     }
1237    
1238 root 1.1 MODULE = cf PACKAGE = cf PREFIX = cf_
1239    
1240     BOOT:
1241     {
1242 root 1.116 I_EVENT_API (PACKAGE); watcher_base::GEventAPI = GEventAPI;
1243     I_CORO_API (PACKAGE); coroapi::GCoroAPI = GCoroAPI;
1244 root 1.80
1245 root 1.189 _connect_to_perl ();
1246    
1247 root 1.109 newCONSTSUB (stash_cf, "VERSION", newSVpv (VERSION, sizeof (VERSION) - 1));
1248 root 1.63
1249 root 1.220 //{
1250     // require_pv ("Time::HiRes");
1251     //
1252     // SV **svp = hv_fetch (PL_modglobal, "Time::NVtime", 12, 0);
1253     // if (!svp) croak ("Time::HiRes is required");
1254     // if (!SvIOK(*svp)) croak ("Time::NVtime isn’t a function pointer");
1255     // coroapi::time = INT2PTR (double(*)(), SvIV(*svp));
1256     //}
1257 root 1.189
1258 root 1.1 static const struct {
1259     const char *name;
1260     IV iv;
1261     } *civ, const_iv[] = {
1262     # define const_iv(name) { # name, (IV)name },
1263 root 1.189 const_iv (llevError) const_iv (llevInfo) const_iv (llevDebug) const_iv (llevMonster)
1264 root 1.198 const_iv (logBacktrace)
1265 root 1.180
1266 root 1.189 const_iv (Map0Cmd) const_iv (Map1Cmd) const_iv (Map1aCmd)
1267    
1268     const_iv (MAP_CLIENT_X) const_iv (MAP_CLIENT_Y)
1269 root 1.180
1270 root 1.5 const_iv (MAX_TIME)
1271 root 1.258 const_iv (MAXSOCKBUF)
1272 root 1.189
1273 root 1.206 const_iv (NUM_BODY_LOCATIONS)
1274     const_iv (body_range) const_iv (body_shield) const_iv (body_combat)
1275     const_iv (body_arm) const_iv (body_torso) const_iv (body_head)
1276     const_iv (body_neck) const_iv (body_skill) const_iv (body_finger)
1277     const_iv (body_shoulder) const_iv (body_foot) const_iv (body_hand)
1278     const_iv (body_wrist) const_iv (body_waist)
1279 root 1.205
1280 root 1.189 const_iv (PLAYER) const_iv (TRANSPORT) const_iv (ROD) const_iv (TREASURE)
1281     const_iv (POTION) const_iv (FOOD) const_iv (POISON) const_iv (BOOK)
1282     const_iv (CLOCK) const_iv (ARROW) const_iv (BOW) const_iv (WEAPON)
1283     const_iv (ARMOUR) const_iv (PEDESTAL) const_iv (ALTAR) const_iv (LOCKED_DOOR)
1284     const_iv (SPECIAL_KEY) const_iv (MAP) const_iv (DOOR) const_iv (KEY)
1285     const_iv (TIMED_GATE) const_iv (TRIGGER) const_iv (GRIMREAPER) const_iv (MAGIC_EAR)
1286     const_iv (TRIGGER_BUTTON) const_iv (TRIGGER_ALTAR) const_iv (TRIGGER_PEDESTAL) const_iv (SHIELD)
1287     const_iv (HELMET) const_iv (HORN) const_iv (MONEY) const_iv (CLASS)
1288     const_iv (GRAVESTONE) const_iv (AMULET) const_iv (PLAYERMOVER) const_iv (TELEPORTER)
1289     const_iv (CREATOR) const_iv (SKILL) const_iv (EARTHWALL) const_iv (GOLEM)
1290     const_iv (THROWN_OBJ) const_iv (BLINDNESS) const_iv (GOD) const_iv (DETECTOR)
1291     const_iv (TRIGGER_MARKER) const_iv (DEAD_OBJECT) const_iv (DRINK) const_iv (MARKER)
1292     const_iv (HOLY_ALTAR) const_iv (PLAYER_CHANGER) const_iv (BATTLEGROUND) const_iv (PEACEMAKER)
1293     const_iv (GEM) const_iv (FIREWALL) const_iv (ANVIL) const_iv (CHECK_INV)
1294     const_iv (MOOD_FLOOR) const_iv (EXIT) const_iv (ENCOUNTER) const_iv (SHOP_FLOOR)
1295     const_iv (SHOP_MAT) const_iv (RING) const_iv (FLOOR) const_iv (FLESH)
1296     const_iv (INORGANIC) const_iv (SKILL_TOOL) const_iv (LIGHTER) const_iv (BUILDABLE_WALL)
1297     const_iv (MISC_OBJECT) const_iv (LAMP) const_iv (DUPLICATOR) const_iv (SPELLBOOK)
1298     const_iv (CLOAK) const_iv (SPINNER) const_iv (GATE) const_iv (BUTTON)
1299     const_iv (CF_HANDLE) const_iv (HOLE) const_iv (TRAPDOOR) const_iv (SIGN)
1300     const_iv (BOOTS) const_iv (GLOVES) const_iv (SPELL) const_iv (SPELL_EFFECT)
1301     const_iv (CONVERTER) const_iv (BRACERS) const_iv (POISONING) const_iv (SAVEBED)
1302     const_iv (WAND) const_iv (SCROLL) const_iv (DIRECTOR) const_iv (GIRDLE)
1303     const_iv (FORCE) const_iv (POTION_EFFECT) const_iv (EVENT_CONNECTOR) const_iv (CLOSE_CON)
1304     const_iv (CONTAINER) const_iv (ARMOUR_IMPROVER) const_iv (WEAPON_IMPROVER) const_iv (SKILLSCROLL)
1305     const_iv (DEEP_SWAMP) const_iv (IDENTIFY_ALTAR) const_iv (MENU) const_iv (RUNE)
1306     const_iv (TRAP) const_iv (POWER_CRYSTAL) const_iv (CORPSE) const_iv (DISEASE)
1307     const_iv (SYMPTOM) const_iv (BUILDER) const_iv (MATERIAL) const_iv (ITEM_TRANSFORMER)
1308 root 1.1
1309 root 1.210 const_iv (NUM_TYPES) const_iv (NUM_SUBTYPES)
1310 root 1.14
1311 root 1.189 const_iv (ST_BD_BUILD) const_iv (ST_BD_REMOVE)
1312     const_iv (ST_MAT_FLOOR) const_iv (ST_MAT_WALL) const_iv (ST_MAT_ITEM)
1313 root 1.1
1314 root 1.189 const_iv (AT_PHYSICAL) const_iv (AT_MAGIC) const_iv (AT_FIRE) const_iv (AT_ELECTRICITY)
1315     const_iv (AT_COLD) const_iv (AT_CONFUSION) const_iv (AT_ACID) const_iv (AT_DRAIN)
1316     const_iv (AT_WEAPONMAGIC) const_iv (AT_GHOSTHIT) const_iv (AT_POISON) const_iv (AT_SLOW)
1317     const_iv (AT_PARALYZE) const_iv (AT_TURN_UNDEAD) const_iv (AT_FEAR) const_iv (AT_CANCELLATION)
1318     const_iv (AT_DEPLETE) const_iv (AT_DEATH) const_iv (AT_CHAOS) const_iv (AT_COUNTERSPELL)
1319     const_iv (AT_GODPOWER) const_iv (AT_HOLYWORD) const_iv (AT_BLIND) const_iv (AT_INTERNAL)
1320     const_iv (AT_LIFE_STEALING) const_iv (AT_DISEASE)
1321    
1322     const_iv (WEAP_HIT) const_iv (WEAP_SLASH) const_iv (WEAP_PIERCE) const_iv (WEAP_CLEAVE)
1323     const_iv (WEAP_SLICE) const_iv (WEAP_STAB) const_iv (WEAP_WHIP) const_iv (WEAP_CRUSH)
1324 root 1.1 const_iv (WEAP_BLUD)
1325    
1326 root 1.189 const_iv (FLAG_ALIVE) const_iv (FLAG_WIZ) const_iv (FLAG_REMOVED) const_iv (FLAG_FREED)
1327 root 1.209 const_iv (FLAG_APPLIED) const_iv (FLAG_UNPAID) const_iv (FLAG_USE_SHIELD)
1328 root 1.189 const_iv (FLAG_NO_PICK) const_iv (FLAG_ANIMATE) const_iv (FLAG_MONSTER) const_iv (FLAG_FRIENDLY)
1329     const_iv (FLAG_GENERATOR) const_iv (FLAG_IS_THROWN) const_iv (FLAG_AUTO_APPLY) const_iv (FLAG_PLAYER_SOLD)
1330     const_iv (FLAG_SEE_INVISIBLE) const_iv (FLAG_CAN_ROLL) const_iv (FLAG_OVERLAY_FLOOR) const_iv (FLAG_IS_TURNABLE)
1331     const_iv (FLAG_IS_USED_UP) const_iv (FLAG_IDENTIFIED) const_iv (FLAG_REFLECTING) const_iv (FLAG_CHANGING)
1332     const_iv (FLAG_SPLITTING) const_iv (FLAG_HITBACK) const_iv (FLAG_STARTEQUIP) const_iv (FLAG_BLOCKSVIEW)
1333     const_iv (FLAG_UNDEAD) const_iv (FLAG_SCARED) const_iv (FLAG_UNAGGRESSIVE) const_iv (FLAG_REFL_MISSILE)
1334     const_iv (FLAG_REFL_SPELL) const_iv (FLAG_NO_MAGIC) const_iv (FLAG_NO_FIX_PLAYER) const_iv (FLAG_IS_LIGHTABLE)
1335     const_iv (FLAG_TEAR_DOWN) const_iv (FLAG_RUN_AWAY) const_iv (FLAG_PICK_UP) const_iv (FLAG_UNIQUE)
1336     const_iv (FLAG_NO_DROP) const_iv (FLAG_WIZCAST) const_iv (FLAG_CAST_SPELL) const_iv (FLAG_USE_SCROLL)
1337     const_iv (FLAG_USE_RANGE) const_iv (FLAG_USE_BOW) const_iv (FLAG_USE_ARMOUR) const_iv (FLAG_USE_WEAPON)
1338     const_iv (FLAG_USE_RING) const_iv (FLAG_READY_RANGE) const_iv (FLAG_READY_BOW) const_iv (FLAG_XRAYS)
1339     const_iv (FLAG_NO_APPLY) const_iv (FLAG_IS_FLOOR) const_iv (FLAG_LIFESAVE) const_iv (FLAG_NO_STRENGTH)
1340     const_iv (FLAG_SLEEP) const_iv (FLAG_STAND_STILL) const_iv (FLAG_RANDOM_MOVE) const_iv (FLAG_ONLY_ATTACK)
1341     const_iv (FLAG_CONFUSED) const_iv (FLAG_STEALTH) const_iv (FLAG_WIZPASS) const_iv (FLAG_IS_LINKED)
1342     const_iv (FLAG_CURSED) const_iv (FLAG_DAMNED) const_iv (FLAG_SEE_ANYWHERE) const_iv (FLAG_KNOWN_MAGICAL)
1343     const_iv (FLAG_KNOWN_CURSED) const_iv (FLAG_CAN_USE_SKILL) const_iv (FLAG_BEEN_APPLIED) const_iv (FLAG_READY_SCROLL)
1344     const_iv (FLAG_USE_ROD) const_iv (FLAG_USE_HORN) const_iv (FLAG_MAKE_INVIS) const_iv (FLAG_INV_LOCKED)
1345     const_iv (FLAG_IS_WOODED) const_iv (FLAG_IS_HILLY) const_iv (FLAG_READY_SKILL) const_iv (FLAG_READY_WEAPON)
1346     const_iv (FLAG_NO_SKILL_IDENT) const_iv (FLAG_BLIND) const_iv (FLAG_SEE_IN_DARK) const_iv (FLAG_IS_CAULDRON)
1347     const_iv (FLAG_NO_STEAL) const_iv (FLAG_ONE_HIT) const_iv (FLAG_CLIENT_SENT) const_iv (FLAG_BERSERK)
1348     const_iv (FLAG_NEUTRAL) const_iv (FLAG_NO_ATTACK) const_iv (FLAG_NO_DAMAGE) const_iv (FLAG_OBJ_ORIGINAL)
1349 root 1.245 const_iv (FLAG_ACTIVATE_ON_PUSH) const_iv (FLAG_ACTIVATE_ON_RELEASE) const_iv (FLAG_IS_WATER)
1350 root 1.189 const_iv (FLAG_CONTENT_ON_GEN) const_iv (FLAG_IS_A_TEMPLATE) const_iv (FLAG_IS_BUILDABLE)
1351     const_iv (FLAG_DESTROY_ON_DEATH) const_iv (FLAG_NO_MAP_SAVE)
1352    
1353     const_iv (NDI_BLACK) const_iv (NDI_WHITE) const_iv (NDI_NAVY) const_iv (NDI_RED)
1354     const_iv (NDI_ORANGE) const_iv (NDI_BLUE) const_iv (NDI_DK_ORANGE) const_iv (NDI_GREEN)
1355     const_iv (NDI_LT_GREEN) const_iv (NDI_GREY) const_iv (NDI_BROWN) const_iv (NDI_GOLD)
1356     const_iv (NDI_TAN) const_iv (NDI_MAX_COLOR) const_iv (NDI_COLOR_MASK) const_iv (NDI_UNIQUE)
1357 root 1.241 const_iv (NDI_ALL) const_iv (NDI_DEF) const_iv (NDI_REPLY) const_iv (NDI_CLIENT_MASK)
1358 root 1.250 const_iv (NDI_NOCREATE) const_iv (NDI_CLEAR)
1359 root 1.1
1360 root 1.189 const_iv (UPD_LOCATION) const_iv (UPD_FLAGS) const_iv (UPD_WEIGHT) const_iv (UPD_FACE)
1361     const_iv (UPD_NAME) const_iv (UPD_ANIM) const_iv (UPD_ANIMSPEED) const_iv (UPD_NROF)
1362    
1363     const_iv (UPD_SP_MANA) const_iv (UPD_SP_GRACE) const_iv (UPD_SP_DAMAGE)
1364    
1365 root 1.212 const_iv (SP_RAISE_DEAD)
1366     const_iv (SP_RUNE)
1367     const_iv (SP_MAKE_MARK)
1368     const_iv (SP_BOLT)
1369     const_iv (SP_BULLET)
1370     const_iv (SP_EXPLOSION)
1371     const_iv (SP_CONE)
1372     const_iv (SP_BOMB)
1373     const_iv (SP_WONDER)
1374     const_iv (SP_SMITE)
1375     const_iv (SP_MAGIC_MISSILE)
1376     const_iv (SP_SUMMON_GOLEM)
1377     const_iv (SP_DIMENSION_DOOR)
1378     const_iv (SP_MAGIC_MAPPING)
1379     const_iv (SP_MAGIC_WALL)
1380     const_iv (SP_DESTRUCTION)
1381     const_iv (SP_PERCEIVE_SELF)
1382     const_iv (SP_WORD_OF_RECALL)
1383     const_iv (SP_INVISIBLE)
1384     const_iv (SP_PROBE)
1385     const_iv (SP_HEALING)
1386     const_iv (SP_CREATE_FOOD)
1387     const_iv (SP_EARTH_TO_DUST)
1388     const_iv (SP_CHANGE_ABILITY)
1389     const_iv (SP_BLESS)
1390     const_iv (SP_CURSE)
1391     const_iv (SP_SUMMON_MONSTER)
1392     const_iv (SP_CHARGING)
1393     const_iv (SP_POLYMORPH)
1394     const_iv (SP_ALCHEMY)
1395     const_iv (SP_REMOVE_CURSE)
1396     const_iv (SP_IDENTIFY)
1397     const_iv (SP_DETECTION)
1398     const_iv (SP_MOOD_CHANGE)
1399     const_iv (SP_MOVING_BALL)
1400     const_iv (SP_SWARM)
1401     const_iv (SP_CHANGE_MANA)
1402     const_iv (SP_DISPEL_RUNE)
1403     const_iv (SP_CREATE_MISSILE)
1404     const_iv (SP_CONSECRATE)
1405     const_iv (SP_ANIMATE_WEAPON)
1406     const_iv (SP_LIGHT)
1407     const_iv (SP_CHANGE_MAP_LIGHT)
1408     const_iv (SP_FAERY_FIRE)
1409     const_iv (SP_CAUSE_DISEASE)
1410     const_iv (SP_AURA)
1411     const_iv (SP_TOWN_PORTAL)
1412     const_iv (SP_PARTY_SPELL)
1413    
1414 root 1.189 const_iv (F_APPLIED) const_iv (F_LOCATION) const_iv (F_UNPAID) const_iv (F_MAGIC)
1415     const_iv (F_CURSED) const_iv (F_DAMNED) const_iv (F_OPEN) const_iv (F_NOPICK)
1416 root 1.1 const_iv (F_LOCKED)
1417    
1418 root 1.189 const_iv (F_BUY) const_iv (F_SHOP) const_iv (F_SELL)
1419    
1420     const_iv (P_BLOCKSVIEW) const_iv (P_PLAYER) const_iv (P_NO_MAGIC) const_iv (P_IS_ALIVE)
1421     const_iv (P_NO_CLERIC) const_iv (P_OUT_OF_MAP) const_iv (P_NEW_MAP) const_iv (P_UPTODATE)
1422    
1423     const_iv (UP_OBJ_INSERT) const_iv (UP_OBJ_REMOVE) const_iv (UP_OBJ_CHANGE) const_iv (UP_OBJ_FACE)
1424    
1425     const_iv (INS_NO_MERGE) const_iv (INS_ABOVE_FLOOR_ONLY) const_iv (INS_NO_WALK_ON)
1426 root 1.258 const_iv (INS_ON_TOP) const_iv (INS_BELOW_ORIGINATOR)
1427 root 1.189
1428     const_iv (WILL_APPLY_HANDLE) const_iv (WILL_APPLY_TREASURE) const_iv (WILL_APPLY_EARTHWALL)
1429     const_iv (WILL_APPLY_DOOR) const_iv (WILL_APPLY_FOOD)
1430    
1431     const_iv (SAVE_MODE) const_iv (SAVE_DIR_MODE)
1432    
1433     const_iv (M_PAPER) const_iv (M_IRON) const_iv (M_GLASS) const_iv (M_LEATHER)
1434     const_iv (M_WOOD) const_iv (M_ORGANIC) const_iv (M_STONE) const_iv (M_CLOTH)
1435     const_iv (M_ADAMANT) const_iv (M_LIQUID) const_iv (M_SOFT_METAL) const_iv (M_BONE)
1436     const_iv (M_ICE) const_iv (M_SPECIAL)
1437    
1438     const_iv (SK_EXP_ADD_SKILL) const_iv (SK_EXP_TOTAL) const_iv (SK_EXP_NONE)
1439     const_iv (SK_SUBTRACT_SKILL_EXP) const_iv (SK_EXP_SKILL_ONLY)
1440    
1441     const_iv (SK_LOCKPICKING) const_iv (SK_HIDING) const_iv (SK_SMITHERY) const_iv (SK_BOWYER)
1442     const_iv (SK_JEWELER) const_iv (SK_ALCHEMY) const_iv (SK_STEALING) const_iv (SK_LITERACY)
1443     const_iv (SK_BARGAINING) const_iv (SK_JUMPING) const_iv (SK_DET_MAGIC) const_iv (SK_ORATORY)
1444     const_iv (SK_SINGING) const_iv (SK_DET_CURSE) const_iv (SK_FIND_TRAPS) const_iv (SK_MEDITATION)
1445     const_iv (SK_PUNCHING) const_iv (SK_FLAME_TOUCH) const_iv (SK_KARATE) const_iv (SK_CLIMBING)
1446     const_iv (SK_WOODSMAN) const_iv (SK_INSCRIPTION) const_iv (SK_ONE_HANDED_WEAPON) const_iv (SK_MISSILE_WEAPON)
1447     const_iv (SK_THROWING) const_iv (SK_USE_MAGIC_ITEM) const_iv (SK_DISARM_TRAPS) const_iv (SK_SET_TRAP)
1448     const_iv (SK_THAUMATURGY) const_iv (SK_PRAYING) const_iv (SK_CLAWING) const_iv (SK_LEVITATION)
1449     const_iv (SK_SUMMONING) const_iv (SK_PYROMANCY) const_iv (SK_EVOCATION) const_iv (SK_SORCERY)
1450     const_iv (SK_TWO_HANDED_WEAPON) const_iv (SK_SPARK_TOUCH) const_iv (SK_SHIVER) const_iv (SK_ACID_SPLASH)
1451 root 1.1 const_iv (SK_POISON_NAIL)
1452    
1453 root 1.189 const_iv (SOUND_NEW_PLAYER) const_iv (SOUND_FIRE_ARROW) const_iv (SOUND_LEARN_SPELL) const_iv (SOUND_FUMBLE_SPELL)
1454     const_iv (SOUND_WAND_POOF) const_iv (SOUND_OPEN_DOOR) const_iv (SOUND_PUSH_PLAYER) const_iv (SOUND_PLAYER_HITS1)
1455     const_iv (SOUND_PLAYER_HITS2) const_iv (SOUND_PLAYER_HITS3) const_iv (SOUND_PLAYER_HITS4) const_iv (SOUND_PLAYER_IS_HIT1)
1456     const_iv (SOUND_PLAYER_IS_HIT2) const_iv (SOUND_PLAYER_IS_HIT3) const_iv (SOUND_PLAYER_KILLS) const_iv (SOUND_PET_IS_KILLED)
1457     const_iv (SOUND_PLAYER_DIES) const_iv (SOUND_OB_EVAPORATE) const_iv (SOUND_OB_EXPLODE) const_iv (SOUND_CLOCK)
1458     const_iv (SOUND_TURN_HANDLE) const_iv (SOUND_FALL_HOLE) const_iv (SOUND_DRINK_POISON) const_iv (SOUND_CAST_SPELL_0)
1459    
1460     const_iv (PREFER_LOW) const_iv (PREFER_HIGH)
1461    
1462     const_iv (ATNR_PHYSICAL) const_iv (ATNR_MAGIC) const_iv (ATNR_FIRE) const_iv (ATNR_ELECTRICITY)
1463     const_iv (ATNR_COLD) const_iv (ATNR_CONFUSION) const_iv (ATNR_ACID) const_iv (ATNR_DRAIN)
1464     const_iv (ATNR_WEAPONMAGIC) const_iv (ATNR_GHOSTHIT) const_iv (ATNR_POISON) const_iv (ATNR_SLOW)
1465     const_iv (ATNR_PARALYZE) const_iv (ATNR_TURN_UNDEAD) const_iv (ATNR_FEAR) const_iv (ATNR_CANCELLATION)
1466     const_iv (ATNR_DEPLETE) const_iv (ATNR_DEATH) const_iv (ATNR_CHAOS) const_iv (ATNR_COUNTERSPELL)
1467     const_iv (ATNR_GODPOWER) const_iv (ATNR_HOLYWORD) const_iv (ATNR_BLIND) const_iv (ATNR_INTERNAL)
1468     const_iv (ATNR_LIFE_STEALING) const_iv (ATNR_DISEASE)
1469    
1470     const_iv (MAP_IN_MEMORY) const_iv (MAP_SWAPPED) const_iv (MAP_LOADING) const_iv (MAP_SAVING)
1471    
1472     const_iv (KLASS_ATTACHABLE) const_iv (KLASS_GLOBAL) const_iv (KLASS_OBJECT)
1473     const_iv (KLASS_CLIENT) const_iv (KLASS_PLAYER) const_iv (KLASS_MAP)
1474    
1475 root 1.251 const_iv (VERSION_CS) const_iv (VERSION_SC)
1476    
1477 root 1.189 const_iv (CS_QUERY_YESNO) const_iv (CS_QUERY_SINGLECHAR) const_iv (CS_QUERY_HIDEINPUT)
1478    
1479     const_iv (ST_DEAD) const_iv (ST_SETUP) const_iv (ST_PLAYING) const_iv (ST_CUSTOM)
1480 root 1.99
1481 root 1.189 const_iv (IO_HEADER) const_iv (IO_OBJECTS) const_iv (IO_UNIQUES)
1482 root 1.117
1483     // random map generator
1484 root 1.189 const_iv (LAYOUT_NONE) const_iv (LAYOUT_ONION) const_iv (LAYOUT_MAZE) const_iv (LAYOUT_SPIRAL)
1485     const_iv (LAYOUT_ROGUELIKE) const_iv (LAYOUT_SNAKE) const_iv (LAYOUT_SQUARE_SPIRAL)
1486    
1487     const_iv (RMOPT_RANDOM) const_iv (RMOPT_CENTERED) const_iv (RMOPT_LINEAR)
1488     const_iv (RMOPT_BOTTOM_C) const_iv (RMOPT_BOTTOM_R) const_iv (RMOPT_IRR_SPACE)
1489     const_iv (RMOPT_WALL_OFF) const_iv (RMOPT_WALLS_ONLY) const_iv (RMOPT_NO_DOORS)
1490    
1491     const_iv (SYMMETRY_RANDOM) const_iv (SYMMETRY_NONE) const_iv (SYMMETRY_X)
1492     const_iv (SYMMETRY_Y) const_iv (SYMMETRY_XY)
1493 root 1.195
1494     const_iv (GT_ENVIRONMENT) const_iv (GT_INVISIBLE) const_iv (GT_STARTEQUIP)
1495     const_iv (GT_APPLY) const_iv (GT_ONLY_GOOD) const_iv (GT_UPDATE_INV)
1496     const_iv (GT_MINIMAL)
1497 root 1.238
1498     const_iv (FT_FACE) const_iv (FT_MUSIC) const_iv (FT_SOUND)
1499     const_iv (FT_RSRC) const_iv (FT_NUM)
1500 root 1.1 };
1501    
1502     for (civ = const_iv + sizeof (const_iv) / sizeof (const_iv [0]); civ-- > const_iv; )
1503 root 1.109 newCONSTSUB (stash_cf, (char *)civ->name, newSViv (civ->iv));
1504 root 1.1
1505     static const struct {
1506     const char *name;
1507 root 1.14 int skip;
1508 root 1.7 IV klass;
1509 root 1.1 IV iv;
1510 root 1.6 } *eiv, event_iv[] = {
1511 root 1.14 # define def(klass,name) { "EVENT_" # klass "_" # name, sizeof ("EVENT_" # klass), (IV)KLASS_ ## klass, (IV)EVENT_ ## klass ## _ ## name },
1512 root 1.6 # include "eventinc.h"
1513     # undef def
1514     };
1515    
1516     AV *av = get_av ("cf::EVENT", 1);
1517    
1518     for (eiv = event_iv + sizeof (event_iv) / sizeof (event_iv [0]); eiv-- > event_iv; )
1519 root 1.7 {
1520     AV *event = newAV ();
1521 root 1.14 av_push (event, newSVpv ((char *)eiv->name + eiv->skip, 0));
1522 root 1.7 av_push (event, newSViv (eiv->klass));
1523     av_store (av, eiv->iv, newRV_noinc ((SV *)event));
1524 root 1.109 newCONSTSUB (stash_cf, (char *)eiv->name, newSViv (eiv->iv));
1525 root 1.7 }
1526 root 1.14 }
1527    
1528 root 1.109 void _connect_to_perl ()
1529 root 1.14
1530 root 1.210 void _recalc_want ()
1531    
1532 root 1.47 void _global_reattach ()
1533 root 1.14 CODE:
1534     {
1535     // reattach to all attachable objects in the game.
1536 root 1.128 for_all_clients (ns)
1537     ns->reattach ();
1538 root 1.96
1539 root 1.128 for_all_objects (op)
1540 root 1.109 op->reattach ();
1541 root 1.1 }
1542    
1543 root 1.192 # support function for map-world.ext
1544     void _quantise (SV *data_sv, SV *plt_sv)
1545     CODE:
1546     {
1547     if (!SvROK (plt_sv) || SvTYPE (SvRV (plt_sv)) != SVt_PVAV)
1548     croak ("_quantise called with invalid agruments");
1549    
1550     plt_sv = SvRV (plt_sv);
1551     SV **plt = AvARRAY (plt_sv);
1552     int plt_count = AvFILL (plt_sv) + 1;
1553    
1554     STRLEN len;
1555     char *data = SvPVbyte (data_sv, len);
1556     char *dst = data;
1557    
1558     while (len >= 3)
1559     {
1560     for (SV **val_sv = plt + plt_count; val_sv-- > plt; )
1561     {
1562     char *val = SvPVX (*val_sv);
1563    
1564     if (val [0] == data [0]
1565     && val [1] == data [1]
1566     && val [2] == data [2])
1567     {
1568     *dst++ = val [3];
1569     goto next;
1570     }
1571     }
1572    
1573     croak ("_quantise: color not found in palette: #%02x%02x%02x, at offset %d %d",
1574     (uint8_t)data [0], (uint8_t)data [1], (uint8_t)data [2],
1575     dst - SvPVX (data_sv), len);
1576    
1577     next:
1578     data += 3;
1579     len -= 3;
1580     }
1581    
1582     SvCUR_set (data_sv, dst - SvPVX (data_sv));
1583     }
1584    
1585 root 1.236 void _post_tick ()
1586     CODE:
1587     coroapi::next_cede = SvNV (sv_next_tick) - TICK * (1. - 1. / CEDES_PER_TICK);
1588    
1589     NV till_cede ()
1590     CODE:
1591     RETVAL = coroapi::next_cede - now ();
1592     OUTPUT:
1593     RETVAL
1594    
1595     NV till_tick ()
1596     CODE:
1597     RETVAL = SvNV (sv_next_tick) - now ();
1598     OUTPUT:
1599     RETVAL
1600    
1601 root 1.1 NV floor (NV x)
1602    
1603     NV ceil (NV x)
1604    
1605 root 1.143 NV rndm (...)
1606     CODE:
1607     switch (items)
1608     {
1609     case 0: RETVAL = rndm (); break;
1610     case 1: RETVAL = rndm (SvUV (ST (0))); break;
1611     case 2: RETVAL = rndm (SvIV (ST (0)), SvIV (ST (1))); break;
1612     default: croak ("cf::rndm requires none, one or two parameters."); break;
1613     }
1614     OUTPUT:
1615     RETVAL
1616    
1617 root 1.207 NV clamp (NV value, NV min_value, NV max_value)
1618     CODE:
1619     RETVAL = clamp (value, min_value, max_value);
1620     OUTPUT:
1621     RETVAL
1622    
1623     NV lerp (NV value, NV min_in, NV max_in, NV min_out, NV max_out)
1624     CODE:
1625     RETVAL = lerp (value, min_in, max_in, min_out, max_out);
1626     OUTPUT:
1627     RETVAL
1628    
1629     void cede_to_tick ()
1630     CODE:
1631     coroapi::cede_to_tick ();
1632    
1633 root 1.5 void server_tick ()
1634 root 1.116 CODE:
1635 root 1.220 NOW = now ();
1636 root 1.116 runtime = SvNVx (sv_runtime);
1637     server_tick ();
1638 root 1.5
1639 root 1.1 void
1640 root 1.198 log_backtrace (utf8_string msg)
1641    
1642     void
1643     LOG (int flags, utf8_string msg)
1644 root 1.1 PROTOTYPE: $$
1645 root 1.198 C_ARGS: flags, "%s", msg
1646 root 1.1
1647 root 1.183 octet_string path_combine (octet_string base, octet_string path)
1648 root 1.1 PROTOTYPE: $$
1649    
1650 root 1.183 octet_string path_combine_and_normalize (octet_string base, octet_string path)
1651 root 1.1 PROTOTYPE: $$
1652    
1653     void
1654 root 1.259 mallinfo ()
1655     PPCODE:
1656     {
1657     #if __GLIBC__
1658     struct mallinfo mai = mallinfo ();
1659 root 1.260 EXTEND (SP, 10*2);
1660 root 1.259 PUSHs (sv_2mortal (newSVpv ("arena" , 0))); PUSHs (sv_2mortal (newSViv (mai.arena)));
1661     PUSHs (sv_2mortal (newSVpv ("ordblks" , 0))); PUSHs (sv_2mortal (newSViv (mai.ordblks)));
1662 root 1.260 PUSHs (sv_2mortal (newSVpv ("smblks" , 0))); PUSHs (sv_2mortal (newSViv (mai.smblks)));
1663 root 1.259 PUSHs (sv_2mortal (newSVpv ("hblks" , 0))); PUSHs (sv_2mortal (newSViv (mai.hblks)));
1664     PUSHs (sv_2mortal (newSVpv ("hblkhd" , 0))); PUSHs (sv_2mortal (newSViv (mai.hblkhd)));
1665 root 1.260 PUSHs (sv_2mortal (newSVpv ("usmblks" , 0))); PUSHs (sv_2mortal (newSViv (mai.usmblks)));
1666     PUSHs (sv_2mortal (newSVpv ("fsmblks" , 0))); PUSHs (sv_2mortal (newSViv (mai.fsmblks)));
1667 root 1.259 PUSHs (sv_2mortal (newSVpv ("uordblks", 0))); PUSHs (sv_2mortal (newSViv (mai.uordblks)));
1668     PUSHs (sv_2mortal (newSVpv ("fordblks", 0))); PUSHs (sv_2mortal (newSViv (mai.fordblks)));
1669     PUSHs (sv_2mortal (newSVpv ("keepcost", 0))); PUSHs (sv_2mortal (newSViv (mai.keepcost)));
1670     #endif
1671     }
1672    
1673     void
1674 root 1.1 sub_generation_inc ()
1675     CODE:
1676     PL_sub_generation++;
1677    
1678 root 1.183 const_octet_string
1679 root 1.1 mapdir ()
1680     PROTOTYPE:
1681     ALIAS:
1682     mapdir = 0
1683     uniquedir = 1
1684     tmpdir = 2
1685     confdir = 3
1686     localdir = 4
1687     playerdir = 5
1688     datadir = 6
1689     CODE:
1690 root 1.19 switch (ix)
1691     {
1692     case 0: RETVAL = settings.mapdir ; break;
1693     case 1: RETVAL = settings.uniquedir; break;
1694     case 2: RETVAL = settings.tmpdir ; break;
1695     case 3: RETVAL = settings.confdir ; break;
1696     case 4: RETVAL = settings.localdir ; break;
1697     case 5: RETVAL = settings.playerdir; break;
1698     case 6: RETVAL = settings.datadir ; break;
1699     }
1700 root 1.1 OUTPUT: RETVAL
1701    
1702 root 1.120 void abort ()
1703    
1704 root 1.199 void reset_signals ()
1705    
1706 root 1.183 void fork_abort (octet_string cause = "cf::fork_abort")
1707 root 1.144
1708 root 1.183 void cleanup (octet_string cause, bool make_core = false)
1709 root 1.134
1710 root 1.116 void emergency_save ()
1711    
1712 root 1.156 void _exit (int status = EXIT_SUCCESS)
1713    
1714 root 1.149 UV sv_2watcher (SV *w)
1715     CODE:
1716     RETVAL = (UV)GEventAPI->sv_2watcher (w);
1717     OUTPUT:
1718     RETVAL
1719    
1720 root 1.125 #if _POSIX_MEMLOCK
1721    
1722     int mlockall (int flags = MCL_CURRENT | MCL_FUTURE)
1723    
1724     int munlockall ()
1725    
1726     #endif
1727    
1728 root 1.183 int find_animation (utf8_string text)
1729 root 1.1 PROTOTYPE: $
1730    
1731 root 1.74 int random_roll (int min, int max, object *op, int goodbad);
1732 root 1.1
1733 root 1.183 const_utf8_string cost_string_from_value(uint64 cost, int approx = 0)
1734 root 1.1
1735     int
1736     exp_to_level (val64 exp)
1737     CODE:
1738     {
1739     int i = 0;
1740    
1741     RETVAL = settings.max_level;
1742    
1743     for (i = 1; i <= settings.max_level; i++)
1744     {
1745     if (levels[i] > exp)
1746     {
1747     RETVAL = i - 1;
1748     break;
1749     }
1750     }
1751     }
1752     OUTPUT: RETVAL
1753    
1754     val64
1755     level_to_min_exp (int level)
1756     CODE:
1757     if (level > settings.max_level)
1758     RETVAL = levels[settings.max_level];
1759     else if (level < 1)
1760     RETVAL = 0;
1761     else
1762     RETVAL = levels[level];
1763     OUTPUT: RETVAL
1764    
1765     SV *
1766     resistance_to_string (int atnr)
1767     CODE:
1768     if (atnr >= 0 && atnr < NROFATTACKS)
1769     RETVAL = newSVpv (resist_plus[atnr], 0);
1770     else
1771     XSRETURN_UNDEF;
1772     OUTPUT: RETVAL
1773    
1774 root 1.162 bool
1775 root 1.183 load_resource_file (octet_string filename)
1776 root 1.162
1777 root 1.97 MODULE = cf PACKAGE = cf::attachable
1778    
1779 root 1.27 int
1780 root 1.97 valid (SV *obj)
1781 root 1.27 CODE:
1782     RETVAL = SvROK (obj) && mg_find (SvRV (obj), PERL_MAGIC_ext);
1783     OUTPUT:
1784     RETVAL
1785    
1786 root 1.164 void
1787     debug_trace (attachable *obj, bool on = true)
1788     CODE:
1789     obj->flags &= ~attachable::F_DEBUG_TRACE;
1790     if (on)
1791     obj->flags |= attachable::F_DEBUG_TRACE;
1792    
1793 root 1.153 int mortals_size ()
1794     CODE:
1795     RETVAL = attachable::mortals.size ();
1796     OUTPUT: RETVAL
1797    
1798     #object *mortals (U32 index)
1799     # CODE:
1800     # RETVAL = index < attachable::mortals.size () ? attachable::mortals [index] : 0;
1801     # OUTPUT: RETVAL
1802    
1803 root 1.242 INCLUDE: $PERL $srcdir/genacc attachable ../include/util.h ../include/cfperl.h |
1804 root 1.115
1805 root 1.101 MODULE = cf PACKAGE = cf::global
1806    
1807     int invoke (SV *klass, int event, ...)
1808     CODE:
1809     if (KLASS_OF (event) != KLASS_GLOBAL) croak ("event class must be GLOBAL");
1810     AV *av = (AV *)sv_2mortal ((SV *)newAV ());
1811     for (int i = 1; i < items; i++) av_push (av, SvREFCNT_inc (ST (i)));
1812 root 1.109 RETVAL = gbl_ev.invoke ((event_type)event, ARG_AV (av), DT_END);
1813 root 1.101 OUTPUT: RETVAL
1814    
1815 root 1.1 MODULE = cf PACKAGE = cf::object PREFIX = cf_object_
1816    
1817 root 1.173 INCLUDE: $PERL $srcdir/genacc object ../include/object.h |
1818 root 1.62
1819 root 1.18 int invoke (object *op, int event, ...)
1820     CODE:
1821     if (KLASS_OF (event) != KLASS_OBJECT) croak ("event class must be OBJECT");
1822 root 1.24 AV *av = (AV *)sv_2mortal ((SV *)newAV ());
1823     for (int i = 2; i < items; i++) av_push (av, SvREFCNT_inc (ST (i)));
1824 root 1.109 RETVAL = op->invoke ((event_type)event, ARG_AV (av), DT_END);
1825 root 1.18 OUTPUT: RETVAL
1826    
1827     SV *registry (object *op)
1828    
1829 root 1.134 int objects_size ()
1830     CODE:
1831     RETVAL = objects.size ();
1832     OUTPUT: RETVAL
1833    
1834     object *objects (U32 index)
1835     CODE:
1836     RETVAL = index < objects.size () ? objects [index] : 0;
1837     OUTPUT: RETVAL
1838    
1839     int actives_size ()
1840     CODE:
1841     RETVAL = actives.size ();
1842     OUTPUT: RETVAL
1843    
1844     object *actives (U32 index)
1845 root 1.57 CODE:
1846 root 1.134 RETVAL = index < actives.size () ? actives [index] : 0;
1847 root 1.57 OUTPUT: RETVAL
1848    
1849 root 1.215 const char *slot_use_name (U32 slot)
1850 root 1.205 ALIAS:
1851 root 1.215 slot_nonuse_name = 1
1852 root 1.205 CODE:
1853     {
1854     if (slot >= NUM_BODY_LOCATIONS)
1855     croak ("body slot index out of range");
1856    
1857     switch (ix)
1858     {
1859 root 1.215 case 0: RETVAL = body_locations[slot].use_name; break;
1860     case 1: RETVAL = body_locations[slot].nonuse_name; break;
1861 root 1.205 }
1862     }
1863     OUTPUT:
1864     RETVAL
1865    
1866 root 1.1 # missing properties
1867    
1868 root 1.54 object *head (object *op)
1869     PROTOTYPE: $
1870     CODE:
1871 root 1.134 RETVAL = op->head_ ();
1872 root 1.54 OUTPUT: RETVAL
1873    
1874 root 1.1 void
1875     inv (object *obj)
1876     PROTOTYPE: $
1877     PPCODE:
1878     {
1879 root 1.254 for (object *o = obj->inv; o; o = o->below)
1880 root 1.100 XPUSHs (sv_2mortal (to_sv (o)));
1881 root 1.1 }
1882    
1883 root 1.102 void
1884     set_animation (object *op, int idx)
1885     CODE:
1886     SET_ANIMATION (op, idx);
1887    
1888 elmex 1.160 int
1889     num_animations (object *op)
1890     CODE:
1891     RETVAL = NUM_ANIMATIONS (op);
1892     OUTPUT: RETVAL
1893    
1894 root 1.205 int slot_info (object *op, UV slot, int value = 0)
1895     ALIAS:
1896     slot_used = 1
1897     CODE:
1898     {
1899     if (slot >= NUM_BODY_LOCATIONS)
1900     croak ("body slot index out of range");
1901    
1902 root 1.208 RETVAL = ix ? op->slot[slot].used : op->slot[slot].info;
1903 root 1.205
1904     if (items > 2)
1905     if (ix)
1906 root 1.208 op->slot[slot].used = value;
1907     else
1908 root 1.205 op->slot[slot].info = value;
1909     }
1910     OUTPUT:
1911     RETVAL
1912    
1913 root 1.183 object *find_best_object_match (object *op, utf8_string match)
1914 root 1.58
1915     object *find_marked_object (object *op)
1916    
1917 root 1.109 int need_identify (object *obj);
1918 root 1.1
1919     int apply_shop_mat (object *shop_mat, object *op);
1920    
1921 root 1.27 int move (object *op, int dir, object *originator = op)
1922     CODE:
1923     RETVAL = move_ob (op, dir, originator);
1924     OUTPUT:
1925     RETVAL
1926 root 1.1
1927 root 1.74 void apply (object *applier, object *applied, int flags = 0)
1928     CODE:
1929     manual_apply (applied, applier, flags);
1930 root 1.1
1931 root 1.74 void apply_below (object *op)
1932     CODE:
1933     player_apply_below (op);
1934 root 1.1
1935 root 1.167 int cast_heal (object *op, object *caster, object *spell, int dir = 0)
1936    
1937 root 1.116 #//TODO
1938     object *clone_ (object *op, int recursive = 0)
1939 root 1.74 CODE:
1940     if (recursive)
1941     RETVAL = object_create_clone (op);
1942     else
1943     {
1944     RETVAL = object::create ();
1945 root 1.75 op->copy_to (RETVAL);
1946 root 1.74 }
1947     OUTPUT: RETVAL
1948 root 1.1
1949 root 1.74 int pay_item (object *op, object *buyer)
1950     CODE:
1951     RETVAL = pay_for_item (op, buyer);
1952     OUTPUT: RETVAL
1953 root 1.1
1954 root 1.74 int pay_amount (object *op, uint64 amount)
1955     CODE:
1956     RETVAL = pay_for_amount (amount, op);
1957     OUTPUT: RETVAL
1958 root 1.1
1959     void pay_player (object *op, uint64 amount)
1960    
1961 root 1.183 val64 pay_player_arch (object *op, utf8_string arch, uint64 amount)
1962 root 1.1
1963 root 1.183 int cast_spell (object *op, object *caster, int dir, object *spell_ob, utf8_string stringarg = 0)
1964 root 1.1
1965 root 1.74 void learn_spell (object *op, object *sp, int special_prayer = 0)
1966     CODE:
1967     do_learn_spell (op, sp, special_prayer);
1968 root 1.1
1969 root 1.74 void forget_spell (object *op, object *sp)
1970     CODE:
1971     do_forget_spell (op, query_name (sp));
1972 root 1.1
1973 root 1.183 object *check_for_spell (object *op, utf8_string spellname)
1974 root 1.74 CODE:
1975     RETVAL = check_spell_known (op, spellname);
1976     OUTPUT: RETVAL
1977 root 1.1
1978 root 1.74 int query_money (object *op)
1979 root 1.1 ALIAS: money = 0
1980    
1981 elmex 1.108 val64 query_cost (object *op, object *who, int flags)
1982 root 1.1 ALIAS: cost = 0
1983    
1984 root 1.74 void spring_trap (object *op, object *victim)
1985 root 1.1
1986 root 1.74 int check_trigger (object *op, object *cause)
1987 root 1.1
1988 root 1.74 void drop (object *who, object *op)
1989 root 1.1
1990 root 1.74 void pick_up (object *who, object *op)
1991 root 1.1
1992 root 1.102 void update_object (object *op, int action)
1993 root 1.1
1994 root 1.183 void change_exp (object *op, uint64 exp, utf8_string skill_name = 0, int flag = 0)
1995 root 1.1
1996     void player_lvl_adj (object *who, object *skill = 0)
1997    
1998     int kill_object (object *op, int dam = 0, object *hitter = 0, int type = AT_PHYSICAL)
1999    
2000     int calc_skill_exp (object *who, object *op, object *skill);
2001    
2002     void push_button (object *op);
2003    
2004     void use_trigger (object *op);
2005    
2006 root 1.61 void add_button_link (object *button, maptile *map, int connected);
2007 root 1.1
2008     void remove_button_link (object *op);
2009    
2010 elmex 1.232 void handle_apply_yield (object *op);
2011    
2012 root 1.1
2013     MODULE = cf PACKAGE = cf::object PREFIX = cf_
2014    
2015     # no clean way to get an object from an archetype - stupid idiotic
2016     # dumb kludgy misdesigned plug-in api slowly gets on my nerves.
2017    
2018 root 1.183 object *new (utf8_string archetype = 0)
2019 root 1.1 PROTOTYPE: ;$
2020     CODE:
2021 elmex 1.219 RETVAL = archetype ? get_archetype (archetype) : object::create ();
2022 root 1.1 OUTPUT:
2023     RETVAL
2024    
2025 root 1.225 object *find_object (U32 tag)
2026    
2027 root 1.218 # TODO: nuke
2028 root 1.61 object *insert_ob_in_map_at (object *ob, maptile *where, object_ornull *orig, int flag, int x, int y)
2029 root 1.1 PROTOTYPE: $$$$$$
2030     CODE:
2031     {
2032 root 1.257 RETVAL = insert_ob_in_map_at (ob, where, orig, flag, x, y);
2033 root 1.1 }
2034    
2035 root 1.183 const_utf8_string get_ob_key_value (object *op, utf8_string key)
2036 root 1.1
2037 root 1.183 bool set_ob_key_value (object *op, utf8_string key, utf8_string value = 0, int add_key = 1)
2038 root 1.1
2039     object *get_nearest_player (object *ob)
2040     ALIAS: nearest_player = 0
2041     PREINIT:
2042     extern object *get_nearest_player (object *);
2043    
2044     void rangevector (object *ob, object *other, int flags = 0)
2045     PROTOTYPE: $$;$
2046     PPCODE:
2047     {
2048     rv_vector rv;
2049     get_rangevector (ob, other, &rv, flags);
2050     EXTEND (SP, 5);
2051     PUSHs (newSVuv (rv.distance));
2052     PUSHs (newSViv (rv.distance_x));
2053     PUSHs (newSViv (rv.distance_y));
2054     PUSHs (newSViv (rv.direction));
2055 root 1.257 PUSHs (to_sv (rv.part));
2056 root 1.1 }
2057    
2058     bool on_same_map_as (object *ob, object *other)
2059     CODE:
2060     RETVAL = on_same_map (ob, other);
2061     OUTPUT: RETVAL
2062    
2063 root 1.183 const_utf8_string
2064 root 1.58 base_name (object *op, int plural = op->nrof > 1)
2065 root 1.1 CODE:
2066 root 1.58 RETVAL = query_base_name (op, plural);
2067 root 1.1 OUTPUT: RETVAL
2068    
2069 elmex 1.86 object *decrease_ob_nr (object *op, unsigned long i)
2070    
2071 root 1.256 # return the tail of an object, excluding itself
2072     void
2073     tail (object *op)
2074     PPCODE:
2075     while ((op = op->more))
2076     XPUSHs (sv_2mortal (to_sv (op)));
2077    
2078 root 1.1 MODULE = cf PACKAGE = cf::object::player PREFIX = cf_player_
2079    
2080     player *player (object *op)
2081     CODE:
2082     RETVAL = op->contr;
2083     OUTPUT: RETVAL
2084    
2085 root 1.257 bool move_player (object *op, int dir)
2086    
2087 root 1.105 void check_score (object *op)
2088    
2089 root 1.183 void message (object *op, utf8_string txt, int flags = NDI_ORANGE | NDI_UNIQUE)
2090 root 1.120 CODE:
2091     new_draw_info (flags, 0, op, txt);
2092 root 1.1
2093     void kill_player (object *op)
2094    
2095 root 1.257 void esrv_send_item (object *pl, object *item)
2096    
2097     void esrv_update_item (object *pl, int what, object *item)
2098     C_ARGS: what, pl, item
2099    
2100     void esrv_del_item (object *pl, int tag)
2101     C_ARGS: pl->contr, tag
2102 root 1.58
2103 root 1.183 int command_summon (object *op, utf8_string params)
2104 root 1.67
2105 root 1.183 int command_arrest (object *op, utf8_string params)
2106 root 1.67
2107 root 1.66
2108 root 1.12 MODULE = cf PACKAGE = cf::player PREFIX = cf_player_
2109 root 1.1
2110 root 1.173 INCLUDE: $PERL $srcdir/genacc player ../include/player.h |
2111 root 1.62
2112 root 1.18 int invoke (player *pl, int event, ...)
2113     CODE:
2114     if (KLASS_OF (event) != KLASS_PLAYER) croak ("event class must be PLAYER");
2115 root 1.24 AV *av = (AV *)sv_2mortal ((SV *)newAV ());
2116     for (int i = 2; i < items; i++) av_push (av, SvREFCNT_inc (ST (i)));
2117 root 1.109 RETVAL = pl->invoke ((event_type)event, ARG_AV (av), DT_END);
2118 root 1.18 OUTPUT: RETVAL
2119    
2120 root 1.12 SV *registry (player *pl)
2121 root 1.1
2122 root 1.102 void
2123     save_stats (player *pl)
2124     CODE:
2125     pl->ob->stats.hp = pl->ob->stats.maxhp;
2126     pl->ob->stats.sp = pl->ob->stats.maxsp;
2127     pl->ob->stats.grace = pl->ob->stats.maxgrace;
2128     pl->orig_stats = pl->ob->stats;
2129    
2130 root 1.217 void clear_los (player *pl)
2131    
2132 root 1.1 bool
2133     cell_visible (player *pl, int dx, int dy)
2134     CODE:
2135 root 1.98 RETVAL = FABS (dx) <= pl->ns->mapx / 2 && FABS (dy) <= pl->ns->mapy / 2
2136     && !pl->blocked_los [dx + pl->ns->mapx / 2][dy + pl->ns->mapy / 2];
2137 root 1.1 OUTPUT:
2138     RETVAL
2139    
2140 root 1.4 void
2141 root 1.1 send (player *pl, SV *packet)
2142     CODE:
2143     {
2144     STRLEN len;
2145     char *buf = SvPVbyte (packet, len);
2146    
2147 root 1.258 if (len > MAXSOCKBUF)
2148     pl->failmsg ("[packet too long for client]");
2149     else if (pl->ns)
2150 root 1.100 pl->ns->send_packet (buf, len);
2151 root 1.1 }
2152    
2153     int
2154     listening (player *pl, int new_value = -1)
2155     CODE:
2156     RETVAL = pl->listening;
2157     if (new_value >= 0)
2158     pl->listening = new_value;
2159     OUTPUT:
2160     RETVAL
2161    
2162 root 1.46 void savebed (player *pl, SV *map_path = 0, SV *x = 0, SV *y = 0)
2163 root 1.45 PROTOTYPE: $;$$$
2164 root 1.1 PPCODE:
2165 root 1.45 if (GIMME_V != G_VOID)
2166     {
2167     EXTEND (SP, 3);
2168     PUSHs (sv_2mortal (newSVpv (pl->savebed_map, 0)));
2169     PUSHs (sv_2mortal (newSViv (pl->bed_x)));
2170     PUSHs (sv_2mortal (newSViv (pl->bed_y)));
2171     }
2172 root 1.46 if (map_path) sv_to (map_path, pl->savebed_map);
2173     if (x) sv_to (x, pl->bed_x);
2174     if (y) sv_to (y, pl->bed_y);
2175 root 1.1
2176     void
2177     list ()
2178     PPCODE:
2179 root 1.128 for_all_players (pl)
2180 root 1.100 XPUSHs (sv_2mortal (to_sv (pl)));
2181 root 1.1
2182    
2183     MODULE = cf PACKAGE = cf::map PREFIX = cf_map_
2184    
2185 root 1.61 int invoke (maptile *map, int event, ...)
2186 root 1.18 CODE:
2187     if (KLASS_OF (event) != KLASS_MAP) croak ("event class must be MAP");
2188 root 1.24 AV *av = (AV *)sv_2mortal ((SV *)newAV ());
2189     for (int i = 2; i < items; i++) av_push (av, SvREFCNT_inc (ST (i)));
2190 root 1.109 RETVAL = map->invoke ((event_type)event, ARG_AV (av), DT_END);
2191 root 1.25 OUTPUT: RETVAL
2192 root 1.18
2193 root 1.61 SV *registry (maptile *map)
2194 root 1.12
2195 root 1.255 void
2196     find_tagged_objects (maptile *map, utf8_string tag = 0)
2197     PPCODE:
2198     {
2199     if (!map->spaces)
2200     XSRETURN_EMPTY;
2201    
2202     if (tag)
2203     {
2204     shstr_cmp tag_ (tag);
2205    
2206     for (mapspace *ms = map->spaces + map->size (); ms-- > map->spaces; )
2207     for (object *op = ms->bot; op; op = op->above)
2208     if (op->tag == tag_)
2209     XPUSHs (sv_2mortal (to_sv (op)));
2210     }
2211     else
2212     {
2213     for (mapspace *ms = map->spaces + map->size (); ms-- > map->spaces; )
2214     for (object *op = ms->bot; op; op = op->above)
2215     if (op->tag)
2216     XPUSHs (sv_2mortal (to_sv (op)));
2217     }
2218     }
2219    
2220 root 1.173 INCLUDE: $PERL $srcdir/genacc maptile ../include/map.h |
2221 root 1.1
2222 root 1.116 void
2223     maptile::instantiate ()
2224    
2225     maptile *new ()
2226 root 1.1 PROTOTYPE:
2227     CODE:
2228 root 1.116 RETVAL = new maptile;
2229 root 1.1 OUTPUT:
2230     RETVAL
2231    
2232 root 1.116 void
2233 root 1.117 maptile::players ()
2234     PPCODE:
2235     if (GIMME_V == G_SCALAR)
2236 root 1.118 XPUSHs (sv_2mortal (to_sv (THIS->players)));
2237 root 1.117 else if (GIMME_V == G_ARRAY)
2238     {
2239     EXTEND (SP, THIS->players);
2240     for_all_players (pl)
2241     if (pl->ob && pl->ob->map == THIS)
2242 root 1.118 PUSHs (sv_2mortal (to_sv (pl->ob)));
2243 root 1.117 }
2244    
2245 root 1.156 void
2246 root 1.168 maptile::add_underlay (SV *data, int offset, int stride, SV *palette)
2247 root 1.156 CODE:
2248     {
2249 root 1.168 if (!SvROK (palette) || SvTYPE (SvRV (palette)) != SVt_PVAV)
2250     croak ("maptile::add_underlay: palette must be arrayref");
2251 root 1.156
2252 root 1.168 palette = SvRV (palette);
2253 root 1.156
2254 root 1.168 STRLEN idxlen;
2255     const uint8_t *idx = (const uint8_t *)SvPVbyte (data, idxlen);
2256 root 1.156
2257 root 1.168 for (int x = 0; x < THIS->width; ++x)
2258     for (int y = 0; y < THIS->height; ++y)
2259     {
2260     for (object *op = THIS->at (x, y).bot; op; op = op->above)
2261     if (op->flag [FLAG_IS_FLOOR])
2262     goto skip_space;
2263    
2264     {
2265     int offs = offset + y * stride + x;
2266     if (IN_RANGE_EXC (offs, 0, idxlen))
2267     {
2268     if (SV **elem = av_fetch ((AV *)palette, idx [offs], 0))
2269     {
2270     object *ob = get_archetype (SvPVutf8_nolen (*elem));
2271     ob->flag [FLAG_NO_MAP_SAVE] = true;
2272     THIS->insert (ob, x, y, 0, INS_ABOVE_FLOOR_ONLY);
2273 root 1.200
2274     if (ob->randomitems)
2275     {
2276 root 1.203 if (!ob->above)
2277     {
2278     ob->create_treasure (ob->randomitems);
2279    
2280     for (object *op = ob->above; op; op = op->above)
2281     op->flag [FLAG_NO_MAP_SAVE] = true;
2282     }
2283    
2284 root 1.200 ob->randomitems = 0;
2285     }
2286 root 1.168 }
2287     }
2288     }
2289 root 1.156
2290 root 1.168 skip_space: ;
2291     }
2292     }
2293    
2294     void
2295     maptile::set_regiondata (SV *data, int offset, int stride, SV *palette)
2296     CODE:
2297     {
2298     if (!SvROK (palette) || SvTYPE (SvRV (palette)) != SVt_PVAV)
2299     croak ("maptile::set_regiondata: palette must be arrayref");
2300    
2301     palette = SvRV (palette);
2302    
2303     STRLEN idxlen;
2304     const uint8_t *idx = (const uint8_t *)SvPVbyte (data, idxlen);
2305    
2306 root 1.230 region_ptr *regionmap = new region_ptr [av_len ((AV *)palette) + 1];
2307 root 1.168 uint8_t *regions = salloc<uint8_t> (THIS->size ());
2308    
2309     for (int i = av_len ((AV *)palette) + 1; i--; )
2310 root 1.230 regionmap [i] = region::find (SvPVutf8_nolen (*av_fetch ((AV *)palette, i, 1)));
2311 root 1.168
2312     for (int y = 0; y < THIS->height; ++y)
2313     memcpy (regions + y * THIS->width, idx + offset + y * stride, THIS->width);
2314    
2315     sfree (THIS->regions, THIS->size ());
2316 root 1.230 delete [] THIS->regionmap;
2317 root 1.168
2318     THIS->regions = regions;
2319 root 1.156 THIS->regionmap = regionmap;
2320     }
2321    
2322 root 1.193 void
2323     maptile::create_region_treasure ()
2324     CODE:
2325     {
2326     object *op = object::create ();
2327     op->type = FLOOR;
2328     op->map = THIS;
2329    
2330     for (int x = 0; x < THIS->width; ++x)
2331     for (int y = 0; y < THIS->height; ++y)
2332     {
2333     region *rgn = THIS->region (x, y);
2334    
2335     //fprintf (stderr, "%d,%d %f %p\n", x, y, rgn->treasure_density,rgn->treasure);//D
2336     if (rgn->treasure && rndm () < rgn->treasure_density)
2337     {
2338     op->x = x;
2339     op->y = y;
2340     create_treasure (rgn->treasure, op, GT_ENVIRONMENT, THIS->difficulty);
2341     }
2342     }
2343    
2344     op->destroy ();
2345     }
2346    
2347 root 1.74 int out_of_map (maptile *map, int x, int y)
2348    
2349 root 1.29 void
2350 root 1.61 trigger (maptile *map, long connection, bool state = true)
2351 root 1.29 CODE:
2352     activate_connection (map, connection, state);
2353    
2354     void
2355 root 1.61 get_connection (maptile *map, long connection)
2356 root 1.29 PPCODE:
2357     oblinkpt *obp = get_connection_links (map, connection);
2358     if (obp)
2359     for (objectlink *ol = obp->link; ol; ol = ol->next)
2360 root 1.257 XPUSHs (sv_2mortal (to_sv ((object *)ol->ob)));
2361 root 1.1
2362     void
2363 root 1.140 get_map_flags (maptile *map, int x, int y)
2364 root 1.1 PPCODE:
2365     {
2366 root 1.61 maptile *nmap = 0;
2367 root 1.1 I16 nx = 0, ny = 0;
2368 root 1.19 int flags = get_map_flags (map, &nmap, x, y, &nx, &ny);
2369 root 1.1
2370     EXTEND (SP, 4);
2371     PUSHs (sv_2mortal (newSViv (flags)));
2372    
2373     if (GIMME_V == G_ARRAY)
2374     {
2375 root 1.257 PUSHs (sv_2mortal (to_sv (nmap)));
2376 root 1.1 PUSHs (sv_2mortal (newSViv (nx)));
2377     PUSHs (sv_2mortal (newSViv (ny)));
2378     }
2379     }
2380    
2381     void
2382 root 1.61 at (maptile *map, unsigned int x, unsigned int y)
2383 root 1.1 PROTOTYPE: $$$
2384     PPCODE:
2385     {
2386     object *o;
2387 root 1.61 maptile *nmap = 0;
2388 root 1.1 I16 nx, ny;
2389    
2390 root 1.19 get_map_flags (map, &nmap, x, y, &nx, &ny);
2391 root 1.1
2392     if (nmap)
2393     for (o = GET_MAP_OB (nmap, nx, ny); o; o = o->above)
2394 root 1.257 XPUSHs (sv_2mortal (to_sv (o)));
2395 root 1.1 }
2396    
2397     SV *
2398 root 1.61 bot_at (maptile *obj, unsigned int x, unsigned int y)
2399 root 1.1 PROTOTYPE: $$$
2400     ALIAS:
2401     top_at = 1
2402     flags_at = 2
2403     light_at = 3
2404     move_block_at = 4
2405     move_slow_at = 5
2406     move_on_at = 6
2407     move_off_at = 7
2408     INIT:
2409 root 1.110 if (x >= obj->width || y >= obj->height) XSRETURN_UNDEF;
2410 root 1.1 CODE:
2411     switch (ix)
2412     {
2413 root 1.257 case 0: RETVAL = to_sv (GET_MAP_OB (obj, x, y)); break;
2414     case 1: RETVAL = to_sv (GET_MAP_TOP (obj, x, y)); break;
2415     case 2: RETVAL = newSVuv (GET_MAP_FLAGS (obj, x, y)); break;
2416     case 3: RETVAL = newSViv (GET_MAP_LIGHT (obj, x, y)); break;
2417     case 4: RETVAL = newSVuv (GET_MAP_MOVE_BLOCK (obj, x, y)); break;
2418     case 5: RETVAL = newSVuv (GET_MAP_MOVE_SLOW (obj, x, y)); break;
2419     case 6: RETVAL = newSVuv (GET_MAP_MOVE_ON (obj, x, y)); break;
2420     case 7: RETVAL = newSVuv (GET_MAP_MOVE_OFF (obj, x, y)); break;
2421 root 1.1 }
2422 root 1.122 OUTPUT: RETVAL
2423 root 1.1
2424 elmex 1.70 void fix_walls (maptile *map, int x, int y)
2425    
2426     void fix_walls_around (maptile *map, int x, int y)
2427 root 1.1
2428 root 1.117 # worst xs function of my life
2429 root 1.140 bool
2430 root 1.117 _create_random_map (\
2431 root 1.140 maptile *self,\
2432 root 1.183 utf8_string wallstyle,\
2433     utf8_string wall_name,\
2434     utf8_string floorstyle,\
2435     utf8_string monsterstyle,\
2436     utf8_string treasurestyle,\
2437     utf8_string layoutstyle,\
2438     utf8_string doorstyle,\
2439     utf8_string decorstyle,\
2440     utf8_string origin_map,\
2441     utf8_string final_map,\
2442     utf8_string exitstyle,\
2443     utf8_string this_map,\
2444     utf8_string exit_on_final_map,\
2445 root 1.146 int xsize,\
2446     int ysize,\
2447 root 1.117 int expand2x,\
2448     int layoutoptions1,\
2449     int layoutoptions2,\
2450     int layoutoptions3,\
2451     int symmetry,\
2452     int difficulty,\
2453     int difficulty_given,\
2454     float difficulty_increase,\
2455     int dungeon_level,\
2456     int dungeon_depth,\
2457     int decoroptions,\
2458     int orientation,\
2459     int origin_y,\
2460     int origin_x,\
2461 root 1.146 U32 random_seed,\
2462 root 1.117 val64 total_map_hp,\
2463     int map_layout_style,\
2464     int treasureoptions,\
2465     int symmetry_used,\
2466 root 1.137 region *region,\
2467 root 1.183 utf8_string custom\
2468 root 1.117 )
2469     CODE:
2470     {
2471     random_map_params rmp;
2472    
2473     assign (rmp.wallstyle , wallstyle);
2474     assign (rmp.wall_name , wall_name);
2475     assign (rmp.floorstyle , floorstyle);
2476     assign (rmp.monsterstyle , monsterstyle);
2477     assign (rmp.treasurestyle , treasurestyle);
2478     assign (rmp.layoutstyle , layoutstyle);
2479     assign (rmp.doorstyle , doorstyle);
2480     assign (rmp.decorstyle , decorstyle);
2481     assign (rmp.exitstyle , exitstyle);
2482     assign (rmp.exit_on_final_map, exit_on_final_map);
2483    
2484 root 1.122 rmp.origin_map = origin_map;
2485     rmp.final_map = final_map;
2486     rmp.this_map = this_map;
2487 root 1.146 rmp.xsize = xsize;
2488     rmp.ysize = ysize;
2489 root 1.117 rmp.expand2x = expand2x;
2490     rmp.layoutoptions1 = layoutoptions1;
2491     rmp.layoutoptions2 = layoutoptions2;
2492     rmp.layoutoptions3 = layoutoptions3;
2493     rmp.symmetry = symmetry;
2494     rmp.difficulty = difficulty;
2495     rmp.difficulty_given = difficulty_given;
2496     rmp.difficulty_increase = difficulty_increase;
2497     rmp.dungeon_level = dungeon_level;
2498     rmp.dungeon_depth = dungeon_depth;
2499     rmp.decoroptions = decoroptions;
2500     rmp.orientation = orientation;
2501     rmp.origin_y = origin_y;
2502     rmp.origin_x = origin_x;
2503     rmp.random_seed = random_seed;
2504 root 1.214 rmp.total_map_hp = (uint64_t) total_map_hp;
2505 root 1.117 rmp.map_layout_style = map_layout_style;
2506     rmp.treasureoptions = treasureoptions;
2507     rmp.symmetry_used = symmetry_used;
2508     rmp.region = region;
2509 root 1.137 rmp.custom = custom;
2510 root 1.117
2511 root 1.140 RETVAL = self->generate_random_map (&rmp);
2512 root 1.117 }
2513     OUTPUT:
2514     RETVAL
2515    
2516 root 1.19 MODULE = cf PACKAGE = cf::arch
2517 root 1.1
2518 root 1.218 int archetypes_size ()
2519     CODE:
2520     RETVAL = archetypes.size ();
2521     OUTPUT: RETVAL
2522    
2523     archetype *archetypes (U32 index)
2524     CODE:
2525     RETVAL = index < archetypes.size () ? archetypes [index] : 0;
2526     OUTPUT: RETVAL
2527 root 1.1
2528 root 1.212 object *instantiate (archetype *arch)
2529     CODE:
2530     RETVAL = arch_to_object (arch);
2531     OUTPUT:
2532     RETVAL
2533    
2534 root 1.173 INCLUDE: $PERL $srcdir/genacc archetype ../include/object.h |
2535 root 1.1
2536 root 1.19 MODULE = cf PACKAGE = cf::party
2537 root 1.1
2538 root 1.19 partylist *first ()
2539 root 1.1 PROTOTYPE:
2540 root 1.19 CODE:
2541     RETVAL = get_firstparty ();
2542     OUTPUT: RETVAL
2543 root 1.1
2544 root 1.173 INCLUDE: $PERL $srcdir/genacc partylist ../include/player.h |
2545 root 1.1
2546 root 1.19 MODULE = cf PACKAGE = cf::region
2547 root 1.1
2548 root 1.161 void
2549     list ()
2550     PPCODE:
2551     for_all_regions (rgn)
2552     XPUSHs (sv_2mortal (to_sv (rgn)));
2553    
2554 root 1.183 region *find (utf8_string name)
2555 root 1.161 PROTOTYPE: $
2556 root 1.19 CODE:
2557 root 1.161 RETVAL = region::find (name);
2558 root 1.19 OUTPUT: RETVAL
2559 root 1.1
2560 root 1.183 region *find_fuzzy (utf8_string name)
2561 root 1.122 PROTOTYPE: $
2562     CODE:
2563 root 1.161 RETVAL = region::find_fuzzy (name);
2564 root 1.122 OUTPUT: RETVAL
2565    
2566 root 1.186 int specificity (region *rgn)
2567     CODE:
2568     RETVAL = 0;
2569     while (rgn = rgn->parent)
2570     RETVAL++;
2571     OUTPUT: RETVAL
2572    
2573 root 1.193 INCLUDE: $PERL $srcdir/genacc region ../include/region.h |
2574 root 1.1
2575 root 1.19 MODULE = cf PACKAGE = cf::living
2576 root 1.1
2577 root 1.173 INCLUDE: $PERL $srcdir/genacc living ../include/living.h |
2578 root 1.1
2579 root 1.76 MODULE = cf PACKAGE = cf::settings
2580    
2581 root 1.173 INCLUDE: $PERL $srcdir/genacc Settings ../include/global.h |
2582 root 1.76
2583 root 1.84 MODULE = cf PACKAGE = cf::client
2584 root 1.79
2585 root 1.173 INCLUDE: $PERL $srcdir/genacc client ../include/client.h |
2586 root 1.79
2587 root 1.84 int invoke (client *ns, int event, ...)
2588 root 1.79 CODE:
2589 root 1.88 if (KLASS_OF (event) != KLASS_CLIENT) croak ("event class must be CLIENT");
2590 root 1.79 AV *av = (AV *)sv_2mortal ((SV *)newAV ());
2591     for (int i = 2; i < items; i++) av_push (av, SvREFCNT_inc (ST (i)));
2592 root 1.109 RETVAL = ns->invoke ((event_type)event, ARG_AV (av), DT_END);
2593 root 1.79 OUTPUT: RETVAL
2594    
2595 root 1.84 SV *registry (client *ns)
2596 root 1.79
2597 root 1.100 void
2598     list ()
2599     PPCODE:
2600     EXTEND (SP, clients.size ());
2601     for (sockvec::iterator i = clients.begin (); i != clients.end (); ++i)
2602     PUSHs (sv_2mortal (to_sv (*i)));
2603    
2604 root 1.88 void
2605 root 1.100 client::send_packet (SV *packet)
2606     CODE:
2607     {
2608     STRLEN len;
2609     char *buf = SvPVbyte (packet, len);
2610    
2611 root 1.258 if (len > MAXSOCKBUF)
2612     {
2613     // ugly
2614     if (THIS->pl)
2615     THIS->pl->failmsg ("[packet too long for client]");
2616     }
2617     else
2618     THIS->send_packet (buf, len);
2619 root 1.100 }
2620    
2621 root 1.237 faceidx
2622 root 1.238 client::need_face (utf8_string name, int pri = 0)
2623 root 1.237 CODE:
2624 root 1.238 RETVAL = face_find (name, 0);
2625     if (RETVAL)
2626     {
2627     THIS->send_face (RETVAL, pri);
2628     THIS->flush_fx ();
2629     }
2630     OUTPUT:
2631     RETVAL
2632    
2633     int
2634     client::fx_want (int idx, int value = -1)
2635     CODE:
2636     if (0 < idx && idx < FT_NUM)
2637     {
2638     RETVAL = THIS->fx_want [idx];
2639     if (items > 2)
2640     THIS->fx_want [idx] = value;
2641     }
2642     else
2643     RETVAL = 0;
2644 root 1.237 OUTPUT:
2645     RETVAL
2646    
2647 root 1.239 MODULE = cf PACKAGE = cf::sound PREFIX = sound_
2648    
2649     faceidx sound_find (utf8_string name)
2650    
2651 root 1.240 void sound_set (utf8_string str, faceidx face)
2652    
2653     # dire hack
2654     void old_sound_index (int idx, faceidx face)
2655     CODE:
2656     extern faceidx old_sound_index [SOUND_CAST_SPELL_0];
2657     old_sound_index [idx] = face;
2658    
2659 root 1.176 MODULE = cf PACKAGE = cf::face PREFIX = face_
2660    
2661 root 1.185 #INCLUDE: $PERL $srcdir/genacc faceset ../include/face.h |
2662 root 1.176
2663 root 1.183 faceidx face_find (utf8_string name, faceidx defidx = 0)
2664 root 1.176
2665 root 1.183 faceidx alloc (utf8_string name)
2666 root 1.176 CODE:
2667     {
2668     do
2669     {
2670     RETVAL = faces.size ();
2671 root 1.177 faces.resize (RETVAL + 1);
2672 root 1.176 }
2673     while (!RETVAL); // crude way to leave index 0
2674    
2675     faces [RETVAL].name = name;
2676     facehash.insert (std::make_pair (faces [RETVAL].name, RETVAL));
2677    
2678     if (!strcmp (name, BLANK_FACE_NAME)) blank_face = RETVAL;
2679     if (!strcmp (name, EMPTY_FACE_NAME)) empty_face = RETVAL;
2680     }
2681     OUTPUT: RETVAL
2682    
2683 root 1.227 void set_type (faceidx idx, int value)
2684     ALIAS:
2685     set_type = 0
2686     set_visibility = 1
2687     set_magicmap = 2
2688     set_smooth = 3
2689     set_smoothlevel = 4
2690 root 1.176 CODE:
2691 root 1.229 faceinfo *f = face_info (idx); assert (f);
2692 root 1.227 switch (ix)
2693     {
2694     case 0: f->type = value; break;
2695     case 1: f->visibility = value; break;
2696     case 2: f->magicmap = value; break;
2697     case 3: f->smooth = value; break;
2698     case 4: f->smoothlevel = value; break;
2699     }
2700 root 1.177
2701     void set_data (faceidx idx, int faceset, SV *data, SV *chksum)
2702 root 1.176 CODE:
2703 root 1.182 {
2704 root 1.231 faceinfo *f = face_info (idx); assert (f);
2705     facedata *d = &(faceset ? f->data64 : f->data32);
2706 root 1.181 sv_to (data, d->data);
2707     STRLEN clen;
2708     char *cdata = SvPVbyte (chksum, clen);
2709 root 1.182 clen = min (CHKSUM_SIZE, clen);
2710    
2711     if (memcmp (d->chksum, cdata, clen))
2712     {
2713     memcpy (d->chksum, cdata, clen);
2714    
2715     // invalidate existing client face info
2716     for_all_clients (ns)
2717     if (ns->faceset == faceset)
2718     {
2719     ns->faces_sent [idx] = false;
2720     ns->force_newmap = true;
2721     }
2722     }
2723     }
2724 root 1.176
2725 root 1.229 int get_data_size (faceidx idx, int faceset = 0)
2726     CODE:
2727     facedata *d = face_data (idx, faceset); assert (d);
2728     RETVAL = d->data.size ();
2729     OUTPUT:
2730     RETVAL
2731    
2732     SV *get_chksum (faceidx idx, int faceset = 0)
2733     CODE:
2734     facedata *d = face_data (idx, faceset); assert (d);
2735     RETVAL = newSVpvn ((char *)d->chksum, CHKSUM_SIZE);
2736     OUTPUT:
2737     RETVAL
2738    
2739 root 1.177 void invalidate (faceidx idx)
2740     CODE:
2741     for_all_clients (ns)
2742 root 1.182 {
2743     ns->faces_sent [idx] = false;
2744     ns->force_newmap = true;
2745     }
2746 root 1.177
2747     void invalidate_all ()
2748     CODE:
2749     for_all_clients (ns)
2750 root 1.182 {
2751     ns->faces_sent.reset ();
2752     ns->force_newmap = true;
2753     }
2754 root 1.177
2755 root 1.185 MODULE = cf PACKAGE = cf::anim PREFIX = anim_
2756    
2757     #INCLUDE: $PERL $srcdir/genacc faceset ../include/anim.h |
2758    
2759     animidx anim_find (utf8_string name)
2760     CODE:
2761     RETVAL = animation::find (name).number;
2762     OUTPUT: RETVAL
2763    
2764     animidx set (utf8_string name, SV *frames, int facings = 1)
2765     CODE:
2766     {
2767     if (!SvROK (frames) && SvTYPE (SvRV (frames)) != SVt_PVAV)
2768     croak ("frames must be an arrayref");
2769    
2770     AV *av = (AV *)SvRV (frames);
2771    
2772     animation *anim = &animation::find (name);
2773     if (anim->number)
2774     {
2775     anim->resize (av_len (av) + 1);
2776     anim->facings = facings;
2777     }
2778     else
2779     anim = &animation::create (name, av_len (av) + 1, facings);
2780    
2781     for (int i = 0; i < anim->num_animations; ++i)
2782     anim->faces [i] = face_find (SvPVutf8_nolen (*av_fetch (av, i, 1)));
2783     }
2784     OUTPUT: RETVAL
2785    
2786     void invalidate_all ()
2787     CODE:
2788     for_all_clients (ns)
2789     ns->anims_sent.reset ();
2790    
2791 root 1.247 MODULE = cf PACKAGE = cf::object::freezer
2792    
2793     INCLUDE: $PERL $srcdir/genacc object_freezer ../include/cfperl.h |
2794    
2795     SV *
2796     new (char *klass)
2797     CODE:
2798     RETVAL = newSVptr (new object_freezer, gv_stashpv ("cf::object::freezer", 1));
2799     OUTPUT: RETVAL
2800    
2801     void
2802     DESTROY (SV *sv)
2803     CODE:
2804     object_freezer *self;
2805     sv_to (sv, self);
2806     delete self;
2807    
2808     MODULE = cf PACKAGE = cf::object::thawer
2809    
2810     INCLUDE: $PERL $srcdir/genacc object_thawer ../include/cfperl.h |
2811    
2812     SV *
2813     new_from_file (char *klass, octet_string path)
2814     CODE:
2815     object_thawer *f = new object_thawer (path);
2816     if (!*f)
2817     {
2818     delete f;
2819     XSRETURN_UNDEF;
2820     }
2821     RETVAL = newSVptr (f, gv_stashpv ("cf::object::thawer", 1));
2822     OUTPUT: RETVAL
2823    
2824     void
2825     DESTROY (SV *sv)
2826     CODE:
2827     object_thawer *self;
2828     sv_to (sv, self);
2829     delete self;
2830    
2831 root 1.252 void
2832 root 1.253 extract_tags (object_thawer *self)
2833 root 1.254 PPCODE:
2834 root 1.252 while (self->kw != KW_EOF)
2835     {
2836 root 1.254 PUTBACK;
2837 root 1.253 coroapi::cede_to_tick_every (5000);
2838 root 1.254 SPAGAIN;
2839 root 1.253
2840 root 1.252 if (self->kw == KW_tag)
2841 root 1.254 XPUSHs (sv_2mortal (newSVpv_utf8 (self->get_str ())));
2842 root 1.252
2843     self->skip ();
2844     }
2845