ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/server/cfperl.xs
Revision: 1.379
Committed: Fri Apr 23 09:47:13 2010 UTC (14 years, 1 month ago) by elmex
Branch: MAIN
Changes since 1.378: +7 -1 lines
Log Message:
added newSVptr 2 argument form.

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