ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/server/cfperl.xs
Revision: 1.262
Committed: Tue Oct 16 06:15:10 2007 UTC (16 years, 8 months ago) by root
Branch: MAIN
Changes since 1.261: +11 -0 lines
Log Message:
more memory optimistaion, possibly

File Contents

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