--- deliantra/server/plugins/cfperl/cfperl.xs 2006/02/08 03:46:15 1.15 +++ deliantra/server/plugins/cfperl/cfperl.xs 2006/03/21 02:08:02 1.39 @@ -31,7 +31,7 @@ #undef save_long // clashes with libproto.h #define PLUGIN_NAME "perl" -#define PLUGIN_VERSION "cfperl 0.0" +#define PLUGIN_VERSION "cfperl 0.2" #ifndef __CEXTRACT__ #include @@ -44,33 +44,38 @@ #endif #include +#include #include #include "perlxsi.c" +typedef object object_ornull; +typedef mapstruct mapstruct_ornull; + static f_plug_api gethook; static f_plug_api registerGlobalEvent; static f_plug_api unregisterGlobalEvent; static f_plug_api systemDirectory; static f_plug_api object_set_property; static f_plug_api map_get_map; +static f_plug_api object_insert; +/* this is a stupid way to do things, and awkward to use for plug-in authors */ typedef struct { object* who; object* activator; object* third; + mapstruct* map; char message[1024]; - int fix; + int fix; // seems to be python-only, and should not be part of the API int event_code; char extension[1024]; // name field, should invoke specific perl extension char options[1024]; // slaying field of event_connectors int returnvalue; } CFPContext; -//static int current_command = -999; - static HV *obj_cache; static PerlInterpreter *perl; @@ -82,7 +87,12 @@ void clean_obj_cache () { - int todo = 10; + static int count; + + if (++count & 7) + return; + + int todo = 1000; do { I32 klen; @@ -91,10 +101,10 @@ if (he) { - SV *sv = SvRV (hv_iterval (obj_cache, he)); + SV *sv = hv_iterval (obj_cache, he); - // emopty and unreferened? nuke it - if (SvREFCNT (sv) == 1 && !HvFILL ((HV *)sv)) + // empty and unreferenced? nuke it + if (SvREFCNT (sv) == 1 && SvREFCNT (SvRV (sv)) == 1 && !HvFILL ((HV *)(SvRV (sv)))) { hv_delete (obj_cache, HeKEY (he), HeKLEN (he), G_DISCARD); todo++; @@ -109,30 +119,47 @@ static SV * newSVptr (void *ptr, const char *klass) { + SV *sv; + if (!ptr) return &PL_sv_undef; - HV *hv = newHV (); - sv_magic ((SV *)hv, 0, PERL_MAGIC_ext, (char *)ptr, 0); - return sv_bless (newRV_noinc ((SV *)hv), gv_stashpv (klass, 1)); + sv = newSV (0); + sv_magic (sv, 0, PERL_MAGIC_ext, (char *)ptr, 0); + return sv_bless (newRV_noinc (sv), gv_stashpv (klass, 1)); +} + +static void +SVptr_cache_set (void *ptr, SV *sv) +{ + hv_store (obj_cache, (char *)&ptr, sizeof (ptr), sv, 0); +} + +static SV * +SVptr_cache_get (void *ptr) +{ + SV **he = hv_fetch (obj_cache, (char *)&ptr, sizeof (ptr), 0); + + return he ? *he : 0; } static SV * newSVptr_cached (void *ptr, const char *klass) { - SV *sv, **he; + SV *sv; if (!ptr) return &PL_sv_undef; - he = hv_fetch (obj_cache, (char *)&ptr, sizeof (ptr), 0); + sv = SVptr_cache_get (ptr); - if (he) - sv = *he; - else + if (!sv) { - sv = newSVptr (ptr, klass); - hv_store (obj_cache, (char *)&ptr, sizeof (ptr), sv, 0); + HV *hv = newHV (); + sv_magic ((SV *)hv, 0, PERL_MAGIC_ext, (char *)ptr, 0); + sv = sv_bless (newRV_noinc ((SV *)hv), gv_stashpv (klass, 1)); + + SVptr_cache_set (ptr, sv); } return newSVsv (sv); @@ -162,6 +189,15 @@ return (long)mg->mg_ptr; } +static long +SvPTR_ornull (SV *sv, const char *klass) +{ + if (SvOK (sv)) + return SvPTR (sv, klass); + else + return 0; +} + SV * newSVcfapi (int type, ...) { @@ -172,12 +208,18 @@ switch (type) { +#if 0 + case CFAPI_INT16: + sv = newSViv (*va_arg (args, sint16_t *)); + break; +#endif + case CFAPI_INT: sv = newSViv (*va_arg (args, int *)); break; case CFAPI_LONG: - sv = newSViv (*va_arg (args, long *)); + sv = newSVnv ((double)*va_arg (args, sint64 *)); /* oh, the humanity! */ break; case CFAPI_DOUBLE: @@ -261,6 +303,7 @@ hv_context (CFAPI_POBJECT, ,who); hv_context (CFAPI_POBJECT, ,activator); hv_context (CFAPI_POBJECT, ,third); + hv_context (CFAPI_PMAP, ,map); hv_context (CFAPI_STRING , ,message); hv_context (CFAPI_INT ,&,fix); hv_context (CFAPI_INT ,&,event_code); @@ -391,6 +434,7 @@ systemDirectory = gethook (&rtype, hooktype, "cfapi_system_directory"); object_set_property = gethook (&rtype, hooktype, "cfapi_object_set_property"); map_get_map = gethook (&rtype, hooktype, "cfapi_map_get_map"); + object_insert = gethook (&rtype, hooktype, "cfapi_object_insert"); cf_init_plugin (gethook); @@ -405,12 +449,18 @@ registerGlobalEvent (NULL, EVENT_MAPENTER, PLUGIN_NAME, globalEventListener); registerGlobalEvent (NULL, EVENT_MAPLEAVE, PLUGIN_NAME, globalEventListener); registerGlobalEvent (NULL, EVENT_MAPRESET, PLUGIN_NAME, globalEventListener); + registerGlobalEvent (NULL, EVENT_MAPLOAD, PLUGIN_NAME, globalEventListener); + registerGlobalEvent (NULL, EVENT_MAPOUT, PLUGIN_NAME, globalEventListener); + registerGlobalEvent (NULL, EVENT_MAPIN, PLUGIN_NAME, globalEventListener); + registerGlobalEvent (NULL, EVENT_MAPCLEAN, PLUGIN_NAME, globalEventListener); registerGlobalEvent (NULL, EVENT_REMOVE, PLUGIN_NAME, globalEventListener); registerGlobalEvent (NULL, EVENT_SHOUT, PLUGIN_NAME, globalEventListener); registerGlobalEvent (NULL, EVENT_TELL, PLUGIN_NAME, globalEventListener); registerGlobalEvent (NULL, EVENT_MUZZLE, PLUGIN_NAME, globalEventListener); registerGlobalEvent (NULL, EVENT_KICK, PLUGIN_NAME, globalEventListener); registerGlobalEvent (NULL, EVENT_FREE_OB, PLUGIN_NAME, globalEventListener); + registerGlobalEvent (NULL, EVENT_PLAYER_LOAD, PLUGIN_NAME, globalEventListener); + registerGlobalEvent (NULL, EVENT_PLAYER_SAVE, PLUGIN_NAME, globalEventListener); char *argv[] = { "", @@ -466,6 +516,21 @@ printf ("Unimplemented for now\n"); break; + case EVENT_PLAYER_LOAD: + case EVENT_PLAYER_SAVE: + context.who = va_arg (args, object *); + buf = va_arg (args, char *); + if (buf != 0) + strncpy (context.message, buf, sizeof (context.message)); + break; + + case EVENT_MAPLOAD: + case EVENT_MAPOUT: + case EVENT_MAPIN: + case EVENT_MAPCLEAN: + context.map = va_arg (args, mapstruct *); + break; + case EVENT_MAPENTER: case EVENT_MAPLEAVE: case EVENT_FREE_OB: @@ -509,6 +574,7 @@ break; case EVENT_MAPRESET: + /* stupid, should be the map itself, not "message"??? */ buf = va_arg (args, char *); if (buf != 0) strncpy (context.message, buf, sizeof (context.message)); @@ -519,13 +585,10 @@ if (context.event_code == EVENT_FREE_OB) { - SV *sv = hv_delete (obj_cache, (char *)&context.activator, sizeof (object *), 0); + SV *sv = hv_delete (obj_cache, (char *)&context.activator, sizeof (void *), 0); if (sv) - { - clearSVptr (sv); - SvREFCNT_dec (sv); - } + clearSVptr (sv); } else inject_event ("cf::inject_global_event", &context); @@ -603,6 +666,7 @@ const_iv (llevMonster) const_iv (PLAYER) + const_iv (TRANSPORT) const_iv (ROD) const_iv (TREASURE) const_iv (POTION) @@ -617,7 +681,6 @@ const_iv (ARMOUR) const_iv (PEDESTAL) const_iv (ALTAR) - const_iv (CONFUSION) const_iv (LOCKED_DOOR) const_iv (SPECIAL_KEY) const_iv (MAP) @@ -728,10 +791,38 @@ const_iv (ST_BD_BUILD) const_iv (ST_BD_REMOVE) + const_iv (ST_MAT_FLOOR) const_iv (ST_MAT_WALL) const_iv (ST_MAT_ITEM) + const_iv (AT_PHYSICAL) + const_iv (AT_MAGIC) + const_iv (AT_FIRE) + const_iv (AT_ELECTRICITY) + const_iv (AT_COLD) + const_iv (AT_CONFUSION) + const_iv (AT_ACID) + const_iv (AT_DRAIN) + const_iv (AT_WEAPONMAGIC) + const_iv (AT_GHOSTHIT) + const_iv (AT_POISON) + const_iv (AT_SLOW) + const_iv (AT_PARALYZE) + const_iv (AT_TURN_UNDEAD) + const_iv (AT_FEAR) + const_iv (AT_CANCELLATION) + const_iv (AT_DEPLETE) + const_iv (AT_DEATH) + const_iv (AT_CHAOS) + const_iv (AT_COUNTERSPELL) + const_iv (AT_GODPOWER) + const_iv (AT_HOLYWORD) + const_iv (AT_BLIND) + const_iv (AT_INTERNAL) + const_iv (AT_LIFE_STEALING) + const_iv (AT_DISEASE) + const_iv (QUEST_IN_PROGRESS) const_iv (QUEST_DONE_QUEST) const_iv (QUEST_DONE_TASK) @@ -908,6 +999,92 @@ const_iv (WILL_APPLY_EARTHWALL) const_iv (WILL_APPLY_DOOR) const_iv (WILL_APPLY_FOOD) + + const_iv (SAVE_MODE) + const_iv (SAVE_DIR_MODE) + + const_iv (M_PAPER) + const_iv (M_IRON) + const_iv (M_GLASS) + const_iv (M_LEATHER) + const_iv (M_WOOD) + const_iv (M_ORGANIC) + const_iv (M_STONE) + const_iv (M_CLOTH) + const_iv (M_ADAMANT) + const_iv (M_LIQUID) + const_iv (M_SOFT_METAL) + const_iv (M_BONE) + const_iv (M_ICE) + const_iv (M_SPECIAL) + + const_iv (SK_EXP_ADD_SKILL) + const_iv (SK_EXP_TOTAL) + const_iv (SK_EXP_NONE) + const_iv (SK_SUBTRACT_SKILL_EXP) + + const_iv (SK_LOCKPICKING) + const_iv (SK_HIDING) + const_iv (SK_SMITHERY) + const_iv (SK_BOWYER) + const_iv (SK_JEWELER) + const_iv (SK_ALCHEMY) + const_iv (SK_STEALING) + const_iv (SK_LITERACY) + const_iv (SK_BARGAINING) + const_iv (SK_JUMPING) + const_iv (SK_DET_MAGIC) + const_iv (SK_ORATORY) + const_iv (SK_SINGING) + const_iv (SK_DET_CURSE) + const_iv (SK_FIND_TRAPS) + const_iv (SK_MEDITATION) + const_iv (SK_PUNCHING) + const_iv (SK_FLAME_TOUCH) + const_iv (SK_KARATE) + const_iv (SK_CLIMBING) + const_iv (SK_WOODSMAN) + const_iv (SK_INSCRIPTION) + const_iv (SK_ONE_HANDED_WEAPON) + const_iv (SK_MISSILE_WEAPON) + const_iv (SK_THROWING) + const_iv (SK_USE_MAGIC_ITEM) + const_iv (SK_DISARM_TRAPS) + const_iv (SK_SET_TRAP) + const_iv (SK_THAUMATURGY) + const_iv (SK_PRAYING) + const_iv (SK_CLAWING) + const_iv (SK_LEVITATION) + const_iv (SK_SUMMONING) + const_iv (SK_PYROMANCY) + const_iv (SK_EVOCATION) + const_iv (SK_SORCERY) + const_iv (SK_TWO_HANDED_WEAPON) + + const_iv (SOUND_NEW_PLAYER) + const_iv (SOUND_FIRE_ARROW) + const_iv (SOUND_LEARN_SPELL) + const_iv (SOUND_FUMBLE_SPELL) + const_iv (SOUND_WAND_POOF) + const_iv (SOUND_OPEN_DOOR) + const_iv (SOUND_PUSH_PLAYER) + const_iv (SOUND_PLAYER_HITS1) + const_iv (SOUND_PLAYER_HITS2) + const_iv (SOUND_PLAYER_HITS3) + const_iv (SOUND_PLAYER_HITS4) + const_iv (SOUND_PLAYER_IS_HIT1) + const_iv (SOUND_PLAYER_IS_HIT2) + const_iv (SOUND_PLAYER_IS_HIT3) + const_iv (SOUND_PLAYER_KILLS) + const_iv (SOUND_PET_IS_KILLED) + const_iv (SOUND_PLAYER_DIES) + const_iv (SOUND_OB_EVAPORATE) + const_iv (SOUND_OB_EXPLODE) + const_iv (SOUND_CLOCK) + const_iv (SOUND_TURN_HANDLE) + const_iv (SOUND_FALL_HOLE) + const_iv (SOUND_DRINK_POISON) + const_iv (SOUND_CAST_SPELL_0) }; for (civ = const_iv + sizeof (const_iv) / sizeof (const_iv [0]); civ-- > const_iv; ) @@ -937,12 +1114,18 @@ const_event (CLOCK) const_event (CRASH) const_event (PLAYER_DEATH) + const_event (PLAYER_LOAD) + const_event (PLAYER_SAVE) const_event (GKILL) const_event (LOGIN) const_event (LOGOUT) const_event (MAPENTER) const_event (MAPLEAVE) const_event (MAPRESET) + const_event (MAPLOAD) + const_event (MAPOUT) + const_event (MAPIN) + const_event (MAPCLEAN) const_event (REMOVE) const_event (SHOUT) const_event (TELL) @@ -1055,7 +1238,6 @@ prop (CFAPI_STRING, OBJECT_PROP_SHORT_NAME) prop (CFAPI_INT, OBJECT_PROP_MAGICAL) prop (CFAPI_INT, OBJECT_PROP_LUCK) - prop (CFAPI_LONG, OBJECT_PROP_EXP) prop (CFAPI_POBJECT, OBJECT_PROP_OWNER) prop (CFAPI_POBJECT, OBJECT_PROP_PRESENT) prop (CFAPI_INT, OBJECT_PROP_CHEATER) @@ -1152,12 +1334,47 @@ } break; case CFAPI_STRING: - cf_object_set_string_property (obj, idx, SvPV_nolen (newval)); + cf_object_set_string_property (obj, idx, SvOK (newval) ? SvPV_nolen (newval) : 0); + break; + case CFAPI_POBJECT: + { + int unused_type; + object_set_property (&unused_type, obj, idx, (object *)SvPTR_ornull (newval, "cf::object")); + } break; default: croak ("unhandled type '%d' in set_property '%d'", type, idx); } +# missing properties + +void +set_attacktype (object *obj, U32 attacktype) + CODE: + obj->attacktype = attacktype; + +U32 +get_attacktype (object *obj) + ALIAS: + attacktype = 0 + CODE: + RETVAL = obj->attacktype; + OUTPUT: RETVAL + +# missing in plug-in api, of course +void +set_food (object *obj, int food) + CODE: + obj->stats.food = food; + +int +get_food (object *obj) + ALIAS: + food = 0 + CODE: + RETVAL = obj->stats.food; + OUTPUT: RETVAL + void inv (object *obj) PROTOTYPE: $ @@ -1176,7 +1393,7 @@ void cf_object_set_flag (object *op, int flag, int value) -void cf_object_move (object *op, object *originator, int dir) +void cf_object_move (object *op, int dir, object *originator = op) void cf_object_apply (object *op, object *author, int flags = 0) @@ -1188,19 +1405,19 @@ object *cf_object_present_archname_inside (object *op, char *whatstr) -int cf_object_transfer (object *op, int x, int y, int r, object *orig) +int cf_object_transfer (object *op, int x, int y, int r = 0, object_ornull *orig = 0) int cf_object_change_map (object *op, int x, int y, mapstruct *map) -object *cf_object_clone (object *op, int clonetype) +object *cf_object_clone (object *op, int clonetype = 0) int cf_object_pay_item (object *op, object *buyer) int cf_object_pay_amount (object *op, double amount) -int cf_object_cast_spell (object *caster, object *ctoo, int dir, object *sp_, char *flags) +int cf_object_cast_spell (object *caster, object *ctoo, int dir, object *spell_ob, char *stringarg = 0) -int cf_object_cast_ability (object *caster, object *ctoo, int dir, object *sp_, char *flags) +int cf_object_cast_ability (object *caster, object *ctoo, int dir, object *sp_, char *stringarg = 0) void cf_object_learn_spell (object *op, object *sp) @@ -1246,48 +1463,55 @@ void cf_object_set_key (object *op, char *keyname, char *value) -char * -base_name (object *ob, int plural) - CODE: - RETVAL = cf_query_base_name (ob, plural); - OUTPUT: RETVAL +object *cf_create_object_by_name (const char *name) -MODULE = cf PACKAGE = cf::object PREFIX = cf_object_ +void change_exp (object *op, double exp, const char *skill_name = 0, int flag = 0) + +void player_lvl_adj (object *who, object *skill = 0) + + +MODULE = cf PACKAGE = cf::object PREFIX = cf_ -object *cf_create_object_by_name (const char *name = 0) +void cf_fix_object (object *pl) + ALIAS: fix = 0 + +object *cf_insert_ob_in_ob (object *ob, object *where) + +# no clean way to get an object from an archetype - stupid idiotic +# dumb kludgy misdesigned plug-in api slowly gets on my nerves. + +object *new (const char *archetype = 0) PROTOTYPE: ;$ - ALIAS: - create_object = 0 - new = 0 CODE: - RETVAL = name ? cf_create_object_by_name (name) : cf_create_object (); + RETVAL = archetype ? get_archetype (archetype) : cf_create_object (); OUTPUT: RETVAL -void cf_fix_object (object *pl) - ALIAS: fix = 0 +object *insert_ob_in_map_at (object *ob, mapstruct *where, object_ornull *orig, int flag, int x, int y) + PROTOTYPE: $$$$$$ + CODE: +{ + int unused_type; + RETVAL = (object *)object_insert (&unused_type, ob, 0, where, orig, flag, x, y); +} -object *cf_insert_ob_in_ob (object *ob, object *where) +object *get_nearest_player (object *ob) + ALIAS: nearest_player = 0 + PREINIT: + extern object *get_nearest_player (object *); void rangevector (object *ob, object *other, int flags = 0) PROTOTYPE: $$;$ - ALIAS: - direction = 1 - distance = 2 - CODE: + PPCODE: { rv_vector rv; - // get_rangevector uses these if the objects are not on the same map - // which is not the same as "on_same_map". - rv.distance_x = 32767; - rv.distance_y = 32767; get_rangevector (ob, other, &rv, flags); EXTEND (SP, 5); - if (!ix || ix == 2) PUSHs (newSVuv (rv.distance)); - if (!ix) PUSHs (newSViv (rv.distance_x)); - if (!ix) PUSHs (newSViv (rv.distance_y)); - if (!ix || ix == 1) PUSHs (newSViv (rv.direction)); - if (!ix) PUSHs (newSVcfapi (CFAPI_POBJECT, rv.part)); + PUSHs (newSVuv (rv.distance)); + PUSHs (newSViv (rv.distance_x)); + PUSHs (newSViv (rv.distance_y)); + PUSHs (newSViv (rv.direction)); + PUSHs (newSVcfapi (CFAPI_POBJECT, rv.part)); } bool on_same_map_as (object *ob, object *other) @@ -1295,6 +1519,18 @@ RETVAL = on_same_map (ob, other); OUTPUT: RETVAL +char * +base_name (object *ob, int plural) + CODE: + RETVAL = cf_query_base_name (ob, plural); + OUTPUT: RETVAL + +living * +stats (object *ob) + CODE: + RETVAL = &ob->stats; + OUTPUT: RETVAL + MODULE = cf PACKAGE = cf::object::player PREFIX = cf_player_ @@ -1307,6 +1543,11 @@ object *cf_player_send_inventory (object *op) +player *contr (object *op) + CODE: + RETVAL = op->contr; + OUTPUT: RETVAL + char *cf_player_get_ip (object *op) ALIAS: ip = 0 @@ -1320,6 +1561,7 @@ void cf_player_set_party (object *op, partylist *party) +void change_skill (object *op, double exp, char *skill_name = 0, int flag = 0) MODULE = cf PACKAGE = cf::object::map PREFIX = cf_ @@ -1330,6 +1572,10 @@ void cf_player_move (player *pl, int dir) +void MapNewmapCmd (player *pl) + +void play_sound_player_only (player *pl, int soundnum, int x = 0, int y = 0); + # nonstandard object *ob (player *pl) CODE: @@ -1346,6 +1592,21 @@ RETVAL = pl->next; OUTPUT: RETVAL +void get_savebed (player *pl) + ALIAS: + savebed = 0 + PPCODE: + EXTEND (SP, 3); + PUSHs (sv_2mortal (newSVpv (pl->savebed_map, 0))); + PUSHs (sv_2mortal (newSViv (pl->bed_x))); + PUSHs (sv_2mortal (newSViv (pl->bed_y))); + +void set_savebed (player *pl, char *map_path, int x, int y) + CODE: + strcpy (pl->savebed_map, map_path); + pl->bed_x = x; + pl->bed_y = y; + void list () PPCODE: @@ -1355,6 +1616,18 @@ XPUSHs (newSVcfapi (CFAPI_PPLAYER, pl)); } +living * +orig_stats (player *pl) + CODE: + RETVAL = &pl->orig_stats; + OUTPUT: RETVAL + +living * +last_stats (player *pl) + CODE: + RETVAL = &pl->last_stats; + OUTPUT: RETVAL + MODULE = cf PACKAGE = cf::map PREFIX = cf_map_ @@ -1386,6 +1659,12 @@ OUTPUT: RETVAL +void delete_map (mapstruct *map) + +void clean_tmp_map (mapstruct *map) + +void play_sound_map (mapstruct *map, int x, int y, int sound_num) + mapstruct *cf_map_get_map (char *name) PROTOTYPE: $ ALIAS: map = 0 @@ -1394,6 +1673,23 @@ PROTOTYPE: ALIAS: first = 0 +# whoever "designed" the plug-in api should have wasted +# his/her time with staying away form the project - would have +# saved others a lot of time, without doubt. +void set_path (mapstruct *where, char *path) + CODE: + strcpy (where->path, path); + +bool unique (mapstruct *map) + CODE: + RETVAL = map->unique; + OUTPUT: + RETVAL + +void set_unique (mapstruct *map, bool unique) + CODE: + map->unique = unique; + object *cf_map_insert_object_there (mapstruct *where, object *op, object *originator, int flags) object *cf_map_insert_object (mapstruct *where, object* op, int x, int y) @@ -1411,6 +1707,7 @@ PPCODE: { object *o; + for (o = GET_MAP_OB (obj, x, y); o; o = o->above) XPUSHs (sv_2mortal (newSVcfapi (CFAPI_POBJECT, o))); } @@ -1443,6 +1740,78 @@ OUTPUT: RETVAL +# "serialise" map perl data into a ref +void +_get_obs (mapstruct *map) + PPCODE: +{ + object *o; + int x, y; + AV *obs = newAV (); + int nonnull = 0; + + for (y = 0; y < MAP_HEIGHT (map); y++) + for (x = 0; x < MAP_WIDTH (map); x++) + { + AV *av = newAV (); + + for (o = GET_MAP_OB (map, x, y); o; o = o->above) + { + SV *sv = SVptr_cache_get (o); + + if (sv && HvFILL (SvRV (sv))) + { + nonnull = 1; + sv = newSVsv (sv); + } + else + sv = &PL_sv_undef; + + av_push (av, sv); + } + + av_store (obs, x + y * MAP_HEIGHT (map), newRV_noinc ((SV *)av)); + } + + if (nonnull) + XPUSHs (sv_2mortal (newRV_noinc ((SV *)obs))); + else + SvREFCNT_dec (obs); +} + +# "deserialise" perl map data into the map +void +_set_obs (mapstruct *map, SV *sv) + CODE: +{ + object *o; + AV *av; + int x, y; + AV *obs = (AV *)SvRV (sv); + + for (y = 0; y < MAP_HEIGHT (map); y++) + for (x = 0; x < MAP_WIDTH (map); x++) + { + sv = *av_fetch (obs, x + y * MAP_HEIGHT (map), 1); + + if (!SvROK (sv)) + continue; + + av = (AV *)SvRV (sv); + + for (o = GET_MAP_OB (map, x, y); o; o = o->above) + { + sv = av_shift (av); + + if (SvROK (sv)) + { + sv_magic ((SV *)SvRV (sv), 0, PERL_MAGIC_ext, (char *)o, 0); + SVptr_cache_set (o, sv); + } + } + } +} + MODULE = cf PACKAGE = cf::arch PREFIX = cf_archetype_ @@ -1505,3 +1874,55 @@ ALIAS: message = 0 +MODULE = cf PACKAGE = cf::living PREFIX = cf_living_ + +double +exp (living *liv, double new_val = 0.) + PROTOTYPE: $;$ + ALIAS: + Str = 1 + Dex = 2 + Con = 3 + Wis = 4 + Cha = 5 + Int = 6 + Pow = 7 + wc = 8 + ac = 9 + hp = 10 + maxhp = 11 + sp = 12 + maxsp = 13 + grace = 14 + maxgrace = 15 + food = 16 + dam = 17 + luck = 18 + CODE: +# define LIVING_ACC(acc,idx) case idx: RETVAL = liv->acc; if (items > 1) liv->acc = new_val; break + switch (ix) + { + LIVING_ACC (exp , 0); + LIVING_ACC (Str , 1); + LIVING_ACC (Dex , 2); + LIVING_ACC (Con , 3); + LIVING_ACC (Wis , 4); + LIVING_ACC (Cha , 5); + LIVING_ACC (Int , 6); + LIVING_ACC (Pow , 7); + LIVING_ACC (wc , 8); + LIVING_ACC (ac , 9); + LIVING_ACC (hp , 10); + LIVING_ACC (maxhp , 11); + LIVING_ACC (sp , 12); + LIVING_ACC (maxsp , 13); + LIVING_ACC (grace , 14); + LIVING_ACC (maxgrace, 15); + LIVING_ACC (food , 16); + LIVING_ACC (dam , 17); + LIVING_ACC (luck , 18); + } +# undef LIVING_ACC + OUTPUT: + RETVAL +