ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/server/cfperl.xs
Revision: 1.378
Committed: Wed Apr 21 03:29:27 2010 UTC (14 years, 1 month ago) by root
Branch: MAIN
Changes since 1.377: +1 -1 lines
Log Message:
support dir in most map accessors, replace get_map_flags by normalise

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