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