ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/server/cfperl.xs
Revision: 1.360
Committed: Mon Apr 5 20:33:13 2010 UTC (14 years, 2 months ago) by root
Branch: MAIN
Changes since 1.359: +2 -0 lines
Log Message:
fix get_levelnumber and rename it to ordinal, also allow more format buffers

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     return 0;
1230     }
1231    
1232     object *
1233 root 1.346 object::deref (const_utf8_string ref)
1234 root 1.247 {
1235 root 1.249 object *retval = 0;
1236 root 1.247
1237 root 1.249 if (ref)
1238     {
1239     CALL_BEGIN (1);
1240     CALL_ARG (ref);
1241     CALL_CALL ("cf::object::deref", G_SCALAR);
1242    
1243     if (count)
1244     sv_to (POPs, retval);
1245 root 1.247
1246 root 1.249 CALL_END;
1247     }
1248 root 1.247
1249     return retval;
1250     }
1251    
1252 root 1.198 void
1253 root 1.345 log_backtrace (const_utf8_string msg)
1254 root 1.198 {
1255     #if HAVE_BACKTRACE
1256     void *addr [20];
1257     int size = backtrace (addr, 20);
1258    
1259     CALL_BEGIN (size);
1260     CALL_ARG (msg);
1261     for (int i = 0; i < size; ++i)
1262     CALL_ARG ((IV)addr [i]);
1263     CALL_CALL ("cf::_log_backtrace", G_VOID);
1264     CALL_END;
1265     #endif
1266     }
1267    
1268 root 1.323 bool
1269 root 1.346 is_match_expr (const_utf8_string expr)
1270 root 1.322 {
1271     return !strncmp (expr, "match ", sizeof ("match ") - 1);
1272     }
1273    
1274 root 1.323 bool
1275 root 1.346 match (const_utf8_string expr, object *ob, object *self, object *source, object *originator)
1276 root 1.322 {
1277 root 1.323 if (!strncmp (expr, "match ", sizeof ("match ") - 1))
1278     expr += sizeof ("match ") - 1;
1279 root 1.322
1280     CALL_BEGIN (5);
1281     CALL_ARG (expr);
1282     CALL_ARG (ob);
1283     CALL_ARG (self);
1284     CALL_ARG (source);
1285     CALL_ARG (originator);
1286 root 1.324 CALL_CALL (cv_cf_match_match, G_SCALAR);
1287 root 1.322
1288 root 1.324 bool matched = count && SvTRUE (TOPs);
1289 root 1.322
1290     CALL_END;
1291    
1292     return matched;
1293     }
1294    
1295 root 1.331 object *
1296 root 1.346 match_one (const_utf8_string expr, object *ob, object *self, object *source, object *originator)
1297 root 1.331 {
1298     if (!strncmp (expr, "match ", sizeof ("match ") - 1))
1299     expr += sizeof ("match ") - 1;
1300    
1301     CALL_BEGIN (5);
1302     CALL_ARG (expr);
1303     CALL_ARG (ob);
1304     CALL_ARG (self);
1305     CALL_ARG (source);
1306     CALL_ARG (originator);
1307     CALL_CALL (cv_cf_match_match, G_ARRAY);
1308    
1309     object *one = 0;
1310    
1311     if (count)
1312     sv_to (TOPs, one);
1313    
1314     CALL_END;
1315    
1316     return one;
1317     }
1318    
1319 root 1.116 /////////////////////////////////////////////////////////////////////////////
1320    
1321 root 1.265 struct EVAPI *evapi::GEVAPI;
1322     struct CoroAPI *coroapi::GCoroAPI;
1323 root 1.80
1324 root 1.314 void
1325     coroapi::do_cede_to_tick ()
1326 root 1.189 {
1327 root 1.272 cede_pending = 0;
1328 root 1.189 cede ();
1329     }
1330 root 1.124
1331 root 1.188 void
1332     coroapi::wait_for_tick ()
1333     {
1334     CALL_BEGIN (0);
1335     CALL_CALL ("cf::wait_for_tick", G_DISCARD);
1336     CALL_END;
1337     }
1338    
1339     void
1340     coroapi::wait_for_tick_begin ()
1341     {
1342     CALL_BEGIN (0);
1343     CALL_CALL ("cf::wait_for_tick_begin", G_DISCARD);
1344     CALL_END;
1345     }
1346    
1347 root 1.85 void
1348 root 1.80 iow::poll (int events)
1349     {
1350 root 1.265 if (events != this->events)
1351 root 1.81 {
1352 root 1.265 int active = ev_is_active ((ev_io *)this);
1353     if (active) stop ();
1354     ev_io_set ((ev_io *)this, fd, events);
1355     if (active) start ();
1356 root 1.81 }
1357 root 1.80 }
1358    
1359 root 1.314 static void
1360 root 1.324 _connect_to_perl_1 ()
1361 root 1.109 {
1362 root 1.272 stash_cf = gv_stashpv ("cf", 1);
1363 root 1.109
1364     stash_cf_object_wrap = gv_stashpv ("cf::object::wrap", 1);
1365     stash_cf_object_player_wrap = gv_stashpv ("cf::object::player::wrap", 1);
1366     stash_cf_player_wrap = gv_stashpv ("cf::player::wrap", 1);
1367     stash_cf_map_wrap = gv_stashpv ("cf::map::wrap" , 1);
1368 root 1.293 stash_cf_mapspace_wrap = gv_stashpv ("cf::mapspace::wrap" , 1);
1369 root 1.109 stash_cf_client_wrap = gv_stashpv ("cf::client::wrap", 1);
1370     stash_cf_arch_wrap = gv_stashpv ("cf::arch::wrap" , 1);
1371     stash_cf_party_wrap = gv_stashpv ("cf::party::wrap" , 1);
1372     stash_cf_region_wrap = gv_stashpv ("cf::region::wrap", 1);
1373     stash_cf_living_wrap = gv_stashpv ("cf::living::wrap", 1);
1374    
1375 root 1.272 sv_now = get_sv ("cf::NOW" , 1); SvUPGRADE (sv_now , SVt_NV);
1376     sv_runtime = get_sv ("cf::RUNTIME" , 1); SvUPGRADE (sv_runtime , SVt_NV);
1377     sv_tick_start = get_sv ("cf::TICK_START", 1); SvUPGRADE (sv_tick_start, SVt_NV);
1378     sv_next_tick = get_sv ("cf::NEXT_TICK" , 1); SvUPGRADE (sv_next_tick , SVt_NV);
1379 root 1.116
1380 root 1.109 cb_global = get_av ("cf::CB_GLOBAL", 1);
1381     cb_attachable = get_av ("cf::CB_ATTACHABLE", 1);
1382     cb_object = get_av ("cf::CB_OBJECT", 1);
1383     cb_player = get_av ("cf::CB_PLAYER", 1);
1384     cb_client = get_av ("cf::CB_CLIENT", 1);
1385     cb_type = get_av ("cf::CB_TYPE" , 1);
1386     cb_map = get_av ("cf::CB_MAP" , 1);
1387 root 1.324 }
1388 root 1.321
1389 root 1.324 static void
1390     _connect_to_perl_2 ()
1391     {
1392     cv_cf_do_invoke = (SV *)get_cv ("cf::do_invoke" , 0); assert (cv_cf_do_invoke);
1393     cv_cf__can_merge = (SV *)get_cv ("cf::_can_merge" , 0); assert (cv_cf__can_merge);
1394     cv_cf_client_send_msg = (SV *)get_cv ("cf::client::send_msg", 0); assert (cv_cf_client_send_msg);
1395     cv_cf_tick = (SV *)get_cv ("cf::tick" , 0); assert (cv_cf_tick);
1396     cv_cf_match_match = (SV *)get_cv ("cf::match::match" , 0); assert (cv_cf_match_match);
1397 root 1.109 }
1398    
1399 root 1.1 MODULE = cf PACKAGE = cf PREFIX = cf_
1400    
1401     BOOT:
1402     {
1403 root 1.265 I_EV_API (PACKAGE); evapi::GEVAPI = GEVAPI;
1404     I_CORO_API (PACKAGE); coroapi::GCoroAPI = GCoroAPI;
1405 root 1.80
1406 root 1.324 _connect_to_perl_1 ();
1407 root 1.189
1408 root 1.109 newCONSTSUB (stash_cf, "VERSION", newSVpv (VERSION, sizeof (VERSION) - 1));
1409 root 1.63
1410 root 1.220 //{
1411     // require_pv ("Time::HiRes");
1412     //
1413     // SV **svp = hv_fetch (PL_modglobal, "Time::NVtime", 12, 0);
1414     // if (!svp) croak ("Time::HiRes is required");
1415     // if (!SvIOK(*svp)) croak ("Time::NVtime isn’t a function pointer");
1416     // coroapi::time = INT2PTR (double(*)(), SvIV(*svp));
1417     //}
1418 root 1.189
1419 root 1.1 static const struct {
1420     const char *name;
1421     IV iv;
1422     } *civ, const_iv[] = {
1423     # define const_iv(name) { # name, (IV)name },
1424 root 1.358 # include "const_iv.h"
1425 root 1.359 # define def(uc, lc, name, plus, change) const_iv (AT_ ## uc) const_iv (ATNR_ ## uc)
1426     # include "attackinc.h"
1427     # undef def
1428     # define def(uc, flags) const_iv (SK_ ## uc)
1429     # include "skillinc.h"
1430     # undef def
1431    
1432 root 1.189 const_iv (llevError) const_iv (llevInfo) const_iv (llevDebug) const_iv (llevMonster)
1433 root 1.198 const_iv (logBacktrace)
1434 root 1.180
1435 root 1.189 const_iv (Map0Cmd) const_iv (Map1Cmd) const_iv (Map1aCmd)
1436    
1437     const_iv (MAP_CLIENT_X) const_iv (MAP_CLIENT_Y)
1438 root 1.180
1439 root 1.5 const_iv (MAX_TIME)
1440 root 1.258 const_iv (MAXSOCKBUF)
1441 root 1.189
1442     const_iv (UPD_LOCATION) const_iv (UPD_FLAGS) const_iv (UPD_WEIGHT) const_iv (UPD_FACE)
1443     const_iv (UPD_NAME) const_iv (UPD_ANIM) const_iv (UPD_ANIMSPEED) const_iv (UPD_NROF)
1444    
1445 root 1.350 const_iv (UPD_SP_MANA) const_iv (UPD_SP_GRACE) const_iv (UPD_SP_LEVEL)
1446 root 1.189
1447     const_iv (F_APPLIED) const_iv (F_LOCATION) const_iv (F_UNPAID) const_iv (F_MAGIC)
1448     const_iv (F_CURSED) const_iv (F_DAMNED) const_iv (F_OPEN) const_iv (F_NOPICK)
1449 root 1.1 const_iv (F_LOCKED)
1450    
1451 root 1.293 const_iv (P_BLOCKSVIEW) const_iv (P_NO_MAGIC) const_iv (P_IS_ALIVE)
1452 root 1.189 const_iv (P_NO_CLERIC) const_iv (P_OUT_OF_MAP) const_iv (P_NEW_MAP) const_iv (P_UPTODATE)
1453    
1454     const_iv (SAVE_MODE) const_iv (SAVE_DIR_MODE)
1455    
1456     const_iv (SK_EXP_ADD_SKILL) const_iv (SK_EXP_TOTAL) const_iv (SK_EXP_NONE)
1457     const_iv (SK_SUBTRACT_SKILL_EXP) const_iv (SK_EXP_SKILL_ONLY)
1458    
1459 root 1.276 const_iv (MAP_ACTIVE) const_iv (MAP_SWAPPED) const_iv (MAP_LOADING) const_iv (MAP_SAVING)
1460     const_iv (MAP_INACTIVE)
1461 root 1.189
1462     const_iv (KLASS_ATTACHABLE) const_iv (KLASS_GLOBAL) const_iv (KLASS_OBJECT)
1463     const_iv (KLASS_CLIENT) const_iv (KLASS_PLAYER) const_iv (KLASS_MAP)
1464    
1465 root 1.251 const_iv (VERSION_CS) const_iv (VERSION_SC)
1466    
1467 root 1.189 const_iv (CS_QUERY_YESNO) const_iv (CS_QUERY_SINGLECHAR) const_iv (CS_QUERY_HIDEINPUT)
1468    
1469     const_iv (IO_HEADER) const_iv (IO_OBJECTS) const_iv (IO_UNIQUES)
1470 root 1.1 };
1471    
1472     for (civ = const_iv + sizeof (const_iv) / sizeof (const_iv [0]); civ-- > const_iv; )
1473 root 1.109 newCONSTSUB (stash_cf, (char *)civ->name, newSViv (civ->iv));
1474 root 1.1
1475     static const struct {
1476     const char *name;
1477 root 1.14 int skip;
1478 root 1.7 IV klass;
1479 root 1.1 IV iv;
1480 root 1.6 } *eiv, event_iv[] = {
1481 root 1.14 # define def(klass,name) { "EVENT_" # klass "_" # name, sizeof ("EVENT_" # klass), (IV)KLASS_ ## klass, (IV)EVENT_ ## klass ## _ ## name },
1482 root 1.6 # include "eventinc.h"
1483     # undef def
1484     };
1485    
1486     AV *av = get_av ("cf::EVENT", 1);
1487    
1488     for (eiv = event_iv + sizeof (event_iv) / sizeof (event_iv [0]); eiv-- > event_iv; )
1489 root 1.7 {
1490     AV *event = newAV ();
1491 root 1.14 av_push (event, newSVpv ((char *)eiv->name + eiv->skip, 0));
1492 root 1.7 av_push (event, newSViv (eiv->klass));
1493     av_store (av, eiv->iv, newRV_noinc ((SV *)event));
1494 root 1.109 newCONSTSUB (stash_cf, (char *)eiv->name, newSViv (eiv->iv));
1495 root 1.7 }
1496 root 1.324
1497     // used by autogenerated BOOT sections from genacc
1498     av_reflect = get_av ("cf::REFLECT", 1);
1499 root 1.14 }
1500    
1501 root 1.295 void _gv_clear (SV *gv)
1502     CODE:
1503     assert (SvTYPE (gv) == SVt_PVGV);
1504     # define f(sv) { SV *sv_ = (SV *)(sv); sv = 0; SvREFCNT_dec (sv_); }
1505     f (GvGP (gv)->gp_form);
1506     f (GvGP (gv)->gp_io);
1507     f (GvGP (gv)->gp_sv);
1508     f (GvGP (gv)->gp_av);
1509     f (GvGP (gv)->gp_hv);
1510     f (GvGP (gv)->gp_cv);
1511     GvCVGEN (gv) = 0;
1512     GvMULTI_off (gv);
1513     # undef f
1514    
1515 root 1.324 void _connect_to_perl_1 ()
1516    
1517     void _connect_to_perl_2 ()
1518 root 1.14
1519 root 1.210 void _recalc_want ()
1520    
1521 root 1.304 # not used by default anymore
1522 root 1.47 void _global_reattach ()
1523 root 1.14 CODE:
1524     {
1525     // reattach to all attachable objects in the game.
1526 root 1.128 for_all_clients (ns)
1527     ns->reattach ();
1528 root 1.96
1529 root 1.128 for_all_objects (op)
1530 root 1.109 op->reattach ();
1531 root 1.1 }
1532    
1533 root 1.192 # support function for map-world.ext
1534     void _quantise (SV *data_sv, SV *plt_sv)
1535     CODE:
1536     {
1537     if (!SvROK (plt_sv) || SvTYPE (SvRV (plt_sv)) != SVt_PVAV)
1538     croak ("_quantise called with invalid agruments");
1539    
1540     plt_sv = SvRV (plt_sv);
1541     SV **plt = AvARRAY (plt_sv);
1542     int plt_count = AvFILL (plt_sv) + 1;
1543    
1544     STRLEN len;
1545     char *data = SvPVbyte (data_sv, len);
1546     char *dst = data;
1547    
1548     while (len >= 3)
1549     {
1550     for (SV **val_sv = plt + plt_count; val_sv-- > plt; )
1551     {
1552     char *val = SvPVX (*val_sv);
1553    
1554     if (val [0] == data [0]
1555     && val [1] == data [1]
1556     && val [2] == data [2])
1557     {
1558     *dst++ = val [3];
1559     goto next;
1560     }
1561     }
1562    
1563     croak ("_quantise: color not found in palette: #%02x%02x%02x, at offset %d %d",
1564     (uint8_t)data [0], (uint8_t)data [1], (uint8_t)data [2],
1565     dst - SvPVX (data_sv), len);
1566    
1567     next:
1568     data += 3;
1569     len -= 3;
1570     }
1571    
1572     SvCUR_set (data_sv, dst - SvPVX (data_sv));
1573     }
1574    
1575 root 1.303 void init_anim ()
1576    
1577     void init_globals ()
1578    
1579     void init_experience ()
1580    
1581     void init_attackmess ()
1582    
1583     void init_dynamic ()
1584    
1585     void load_settings ()
1586    
1587     void load_materials ()
1588    
1589     void init_uuid ()
1590     CODE:
1591     UUID::init ();
1592    
1593     void init_signals ()
1594    
1595     void init_commands ()
1596    
1597     void init_skills ()
1598    
1599     void init_beforeplay ()
1600    
1601 root 1.273 void evthread_start (int aiofd)
1602 root 1.272
1603     void cede_to_tick ()
1604 root 1.236 CODE:
1605 root 1.272 coroapi::cede_to_tick ();
1606 root 1.236
1607 root 1.272 NV till_tick ()
1608 root 1.236 CODE:
1609 root 1.272 RETVAL = SvNVX (sv_next_tick) - now ();
1610 root 1.236 OUTPUT:
1611     RETVAL
1612    
1613 root 1.272 int tick_inhibit ()
1614 root 1.236 CODE:
1615 root 1.272 RETVAL = tick_inhibit;
1616 root 1.236 OUTPUT:
1617     RETVAL
1618    
1619 root 1.272 void tick_inhibit_inc ()
1620     CODE:
1621     ++tick_inhibit;
1622    
1623     void tick_inhibit_dec ()
1624     CODE:
1625     if (!--tick_inhibit)
1626     if (tick_pending)
1627     {
1628     ev_async_send (EV_DEFAULT, &tick_watcher);
1629     coroapi::cede ();
1630     }
1631    
1632     void server_tick ()
1633     CODE:
1634     {
1635 root 1.347 ev_now_update (EV_DEFAULT);
1636 root 1.272 NOW = ev_now (EV_DEFAULT);
1637     SvNV_set (sv_now, NOW); SvNOK_only (sv_now);
1638     SvNV_set (sv_tick_start, NOW); SvNOK_only (sv_tick_start);
1639     runtime = SvNVX (sv_runtime);
1640    
1641     server_tick ();
1642    
1643 root 1.347 ev_now_update (EV_DEFAULT);
1644     NOW = ev_now (EV_DEFAULT);
1645 root 1.272 SvNV_set (sv_now, NOW); SvNOK_only (sv_now);
1646     runtime += TICK;
1647     SvNV_set (sv_runtime, runtime); SvNOK_only (sv_runtime);
1648     }
1649    
1650 root 1.1 NV floor (NV x)
1651    
1652     NV ceil (NV x)
1653    
1654 root 1.143 NV rndm (...)
1655 root 1.286 ALIAS:
1656     rmg_rndm = 1
1657 root 1.143 CODE:
1658 root 1.286 {
1659     rand_gen &gen = ix ? rmg_rndm : rndm;
1660 root 1.143 switch (items)
1661     {
1662 root 1.286 case 0: RETVAL = gen (); break;
1663     case 1: RETVAL = gen (SvUV (ST (0))); break;
1664     case 2: RETVAL = gen (SvIV (ST (0)), SvIV (ST (1))); break;
1665 root 1.143 default: croak ("cf::rndm requires none, one or two parameters."); break;
1666     }
1667 root 1.286 }
1668 root 1.143 OUTPUT:
1669     RETVAL
1670    
1671 root 1.207 NV clamp (NV value, NV min_value, NV max_value)
1672     CODE:
1673     RETVAL = clamp (value, min_value, max_value);
1674     OUTPUT:
1675     RETVAL
1676    
1677     NV lerp (NV value, NV min_in, NV max_in, NV min_out, NV max_out)
1678     CODE:
1679     RETVAL = lerp (value, min_in, max_in, min_out, max_out);
1680     OUTPUT:
1681     RETVAL
1682    
1683 root 1.360 const char *ordinal (int i)
1684    
1685 root 1.268 void weaken (...)
1686     PROTOTYPE: @
1687     CODE:
1688     while (items > 0)
1689     sv_rvweaken (ST (--items));
1690    
1691 root 1.1 void
1692 root 1.198 log_backtrace (utf8_string msg)
1693    
1694     void
1695     LOG (int flags, utf8_string msg)
1696 root 1.1 PROTOTYPE: $$
1697 root 1.198 C_ARGS: flags, "%s", msg
1698 root 1.1
1699 root 1.183 octet_string path_combine (octet_string base, octet_string path)
1700 root 1.1 PROTOTYPE: $$
1701    
1702 root 1.183 octet_string path_combine_and_normalize (octet_string base, octet_string path)
1703 root 1.1 PROTOTYPE: $$
1704    
1705     void
1706     sub_generation_inc ()
1707     CODE:
1708     PL_sub_generation++;
1709    
1710 root 1.183 const_octet_string
1711 root 1.1 mapdir ()
1712     PROTOTYPE:
1713     ALIAS:
1714     mapdir = 0
1715     uniquedir = 1
1716     tmpdir = 2
1717     confdir = 3
1718     localdir = 4
1719     playerdir = 5
1720     datadir = 6
1721     CODE:
1722 root 1.19 switch (ix)
1723     {
1724     case 0: RETVAL = settings.mapdir ; break;
1725     case 1: RETVAL = settings.uniquedir; break;
1726     case 2: RETVAL = settings.tmpdir ; break;
1727     case 3: RETVAL = settings.confdir ; break;
1728     case 4: RETVAL = settings.localdir ; break;
1729     case 5: RETVAL = settings.playerdir; break;
1730     case 6: RETVAL = settings.datadir ; break;
1731     }
1732 root 1.1 OUTPUT: RETVAL
1733    
1734 root 1.120 void abort ()
1735    
1736 root 1.199 void reset_signals ()
1737    
1738 root 1.270 void fork_abort (const_octet_string cause = "cf::fork_abort")
1739 root 1.144
1740 root 1.270 void cleanup (const_octet_string cause, bool make_core = false)
1741 root 1.134
1742 root 1.116 void emergency_save ()
1743    
1744 root 1.156 void _exit (int status = EXIT_SUCCESS)
1745    
1746 root 1.125 #if _POSIX_MEMLOCK
1747    
1748     int mlockall (int flags = MCL_CURRENT | MCL_FUTURE)
1749 root 1.271 INIT:
1750 root 1.279 #if __GLIBC__
1751 root 1.300 mallopt (M_TOP_PAD, 1024 * 1024);
1752     mallopt (M_MMAP_THRESHOLD, 1024 * 1024 * 128);
1753     mallopt (M_MMAP_MAX, 0); // likely bug-workaround, also frees memory
1754 root 1.279 mallopt (M_PERTURB, 0xee); // bug-workaround for linux glibc+mlockall+calloc
1755 root 1.277 #endif
1756 root 1.125
1757     int munlockall ()
1758    
1759     #endif
1760    
1761 root 1.279 int
1762     malloc_trim (IV pad = 0)
1763    
1764     void
1765     mallinfo ()
1766     PPCODE:
1767     {
1768     #if __GLIBC__
1769     struct mallinfo mai = mallinfo ();
1770     EXTEND (SP, 10*2);
1771     PUSHs (sv_2mortal (newSVpv ("arena" , 0))); PUSHs (sv_2mortal (newSViv (mai.arena)));
1772     PUSHs (sv_2mortal (newSVpv ("ordblks" , 0))); PUSHs (sv_2mortal (newSViv (mai.ordblks)));
1773     PUSHs (sv_2mortal (newSVpv ("smblks" , 0))); PUSHs (sv_2mortal (newSViv (mai.smblks)));
1774     PUSHs (sv_2mortal (newSVpv ("hblks" , 0))); PUSHs (sv_2mortal (newSViv (mai.hblks)));
1775     PUSHs (sv_2mortal (newSVpv ("hblkhd" , 0))); PUSHs (sv_2mortal (newSViv (mai.hblkhd)));
1776     PUSHs (sv_2mortal (newSVpv ("usmblks" , 0))); PUSHs (sv_2mortal (newSViv (mai.usmblks)));
1777     PUSHs (sv_2mortal (newSVpv ("fsmblks" , 0))); PUSHs (sv_2mortal (newSViv (mai.fsmblks)));
1778     PUSHs (sv_2mortal (newSVpv ("uordblks", 0))); PUSHs (sv_2mortal (newSViv (mai.uordblks)));
1779     PUSHs (sv_2mortal (newSVpv ("fordblks", 0))); PUSHs (sv_2mortal (newSViv (mai.fordblks)));
1780     PUSHs (sv_2mortal (newSVpv ("keepcost", 0))); PUSHs (sv_2mortal (newSViv (mai.keepcost)));
1781     #endif
1782 root 1.308 EXTEND (SP, 5*2);
1783 root 1.279 PUSHs (sv_2mortal (newSVpv ("slice_alloc", 0))); PUSHs (sv_2mortal (newSVuv (slice_alloc)));
1784     PUSHs (sv_2mortal (newSVpv ("shstr_alloc", 0))); PUSHs (sv_2mortal (newSVuv (shstr_alloc)));
1785 root 1.282 PUSHs (sv_2mortal (newSVpv ("objects" , 0))); PUSHs (sv_2mortal (newSVuv (objects.size () * sizeof (object))));
1786 root 1.308 PUSHs (sv_2mortal (newSVpv ("sv_count" , 0))); PUSHs (sv_2mortal (newSVuv (PL_sv_count)));
1787     PUSHs (sv_2mortal (newSVpv ("sv_objcount", 0))); PUSHs (sv_2mortal (newSVuv (PL_sv_objcount)));
1788 root 1.279 }
1789    
1790 root 1.183 int find_animation (utf8_string text)
1791 root 1.1 PROTOTYPE: $
1792    
1793 root 1.74 int random_roll (int min, int max, object *op, int goodbad);
1794 root 1.1
1795 root 1.183 const_utf8_string cost_string_from_value(uint64 cost, int approx = 0)
1796 root 1.1
1797     int
1798     exp_to_level (val64 exp)
1799     CODE:
1800     {
1801     int i = 0;
1802    
1803     RETVAL = settings.max_level;
1804    
1805     for (i = 1; i <= settings.max_level; i++)
1806     {
1807     if (levels[i] > exp)
1808     {
1809     RETVAL = i - 1;
1810     break;
1811     }
1812     }
1813     }
1814     OUTPUT: RETVAL
1815    
1816     val64
1817     level_to_min_exp (int level)
1818     CODE:
1819     if (level > settings.max_level)
1820     RETVAL = levels[settings.max_level];
1821     else if (level < 1)
1822     RETVAL = 0;
1823     else
1824     RETVAL = levels[level];
1825     OUTPUT: RETVAL
1826    
1827     SV *
1828     resistance_to_string (int atnr)
1829     CODE:
1830     if (atnr >= 0 && atnr < NROFATTACKS)
1831     RETVAL = newSVpv (resist_plus[atnr], 0);
1832     else
1833     XSRETURN_UNDEF;
1834     OUTPUT: RETVAL
1835    
1836 root 1.275 UUID
1837 root 1.274 uuid_cur ()
1838     CODE:
1839 root 1.275 RETVAL = UUID::cur;
1840 root 1.274 OUTPUT:
1841     RETVAL
1842    
1843 root 1.275 UUID
1844 root 1.274 uuid_gen ()
1845     CODE:
1846 root 1.275 RETVAL = UUID::gen ();
1847     OUTPUT:
1848     RETVAL
1849    
1850     val64
1851     uuid_seq (UUID uuid)
1852     CODE:
1853     RETVAL = uuid.seq;
1854     OUTPUT:
1855     RETVAL
1856    
1857     UUID
1858     uuid_str (val64 seq)
1859     CODE:
1860     RETVAL.seq = seq;
1861 root 1.274 OUTPUT:
1862     RETVAL
1863    
1864     void
1865     coin_names ()
1866     PPCODE:
1867     EXTEND (SP, NUM_COINS);
1868     for (int i = 0; i < NUM_COINS; ++i)
1869     PUSHs (sv_2mortal (newSVpv (coins [i], 0)));
1870    
1871     void
1872     coin_archetypes ()
1873     PPCODE:
1874     EXTEND (SP, NUM_COINS);
1875     for (int i = 0; i < NUM_COINS; ++i)
1876     PUSHs (sv_2mortal (to_sv (archetype::find (coins [i]))));
1877    
1878 root 1.162 bool
1879 root 1.278 load_resource_file_ (octet_string filename)
1880 root 1.162
1881 root 1.288 void
1882     fix_weight ()
1883    
1884 root 1.97 MODULE = cf PACKAGE = cf::attachable
1885    
1886 root 1.27 int
1887 root 1.97 valid (SV *obj)
1888 root 1.27 CODE:
1889     RETVAL = SvROK (obj) && mg_find (SvRV (obj), PERL_MAGIC_ext);
1890     OUTPUT:
1891     RETVAL
1892    
1893 root 1.164 void
1894     debug_trace (attachable *obj, bool on = true)
1895     CODE:
1896 root 1.336 obj->attachable_flags &= ~attachable::F_DEBUG_TRACE;
1897 root 1.164 if (on)
1898 root 1.336 obj->attachable_flags |= attachable::F_DEBUG_TRACE;
1899 root 1.164
1900 root 1.153 int mortals_size ()
1901     CODE:
1902     RETVAL = attachable::mortals.size ();
1903     OUTPUT: RETVAL
1904    
1905     #object *mortals (U32 index)
1906     # CODE:
1907     # RETVAL = index < attachable::mortals.size () ? attachable::mortals [index] : 0;
1908     # OUTPUT: RETVAL
1909    
1910 root 1.358 INCLUDE: $PERL $srcdir/genacc attachable $srcdir/../include/util.h $srcdir/../include/cfperl.h |
1911 root 1.115
1912 root 1.101 MODULE = cf PACKAGE = cf::global
1913    
1914     int invoke (SV *klass, int event, ...)
1915     CODE:
1916     if (KLASS_OF (event) != KLASS_GLOBAL) croak ("event class must be GLOBAL");
1917     AV *av = (AV *)sv_2mortal ((SV *)newAV ());
1918     for (int i = 1; i < items; i++) av_push (av, SvREFCNT_inc (ST (i)));
1919 root 1.109 RETVAL = gbl_ev.invoke ((event_type)event, ARG_AV (av), DT_END);
1920 root 1.101 OUTPUT: RETVAL
1921    
1922 root 1.1 MODULE = cf PACKAGE = cf::object PREFIX = cf_object_
1923    
1924 root 1.358 INCLUDE: $PERL $srcdir/genacc object $srcdir/../include/object.h |
1925 root 1.62
1926 root 1.18 int invoke (object *op, int event, ...)
1927     CODE:
1928     if (KLASS_OF (event) != KLASS_OBJECT) croak ("event class must be OBJECT");
1929 root 1.24 AV *av = (AV *)sv_2mortal ((SV *)newAV ());
1930     for (int i = 2; i < items; i++) av_push (av, SvREFCNT_inc (ST (i)));
1931 root 1.109 RETVAL = op->invoke ((event_type)event, ARG_AV (av), DT_END);
1932 root 1.18 OUTPUT: RETVAL
1933    
1934     SV *registry (object *op)
1935    
1936 root 1.134 int objects_size ()
1937     CODE:
1938     RETVAL = objects.size ();
1939     OUTPUT: RETVAL
1940    
1941     object *objects (U32 index)
1942     CODE:
1943     RETVAL = index < objects.size () ? objects [index] : 0;
1944     OUTPUT: RETVAL
1945    
1946     int actives_size ()
1947     CODE:
1948     RETVAL = actives.size ();
1949     OUTPUT: RETVAL
1950    
1951     object *actives (U32 index)
1952 root 1.57 CODE:
1953 root 1.134 RETVAL = index < actives.size () ? actives [index] : 0;
1954 root 1.57 OUTPUT: RETVAL
1955    
1956 root 1.283 int mortals_size ()
1957     CODE:
1958     RETVAL = attachable::mortals.size ();
1959     OUTPUT: RETVAL
1960    
1961 root 1.346 const_utf8_string slot_use_name (U32 slot)
1962 root 1.205 ALIAS:
1963 root 1.215 slot_nonuse_name = 1
1964 root 1.205 CODE:
1965     {
1966     if (slot >= NUM_BODY_LOCATIONS)
1967     croak ("body slot index out of range");
1968    
1969     switch (ix)
1970     {
1971 root 1.215 case 0: RETVAL = body_locations[slot].use_name; break;
1972     case 1: RETVAL = body_locations[slot].nonuse_name; break;
1973 root 1.205 }
1974     }
1975     OUTPUT:
1976     RETVAL
1977    
1978 root 1.1 # missing properties
1979    
1980 root 1.54 object *head (object *op)
1981     PROTOTYPE: $
1982     CODE:
1983 root 1.134 RETVAL = op->head_ ();
1984 root 1.54 OUTPUT: RETVAL
1985    
1986 root 1.1 void
1987     inv (object *obj)
1988     PROTOTYPE: $
1989     PPCODE:
1990     {
1991 root 1.254 for (object *o = obj->inv; o; o = o->below)
1992 root 1.100 XPUSHs (sv_2mortal (to_sv (o)));
1993 root 1.1 }
1994    
1995 root 1.102 void
1996     set_animation (object *op, int idx)
1997     CODE:
1998     SET_ANIMATION (op, idx);
1999    
2000 elmex 1.160 int
2001     num_animations (object *op)
2002     CODE:
2003     RETVAL = NUM_ANIMATIONS (op);
2004     OUTPUT: RETVAL
2005    
2006 root 1.205 int slot_info (object *op, UV slot, int value = 0)
2007     ALIAS:
2008     slot_used = 1
2009     CODE:
2010     {
2011     if (slot >= NUM_BODY_LOCATIONS)
2012     croak ("body slot index out of range");
2013    
2014 root 1.208 RETVAL = ix ? op->slot[slot].used : op->slot[slot].info;
2015 root 1.205
2016     if (items > 2)
2017     if (ix)
2018 root 1.208 op->slot[slot].used = value;
2019     else
2020 root 1.205 op->slot[slot].info = value;
2021     }
2022     OUTPUT:
2023     RETVAL
2024    
2025 root 1.183 object *find_best_object_match (object *op, utf8_string match)
2026 root 1.58
2027     object *find_marked_object (object *op)
2028    
2029 root 1.109 int need_identify (object *obj);
2030 root 1.1
2031     int apply_shop_mat (object *shop_mat, object *op);
2032    
2033 root 1.27 int move (object *op, int dir, object *originator = op)
2034     CODE:
2035 root 1.353 RETVAL = op->move (dir, originator);
2036 root 1.27 OUTPUT:
2037     RETVAL
2038 root 1.1
2039 root 1.74 void apply_below (object *op)
2040     CODE:
2041     player_apply_below (op);
2042 root 1.1
2043 root 1.167 int cast_heal (object *op, object *caster, object *spell, int dir = 0)
2044    
2045 root 1.330 int casting_level (object *caster, object *spell)
2046    
2047 root 1.74 int pay_item (object *op, object *buyer)
2048     CODE:
2049     RETVAL = pay_for_item (op, buyer);
2050     OUTPUT: RETVAL
2051 root 1.1
2052 root 1.74 int pay_amount (object *op, uint64 amount)
2053     CODE:
2054     RETVAL = pay_for_amount (amount, op);
2055     OUTPUT: RETVAL
2056 root 1.1
2057     void pay_player (object *op, uint64 amount)
2058    
2059 root 1.183 val64 pay_player_arch (object *op, utf8_string arch, uint64 amount)
2060 root 1.1
2061 root 1.183 int cast_spell (object *op, object *caster, int dir, object *spell_ob, utf8_string stringarg = 0)
2062 root 1.1
2063 root 1.74 void learn_spell (object *op, object *sp, int special_prayer = 0)
2064     CODE:
2065     do_learn_spell (op, sp, special_prayer);
2066 root 1.1
2067 root 1.74 void forget_spell (object *op, object *sp)
2068     CODE:
2069     do_forget_spell (op, query_name (sp));
2070 root 1.1
2071 root 1.183 object *check_for_spell (object *op, utf8_string spellname)
2072 root 1.74 CODE:
2073     RETVAL = check_spell_known (op, spellname);
2074     OUTPUT: RETVAL
2075 root 1.1
2076 root 1.74 int query_money (object *op)
2077 root 1.1 ALIAS: money = 0
2078    
2079 elmex 1.108 val64 query_cost (object *op, object *who, int flags)
2080 root 1.1 ALIAS: cost = 0
2081    
2082 root 1.74 void spring_trap (object *op, object *victim)
2083 root 1.1
2084 root 1.74 int check_trigger (object *op, object *cause)
2085 root 1.1
2086 root 1.74 void drop (object *who, object *op)
2087 root 1.1
2088 root 1.74 void pick_up (object *who, object *op)
2089 root 1.1
2090 root 1.102 void update_object (object *op, int action)
2091 root 1.1
2092 root 1.183 void change_exp (object *op, uint64 exp, utf8_string skill_name = 0, int flag = 0)
2093 root 1.1
2094     void player_lvl_adj (object *who, object *skill = 0)
2095    
2096     int kill_object (object *op, int dam = 0, object *hitter = 0, int type = AT_PHYSICAL)
2097    
2098 root 1.334 int calc_skill_exp (object *who, object *op, object *skill)
2099 root 1.1
2100 root 1.334 void push_button (object *op, object *originator)
2101 root 1.1
2102 root 1.334 void use_trigger (object *op, object *originator)
2103 root 1.1
2104 root 1.334 void handle_apply_yield (object *op)
2105 elmex 1.232
2106 root 1.334 int convert_item (object *item, object *converter)
2107 elmex 1.319
2108 elmex 1.352 void fix_generated_item (object *op, object *creator, int difficulty, int max_magic, int flags);
2109 root 1.1
2110     MODULE = cf PACKAGE = cf::object PREFIX = cf_
2111    
2112     # no clean way to get an object from an archetype - stupid idiotic
2113     # dumb kludgy misdesigned plug-in api slowly gets on my nerves.
2114    
2115 root 1.183 object *new (utf8_string archetype = 0)
2116 root 1.1 PROTOTYPE: ;$
2117     CODE:
2118 elmex 1.219 RETVAL = archetype ? get_archetype (archetype) : object::create ();
2119 root 1.1 OUTPUT:
2120     RETVAL
2121    
2122 elmex 1.351 object *generate (utf8_string arch, object *creator)
2123     CODE:
2124     object *obj = get_archetype (arch);
2125     fix_generated_item (obj, creator, 0, 0, GT_MINIMAL);
2126     RETVAL = obj;
2127     OUTPUT:
2128     RETVAL
2129    
2130 root 1.225 object *find_object (U32 tag)
2131    
2132 elmex 1.349 object *find_object_uuid (UUID i)
2133    
2134 root 1.218 # TODO: nuke
2135 root 1.61 object *insert_ob_in_map_at (object *ob, maptile *where, object_ornull *orig, int flag, int x, int y)
2136 root 1.1 PROTOTYPE: $$$$$$
2137     CODE:
2138     {
2139 root 1.257 RETVAL = insert_ob_in_map_at (ob, where, orig, flag, x, y);
2140 root 1.329
2141     if (RETVAL->destroyed ())
2142     RETVAL = 0;
2143 root 1.1 }
2144    
2145 root 1.284 shstr
2146     object::kv_get (shstr key)
2147 root 1.1
2148 root 1.284 void
2149     object::kv_del (shstr key)
2150    
2151     void
2152     object::kv_set (shstr key, shstr value)
2153 root 1.1
2154     object *get_nearest_player (object *ob)
2155     ALIAS: nearest_player = 0
2156     PREINIT:
2157     extern object *get_nearest_player (object *);
2158    
2159     void rangevector (object *ob, object *other, int flags = 0)
2160     PROTOTYPE: $$;$
2161     PPCODE:
2162     {
2163     rv_vector rv;
2164 root 1.291
2165     PUTBACK;
2166 root 1.1 get_rangevector (ob, other, &rv, flags);
2167 root 1.291 SPAGAIN;
2168    
2169 root 1.1 EXTEND (SP, 5);
2170     PUSHs (newSVuv (rv.distance));
2171     PUSHs (newSViv (rv.distance_x));
2172     PUSHs (newSViv (rv.distance_y));
2173     PUSHs (newSViv (rv.direction));
2174 root 1.257 PUSHs (to_sv (rv.part));
2175 root 1.1 }
2176    
2177     bool on_same_map_as (object *ob, object *other)
2178     CODE:
2179     RETVAL = on_same_map (ob, other);
2180     OUTPUT: RETVAL
2181    
2182 root 1.183 const_utf8_string
2183 root 1.58 base_name (object *op, int plural = op->nrof > 1)
2184 root 1.1 CODE:
2185 root 1.58 RETVAL = query_base_name (op, plural);
2186 root 1.1 OUTPUT: RETVAL
2187    
2188 root 1.256 # return the tail of an object, excluding itself
2189     void
2190     tail (object *op)
2191     PPCODE:
2192     while ((op = op->more))
2193     XPUSHs (sv_2mortal (to_sv (op)));
2194    
2195 root 1.1 MODULE = cf PACKAGE = cf::object::player PREFIX = cf_player_
2196    
2197     player *player (object *op)
2198     CODE:
2199     RETVAL = op->contr;
2200     OUTPUT: RETVAL
2201    
2202 root 1.257 bool move_player (object *op, int dir)
2203    
2204 root 1.183 void message (object *op, utf8_string txt, int flags = NDI_ORANGE | NDI_UNIQUE)
2205 root 1.120 CODE:
2206     new_draw_info (flags, 0, op, txt);
2207 root 1.1
2208     void kill_player (object *op)
2209    
2210 root 1.257 void esrv_send_item (object *pl, object *item)
2211    
2212     void esrv_update_item (object *pl, int what, object *item)
2213     C_ARGS: what, pl, item
2214    
2215     void esrv_del_item (object *pl, int tag)
2216     C_ARGS: pl->contr, tag
2217 root 1.58
2218 root 1.183 int command_summon (object *op, utf8_string params)
2219 root 1.67
2220 root 1.183 int command_arrest (object *op, utf8_string params)
2221 root 1.67
2222 root 1.66
2223 root 1.12 MODULE = cf PACKAGE = cf::player PREFIX = cf_player_
2224 root 1.1
2225 root 1.358 INCLUDE: $PERL $srcdir/genacc player $srcdir/../include/player.h |
2226 root 1.62
2227 root 1.18 int invoke (player *pl, int event, ...)
2228     CODE:
2229     if (KLASS_OF (event) != KLASS_PLAYER) croak ("event class must be PLAYER");
2230 root 1.24 AV *av = (AV *)sv_2mortal ((SV *)newAV ());
2231     for (int i = 2; i < items; i++) av_push (av, SvREFCNT_inc (ST (i)));
2232 root 1.109 RETVAL = pl->invoke ((event_type)event, ARG_AV (av), DT_END);
2233 root 1.18 OUTPUT: RETVAL
2234    
2235 root 1.12 SV *registry (player *pl)
2236 root 1.1
2237 root 1.102 void
2238     save_stats (player *pl)
2239     CODE:
2240     pl->ob->stats.hp = pl->ob->stats.maxhp;
2241     pl->ob->stats.sp = pl->ob->stats.maxsp;
2242     pl->ob->stats.grace = pl->ob->stats.maxgrace;
2243     pl->orig_stats = pl->ob->stats;
2244    
2245 root 1.307 # should only be temporary
2246 elmex 1.306 void esrv_new_player (player *pl)
2247    
2248 root 1.310 #d# TODO: replace by blocked_los accessor, fix code using this
2249 root 1.1 bool
2250     cell_visible (player *pl, int dx, int dy)
2251     CODE:
2252 root 1.310 RETVAL = pl->blocked_los (dx, dy) != LOS_BLOCKED;
2253 root 1.1 OUTPUT:
2254     RETVAL
2255    
2256 root 1.4 void
2257 root 1.1 send (player *pl, SV *packet)
2258     CODE:
2259     {
2260     STRLEN len;
2261     char *buf = SvPVbyte (packet, len);
2262    
2263 root 1.258 if (len > MAXSOCKBUF)
2264     pl->failmsg ("[packet too long for client]");
2265     else if (pl->ns)
2266 root 1.100 pl->ns->send_packet (buf, len);
2267 root 1.1 }
2268    
2269 root 1.46 void savebed (player *pl, SV *map_path = 0, SV *x = 0, SV *y = 0)
2270 root 1.45 PROTOTYPE: $;$$$
2271 root 1.1 PPCODE:
2272 root 1.45 if (GIMME_V != G_VOID)
2273     {
2274     EXTEND (SP, 3);
2275     PUSHs (sv_2mortal (newSVpv (pl->savebed_map, 0)));
2276     PUSHs (sv_2mortal (newSViv (pl->bed_x)));
2277     PUSHs (sv_2mortal (newSViv (pl->bed_y)));
2278     }
2279 root 1.46 if (map_path) sv_to (map_path, pl->savebed_map);
2280     if (x) sv_to (x, pl->bed_x);
2281     if (y) sv_to (y, pl->bed_y);
2282 root 1.1
2283     void
2284     list ()
2285     PPCODE:
2286 root 1.128 for_all_players (pl)
2287 root 1.100 XPUSHs (sv_2mortal (to_sv (pl)));
2288 root 1.1
2289    
2290     MODULE = cf PACKAGE = cf::map PREFIX = cf_map_
2291    
2292 root 1.61 int invoke (maptile *map, int event, ...)
2293 root 1.18 CODE:
2294     if (KLASS_OF (event) != KLASS_MAP) croak ("event class must be MAP");
2295 root 1.24 AV *av = (AV *)sv_2mortal ((SV *)newAV ());
2296     for (int i = 2; i < items; i++) av_push (av, SvREFCNT_inc (ST (i)));
2297 root 1.109 RETVAL = map->invoke ((event_type)event, ARG_AV (av), DT_END);
2298 root 1.25 OUTPUT: RETVAL
2299 root 1.18
2300 root 1.61 SV *registry (maptile *map)
2301 root 1.12
2302 root 1.255 void
2303     find_tagged_objects (maptile *map, utf8_string tag = 0)
2304     PPCODE:
2305     {
2306     if (!map->spaces)
2307     XSRETURN_EMPTY;
2308    
2309     if (tag)
2310     {
2311     shstr_cmp tag_ (tag);
2312    
2313     for (mapspace *ms = map->spaces + map->size (); ms-- > map->spaces; )
2314     for (object *op = ms->bot; op; op = op->above)
2315     if (op->tag == tag_)
2316     XPUSHs (sv_2mortal (to_sv (op)));
2317     }
2318     else
2319     {
2320     for (mapspace *ms = map->spaces + map->size (); ms-- > map->spaces; )
2321     for (object *op = ms->bot; op; op = op->above)
2322     if (op->tag)
2323     XPUSHs (sv_2mortal (to_sv (op)));
2324     }
2325     }
2326    
2327 root 1.358 INCLUDE: $PERL $srcdir/genacc maptile $srcdir/../include/map.h |
2328 root 1.1
2329 root 1.116 void
2330 root 1.312 adjust_daylight ()
2331     CODE:
2332     maptile::adjust_daylight ();
2333    
2334 root 1.318 int
2335     outdoor_darkness (int darkness = 0)
2336     CODE:
2337     RETVAL = maptile::outdoor_darkness;
2338     if (items)
2339     maptile::outdoor_darkness = darkness;
2340     OUTPUT:
2341     RETVAL
2342    
2343 root 1.312 void
2344 root 1.116 maptile::instantiate ()
2345    
2346     maptile *new ()
2347 root 1.1 PROTOTYPE:
2348     CODE:
2349 root 1.116 RETVAL = new maptile;
2350 root 1.1 OUTPUT:
2351     RETVAL
2352    
2353 root 1.116 void
2354 root 1.117 maptile::players ()
2355     PPCODE:
2356     if (GIMME_V == G_SCALAR)
2357 root 1.118 XPUSHs (sv_2mortal (to_sv (THIS->players)));
2358 root 1.117 else if (GIMME_V == G_ARRAY)
2359     {
2360     EXTEND (SP, THIS->players);
2361     for_all_players (pl)
2362     if (pl->ob && pl->ob->map == THIS)
2363 root 1.118 PUSHs (sv_2mortal (to_sv (pl->ob)));
2364 root 1.117 }
2365    
2366 root 1.156 void
2367 root 1.168 maptile::add_underlay (SV *data, int offset, int stride, SV *palette)
2368 root 1.156 CODE:
2369     {
2370 root 1.168 if (!SvROK (palette) || SvTYPE (SvRV (palette)) != SVt_PVAV)
2371     croak ("maptile::add_underlay: palette must be arrayref");
2372 root 1.156
2373 root 1.168 palette = SvRV (palette);
2374 root 1.156
2375 root 1.168 STRLEN idxlen;
2376     const uint8_t *idx = (const uint8_t *)SvPVbyte (data, idxlen);
2377 root 1.156
2378 root 1.168 for (int x = 0; x < THIS->width; ++x)
2379     for (int y = 0; y < THIS->height; ++y)
2380     {
2381     for (object *op = THIS->at (x, y).bot; op; op = op->above)
2382     if (op->flag [FLAG_IS_FLOOR])
2383 root 1.340 goto skip;
2384 root 1.168
2385     {
2386     int offs = offset + y * stride + x;
2387 root 1.340
2388 root 1.168 if (IN_RANGE_EXC (offs, 0, idxlen))
2389     {
2390     if (SV **elem = av_fetch ((AV *)palette, idx [offs], 0))
2391     {
2392 root 1.345 object *ob = get_archetype (cfSvPVutf8_nolen (*elem));
2393 root 1.168 ob->flag [FLAG_NO_MAP_SAVE] = true;
2394     THIS->insert (ob, x, y, 0, INS_ABOVE_FLOOR_ONLY);
2395 root 1.200
2396 root 1.340 if (ob->randomitems && !ob->above)
2397 root 1.200 {
2398 root 1.340 ob->create_treasure (ob->randomitems);
2399 root 1.203
2400 root 1.340 for (object *op = ob->above; op; op = op->above)
2401     op->flag [FLAG_NO_MAP_SAVE] = true;
2402     // TODO: if this is a pickable object, then the item
2403     // will at a bit weird - saving inside the player
2404     // will clear the flag, but when the player drops
2405     // it without logging out, it keeps the flag.
2406     // nobody ahs reported this, but this can be rather
2407     // annoying on persistent maps.
2408 root 1.200 }
2409 root 1.168 }
2410     }
2411     }
2412 root 1.156
2413 root 1.340 skip: ;
2414 root 1.168 }
2415     }
2416    
2417     void
2418     maptile::set_regiondata (SV *data, int offset, int stride, SV *palette)
2419     CODE:
2420     {
2421     if (!SvROK (palette) || SvTYPE (SvRV (palette)) != SVt_PVAV)
2422     croak ("maptile::set_regiondata: palette must be arrayref");
2423    
2424     palette = SvRV (palette);
2425    
2426     STRLEN idxlen;
2427     const uint8_t *idx = (const uint8_t *)SvPVbyte (data, idxlen);
2428    
2429 root 1.230 region_ptr *regionmap = new region_ptr [av_len ((AV *)palette) + 1];
2430 root 1.168 uint8_t *regions = salloc<uint8_t> (THIS->size ());
2431    
2432     for (int i = av_len ((AV *)palette) + 1; i--; )
2433 root 1.345 regionmap [i] = region::find (cfSvPVutf8_nolen (*av_fetch ((AV *)palette, i, 1)));
2434 root 1.168
2435     for (int y = 0; y < THIS->height; ++y)
2436     memcpy (regions + y * THIS->width, idx + offset + y * stride, THIS->width);
2437    
2438     sfree (THIS->regions, THIS->size ());
2439 root 1.230 delete [] THIS->regionmap;
2440 root 1.168
2441     THIS->regions = regions;
2442 root 1.156 THIS->regionmap = regionmap;
2443     }
2444    
2445 root 1.193 void
2446     maptile::create_region_treasure ()
2447     CODE:
2448     for (int x = 0; x < THIS->width; ++x)
2449     for (int y = 0; y < THIS->height; ++y)
2450     {
2451     region *rgn = THIS->region (x, y);
2452    
2453     //fprintf (stderr, "%d,%d %f %p\n", x, y, rgn->treasure_density,rgn->treasure);//D
2454 root 1.301 if (object *op = THIS->at (x, y).top)
2455     if (rgn->treasure && rndm () < rgn->treasure_density)
2456 root 1.193 create_treasure (rgn->treasure, op, GT_ENVIRONMENT, THIS->difficulty);
2457     }
2458    
2459 root 1.74 int out_of_map (maptile *map, int x, int y)
2460    
2461 root 1.29 void
2462 root 1.315 find_link (maptile *map, shstr_tmp connection)
2463 root 1.29 PPCODE:
2464 root 1.315 if (oblinkpt *obp = map->find_link (connection))
2465 root 1.29 for (objectlink *ol = obp->link; ol; ol = ol->next)
2466 root 1.257 XPUSHs (sv_2mortal (to_sv ((object *)ol->ob)));
2467 root 1.1
2468     void
2469 root 1.140 get_map_flags (maptile *map, int x, int y)
2470 root 1.1 PPCODE:
2471     {
2472 root 1.61 maptile *nmap = 0;
2473 root 1.1 I16 nx = 0, ny = 0;
2474 root 1.291
2475     PUTBACK;
2476 root 1.19 int flags = get_map_flags (map, &nmap, x, y, &nx, &ny);
2477 root 1.291 SPAGAIN;
2478 root 1.1
2479     EXTEND (SP, 4);
2480     PUSHs (sv_2mortal (newSViv (flags)));
2481    
2482     if (GIMME_V == G_ARRAY)
2483     {
2484 root 1.257 PUSHs (sv_2mortal (to_sv (nmap)));
2485 root 1.1 PUSHs (sv_2mortal (newSViv (nx)));
2486     PUSHs (sv_2mortal (newSViv (ny)));
2487     }
2488     }
2489    
2490 root 1.293 mapspace *
2491     ms (maptile *map, unsigned int x, unsigned int y)
2492     PROTOTYPE: $$$
2493     CODE:
2494     {
2495     maptile *nmap = 0;
2496     I16 nx, ny;
2497    
2498     PUTBACK;
2499     get_map_flags (map, &nmap, x, y, &nx, &ny);
2500     SPAGAIN;
2501    
2502     if (!nmap)
2503     XSRETURN_UNDEF;
2504    
2505     RETVAL = &nmap->at (nx, ny);
2506     }
2507     OUTPUT:
2508     RETVAL
2509    
2510 root 1.1 void
2511 root 1.61 at (maptile *map, unsigned int x, unsigned int y)
2512 root 1.1 PROTOTYPE: $$$
2513     PPCODE:
2514     {
2515 root 1.61 maptile *nmap = 0;
2516 root 1.1 I16 nx, ny;
2517    
2518 root 1.291 PUTBACK;
2519 root 1.19 get_map_flags (map, &nmap, x, y, &nx, &ny);
2520 root 1.291 SPAGAIN;
2521 root 1.1
2522     if (nmap)
2523 root 1.291 for (object *o = nmap->at (nx, ny).bot; o; o = o->above)
2524 root 1.257 XPUSHs (sv_2mortal (to_sv (o)));
2525 root 1.1 }
2526    
2527     SV *
2528 root 1.309 bot_at (maptile *map, unsigned int x, unsigned int y)
2529 root 1.1 PROTOTYPE: $$$
2530     ALIAS:
2531     top_at = 1
2532     flags_at = 2
2533     light_at = 3
2534     move_block_at = 4
2535     move_slow_at = 5
2536     move_on_at = 6
2537     move_off_at = 7
2538     CODE:
2539 root 1.309 {
2540     sint16 nx = x;
2541     sint16 ny = y;
2542    
2543     if (!xy_normalise (map, nx, ny))
2544     XSRETURN_UNDEF;
2545    
2546     mapspace &ms = map->at (nx, ny);
2547    
2548     ms.update ();
2549    
2550 root 1.1 switch (ix)
2551     {
2552 root 1.309 case 0: RETVAL = to_sv (ms.bot ); break;
2553     case 1: RETVAL = to_sv (ms.top ); break;
2554     case 2: RETVAL = newSVuv (ms.flags_ ); break;
2555     case 3: RETVAL = newSViv (ms.light ); break;
2556     case 4: RETVAL = newSVuv (ms.move_block); break;
2557     case 5: RETVAL = newSVuv (ms.move_slow ); break;
2558     case 6: RETVAL = newSVuv (ms.move_on ); break;
2559     case 7: RETVAL = newSVuv (ms.move_off ); break;
2560 root 1.1 }
2561 root 1.309 }
2562 root 1.122 OUTPUT: RETVAL
2563 root 1.1
2564 root 1.117 # worst xs function of my life
2565 root 1.140 bool
2566 root 1.117 _create_random_map (\
2567 root 1.140 maptile *self,\
2568 root 1.183 utf8_string wallstyle,\
2569     utf8_string wall_name,\
2570     utf8_string floorstyle,\
2571     utf8_string monsterstyle,\
2572     utf8_string treasurestyle,\
2573     utf8_string layoutstyle,\
2574     utf8_string doorstyle,\
2575     utf8_string decorstyle,\
2576 root 1.354 utf8_string miningstyle,\
2577 root 1.183 utf8_string origin_map,\
2578     utf8_string final_map,\
2579     utf8_string exitstyle,\
2580     utf8_string this_map,\
2581     utf8_string exit_on_final_map,\
2582 root 1.146 int xsize,\
2583     int ysize,\
2584 root 1.117 int expand2x,\
2585     int layoutoptions1,\
2586     int layoutoptions2,\
2587     int layoutoptions3,\
2588     int symmetry,\
2589     int difficulty,\
2590     int difficulty_given,\
2591     float difficulty_increase,\
2592     int dungeon_level,\
2593     int dungeon_depth,\
2594     int decoroptions,\
2595     int orientation,\
2596     int origin_y,\
2597     int origin_x,\
2598 root 1.146 U32 random_seed,\
2599 root 1.117 val64 total_map_hp,\
2600     int map_layout_style,\
2601     int treasureoptions,\
2602     int symmetry_used,\
2603 root 1.137 region *region,\
2604 root 1.183 utf8_string custom\
2605 root 1.117 )
2606     CODE:
2607     {
2608     random_map_params rmp;
2609    
2610     assign (rmp.wallstyle , wallstyle);
2611     assign (rmp.wall_name , wall_name);
2612     assign (rmp.floorstyle , floorstyle);
2613     assign (rmp.monsterstyle , monsterstyle);
2614     assign (rmp.treasurestyle , treasurestyle);
2615     assign (rmp.layoutstyle , layoutstyle);
2616     assign (rmp.doorstyle , doorstyle);
2617     assign (rmp.decorstyle , decorstyle);
2618 root 1.354 assign (rmp.miningstyle , miningstyle);
2619 root 1.117 assign (rmp.exitstyle , exitstyle);
2620     assign (rmp.exit_on_final_map, exit_on_final_map);
2621    
2622 root 1.122 rmp.origin_map = origin_map;
2623     rmp.final_map = final_map;
2624     rmp.this_map = this_map;
2625 root 1.146 rmp.xsize = xsize;
2626     rmp.ysize = ysize;
2627 root 1.117 rmp.expand2x = expand2x;
2628     rmp.layoutoptions1 = layoutoptions1;
2629     rmp.layoutoptions2 = layoutoptions2;
2630     rmp.layoutoptions3 = layoutoptions3;
2631     rmp.symmetry = symmetry;
2632     rmp.difficulty = difficulty;
2633     rmp.difficulty_given = difficulty_given;
2634     rmp.difficulty_increase = difficulty_increase;
2635     rmp.dungeon_level = dungeon_level;
2636     rmp.dungeon_depth = dungeon_depth;
2637     rmp.decoroptions = decoroptions;
2638     rmp.orientation = orientation;
2639     rmp.origin_y = origin_y;
2640     rmp.origin_x = origin_x;
2641     rmp.random_seed = random_seed;
2642 root 1.214 rmp.total_map_hp = (uint64_t) total_map_hp;
2643 root 1.117 rmp.map_layout_style = map_layout_style;
2644     rmp.treasureoptions = treasureoptions;
2645     rmp.symmetry_used = symmetry_used;
2646     rmp.region = region;
2647 root 1.137 rmp.custom = custom;
2648 root 1.117
2649 root 1.140 RETVAL = self->generate_random_map (&rmp);
2650 root 1.117 }
2651     OUTPUT:
2652     RETVAL
2653    
2654 root 1.293 MODULE = cf PACKAGE = cf::mapspace
2655    
2656 root 1.358 INCLUDE: $PERL $srcdir/genacc mapspace $srcdir/../include/map.h |
2657 root 1.293
2658 root 1.19 MODULE = cf PACKAGE = cf::arch
2659 root 1.1
2660 root 1.218 int archetypes_size ()
2661     CODE:
2662     RETVAL = archetypes.size ();
2663     OUTPUT: RETVAL
2664    
2665     archetype *archetypes (U32 index)
2666     CODE:
2667     RETVAL = index < archetypes.size () ? archetypes [index] : 0;
2668     OUTPUT: RETVAL
2669 root 1.1
2670 root 1.358 INCLUDE: $PERL $srcdir/genacc archetype $srcdir/../include/object.h |
2671 root 1.1
2672 root 1.19 MODULE = cf PACKAGE = cf::party
2673 root 1.1
2674 root 1.19 partylist *first ()
2675 root 1.1 PROTOTYPE:
2676 root 1.19 CODE:
2677     RETVAL = get_firstparty ();
2678     OUTPUT: RETVAL
2679 root 1.1
2680 root 1.358 INCLUDE: $PERL $srcdir/genacc partylist $srcdir/../include/player.h |
2681 root 1.1
2682 root 1.19 MODULE = cf PACKAGE = cf::region
2683 root 1.1
2684 root 1.161 void
2685     list ()
2686     PPCODE:
2687     for_all_regions (rgn)
2688     XPUSHs (sv_2mortal (to_sv (rgn)));
2689    
2690 root 1.183 region *find (utf8_string name)
2691 root 1.161 PROTOTYPE: $
2692 root 1.19 CODE:
2693 root 1.161 RETVAL = region::find (name);
2694 root 1.19 OUTPUT: RETVAL
2695 root 1.1
2696 root 1.186 int specificity (region *rgn)
2697     CODE:
2698     RETVAL = 0;
2699     while (rgn = rgn->parent)
2700     RETVAL++;
2701     OUTPUT: RETVAL
2702    
2703 root 1.358 INCLUDE: $PERL $srcdir/genacc region $srcdir/../include/region.h |
2704 root 1.1
2705 root 1.19 MODULE = cf PACKAGE = cf::living
2706 root 1.1
2707 root 1.358 INCLUDE: $PERL $srcdir/genacc living $srcdir/../include/living.h |
2708 root 1.1
2709 root 1.76 MODULE = cf PACKAGE = cf::settings
2710    
2711 root 1.358 INCLUDE: $PERL $srcdir/genacc Settings $srcdir/../include/global.h |
2712 root 1.76
2713 root 1.84 MODULE = cf PACKAGE = cf::client
2714 root 1.79
2715 root 1.358 INCLUDE: $PERL $srcdir/genacc client $srcdir/../include/client.h |
2716 root 1.79
2717 root 1.84 int invoke (client *ns, int event, ...)
2718 root 1.79 CODE:
2719 root 1.88 if (KLASS_OF (event) != KLASS_CLIENT) croak ("event class must be CLIENT");
2720 root 1.79 AV *av = (AV *)sv_2mortal ((SV *)newAV ());
2721     for (int i = 2; i < items; i++) av_push (av, SvREFCNT_inc (ST (i)));
2722 root 1.109 RETVAL = ns->invoke ((event_type)event, ARG_AV (av), DT_END);
2723 root 1.79 OUTPUT: RETVAL
2724    
2725 root 1.84 SV *registry (client *ns)
2726 root 1.79
2727 root 1.100 void
2728     list ()
2729     PPCODE:
2730     EXTEND (SP, clients.size ());
2731     for (sockvec::iterator i = clients.begin (); i != clients.end (); ++i)
2732     PUSHs (sv_2mortal (to_sv (*i)));
2733    
2734 root 1.88 void
2735 root 1.100 client::send_packet (SV *packet)
2736     CODE:
2737     {
2738     STRLEN len;
2739     char *buf = SvPVbyte (packet, len);
2740    
2741 root 1.258 if (len > MAXSOCKBUF)
2742     {
2743     // ugly
2744     if (THIS->pl)
2745     THIS->pl->failmsg ("[packet too long for client]");
2746     }
2747     else
2748     THIS->send_packet (buf, len);
2749 root 1.100 }
2750    
2751 root 1.237 faceidx
2752 root 1.238 client::need_face (utf8_string name, int pri = 0)
2753 root 1.237 CODE:
2754 root 1.238 RETVAL = face_find (name, 0);
2755     if (RETVAL)
2756     {
2757     THIS->send_face (RETVAL, pri);
2758     THIS->flush_fx ();
2759     }
2760     OUTPUT:
2761     RETVAL
2762    
2763     int
2764     client::fx_want (int idx, int value = -1)
2765     CODE:
2766     if (0 < idx && idx < FT_NUM)
2767     {
2768     RETVAL = THIS->fx_want [idx];
2769     if (items > 2)
2770     THIS->fx_want [idx] = value;
2771     }
2772     else
2773     RETVAL = 0;
2774 root 1.237 OUTPUT:
2775     RETVAL
2776    
2777 root 1.239 MODULE = cf PACKAGE = cf::sound PREFIX = sound_
2778    
2779     faceidx sound_find (utf8_string name)
2780    
2781 root 1.240 void sound_set (utf8_string str, faceidx face)
2782    
2783     # dire hack
2784     void old_sound_index (int idx, faceidx face)
2785     CODE:
2786     extern faceidx old_sound_index [SOUND_CAST_SPELL_0];
2787     old_sound_index [idx] = face;
2788    
2789 root 1.176 MODULE = cf PACKAGE = cf::face PREFIX = face_
2790    
2791 root 1.358 #INCLUDE: $PERL $srcdir/genacc faceset $srcdir/../include/face.h |
2792 root 1.176
2793 root 1.183 faceidx face_find (utf8_string name, faceidx defidx = 0)
2794 root 1.176
2795 root 1.183 faceidx alloc (utf8_string name)
2796 root 1.176 CODE:
2797     {
2798     do
2799     {
2800     RETVAL = faces.size ();
2801 root 1.177 faces.resize (RETVAL + 1);
2802 root 1.176 }
2803     while (!RETVAL); // crude way to leave index 0
2804    
2805     faces [RETVAL].name = name;
2806     facehash.insert (std::make_pair (faces [RETVAL].name, RETVAL));
2807    
2808     if (!strcmp (name, BLANK_FACE_NAME)) blank_face = RETVAL;
2809     if (!strcmp (name, EMPTY_FACE_NAME)) empty_face = RETVAL;
2810     }
2811     OUTPUT: RETVAL
2812    
2813 root 1.227 void set_type (faceidx idx, int value)
2814     ALIAS:
2815     set_type = 0
2816     set_visibility = 1
2817     set_magicmap = 2
2818     set_smooth = 3
2819     set_smoothlevel = 4
2820 root 1.176 CODE:
2821 root 1.229 faceinfo *f = face_info (idx); assert (f);
2822 root 1.227 switch (ix)
2823     {
2824     case 0: f->type = value; break;
2825     case 1: f->visibility = value; break;
2826     case 2: f->magicmap = value; break;
2827     case 3: f->smooth = value; break;
2828     case 4: f->smoothlevel = value; break;
2829     }
2830 root 1.177
2831     void set_data (faceidx idx, int faceset, SV *data, SV *chksum)
2832 root 1.176 CODE:
2833 root 1.182 {
2834 root 1.231 faceinfo *f = face_info (idx); assert (f);
2835     facedata *d = &(faceset ? f->data64 : f->data32);
2836 root 1.181 sv_to (data, d->data);
2837     STRLEN clen;
2838     char *cdata = SvPVbyte (chksum, clen);
2839 root 1.338 clen = min (CHKSUM_MAXLEN, clen);
2840 root 1.182
2841 root 1.344 assert (("cf::face::set_data must be called with a non-empty checksum", clen));
2842    
2843 root 1.338 if (clen != d->chksum_len || memcmp (d->chksum, cdata, clen))
2844 root 1.182 {
2845 root 1.338 d->chksum_len = clen;
2846 root 1.182 memcpy (d->chksum, cdata, clen);
2847    
2848     // invalidate existing client face info
2849     for_all_clients (ns)
2850     if (ns->faceset == faceset)
2851     {
2852     ns->faces_sent [idx] = false;
2853     ns->force_newmap = true;
2854     }
2855     }
2856     }
2857 root 1.176
2858 root 1.229 int get_data_size (faceidx idx, int faceset = 0)
2859     CODE:
2860 root 1.267 facedata *d = face_data (idx, faceset);
2861     if (!d) XSRETURN_UNDEF;
2862 root 1.229 RETVAL = d->data.size ();
2863     OUTPUT:
2864     RETVAL
2865    
2866     SV *get_chksum (faceidx idx, int faceset = 0)
2867     CODE:
2868 root 1.267 facedata *d = face_data (idx, faceset);
2869     if (!d) XSRETURN_UNDEF;
2870 root 1.338 RETVAL = newSVpvn ((char *)d->chksum, d->chksum_len);
2871 root 1.229 OUTPUT:
2872     RETVAL
2873    
2874 root 1.267 SV *get_data (faceidx idx, int faceset = 0)
2875     CODE:
2876     facedata *d = face_data (idx, faceset);
2877     if (!d) XSRETURN_UNDEF;
2878     RETVAL = newSVpvn (d->data.data (), d->data.length ());
2879     OUTPUT:
2880     RETVAL
2881    
2882 root 1.177 void invalidate (faceidx idx)
2883     CODE:
2884     for_all_clients (ns)
2885 root 1.182 {
2886     ns->faces_sent [idx] = false;
2887     ns->force_newmap = true;
2888     }
2889 root 1.177
2890     void invalidate_all ()
2891     CODE:
2892     for_all_clients (ns)
2893 root 1.182 {
2894     ns->faces_sent.reset ();
2895     ns->force_newmap = true;
2896     }
2897 root 1.177
2898 root 1.185 MODULE = cf PACKAGE = cf::anim PREFIX = anim_
2899    
2900 root 1.358 #INCLUDE: $PERL $srcdir/genacc faceset $srcdir/../include/anim.h |
2901 root 1.185
2902     animidx anim_find (utf8_string name)
2903     CODE:
2904     RETVAL = animation::find (name).number;
2905     OUTPUT: RETVAL
2906    
2907     animidx set (utf8_string name, SV *frames, int facings = 1)
2908     CODE:
2909     {
2910     if (!SvROK (frames) && SvTYPE (SvRV (frames)) != SVt_PVAV)
2911     croak ("frames must be an arrayref");
2912    
2913     AV *av = (AV *)SvRV (frames);
2914    
2915     animation *anim = &animation::find (name);
2916     if (anim->number)
2917     {
2918     anim->resize (av_len (av) + 1);
2919     anim->facings = facings;
2920     }
2921     else
2922     anim = &animation::create (name, av_len (av) + 1, facings);
2923    
2924     for (int i = 0; i < anim->num_animations; ++i)
2925 root 1.345 anim->faces [i] = face_find (cfSvPVutf8_nolen (*av_fetch (av, i, 1)));
2926 root 1.185 }
2927     OUTPUT: RETVAL
2928    
2929     void invalidate_all ()
2930     CODE:
2931     for_all_clients (ns)
2932     ns->anims_sent.reset ();
2933    
2934 root 1.247 MODULE = cf PACKAGE = cf::object::freezer
2935    
2936 root 1.358 INCLUDE: $PERL $srcdir/genacc object_freezer $srcdir/../include/cfperl.h |
2937 root 1.247
2938     SV *
2939     new (char *klass)
2940     CODE:
2941     RETVAL = newSVptr (new object_freezer, gv_stashpv ("cf::object::freezer", 1));
2942     OUTPUT: RETVAL
2943    
2944     void
2945     DESTROY (SV *sv)
2946     CODE:
2947     object_freezer *self;
2948     sv_to (sv, self);
2949     delete self;
2950    
2951     MODULE = cf PACKAGE = cf::object::thawer
2952    
2953 root 1.358 INCLUDE: $PERL $srcdir/genacc object_thawer $srcdir/../include/cfperl.h |
2954 root 1.247
2955     SV *
2956     new_from_file (char *klass, octet_string path)
2957     CODE:
2958     object_thawer *f = new object_thawer (path);
2959     if (!*f)
2960     {
2961     delete f;
2962     XSRETURN_UNDEF;
2963     }
2964     RETVAL = newSVptr (f, gv_stashpv ("cf::object::thawer", 1));
2965     OUTPUT: RETVAL
2966    
2967     void
2968     DESTROY (SV *sv)
2969     CODE:
2970     object_thawer *self;
2971     sv_to (sv, self);
2972     delete self;
2973    
2974 root 1.252 void
2975 root 1.253 extract_tags (object_thawer *self)
2976 root 1.254 PPCODE:
2977 root 1.252 while (self->kw != KW_EOF)
2978     {
2979 root 1.254 PUTBACK;
2980 root 1.272 coroapi::cede_to_tick ();
2981 root 1.254 SPAGAIN;
2982 root 1.253
2983 root 1.252 if (self->kw == KW_tag)
2984 root 1.254 XPUSHs (sv_2mortal (newSVpv_utf8 (self->get_str ())));
2985 root 1.252
2986     self->skip ();
2987     }
2988