ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/server/cfperl.xs
Revision: 1.373
Committed: Thu Apr 15 04:56:47 2010 UTC (14 years, 1 month ago) by root
Branch: MAIN
Changes since 1.372: +2 -30 lines
Log Message:
raramraramraram

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