ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/server/cfperl.xs
Revision: 1.367
Committed: Mon Apr 12 05:22:38 2010 UTC (14 years, 2 months ago) by root
Branch: MAIN
Changes since 1.366: +8 -1 lines
Log Message:
freelist management

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