--- deliantra/server/plugins/cfperl/cfperl.xs 2006/03/07 13:44:43 1.30 +++ deliantra/server/plugins/cfperl/cfperl.xs 2006/07/19 08:50:42 1.61 @@ -1,6 +1,5 @@ /*****************************************************************************/ /* CrossFire, A Multiplayer game for the X Window System */ -/* */ /*****************************************************************************/ /* @@ -31,7 +30,7 @@ #undef save_long // clashes with libproto.h #define PLUGIN_NAME "perl" -#define PLUGIN_VERSION "cfperl 0.2" +#define PLUGIN_VERSION "cfperl 0.3" #ifndef __CEXTRACT__ #include @@ -44,14 +43,22 @@ #endif #include +#include #include +//#include "EventAPI.h" #include "perlxsi.c" +extern sint64 *levels; // the experience table + typedef object object_ornull; typedef mapstruct mapstruct_ornull; +typedef double val64; +#define newSVval64 newSVnv +#define SvVAL64 SvNV + static f_plug_api gethook; static f_plug_api registerGlobalEvent; static f_plug_api unregisterGlobalEvent; @@ -66,6 +73,7 @@ object* who; object* activator; object* third; + object* event; mapstruct* map; char message[1024]; int fix; // seems to be python-only, and should not be part of the API @@ -78,6 +86,17 @@ static HV *obj_cache; static PerlInterpreter *perl; +#define PUSHcfapi(type,value) PUSHs (sv_2mortal (newSVcfapi (CFAPI_ ## type, (value)))) +#define PUSHcfapi_va(type,ctype) PUSHcfapi (type, va_arg (args, ctype)) +#define PUSH_OB PUSHcfapi_va(POBJECT, object *) +#define PUSH_PL PUSHcfapi_va(PPLAYER, player *) +#define PUSH_MAP PUSHcfapi_va(PMAP, mapstruct *) +#define PUSH_PV PUSHcfapi_va(STRING, const char *) +#define PUSH_IV PUSHs (sv_2mortal (newSViv (va_arg (args, int)))) + +extern void pay_player(object *op, uint64 amount); +extern uint64 pay_player_arch(object *op, const char *arch, uint64 amount); + ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // garbage collect some perl objects, if possible @@ -218,11 +237,11 @@ break; case CFAPI_LONG: - sv = newSViv (*va_arg (args, long *)); + sv = newSVval64 ((val64)*va_arg (args, sint64 *)); break; case CFAPI_DOUBLE: - sv = newSViv (*va_arg (args, double *)); + sv = newSVnv (*va_arg (args, double *)); break; case CFAPI_STRING: @@ -239,7 +258,7 @@ if (!obj) sv = &PL_sv_undef; else - switch (*(int *)cf_object_get_property (obj, CFAPI_OBJECT_PROP_TYPE)) + switch (obj->type) { case MAP: sv = newSVptr_cached (obj, "cf::object::map"); @@ -287,46 +306,6 @@ ///////////////////////////////////////////////////////////////////////////// -void -inject_event (const char *func, CFPContext *context) -{ - dSP; - - ENTER; - SAVETMPS; - - PUSHMARK (SP); - - HV *hv = newHV (); -#define hv_context(type,addr,expr) hv_store (hv, #expr, sizeof (#expr) - 1, newSVcfapi (type, addr context->expr), 0) - 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); - hv_context (CFAPI_STRING , ,options); - hv_context (CFAPI_STRING , ,extension); - - XPUSHs (sv_2mortal (newRV_noinc ((SV *)hv))); - - PUTBACK; - int count = call_pv (func, G_SCALAR | G_EVAL); - SPAGAIN; - - if (SvTRUE (ERRSV)) - LOG (llevError, "event '%d' callback evaluation error: %s", context->event_code, SvPV_nolen (ERRSV)); - - context->returnvalue = count > 0 ? POPi : 0; - - PUTBACK; - FREETMPS; - LEAVE; -} - -///////////////////////////////////////////////////////////////////////////// - int initPlugin (const char *iversion, f_plug_api gethooksptr) { @@ -441,6 +420,9 @@ registerGlobalEvent (NULL, EVENT_BORN, PLUGIN_NAME, globalEventListener); registerGlobalEvent (NULL, EVENT_CLOCK, PLUGIN_NAME, globalEventListener); //registerGlobalEvent (NULL, EVENT_CRASH, PLUGIN_NAME, globalEventListener); + registerGlobalEvent (NULL, EVENT_FIND_UNARMED_SKILL, PLUGIN_NAME, globalEventListener); + registerGlobalEvent (NULL, EVENT_PLAYER_USE_SKILL, PLUGIN_NAME, globalEventListener); + registerGlobalEvent (NULL, EVENT_MONSTER_USE_SKILL, PLUGIN_NAME, globalEventListener); registerGlobalEvent (NULL, EVENT_PLAYER_DEATH, PLUGIN_NAME, globalEventListener); registerGlobalEvent (NULL, EVENT_GKILL, PLUGIN_NAME, globalEventListener); registerGlobalEvent (NULL, EVENT_LOGIN, PLUGIN_NAME, globalEventListener); @@ -451,12 +433,16 @@ 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); + registerGlobalEvent (NULL, EVENT_EXTCMD, PLUGIN_NAME, globalEventListener); char *argv[] = { "", @@ -472,6 +458,8 @@ perl = perl_alloc (); perl_construct (perl); + PL_exit_flags |= PERL_EXIT_DESTRUCT_END; + if (perl_parse (perl, xs_init, 2, argv, (char **)NULL) || perl_run (perl)) { printf ("unable to initialize perl-interpreter, continuing without.\n"); @@ -492,95 +480,155 @@ globalEventListener (int *type, ...) { va_list args; - static int rv = 0; - CFPContext context; - char *buf; - player *pl; - object *op; + static int rv; + int event_code; if (!perl) return; - memset (&context, 0, sizeof (context)); - va_start (args, type); - context.event_code = va_arg (args, int); + event_code = va_arg (args, int); - switch (context.event_code) + if (event_code == EVENT_FREE_OB) { - case EVENT_CRASH: - printf ("Unimplemented for now\n"); - break; + player *pl; + object *op; + SV *sv; - case EVENT_MAPLOAD: - case EVENT_MAPOUT: - case EVENT_MAPIN: - context.map = va_arg (args, mapstruct *); - break; + op = va_arg (args, object *); + sv = hv_delete (obj_cache, (char *)&op, sizeof (void *), 0); - case EVENT_MAPENTER: - case EVENT_MAPLEAVE: - case EVENT_FREE_OB: - case EVENT_BORN: - case EVENT_REMOVE: - context.activator = va_arg (args, object *); - break; - - case EVENT_PLAYER_DEATH: - context.who = va_arg (args, object *); - break; + if (sv) + clearSVptr (sv); - case EVENT_GKILL: - context.who = va_arg (args, object *); - context.activator = va_arg (args, object *); - break; + rv = 0; + } + else if (event_code == EVENT_CLOCK) + { + dSP; + int i, count; - case EVENT_LOGIN: - case EVENT_LOGOUT: - pl = va_arg (args, player *); - context.activator = pl->ob; - buf = va_arg (args, char *); - if (buf != 0) - strncpy (context.message, buf, sizeof (context.message)); - break; + clean_obj_cache (); - case EVENT_SHOUT: - case EVENT_MUZZLE: - case EVENT_KICK: - context.activator = va_arg (args, object *); - buf = va_arg (args, char *); - if (buf != 0) - strncpy (context.message, buf, sizeof (context.message)); - break; + ENTER; + SAVETMPS; - case EVENT_CLOCK: - clean_obj_cache (); - break; + // service up to 8 events per tick better would be + // to check for elapsed time and stop processing after + // 0.25 * server_tick or so + for (i = 9; --i; ) + { + PUSHMARK (SP); + XPUSHs (sv_2mortal (newSViv (0))); + PUTBACK; + count = call_pv ("Event::one_event", G_SCALAR | G_EVAL); + SPAGAIN; - case EVENT_TELL: - break; + if (!count || !POPi) + 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)); - break; + FREETMPS; + LEAVE; } + else + { + dSP; - va_end (args); + ENTER; + SAVETMPS; - if (context.event_code == EVENT_FREE_OB) - { - SV *sv = hv_delete (obj_cache, (char *)&context.activator, sizeof (void *), 0); + PUSHMARK (SP); - if (sv) - clearSVptr (sv); + EXTEND (SP, 10); + PUSHs (sv_2mortal (newSViv (event_code))); + + switch (event_code) + { + case EVENT_CRASH: + break; + + case EVENT_PLAYER_LOAD: + case EVENT_PLAYER_SAVE: + PUSH_OB; + PUSH_PV; + break; + + case EVENT_MAPLOAD: + case EVENT_MAPOUT: + case EVENT_MAPIN: + case EVENT_MAPCLEAN: + case EVENT_MAPRESET: + PUSH_MAP; + break; + + case EVENT_MAPENTER: + case EVENT_MAPLEAVE: + case EVENT_BORN: + case EVENT_REMOVE: + case EVENT_PLAYER_DEATH: + PUSH_OB; + break; + + case EVENT_GKILL: + PUSH_OB; + PUSH_OB; + break; + + case EVENT_LOGIN: + case EVENT_LOGOUT: + PUSH_PL; + PUSH_PV; + break; + + case EVENT_SHOUT: + case EVENT_MUZZLE: + case EVENT_KICK: + PUSH_OB; + PUSH_PV; + break; + + case EVENT_FIND_UNARMED_SKILL: + PUSH_OB; + break; + + case EVENT_PLAYER_USE_SKILL: + case EVENT_MONSTER_USE_SKILL: + PUSH_OB; + PUSH_OB; + PUSH_OB; + PUSH_IV; + PUSH_PV; + break; + + case EVENT_EXTCMD: + PUSH_PL; + { + char *buf = va_arg (args, char *); + int len = va_arg (args, int); + PUSHs (sv_2mortal (newSVpvn (buf, len))); + } + break; + + case EVENT_TELL: + break; + } + + va_end (args); + + PUTBACK; + int count = call_pv ("cf::inject_global_event", G_SCALAR | G_EVAL); + SPAGAIN; + + if (SvTRUE (ERRSV)) + LOG (llevError, "global event '%d' callback evaluation error: %s", event_code, SvPV_nolen (ERRSV)); + + rv = count > 0 ? POPi : 0; + + PUTBACK; + FREETMPS; + LEAVE; } - else - inject_event ("cf::inject_global_event", &context); - - rv = context.returnvalue; return &rv; } @@ -588,36 +636,93 @@ void * eventListener (int *type, ...) { - static int rv = 0; + static int rv; va_list args; - char *buf; - CFPContext context; + int event_code; + object *who, *activator, *third, *event; + char *message, *extension, *options; if (!perl) return; - memset (&context, 0, sizeof (context)); - va_start (args, type); - - context.who = va_arg (args, object *); - context.event_code = va_arg (args, int); - context.activator = va_arg (args, object *); - context.third = va_arg (args, object *); - - buf = va_arg (args, char *); - if (buf != 0) - strncpy (context.message, buf, sizeof (context.message)); - - context.fix = va_arg (args, int); - strncpy (context.extension, va_arg (args, char *), sizeof (context.extension)); - strncpy (context.options, va_arg (args, char *), sizeof (context.options)); - context.returnvalue = 0; + who = va_arg (args, object *); + event_code = va_arg (args, int); + activator = va_arg (args, object *); + third = va_arg (args, object *); + message = va_arg (args, char *); + va_arg (args, int); // fix yourself + extension = va_arg (args, char *); + options = va_arg (args, char *); + event = va_arg (args, object *); va_end (args); - inject_event ("cf::inject_event", &context); + { + dSP; + + ENTER; + SAVETMPS; + + PUSHMARK (SP); + EXTEND (SP, 10); + + PUSHcfapi (STRING, extension); + PUSHs (sv_2mortal (newSViv (event_code))); + + PUSHcfapi (POBJECT, event); + PUSHcfapi (POBJECT, who); + + switch (event_code) + { + case EVENT_STOP: // $ob (e.g. arrow) + case EVENT_TIME: // $ob + case EVENT_TIMER: // $ob + break; + + case EVENT_APPLY: // $ob, $who + case EVENT_DROP: // $ob, $who + case EVENT_CLOSE: // $ob, $who + case EVENT_DEATH: // $ob[, $killer] + case EVENT_MOVE: // $ob, $enemy + case EVENT_THROW: // $ob, $thrower + PUSHcfapi (POBJECT, activator); + break; + + case EVENT_ATTACK: // $ob, $who, $victim (?? please god enlighten me) + PUSHcfapi (POBJECT, activator); + PUSHcfapi (POBJECT, third); + break; + + case EVENT_TRIGGER: // $ob, $originator, [$victim], [$msg] + PUSHcfapi (POBJECT, activator); + PUSHcfapi (POBJECT, third); + PUSHcfapi (POBJECT, message); + break; + + case EVENT_SAY: // $ob, $who, $msg + PUSHcfapi (POBJECT, activator); + PUSHcfapi (STRING, message); + break; + + default: + LOG (llevError, "perl plugin called for unsupported event type %d", event_code); + break; + } + + PUTBACK; + int count = call_pv ("cf::inject_event", G_SCALAR | G_EVAL); + SPAGAIN; + + if (SvTRUE (ERRSV)) + LOG (llevError, "event '%d' callback evaluation error: %s", event_code, SvPV_nolen (ERRSV)); + + rv = count > 0 ? POPi : 0; + + PUTBACK; + FREETMPS; + LEAVE; + } - rv = context.returnvalue; return &rv; } @@ -653,6 +758,7 @@ const_iv (llevMonster) const_iv (PLAYER) + const_iv (TRANSPORT) const_iv (ROD) const_iv (TREASURE) const_iv (POTION) @@ -667,7 +773,6 @@ const_iv (ARMOUR) const_iv (PEDESTAL) const_iv (ALTAR) - const_iv (CONFUSION) const_iv (LOCKED_DOOR) const_iv (SPECIAL_KEY) const_iv (MAP) @@ -778,6 +883,7 @@ 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) @@ -988,6 +1094,134 @@ 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 (SK_SPARK_TOUCH) + const_iv (SK_SHIVER) + const_iv (SK_ACID_SPLASH) + const_iv (SK_POISON_NAIL) + + 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) + + const_iv (PREFER_LOW) + const_iv (PREFER_HIGH) + + const_iv (ATNR_PHYSICAL) + const_iv (ATNR_MAGIC) + const_iv (ATNR_FIRE) + const_iv (ATNR_ELECTRICITY) + const_iv (ATNR_COLD) + const_iv (ATNR_CONFUSION) + const_iv (ATNR_ACID) + const_iv (ATNR_DRAIN) + const_iv (ATNR_WEAPONMAGIC) + const_iv (ATNR_GHOSTHIT) + const_iv (ATNR_POISON) + const_iv (ATNR_SLOW) + const_iv (ATNR_PARALYZE) + const_iv (ATNR_TURN_UNDEAD) + const_iv (ATNR_FEAR) + const_iv (ATNR_CANCELLATION) + const_iv (ATNR_DEPLETE) + const_iv (ATNR_DEATH) + const_iv (ATNR_CHAOS) + const_iv (ATNR_COUNTERSPELL) + const_iv (ATNR_GODPOWER) + const_iv (ATNR_HOLYWORD) + const_iv (ATNR_BLIND) + const_iv (ATNR_INTERNAL) + const_iv (ATNR_LIFE_STEALING) + const_iv (ATNR_DISEASE) + + const_iv (MAP_FLUSH) + const_iv (MAP_PLAYER_UNIQUE) + const_iv (MAP_BLOCK) + const_iv (MAP_STYLE) + const_iv (MAP_OVERLAY) + + const_iv (MAP_IN_MEMORY) + const_iv (MAP_SWAPPED) + const_iv (MAP_LOADING) + const_iv (MAP_SAVING) }; for (civ = const_iv + sizeof (const_iv) / sizeof (const_iv [0]); civ-- > const_iv; ) @@ -1014,9 +1248,11 @@ const_event (MOVE) const_event (BORN) - const_event (CLOCK) + //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) @@ -1026,11 +1262,16 @@ const_event (MAPLOAD) const_event (MAPOUT) const_event (MAPIN) + const_event (MAPCLEAN) const_event (REMOVE) const_event (SHOUT) const_event (TELL) const_event (MUZZLE) const_event (KICK) + const_event (PLAYER_USE_SKILL) + const_event (MONSTER_USE_SKILL) + const_event (FIND_UNARMED_SKILL) + const_event (EXTCMD) //const_event (FREE_OB) }; @@ -1138,7 +1379,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) @@ -1175,6 +1415,8 @@ hv_store (prop_type, cprop->name, strlen (cprop->name), newSViv (cprop->dtype), 0); hv_store (prop_idx, cprop->name, strlen (cprop->name), newSViv (cprop->idx ), 0); } + + //I_EVENT_API (PACKAGE); } void @@ -1182,6 +1424,12 @@ PROTOTYPE: $$ C_ARGS: level, "%s", msg +char *path_combine (char *base, char *path) + PROTOTYPE: $$ + +char *path_combine_and_normalize (char *base, char *path) + PROTOTYPE: $$ + char * cf_get_maps_directory (char *path) PROTOTYPE: $ @@ -1209,6 +1457,47 @@ cf_find_animation (char *text) PROTOTYPE: $ +int random_roll(int min, int max, object *op, int goodbad); + +int +exp_to_level (val64 exp) + CODE: +{ + int i = 0; + + RETVAL = settings.max_level; + + for (i = 1; i <= settings.max_level; i++) + { + if (levels[i] > exp) + { + RETVAL = i - 1; + break; + } + } +} + OUTPUT: RETVAL + +val64 +level_to_min_exp (int level) + CODE: + if (level > settings.max_level) + RETVAL = levels[settings.max_level]; + else if (level < 1) + RETVAL = 0; + else + RETVAL = levels[level]; + OUTPUT: RETVAL + +SV * +resistance_to_string (int atnr) + CODE: + if (atnr >= 0 && atnr < NROFATTACKS) + RETVAL = newSVpv (resist_plus[atnr], 0); + else + XSRETURN_UNDEF; + OUTPUT: RETVAL + MODULE = cf PACKAGE = cf::object PREFIX = cf_object_ SV * @@ -1226,7 +1515,7 @@ cf_object_set_int_property (obj, idx, SvIV (newval)); break; case CFAPI_LONG: - cf_object_set_long_property (obj, idx, SvNV (newval)); + cf_object_set_long_property (obj, idx, SvVAL64 (newval)); break; case CFAPI_DOUBLE: { @@ -1262,6 +1551,7 @@ RETVAL = obj->attacktype; OUTPUT: RETVAL +# missing in plug-in api, of course void set_food (object *obj, int food) CODE: @@ -1305,7 +1595,7 @@ 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) @@ -1313,7 +1603,7 @@ int cf_object_pay_item (object *op, object *buyer) -int cf_object_pay_amount (object *op, double amount) +int cf_object_pay_amount (object *op, val64 amount) int cf_object_cast_spell (object *caster, object *ctoo, int dir, object *spell_ob, char *stringarg = 0) @@ -1358,12 +1648,30 @@ void cf_object_pickup (object *op, object *what) -char *cf_object_get_key (object *op, char *keyname) - ALIAS: key = 0 +object *cf_create_object_by_name (const char *name) -void cf_object_set_key (object *op, char *keyname, char *value) +void change_exp (object *op, val64 exp, const char *skill_name = 0, int flag = 0) + +void pay_player (object *op, val64 amount) + +val64 pay_player_arch (object *op, const char *arch, val64 amount) + +void player_lvl_adj (object *who, object *skill = 0) + +int kill_object (object *op, int dam = 0, object *hitter = 0, int type = AT_PHYSICAL) + +int calc_skill_exp (object *who, object *op, object *skill); + +void push_button (object *op); + +void use_trigger (object *op); + +void +cf_object_set_resistance (object *op, int rtype, int val) + CODE: + if (rtype >= 0 && rtype < NROFATTACKS) + op->resist[rtype] = val; -object *cf_create_object_by_name (const char *name) MODULE = cf PACKAGE = cf::object PREFIX = cf_ @@ -1390,6 +1698,17 @@ RETVAL = (object *)object_insert (&unused_type, ob, 0, where, orig, flag, x, y); } +# syntatic sugar for easier use in event callbacks. +const char *options (object *op) + CODE: + RETVAL = op->name; + OUTPUT: + RETVAL + +const char *get_ob_key_value (object *op, const char *key) + +bool set_ob_key_value (object *op, const char *key, const char *value = 0, int add_key = 1) + object *get_nearest_player (object *ob) ALIAS: nearest_player = 0 PREINIT: @@ -1420,12 +1739,18 @@ 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_ player *player (object *op) CODE: - RETVAL = cf_player_find (cf_query_name (op)); + RETVAL = op->contr; OUTPUT: RETVAL void cf_player_message (object *obj, char *txt, int flags = NDI_ORANGE | NDI_UNIQUE) @@ -1450,6 +1775,9 @@ void cf_player_set_party (object *op, partylist *party) +void change_skill (object *op, val64 exp, char *skill_name = 0, int flag = 0) + +void kill_player (object *op) MODULE = cf PACKAGE = cf::object::map PREFIX = cf_ @@ -1462,6 +1790,8 @@ 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: @@ -1478,6 +1808,48 @@ RETVAL = pl->next; OUTPUT: RETVAL +bool +cell_visible (player *pl, int dx, int dy) + CODE: + RETVAL = FABS (dx) <= pl->socket.mapx / 2 && FABS (dy) <= pl->socket.mapy / 2 + && !pl->blocked_los [dx + pl->socket.mapx / 2][dy + pl->socket.mapy / 2]; + OUTPUT: + RETVAL + +void +send (player *pl, SV *packet) + CODE: +{ + STRLEN len; + char *buf = SvPVbyte (packet, len); + + Write_String_To_Socket (&pl->socket, buf, len); +} + +int +listening (player *pl, int new_value = -1) + CODE: + RETVAL = pl->listening; + if (new_value >= 0) + pl->listening = new_value; + 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: @@ -1487,6 +1859,28 @@ XPUSHs (newSVcfapi (CFAPI_PPLAYER, pl)); } +bool +peaceful (player *pl, bool new_setting = 0) + PROTOTYPE: $;$ + CODE: + RETVAL = pl->peaceful; + if (items > 1) + pl->peaceful = new_setting; + OUTPUT: + RETVAL + +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_ @@ -1518,14 +1912,60 @@ 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 *tile_map (mapstruct *map, unsigned int dir) + CODE: + RETVAL = dir < 4 ? map->tile_map [dir] : 0; + OUTPUT: + RETVAL + +char *tile_path (mapstruct *map, unsigned int dir) + CODE: + if (dir >= 4) + XSRETURN_UNDEF; + RETVAL = map->tile_path [dir]; + OUTPUT: + RETVAL + mapstruct *cf_map_get_map (char *name) PROTOTYPE: $ ALIAS: map = 0 +mapstruct *has_been_loaded (char *name) + PROTOTYPE: $ + mapstruct *cf_map_get_first () PROTOTYPE: ALIAS: first = 0 +# whoever "designed" the plug-in api should have wasted +# his/her time with staying away from the project - would have +# saved others a lot of time, without doubt. +void set_path (mapstruct *where, char *path) + CODE: + strcpy (where->path, path); + +int in_memory (mapstruct *map) + CODE: + RETVAL = map->in_memory; + OUTPUT: + RETVAL + +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) @@ -1533,19 +1973,39 @@ object* cf_map_present_arch_by_name (mapstruct *map, const char* str, int nx, int ny) C_ARGS: str, map, nx, ny -#int cf_map_get_flags (mapstruct* map, mapstruct** nmap, I16 x, I16 y, I16 *nx, I16 *ny) +void +cf_map_normalise (mapstruct *map, int x, int y) + PPCODE: +{ + mapstruct *nmap = 0; + I16 nx = 0, ny = 0; + int flags = cf_map_get_flags (map, &nmap, x, y, &nx, &ny); + + EXTEND (SP, 4); + PUSHs (sv_2mortal (newSViv (flags))); + + if (GIMME_V == G_ARRAY) + { + PUSHs (sv_2mortal (newSVcfapi (CFAPI_PMAP, nmap))); + PUSHs (sv_2mortal (newSViv (nx))); + PUSHs (sv_2mortal (newSViv (ny))); + } +} void -at (mapstruct *obj, unsigned int x, unsigned int y) +at (mapstruct *map, unsigned int x, unsigned int y) PROTOTYPE: $$$ - INIT: - if (x >= MAP_WIDTH (obj) || y >= MAP_HEIGHT (obj)) XSRETURN_EMPTY; PPCODE: { object *o; - - for (o = GET_MAP_OB (obj, x, y); o; o = o->above) - XPUSHs (sv_2mortal (newSVcfapi (CFAPI_POBJECT, o))); + mapstruct *nmap = 0; + I16 nx, ny; + + cf_map_get_flags (map, &nmap, x, y, &nx, &ny); + + if (nmap) + for (o = GET_MAP_OB (nmap, nx, ny); o; o = o->above) + XPUSHs (sv_2mortal (newSVcfapi (CFAPI_POBJECT, o))); } SV * @@ -1648,6 +2108,7 @@ } } + MODULE = cf PACKAGE = cf::arch PREFIX = cf_archetype_ archetype *cf_archetype_get_first() @@ -1709,3 +2170,55 @@ ALIAS: message = 0 +MODULE = cf PACKAGE = cf::living PREFIX = cf_living_ + +val64 +exp (living *liv, val64 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 +