ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/server/cfperl.xs
Revision: 1.365
Committed: Sun Apr 11 04:09:56 2010 UTC (14 years, 1 month ago) by root
Branch: MAIN
Changes since 1.364: +1 -3 lines
Log Message:
experimental pushstack/popstack around all callbacks, maybe this is our memory leak/mystery bug?

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