ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/server/cfperl.xs
Revision: 1.372
Committed: Thu Apr 15 04:17:59 2010 UTC (14 years, 1 month ago) by root
Branch: MAIN
Changes since 1.371: +1 -1 lines
Log Message:
create freezethaw.h

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