ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/server/cfperl.xs
Revision: 1.288
Committed: Tue May 6 18:47:32 2008 UTC (16 years, 1 month ago) by root
Branch: MAIN
Changes since 1.287: +3 -0 lines
Log Message:
*** empty log message ***

File Contents

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