ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/server/cfperl.xs
Revision: 1.271
Committed: Tue Apr 1 19:50:39 2008 UTC (16 years, 2 months ago) by root
Branch: MAIN
Changes since 1.270: +6 -4 lines
Log Message:
tuning, glibc-bugworkaround

File Contents

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