/* * static char *rcsid_plugins_c = * "$Id: plugins.c 11578 2009-02-23 22:02:27Z lalo $"; */ /*****************************************************************************/ /* CrossFire, A Multiplayer game for X-windows */ /* */ /* Copyright (C) 2000-2006 Mark Wedel & Crossfire Development Team */ /* Copyright (C) 1992 Frank Tore Johansen */ /* */ /* This program is free software; you can redistribute it and/or modify */ /* it under the terms of the GNU General Public License as published by */ /* the Free Software Foundation; either version 2 of the License, or */ /* (at your option) any later version. */ /* */ /* This program is distributed in the hope that it will be useful, */ /* but WITHOUT ANY WARRANTY; without even the implied warranty of */ /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ /* GNU General Public License for more details. */ /* */ /* You should have received a copy of the GNU General Public License */ /* along with this program; if not, write to the Free Software */ /* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ /* */ /* The authors can be reached via e-mail to crossfire-devel@real-time.com */ /*****************************************************************************/ /* This is the server-side plugin management part. */ /*****************************************************************************/ /* Original code by Yann Chachkoff (yann.chachkoff@mailandnews.com). */ /* Special thanks to: */ /* David Delbecq (david.delbecq@mailandnews.com); */ /* Joris Bontje (jbontje@suespammers.org); */ /* Philip Currlin (?); */ /*****************************************************************************/ /** * @file * Plugin API. * * @todo * describe "wrappers" for functions, conventions used (parameters + return value). */ #if 0 /** If set, will log much info about plugin activity. */ #define PLUGIN_DEBUG #endif /*****************************************************************************/ /* First, the headers. We only include plugin.h, because all other includes */ /* are done into it, and plugproto.h (which is used only by this file). */ /*****************************************************************************/ #include #ifndef __CEXTRACT__ #include #include #endif #define NR_OF_HOOKS 89 static const hook_entry plug_hooks[NR_OF_HOOKS] = { { cfapi_system_add_string, 0, "cfapi_system_add_string" }, { cfapi_system_register_global_event, 1, "cfapi_system_register_global_event" }, { cfapi_system_remove_string, 2, "cfapi_system_remove_string" }, { cfapi_system_unregister_global_event, 3, "cfapi_system_unregister_global_event" }, { cfapi_system_check_path, 4, "cfapi_system_check_path" }, { cfapi_system_re_cmp, 5, "cfapi_system_re_cmp" }, { cfapi_system_strdup_local, 6, "cfapi_system_strdup_local" }, { cfapi_system_directory, 7, "cfapi_system_directory" }, { cfapi_system_find_animation, 8, "cfapi_system_find_animation" }, { cfapi_object_clean_object, 9, "cfapi_object_clean_object" }, { cfapi_object_on_same_map, 10, "cfapi_object_on_same_map" }, { cfapi_object_get_key, 11, "cfapi_object_get_key" }, { cfapi_object_set_key, 12, "cfapi_object_set_key" }, { cfapi_object_get_property, 13, "cfapi_object_get_property" }, { cfapi_object_set_property, 14, "cfapi_object_set_property" }, { cfapi_object_apply, 15, "cfapi_object_apply" }, { cfapi_object_identify, 16, "cfapi_object_identify" }, { cfapi_object_describe, 17, "cfapi_object_describe" }, { cfapi_object_drain, 18, "cfapi_object_drain" }, { cfapi_object_fix, 19, "cfapi_object_fix" }, { cfapi_object_give_skill, 20, "cfapi_object_give_skill" }, { cfapi_object_transmute, 21, "cfapi_object_transmute" }, { cfapi_object_remove, 22, "cfapi_object_remove" }, { cfapi_object_delete, 23, "cfapi_object_delete" }, { cfapi_object_clone, 24, "cfapi_object_clone" }, { cfapi_object_find, 25, "cfapi_object_find" }, { cfapi_object_create, 26, "cfapi_object_create" }, { cfapi_object_insert, 27, "cfapi_object_insert" }, { cfapi_object_split, 28, "cfapi_object_split" }, { cfapi_object_merge, 29, "cfapi_object_merge" }, { cfapi_object_distance, 30, "cfapi_object_distance" }, { cfapi_object_update, 31, "cfapi_object_update" }, { cfapi_object_clear, 32, "cfapi_object_clear" }, { cfapi_object_reset, 33, "cfapi_object_reset" }, { cfapi_object_check_inventory, 34, "cfapi_object_check_inventory" }, { cfapi_object_spring_trap, 35, "cfapi_object_spring_trap" }, { cfapi_object_check_trigger, 36, "cfapi_object_check_trigger" }, { cfapi_object_query_cost, 37, "cfapi_object_query_cost" }, { cfapi_object_query_money, 38, "cfapi_object_query_money" }, { cfapi_object_cast, 39, "cfapi_object_cast" }, { cfapi_object_learn_spell, 40, "cfapi_object_learn_spell" }, { cfapi_object_forget_spell, 41, "cfapi_object_forget_spell" }, { cfapi_object_check_spell, 42, "cfapi_object_check_spell" }, { cfapi_object_pay_amount, 43, "cfapi_object_pay_amount" }, { cfapi_object_pay_item, 44, "cfapi_object_pay_item" }, { cfapi_object_transfer, 45, "cfapi_object_transfer" }, { cfapi_object_drop, 46, "cfapi_object_drop" }, { cfapi_object_change_abil, 47, "cfapi_object_change_abil" }, { cfapi_object_find_archetype_inside, 48, "cfapi_object_find_archetype_inside" }, { cfapi_object_say, 49, "cfapi_object_say" }, { cfapi_map_get_map, 50, "cfapi_map_get_map" }, { cfapi_map_has_been_loaded, 51, "cfapi_map_has_been_loaded" }, { cfapi_map_create_path, 52, "cfapi_map_create_path" }, { cfapi_map_get_map_property, 53, "cfapi_map_get_property" }, { cfapi_map_set_map_property, 54, "cfapi_map_set_property" }, { cfapi_map_out_of_map, 55, "cfapi_map_out_of_map" }, { cfapi_map_update_position, 56, "cfapi_map_update_position" }, { cfapi_map_delete_map, 57, "cfapi_map_delete_map" }, { cfapi_map_message, 58, "cfapi_map_message" }, { cfapi_map_get_object_at, 59, "cfapi_map_get_object_at" }, { cfapi_map_change_light, 60, "cfapi_map_change_light" }, { cfapi_map_present_arch_by_name, 61, "cfapi_map_present_arch_by_name" }, { cfapi_player_find, 62, "cfapi_player_find" }, { cfapi_player_message, 63, "cfapi_player_message" }, { cfapi_object_change_exp, 64, "cfapi_object_change_exp" }, { cfapi_object_teleport, 65, "cfapi_object_teleport" }, { cfapi_object_pickup, 67, "cfapi_object_pickup" }, { cfapi_object_move, 68, "cfapi_object_move" }, { cfapi_object_apply_below, 69, "cfapi_object_apply_below" }, { cfapi_generate_random_map, 70, "cfapi_generate_random_map" }, { cfapi_archetype_get_property, 71, "cfapi_archetype_get_property" }, { cfapi_party_get_property, 72, "cfapi_party_get_property" }, { cfapi_region_get_property, 73, "cfapi_region_get_property" }, { cfapi_player_can_pay, 74, "cfapi_player_can_pay" }, { cfapi_log, 75, "cfapi_log" }, { cfapi_get_time, 76, "cfapi_system_get_time" }, { cfapi_timer_create, 77, "cfapi_system_timer_create" }, { cfapi_timer_destroy, 78, "cfapi_system_timer_destroy" }, { cfapi_friendlylist_get_next, 79, "cfapi_friendlylist_get_next" }, { cfapi_set_random_map_variable, 80, "cfapi_set_random_map_variable" }, { cfapi_system_find_face, 81, "cfapi_system_find_face" }, { cfapi_get_season_name, 82, "cfapi_system_get_season_name" }, { cfapi_get_month_name, 83, "cfapi_system_get_month_name" }, { cfapi_get_weekday_name, 84, "cfapi_system_get_weekday_name" }, { cfapi_get_periodofday_name, 85, "cfapi_system_get_periodofday_name" }, { cfapi_map_trigger_connected, 86, "cfapi_map_trigger_connected" }, { cfapi_object_user_event, 87, "cfapi_object_user_event" }, { cfapi_system_find_string, 88, "cfapi_system_find_string" } }; int plugin_number = 0; crossfire_plugin *plugins_list = NULL; /*****************************************************************************/ /* NEW PLUGIN STUFF STARTS HERE */ /*****************************************************************************/ #ifdef WIN32 static const char *plugins_dlerror(void) { static char buf[256]; DWORD err; char *p; err = GetLastError(); if (FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, err, 0, buf, sizeof(buf), NULL) == 0) snprintf(buf, sizeof(buf), "error %lu", err); p = strchr(buf, '\0'); while (p > buf && (p[-1] == '\r' || p[-1] == '\n')) p--; *p = '\0'; return buf; } #endif /* WIN32 */ /** * Notify clients about a changed object. * * @param op the object that has changed */ static void send_changed_object(object *op) { object *tmp; player *pl; if (op->env != NULL) { tmp = get_player_container(op->env); if (!tmp) { for (pl = first_player; pl; pl = pl->next) if (pl->ob->container == op->env) break; if (pl) tmp = pl->ob; else tmp = NULL; } if (tmp) /* We don't know what changed, so we send everything. */ esrv_update_item(UPD_ALL, tmp, op); } else { for (tmp = op->above; tmp != NULL; tmp = tmp->above) if (tmp->type == PLAYER) tmp->contr->socket.update_look = 1; } } int user_event(object *op, object *activator, object *third, const char *message, int fix) { return execute_event(op, EVENT_USER, activator, third, message, fix); } int execute_event(object *op, int eventcode, object *activator, object *third, const char *message, int fix) { object *tmp, *next; crossfire_plugin *plugin; int rv = 0; for (tmp = op->inv; tmp != NULL; tmp = next) { next = tmp->below; if (tmp->type == EVENT_CONNECTOR && tmp->subtype == eventcode) { #ifdef PLUGIN_DEBUG LOG(llevDebug, "********** EVENT HANDLER **********\n"); LOG(llevDebug, " - Who am I :%s\n", op->name); if (activator != NULL) LOG(llevDebug, " - Activator :%s\n", activator->name); if (third != NULL) LOG(llevDebug, " - Other object :%s\n", third->name); LOG(llevDebug, " - Event code :%d\n", tmp->subtype); if (tmp->title != NULL) LOG(llevDebug, " - Event plugin :%s\n", tmp->title); if (tmp->slaying != NULL) LOG(llevDebug, " - Event hook :%s\n", tmp->slaying); if (tmp->name != NULL) LOG(llevDebug, " - Event options :%s\n", tmp->name); #endif if (tmp->title == NULL) { object *env = object_get_env_recursive(tmp); LOG(llevError, "Event object without title at %d/%d in map %s\n", env->x, env->y, env->map->name); remove_ob(tmp); free_object(tmp); } else if (tmp->slaying == NULL) { object *env = object_get_env_recursive(tmp); LOG(llevError, "Event object without slaying at %d/%d in map %s\n", env->x, env->y, env->map->name); remove_ob(tmp); free_object(tmp); } else { plugin = plugins_find_plugin(tmp->title); if (plugin == NULL) { object *env = object_get_env_recursive(tmp); LOG(llevError, "The requested plugin doesn't exit: %s at %d/%d in map %s\n", tmp->title, env->x, env->y, env->map->name); remove_ob(tmp); free_object(tmp); } else { int rvt = 0; int *rv; rv = plugin->eventfunc(&rvt, op, /*eventcode, */ activator, third, message, fix, /*tmp->slaying, tmp->name*/ tmp); if (QUERY_FLAG(tmp, FLAG_UNIQUE)) { #ifdef PLUGIN_DEBUG LOG(llevDebug, "Removing unique event %s\n", tmp->slaying); #endif remove_ob(tmp); free_object(tmp); } return *rv; } } } } return rv; } int execute_global_event(int eventcode, ...) { va_list args; mapstruct *map; object *op; object *op2; player *pl; const char *buf; int i, rt; crossfire_plugin *cp; if (plugins_list == NULL) return -1; va_start(args, eventcode); switch (eventcode) { case EVENT_BORN: /*BORN: op*/ op = va_arg(args, object *); for (cp = plugins_list; cp != NULL; cp = cp->next) { if (cp->gevent[eventcode] != NULL) cp->gevent[eventcode](&rt, eventcode, op); } break; case EVENT_CLOCK: /*CLOCK: -*/ for (cp = plugins_list; cp != NULL; cp = cp->next) { if (cp->gevent[eventcode] != NULL) cp->gevent[eventcode](&rt, eventcode); } break; case EVENT_CRASH: for (cp = plugins_list; cp != NULL; cp = cp->next) { if (cp->gevent[eventcode] != NULL) cp->gevent[eventcode](&rt, eventcode); } break; case EVENT_PLAYER_DEATH: /*PLAYER_DEATH: op*/ op = va_arg(args, object *); for (cp = plugins_list; cp != NULL; cp = cp->next) { if (cp->gevent[eventcode] != NULL) cp->gevent[eventcode](&rt, eventcode, op); } break; case EVENT_GKILL: /*GKILL: op, hitter*/ op = va_arg(args, object *); op2 = va_arg(args, object *); for (cp = plugins_list; cp != NULL; cp = cp->next) { if (cp->gevent[eventcode] != NULL) cp->gevent[eventcode](&rt, eventcode, op, op2); } break; case EVENT_LOGIN: /*LOGIN: pl, pl->socket.host*/ pl = va_arg(args, player *); buf = va_arg(args, char *); for (cp = plugins_list; cp != NULL; cp = cp->next) { if (cp->gevent[eventcode] != NULL) cp->gevent[eventcode](&rt, eventcode, pl, buf); } break; case EVENT_LOGOUT: /*LOGOUT: pl, pl->socket.host*/ pl = va_arg(args, player *); buf = va_arg(args, char *); for (cp = plugins_list; cp != NULL; cp = cp->next) { if (cp->gevent[eventcode] != NULL) cp->gevent[eventcode](&rt, eventcode, pl, buf); } break; case EVENT_MAPENTER: /*MAPENTER: op, map*/ op = va_arg(args, object *); map = va_arg(args, mapstruct *); for (cp = plugins_list; cp != NULL; cp = cp->next) { if (cp->gevent[eventcode] != NULL) cp->gevent[eventcode](&rt, eventcode, op, map); } break; case EVENT_MAPLEAVE: /*MAPLEAVE: op, map*/ op = va_arg(args, object *); map = va_arg(args, mapstruct *); for (cp = plugins_list; cp != NULL; cp = cp->next) { if (cp->gevent[eventcode] != NULL) cp->gevent[eventcode](&rt, eventcode, op, map); } break; case EVENT_MAPRESET: /*MAPRESET: map*/ map = va_arg(args, mapstruct *); for (cp = plugins_list; cp != NULL; cp = cp->next) { if (cp->gevent[eventcode] != NULL) cp->gevent[eventcode](&rt, eventcode, map); } break; case EVENT_REMOVE: /*REMOVE: op*/ op = va_arg(args, object *); for (cp = plugins_list; cp != NULL; cp = cp->next) { if (cp->gevent[eventcode] != NULL) cp->gevent[eventcode](&rt, eventcode, op); } break; case EVENT_SHOUT: /*SHOUT: op, parms, priority*/ op = va_arg(args, object *); buf = va_arg(args, char *); i = va_arg(args, int); for (cp = plugins_list; cp != NULL; cp = cp->next) { if (cp->gevent[eventcode] != NULL) cp->gevent[eventcode](&rt, eventcode, op, buf, i); } break; case EVENT_TELL: /* Tell: who, what, to who */ op = va_arg(args, object *); buf = va_arg(args, const char *); op2 = va_arg(args, object *); for (cp = plugins_list; cp != NULL; cp = cp->next) { if (cp->gevent[eventcode] != NULL) cp->gevent[eventcode](&rt, eventcode, op, buf, op2); } break; case EVENT_MUZZLE: /*MUZZLE: op, parms*/ op = va_arg(args, object *); buf = va_arg(args, char *); for (cp = plugins_list; cp != NULL; cp = cp->next) { if (cp->gevent[eventcode] != NULL) cp->gevent[eventcode](&rt, eventcode, op, buf); } break; case EVENT_KICK: /*KICK: op, parms*/ op = va_arg(args, object *); buf = va_arg(args, char *); for (cp = plugins_list; cp != NULL; cp = cp->next) { if (cp->gevent[eventcode] != NULL) cp->gevent[eventcode](&rt, eventcode, op, buf); } break; case EVENT_MAPUNLOAD: /*MAPUNLOAD: map*/ map = va_arg(args, mapstruct *); for (cp = plugins_list; cp != NULL; cp = cp->next) { if (cp->gevent[eventcode] != NULL) cp->gevent[eventcode](&rt, eventcode, map); } break; case EVENT_MAPLOAD: /*MAPLOAD: map*/ map = va_arg(args, mapstruct *); for (cp = plugins_list; cp != NULL; cp = cp->next) { if (cp->gevent[eventcode] != NULL) cp->gevent[eventcode](&rt, eventcode, map); } break; } va_end(args); return 0; } int plugins_init_plugin(const char *libfile) { LIBPTRTYPE ptr; f_plug_init initfunc; f_plug_api propfunc; f_plug_api eventfunc; f_plug_postinit postfunc; f_plug_postinit closefunc; int i; crossfire_plugin *cp; crossfire_plugin *ccp; /* Open the plugin lib and load the required functions */ ptr = plugins_dlopen(libfile); if (ptr == NULL) { LOG(llevError, "Error trying to load %s: %s\n", libfile, plugins_dlerror()); return -1; } initfunc = (f_plug_init)plugins_dlsym(ptr, "initPlugin"); if (initfunc == NULL) { LOG(llevError, "Plugin error while requesting %s.initPlugin: %s\n", libfile, plugins_dlerror()); plugins_dlclose(ptr); return -1; } propfunc = (f_plug_api)plugins_dlsym(ptr, "getPluginProperty"); if (propfunc == NULL) { LOG(llevError, "Plugin error while requesting %s.getPluginProperty: %s\n", libfile, plugins_dlerror()); plugins_dlclose(ptr); return -1; } eventfunc = (f_plug_api)plugins_dlsym(ptr, "eventListener"); if (eventfunc == NULL) { LOG(llevError, "Plugin error while requesting %s.eventListener: %s\n", libfile, plugins_dlerror()); plugins_dlclose(ptr); return -1; } postfunc = (f_plug_postinit)plugins_dlsym(ptr, "postInitPlugin"); if (postfunc == NULL) { LOG(llevError, "Plugin error while requesting %s.postInitPlugin: %s\n", libfile, plugins_dlerror()); plugins_dlclose(ptr); return -1; } closefunc = (f_plug_postinit)plugins_dlsym(ptr, "closePlugin"); if (closefunc == NULL) { LOG(llevError, "Plugin error while requesting %s.closePlugin: %s\n", libfile, plugins_dlerror()); plugins_dlclose(ptr); return -1; } i = initfunc("2.0", cfapi_get_hooks); cp = malloc(sizeof(crossfire_plugin)); for (i = 0; i < NR_EVENTS; i++) cp->gevent[i] = NULL; cp->eventfunc = eventfunc; cp->propfunc = propfunc; cp->closefunc = closefunc; cp->libptr = ptr; propfunc(&i, "Identification", cp->id, sizeof(cp->id)); propfunc(&i, "FullName", cp->fullname, sizeof(cp->fullname)); cp->next = NULL; cp->prev = NULL; if (plugins_list == NULL) { plugins_list = cp; } else { for (ccp = plugins_list; ccp->next != NULL; ccp = ccp->next) ; ccp->next = cp; cp->prev = ccp; } postfunc(); plugin_number++; return 0; } void *cfapi_get_hooks(int *type, ...) { va_list args; int request_type; char *buf; int fid; f_plug_api *rapi; int i; *type = CFAPI_NONE; va_start(args, type); request_type = va_arg(args, int); if (request_type == 0) { /* By nr */ fid = va_arg(args, int); rapi = va_arg(args, f_plug_api *); if (fid < 0 || fid >= NR_OF_HOOKS) { *rapi = NULL; *type = CFAPI_NONE; } else { *rapi = plug_hooks[fid].func; *type = CFAPI_FUNC; } } else { /* by name */ buf = va_arg(args, char *); rapi = va_arg(args, f_plug_api *); *rapi = NULL; *type = CFAPI_NONE; for (i = 0; i < NR_OF_HOOKS; i++) { if (!strcmp(buf, plug_hooks[i].fname)) { *rapi = plug_hooks[i].func; *type = CFAPI_FUNC; break; } } } va_end(args); return NULL; } int plugins_remove_plugin(const char *id) { crossfire_plugin *cp; if (plugins_list == NULL) return -1; for (cp = plugins_list; cp != NULL; cp = cp->next) { if (!strcmp(id, cp->id)) { crossfire_plugin *n; crossfire_plugin *p; n = cp->next; p = cp->prev; if (cp->closefunc) cp->closefunc(); plugins_dlclose(cp->libptr); if (n != NULL) { if (p != NULL) { n->prev = p; p->next = n; } else { n->prev = NULL; plugins_list = n; } } else { if (p != NULL) p->next = NULL; else plugins_list = NULL; } free(cp); plugin_number--; return 0; } } return -1; } crossfire_plugin *plugins_find_plugin(const char *id) { crossfire_plugin *cp; if (plugins_list == NULL) return NULL; for (cp = plugins_list; cp != NULL; cp = cp->next) { if (!strcmp(id, cp->id)) { return cp; } } return NULL; } /*****************************************************************************/ /* Displays a list of loaded plugins (keystrings and description) in the */ /* game log window. */ /*****************************************************************************/ void plugins_display_list(object *op) { crossfire_plugin *cp; draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_DEBUG, "List of loaded plugins:\n-----------------------", NULL); if (plugins_list == NULL) return; for (cp = plugins_list; cp != NULL; cp = cp->next) { draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_DEBUG, "%s, %s", "%s, %s", cp->id, cp->fullname); } } /* SYSTEM-RELATED HOOKS */ /** * Wrapper for find_animation(). * @param type * will be CFAPI_INT. * @return * NULL. */ void *cfapi_system_find_animation(int *type, ...) { va_list args; const char *anim; int *num; va_start(args, type); anim = va_arg(args, const char *); num = va_arg(args, int *); va_end(args); *num = find_animation(anim); *type = CFAPI_INT; return NULL; } /** * Wrapper for find_face(). * @param type * will be CFAPI_INT. * @return * NULL. */ void *cfapi_system_find_face(int *type, ...) { va_list args; const char *face; int error; int *num; va_start(args, type); face = va_arg(args, const char *); error = va_arg(args, int); num = va_arg(args, int *); va_end(args); *num = find_face(face, error); *type = CFAPI_INT; return NULL; } /** * Wrapper for strdup_local(). * @param type * will be CFAPI_STRING. * @return * NULL. */ void *cfapi_system_strdup_local(int *type, ...) { va_list args; const char *txt; char **ret; va_start(args, type); txt = va_arg(args, const char *); ret = va_arg(args, char **); va_end(args); *ret = strdup_local(txt); *type = CFAPI_STRING; return NULL; } void *cfapi_system_register_global_event(int *type, ...) { va_list args; int eventcode; char *pname; f_plug_api hook; crossfire_plugin *cp; va_start(args, type); eventcode = va_arg(args, int); pname = va_arg(args, char *); hook = va_arg(args, f_plug_api); va_end(args); *type = CFAPI_NONE; cp = plugins_find_plugin(pname); cp->gevent[eventcode] = hook; return NULL; } void *cfapi_system_unregister_global_event(int *type, ...) { va_list args; int eventcode; char *pname; crossfire_plugin *cp; va_start(args, type); eventcode = va_arg(args, int); pname = va_arg(args, char *); va_end(args); *type = CFAPI_NONE; cp = plugins_find_plugin(pname); cp->gevent[eventcode] = NULL; return NULL; } /** * Wrapper for add_string(). * * @param type * will be CFAPI_SSTRING. * @return * NULL. */ void *cfapi_system_add_string(int *type, ...) { va_list args; const char *str; sstring *rv; va_start(args, type); str = va_arg(args, const char *); rv = va_arg(args, sstring *); va_end(args); *rv = add_string(str); *type = CFAPI_SSTRING; return NULL; } /** * Wrapper for free_string(). * * @param type * will be CFAPI_NONE. * @return * NULL. */ void *cfapi_system_remove_string(int *type, ...) { va_list args; sstring str; va_start(args, type); str = va_arg(args, sstring); va_end(args); free_string(str); *type = CFAPI_NONE; return NULL; } /** * Wrapper for find_string(). * * @param type * will be CFAPI_SSTRING. * @return * NULL. */ void *cfapi_system_find_string(int *type, ...) { va_list args; const char *str; sstring *rv; va_start(args, type); str = va_arg(args, const char *); rv = va_arg(args, sstring *); va_end(args); *rv = find_string(str); *type = CFAPI_SSTRING; return NULL; } /** * Wrapper for check_path(). * @param type * will be CFAPI_INT. * @return * NULL. */ void *cfapi_system_check_path(int *type, ...) { va_list args; const char *name; int prepend_dir; int *ret; va_start(args, type); name = va_arg(args, char *); prepend_dir = va_arg(args, int); ret = va_arg(args, int *); *ret = check_path(name, prepend_dir); va_end(args); *type = CFAPI_INT; return NULL; } /** * Wrapper for re_cmp(). * @param type * will be CFAPI_STRING. * @return * NULL. */ void *cfapi_system_re_cmp(int *type, ...) { va_list args; const char *str; const char *regexp; const char **rv; va_start(args, type); str = va_arg(args, char *); regexp = va_arg(args, char *); rv = va_arg(args, const char **); *rv = re_cmp(str, regexp); va_end(args); *type = CFAPI_STRING; return NULL; } void *cfapi_system_directory(int *type, ...) { va_list args; int dirtype; const char **str; va_start(args, type); dirtype = va_arg(args, int); str = va_arg(args, const char **); va_end(args); *type = CFAPI_STRING; switch (dirtype) { case 0: *str = settings.mapdir; break; case 1: *str = settings.uniquedir; break; case 2: *str = settings.tmpdir; break; case 3: *str = settings.confdir; break; case 4: *str = settings.localdir; break; case 5: *str = settings.playerdir; break; case 6: *str = settings.datadir; break; default: *str = NULL; } return NULL; } /** * Wrapper for get_tod(). * * @param type * will be CFAPI_NONE. * @return * NULL. */ void *cfapi_get_time(int *type, ...) { va_list args; timeofday_t *tod; va_start(args, type); tod = va_arg(args, timeofday_t *); va_end(args); get_tod(tod); *type = CFAPI_NONE; return NULL; } #define string_get_int(name) \ va_list args; \ int index; \ const char **str; \ va_start(args, type); \ index = va_arg(args, int); \ str = va_arg(args, const char **); \ va_end(args); \ *str = name(index); \ *type = CFAPI_STRING; \ return NULL; \ /** * Wrapper for get_season_name(). * * @param type * will be CFAPI_STRING. Other parameters are int index and char** where to store result string * @return * NULL. */ void *cfapi_get_season_name(int *type, ...) { string_get_int(get_season_name) } /** * Wrapper for get_season_name(). * * @param type * will be CFAPI_STRING. Other parameters are int index and char** where to store result string * @return * NULL. */ void *cfapi_get_weekday_name(int *type, ...) { string_get_int(get_weekday) } /** * Wrapper for get_season_name(). * * @param type * will be CFAPI_STRING. Other parameters are int index and char** where to store result string * @return * NULL. */ void *cfapi_get_month_name(int *type, ...) { string_get_int(get_month_name) } /** * Wrapper for get_season_name(). * * @param type * will be CFAPI_STRING. Other parameters are int index and char** where to store result string * @return * NULL. */ void *cfapi_get_periodofday_name(int *type, ...) { string_get_int(get_periodofday) } /** * Wrapper for cfapi_timer_create(). * @param type * unused * @return * always 0 * * Additional parameters: * - ob : ::object *for which to create a timer * - delay : long, ticks or seconds * - mode : int, either ::TIMER_MODE_SECONDS or ::TIMER_MODE_CYCLES * - timer : int *that will contain timer's id */ void *cfapi_timer_create(int *type, ...) { va_list args; int res; object *ob; long delay; int mode; int *timer; va_start(args, type); ob = va_arg(args, object *); delay = va_arg(args, long); mode = va_arg(args, int); timer = va_arg(args, int *); va_end(args); *type = CFAPI_INT; *timer = cftimer_find_free_id(); if (*timer != TIMER_ERR_ID) { res = cftimer_create(*timer, delay, ob, mode); if (res != TIMER_ERR_NONE) *timer = res; } return NULL; } /** * Wrapper for cftimer_destroy(). * @param type * will be CFAPI_INT. * @return * always 0 * * Additional parameters: * - timer: int that should be destroyed * - err: int *which will contain the return code of cftimer_destroy(). */ void *cfapi_timer_destroy(int *type, ...) { va_list args; int id; int *err; va_start(args, type); id = va_arg(args, int); err = va_arg(args, int *); va_end(args); *type = CFAPI_INT; *err = cftimer_destroy(id); return NULL; } /** * Wrapper for LOG(). * @param type * will be CFAPI_NONE. * @return * NULL. */ void *cfapi_log(int *type, ...) { va_list args; LogLevel logLevel; const char *message; va_start(args, type); logLevel = va_arg(args, LogLevel); message = va_arg(args, const char *); LOG(logLevel, "%s", message); va_end(args); *type = CFAPI_NONE; return NULL; } /* MAP RELATED HOOKS */ /** * Gets map information. * * First parameter is a integer, which should be: * - 0 with 2 int and a mapstruct**: new map of specified size. * - 1 with char*, int, mapstruct**: call ready_map_name(). * - 2 with mapstruct*, 2 int and mapstruct**: call to get_map_from_coord(). */ void *cfapi_map_get_map(int *type, ...) { va_list args; mapstruct **ret; int ctype; int x, y; sint16 nx, ny; const char *name; mapstruct *m; va_start(args, type); ctype = va_arg(args, int); switch (ctype) { case 0: x = va_arg(args, int); y = va_arg(args, int); ret = va_arg(args, mapstruct **); *ret = get_empty_map(x, y); break; case 1: name = va_arg(args, const char *); x = va_arg(args, int); ret = va_arg(args, mapstruct **); *ret = ready_map_name(name, x); break; case 2: m = va_arg(args, mapstruct *); nx = va_arg(args, int); ny = va_arg(args, int); ret = va_arg(args, mapstruct **); *ret = get_map_from_coord(m, &nx, &ny); break; default: *type = CFAPI_NONE; va_end(args); return NULL; break; } va_end(args); *type = CFAPI_PMAP; return NULL; } /** * Wrapper for has_been_loaded(). * @param type * will be CFAPI_PMAP. * @return * NULL. */ void *cfapi_map_has_been_loaded(int *type, ...) { va_list args; mapstruct **map; char *string; va_start(args, type); string = va_arg(args, char *); map = va_arg(args, mapstruct **); *map = has_been_loaded(string); va_end(args); *type = CFAPI_PMAP; return NULL; } /** * Wrapper for create_pathname() and create_overlay_pathname(). * @param type * will be CFAPI_STRING. * @return * NULL. */ void *cfapi_map_create_path(int *type, ...) { va_list args; int ctype, size; const char *str; char *name; va_start(args, type); ctype = va_arg(args, int); str = va_arg(args, const char *); name = va_arg(args, char *); size = va_arg(args, int); *type = CFAPI_STRING; switch (ctype) { case 0: create_pathname(str, name, size); break; case 1: create_overlay_pathname(str, name, MAX_BUF); break; /* case 2: rv = create_items_path(str); break;*/ default: *type = CFAPI_NONE; break; } va_end(args); return NULL; } void *cfapi_map_get_map_property(int *type, ...) { va_list args; mapstruct *map; int property; int *rint; mapstruct **rmap; sstring *rstr; region **rreg; sint16 *nx, *ny; int x, y; va_start(args, type); map = va_arg(args, mapstruct *); property = va_arg(args, int); switch (property) { case CFAPI_MAP_PROP_FLAGS: rmap = va_arg(args, mapstruct **); x = va_arg(args, int); y = va_arg(args, int); nx = va_arg(args, sint16 *); ny = va_arg(args, sint16 *); rint = va_arg(args, int *); *rint = get_map_flags(map, rmap, x, y, nx, ny); *type = CFAPI_INT; break; case CFAPI_MAP_PROP_DIFFICULTY: rint = va_arg(args, int *); *rint = calculate_difficulty(map); *type = CFAPI_INT; break; case CFAPI_MAP_PROP_PATH: rstr = va_arg(args, sstring *); *rstr = map->path; *type = CFAPI_SSTRING; break; case CFAPI_MAP_PROP_TMPNAME: rstr = va_arg(args, sstring *); *rstr = map->tmpname; *type = CFAPI_SSTRING; break; case CFAPI_MAP_PROP_NAME: rstr = va_arg(args, sstring *); *rstr = map->name; *type = CFAPI_SSTRING; break; case CFAPI_MAP_PROP_RESET_TIME: rint = va_arg(args, int *); *rint = map->reset_time; *type = CFAPI_INT; break; case CFAPI_MAP_PROP_RESET_TIMEOUT: rint = va_arg(args, int *); *rint = map->reset_timeout; *type = CFAPI_INT; break; case CFAPI_MAP_PROP_PLAYERS: rint = va_arg(args, int *); *rint = map->players; *type = CFAPI_INT; break; case CFAPI_MAP_PROP_DARKNESS: rint = va_arg(args, int *); *rint = map->darkness; *type = CFAPI_INT; break; case CFAPI_MAP_PROP_WIDTH: rint = va_arg(args, int *); *rint = map->width; *type = CFAPI_INT; break; case CFAPI_MAP_PROP_HEIGHT: rint = va_arg(args, int *); *rint = map->height; *type = CFAPI_INT; break; case CFAPI_MAP_PROP_ENTER_X: rint = va_arg(args, int *); *rint = map->enter_x; *type = CFAPI_INT; break; case CFAPI_MAP_PROP_ENTER_Y: rint = va_arg(args, int *); *rint = map->enter_y; *type = CFAPI_INT; break; case CFAPI_MAP_PROP_MESSAGE: rstr = va_arg(args, sstring *); *rstr = map->msg; *type = CFAPI_SSTRING; break; case CFAPI_MAP_PROP_NEXT: rmap = va_arg(args, mapstruct **); *rmap = map ? map->next : first_map; *type = CFAPI_PMAP; break; case CFAPI_MAP_PROP_REGION: rreg = va_arg(args, region **); *rreg = get_region_by_map(map); *type = CFAPI_PREGION; break; case CFAPI_MAP_PROP_UNIQUE: rint = va_arg(args, int *); *rint = map->unique; *type = CFAPI_INT; break; default: *type = CFAPI_NONE; break; } va_end(args); return NULL; } void *cfapi_map_set_map_property(int *type, ...) { va_list args; mapstruct *map; int property; const char *buf; va_start(args, type); map = va_arg(args, mapstruct *); property = va_arg(args, int); switch (property) { case CFAPI_MAP_PROP_PATH: buf = va_arg(args, const char *); snprintf(map->path, sizeof(map->path), "%s", buf); *type = CFAPI_STRING; break; default: *type = CFAPI_NONE; break; } va_end(args); return NULL; } /** * Wrapper for out_of_map(). * @param type * will be CFAPI_INT. * @return * NULL. */ void *cfapi_map_out_of_map(int *type, ...) { va_list args; mapstruct *map; int x, y; int *rint; va_start(args, type); map = va_arg(args, mapstruct *); x = va_arg(args, int); y = va_arg(args, int); rint = va_arg(args, int *); *rint = out_of_map(map, x, y); va_end(args); *type = CFAPI_INT; return NULL; } /** * Wrapper for update_position(). * @param type * CFAPI_NONE. * @return * NULL. */ void *cfapi_map_update_position(int *type, ...) { va_list args; mapstruct *map; int x, y; va_start(args, type); map = va_arg(args, mapstruct *); x = va_arg(args, int); y = va_arg(args, int); update_position(map, x, y); va_end(args); *type = CFAPI_NONE; return NULL; } void *cfapi_map_delete_map(int *type, ...) { va_list args; mapstruct *map; va_start(args, type); map = va_arg(args, mapstruct *); delete_map(map); va_end(args); *type = CFAPI_NONE; return NULL; } void *cfapi_map_message(int *type, ...) { va_list args; mapstruct *map; const char *string; int color; va_start(args, type); map = va_arg(args, mapstruct *); string = va_arg(args, const char *); color = va_arg(args, int); va_end(args); /* function should be extended to take message types probably */ ext_info_map(color, map, MSG_TYPE_MISC, MSG_SUBTYPE_NONE, string, string); *type = CFAPI_NONE; return NULL; } /** * Wrapper for GET_MAP_OB(). * @param type * will be CFAPI_POBJECT. * @return * NULL. */ void *cfapi_map_get_object_at(int *type, ...) { va_list args; mapstruct *map; int x, y; sint16 sx, sy; object **robj; va_start(args, type); map = va_arg(args, mapstruct *); x = va_arg(args, int); y = va_arg(args, int); robj = va_arg(args, object **); va_end(args); sx = x; sy = y; if (get_map_flags(map, &map, x, y, &sx, &sy)&P_OUT_OF_MAP) *robj = NULL; else *robj = GET_MAP_OB(map, sx, sy); *type = CFAPI_POBJECT; return NULL; } /** * Kinda wrapper for present_arch() (but uses a string, not an archetype*). * @param type * will be CFAPI_POBJECT. * @return * NULL. * @todo fix archetype instead of string. */ void *cfapi_map_present_arch_by_name(int *type, ...) { va_list args; int x, y; mapstruct *map; char *msg; object **robj; va_start(args, type); msg = va_arg(args, char *); map = va_arg(args, mapstruct *); x = va_arg(args, int); y = va_arg(args, int); robj = va_arg(args, object **); va_end(args); *robj = present_arch(try_find_archetype(msg), map, x, y); *type = CFAPI_POBJECT; return NULL; } /** * Wrapper for change_map_light(). * @param type * will be CFAPI_INT. * @return * NULL. */ void *cfapi_map_change_light(int *type, ...) { va_list args; int change; mapstruct *map; int *rint; va_start(args, type); map = va_arg(args, mapstruct *); change = va_arg(args, int); rint = va_arg(args, int *); va_end(args); *type = CFAPI_INT; *rint = change_map_light(map, change); return NULL; } /* OBJECT-RELATED HOOKS */ /** * Moves an object. * * Syntax is: * cfapi_object_move(&type, kind) * where kind is: * - 0: call move_ob() * - 1: call move_player() * * @param type * unused * @return * NULL. */ void *cfapi_object_move(int *type, ...) { va_list args; int kind; object *op; object *activator; player *pl; int direction; int *ret; va_start(args, type); kind = va_arg(args, int); switch (kind) { case 0: op = va_arg(args, object *); direction = va_arg(args, int); activator = va_arg(args, object *); ret = va_arg(args, int *); va_end(args); *ret = move_ob(op, direction, activator); break; case 1: pl = va_arg(args, player *); direction = va_arg(args, int); ret = va_arg(args, int *); va_end(args); *ret = move_player(pl->ob, direction); break; } *type = CFAPI_INT; return NULL; } /** * Gets a key/value value for an object. * * @param type * will contain CFAPI_SSTRING. * @return * NULL. * @see get_ob_key_value(). */ void *cfapi_object_get_key(int *type, ...) { va_list args; const char *keyname; const char **value; object *op; va_start(args, type); op = va_arg(args, object *); keyname = va_arg(args, const char *); value = va_arg(args, const char **); va_end(args); *value = get_ob_key_value(op, keyname); *type = CFAPI_SSTRING; return NULL; } /** * Write a key/value for an object. * @param type * will contain CFAPI_SSTRING. * @return * NULL. * @see set_ob_key_value(). */ void *cfapi_object_set_key(int *type, ...) { va_list args; const char *keyname; const char *value; int *ret; object *op; int add_key; va_start(args, type); op = va_arg(args, object *); keyname = va_arg(args, char *); value = va_arg(args, char *); add_key = va_arg(args, int); ret = va_arg(args, int *); va_end(args); *ret = set_ob_key_value(op, keyname, value, add_key); *type = CFAPI_INT; return NULL; } /** * Main object property getter. */ void *cfapi_object_get_property(int *type, ...) { va_list args; int property; object *op; int *rint; object **robject; mapstruct **rmap; float *rfloat; archetype **rarch; sstring *rsstring; char *rbuffer; int rbufsize; MoveType *rmove; sint64 *rint64; partylist **rparty; double *rdouble; long *rlong; va_start(args, type); op = va_arg(args, object *); property = va_arg(args, int); switch (property) { case CFAPI_OBJECT_PROP_OB_ABOVE: robject = va_arg(args, object **); *robject = op->above; *type = CFAPI_POBJECT; break; case CFAPI_OBJECT_PROP_OB_BELOW: robject = va_arg(args, object **); *robject = op->below; *type = CFAPI_POBJECT; break; case CFAPI_OBJECT_PROP_NEXT_ACTIVE_OB: robject = va_arg(args, object **); *robject = op->active_next; *type = CFAPI_POBJECT; break; case CFAPI_OBJECT_PROP_PREV_ACTIVE_OB: robject = va_arg(args, object **); *robject = op->active_prev; *type = CFAPI_POBJECT; break; case CFAPI_OBJECT_PROP_INVENTORY: robject = va_arg(args, object **); *robject = op->inv; *type = CFAPI_POBJECT; break; case CFAPI_OBJECT_PROP_ENVIRONMENT: robject = va_arg(args, object **); *robject = op->env; *type = CFAPI_POBJECT; break; case CFAPI_OBJECT_PROP_HEAD: robject = va_arg(args, object **); *robject = op->head; *type = CFAPI_POBJECT; break; case CFAPI_OBJECT_PROP_CONTAINER: robject = va_arg(args, object **); *robject = op->container; *type = CFAPI_POBJECT; break; case CFAPI_OBJECT_PROP_MAP: rmap = va_arg(args, mapstruct **); *rmap = op->map; *type = CFAPI_PMAP; break; case CFAPI_OBJECT_PROP_COUNT: rint = va_arg(args, int *); *rint = op->count; *type = CFAPI_INT; break; case CFAPI_OBJECT_PROP_NAME: rbuffer = va_arg(args, char *); rbufsize = va_arg(args, int); query_name(op, rbuffer, rbufsize); *type = CFAPI_STRING; break; case CFAPI_OBJECT_PROP_NAME_PLURAL: rsstring = va_arg(args, sstring *); *rsstring = op->name_pl; *type = CFAPI_SSTRING; break; case CFAPI_OBJECT_PROP_TITLE: rsstring = va_arg(args, sstring *); *rsstring = op->title; *type = CFAPI_SSTRING; break; case CFAPI_OBJECT_PROP_RACE: rsstring = va_arg(args, sstring *); *rsstring = op->race; *type = CFAPI_SSTRING; break; case CFAPI_OBJECT_PROP_SLAYING: rsstring = va_arg(args, sstring *); *rsstring = op->slaying; *type = CFAPI_SSTRING; break; case CFAPI_OBJECT_PROP_SKILL: rsstring = va_arg(args, sstring *); *rsstring = op->skill; *type = CFAPI_SSTRING; break; case CFAPI_OBJECT_PROP_MESSAGE: rsstring = va_arg(args, sstring *); *rsstring = op->msg; *type = CFAPI_SSTRING; break; case CFAPI_OBJECT_PROP_LORE: rsstring = va_arg(args, sstring *); *rsstring = op->lore; *type = CFAPI_SSTRING; break; case CFAPI_OBJECT_PROP_X: rint = va_arg(args, int *); *rint = op->x; *type = CFAPI_INT; break; case CFAPI_OBJECT_PROP_Y: rint = va_arg(args, int *); *rint = op->y; *type = CFAPI_INT; break; case CFAPI_OBJECT_PROP_SPEED: rfloat = va_arg(args, float *); *rfloat = op->speed; *type = CFAPI_FLOAT; break; case CFAPI_OBJECT_PROP_SPEED_LEFT: rfloat = va_arg(args, float *); *rfloat = op->speed_left; *type = CFAPI_FLOAT; break; case CFAPI_OBJECT_PROP_NROF: rint = va_arg(args, int *); *rint = op->nrof; *type = CFAPI_INT; break; case CFAPI_OBJECT_PROP_DIRECTION: rint = va_arg(args, int *); *rint = op->direction; *type = CFAPI_INT; break; case CFAPI_OBJECT_PROP_FACING: rint = va_arg(args, int *); *rint = op->facing; *type = CFAPI_INT; break; case CFAPI_OBJECT_PROP_TYPE: rint = va_arg(args, int *); *rint = op->type; *type = CFAPI_INT; break; case CFAPI_OBJECT_PROP_SUBTYPE: rint = va_arg(args, int *); *rint = op->subtype; *type = CFAPI_INT; break; case CFAPI_OBJECT_PROP_CLIENT_TYPE: rint = va_arg(args, int *); *rint = op->client_type; *type = CFAPI_INT; break; case CFAPI_OBJECT_PROP_RESIST: { int idx; sint16 *resist; idx = va_arg(args, int); resist = va_arg(args, sint16 *); *resist = op->resist[idx]; } *type = CFAPI_INT16; break; case CFAPI_OBJECT_PROP_ATTACK_TYPE: rint = va_arg(args, int *); *rint = op->attacktype; *type = CFAPI_INT; break; case CFAPI_OBJECT_PROP_PATH_ATTUNED: rint = va_arg(args, int *); *rint = op->path_attuned; *type = CFAPI_INT; break; case CFAPI_OBJECT_PROP_PATH_REPELLED: rint = va_arg(args, int *); *rint = op->path_repelled; *type = CFAPI_INT; break; case CFAPI_OBJECT_PROP_PATH_DENIED: rint = va_arg(args, int *); *rint = op->path_denied; *type = CFAPI_INT; break; case CFAPI_OBJECT_PROP_MATERIAL: rint = va_arg(args, int *); *rint = op->material; *type = CFAPI_INT; break; case CFAPI_OBJECT_PROP_MATERIAL_NAME: rsstring = va_arg(args, sstring *); *rsstring = op->materialname; *type = CFAPI_SSTRING; break; case CFAPI_OBJECT_PROP_MAGIC: rint = va_arg(args, int *); *rint = op->magic; *type = CFAPI_INT; break; case CFAPI_OBJECT_PROP_VALUE: rlong = va_arg(args, long *); *rlong = op->value; *type = CFAPI_LONG; break; case CFAPI_OBJECT_PROP_LEVEL: rint = va_arg(args, int *); *rint = op->level; *type = CFAPI_INT; break; case CFAPI_OBJECT_PROP_LAST_HEAL: rint = va_arg(args, int *); *rint = op->last_heal; *type = CFAPI_INT; break; case CFAPI_OBJECT_PROP_LAST_SP: rint = va_arg(args, int *); *rint = op->last_sp; *type = CFAPI_INT; break; case CFAPI_OBJECT_PROP_LAST_GRACE: rint = va_arg(args, int *); *rint = op->last_grace; *type = CFAPI_INT; break; case CFAPI_OBJECT_PROP_LAST_EAT: rint = va_arg(args, int *); *rint = op->last_eat; *type = CFAPI_INT; break; case CFAPI_OBJECT_PROP_INVISIBLE_TIME: rint = va_arg(args, int *); *rint = op->invisible; *type = CFAPI_INT; break; case CFAPI_OBJECT_PROP_PICK_UP: rint = va_arg(args, int *); *rint = op->pick_up; *type = CFAPI_INT; break; case CFAPI_OBJECT_PROP_ITEM_POWER: rint = va_arg(args, int *); *rint = op->item_power; *type = CFAPI_INT; break; case CFAPI_OBJECT_PROP_GEN_SP_ARMOUR: rint = va_arg(args, int *); *rint = op->gen_sp_armour; *type = CFAPI_INT; break; case CFAPI_OBJECT_PROP_WEIGHT: rint = va_arg(args, int *); *rint = op->weight; *type = CFAPI_INT; break; case CFAPI_OBJECT_PROP_WEIGHT_LIMIT: rint = va_arg(args, int *); *rint = op->weight_limit; *type = CFAPI_INT; break; case CFAPI_OBJECT_PROP_CARRYING: rint = va_arg(args, int *); *rint = op->carrying; *type = CFAPI_INT; break; case CFAPI_OBJECT_PROP_GLOW_RADIUS: rint = va_arg(args, int *); *rint = op->glow_radius; *type = CFAPI_INT; break; case CFAPI_OBJECT_PROP_PERM_EXP: rint64 = va_arg(args, sint64 *); *rint64 = op->perm_exp; *type = CFAPI_SINT64; break; case CFAPI_OBJECT_PROP_CURRENT_WEAPON: robject = va_arg(args, object **); *robject = op->current_weapon; *type = CFAPI_POBJECT; break; case CFAPI_OBJECT_PROP_ENEMY: robject = va_arg(args, object **); *robject = op->enemy; *type = CFAPI_POBJECT; break; case CFAPI_OBJECT_PROP_ATTACKED_BY: robject = va_arg(args, object **); *robject = op->attacked_by; *type = CFAPI_POBJECT; break; case CFAPI_OBJECT_PROP_RUN_AWAY: rint = va_arg(args, int *); *rint = op->run_away; *type = CFAPI_INT; break; case CFAPI_OBJECT_PROP_CHOSEN_SKILL: robject = va_arg(args, object **); *robject = op->chosen_skill; *type = CFAPI_POBJECT; break; case CFAPI_OBJECT_PROP_HIDDEN: rint = va_arg(args, int *); *rint = op->hide; *type = CFAPI_INT; break; case CFAPI_OBJECT_PROP_MOVE_STATUS: rint = va_arg(args, int *); *rint = op->move_status; *type = CFAPI_INT; break; case CFAPI_OBJECT_PROP_ATTACK_MOVEMENT: rint = va_arg(args, int *); *rint = op->attack_movement; *type = CFAPI_INT; break; case CFAPI_OBJECT_PROP_SPELL_ITEM: robject = va_arg(args, object **); *robject = op->spellitem; *type = CFAPI_POBJECT; break; case CFAPI_OBJECT_PROP_EXP_MULTIPLIER: rdouble = va_arg(args, double *); *rdouble = op->expmul; *type = CFAPI_DOUBLE; break; case CFAPI_OBJECT_PROP_ARCHETYPE: rarch = va_arg(args, archetype **); *rarch = op->arch; *type = CFAPI_PARCH; break; case CFAPI_OBJECT_PROP_OTHER_ARCH: rarch = va_arg(args, archetype **); *rarch = op->other_arch; *type = CFAPI_PARCH; break; case CFAPI_OBJECT_PROP_CUSTOM_NAME: rsstring = va_arg(args, sstring *); *rsstring = (char *)op->custom_name; *type = CFAPI_SSTRING; break; case CFAPI_OBJECT_PROP_ANIM_SPEED: rint = va_arg(args, int *); *rint = op->anim_speed; *type = CFAPI_INT; break; case CFAPI_OBJECT_PROP_FRIENDLY: rint = va_arg(args, int *); *rint = is_friendly(op); *type = CFAPI_INT; break; case CFAPI_OBJECT_PROP_SHORT_NAME: rbuffer = va_arg(args, char *); rbufsize = va_arg(args, int); query_short_name(op, rbuffer, rbufsize); *type = CFAPI_STRING; break; case CFAPI_OBJECT_PROP_BASE_NAME: { int i; i = va_arg(args, int); rbuffer = va_arg(args, char *); rbufsize = va_arg(args, int); query_base_name(op, i, rbuffer, rbufsize); *type = CFAPI_STRING; } break; case CFAPI_OBJECT_PROP_MAGICAL: rint = va_arg(args, int *); *rint = is_magical(op); *type = CFAPI_INT; break; case CFAPI_OBJECT_PROP_LUCK: rint = va_arg(args, int *); *rint = op->stats.luck; *type = CFAPI_INT; break; case CFAPI_OBJECT_PROP_EXP: rint64 = va_arg(args, sint64 *); *rint64 = op->stats.exp; *type = CFAPI_SINT64; break; case CFAPI_OBJECT_PROP_OWNER: robject = va_arg(args, object **); *robject = get_owner(op); *type = CFAPI_POBJECT; break; case CFAPI_OBJECT_PROP_PRESENT: { int stype; stype = va_arg(args, int); switch (stype) { unsigned char ptype; char *buf; archetype *at; case 0: /* present_in_ob */ ptype = (unsigned char)(va_arg(args, int)); robject = va_arg(args, object **); *robject = present_in_ob(ptype, op); break; case 1: /* present_in_ob_by_name */ ptype = (unsigned char)(va_arg(args, int)); buf = va_arg(args, char *); robject = va_arg(args, object **); *robject = present_in_ob_by_name(ptype, buf, op); break; case 2: /* present_arch_in_ob */ at = va_arg(args, archetype *); robject = va_arg(args, object **); *robject = present_arch_in_ob(at, op); break; } } *type = CFAPI_POBJECT; break; case CFAPI_OBJECT_PROP_CHEATER: rint = va_arg(args, int *); *rint = (QUERY_FLAG(op, FLAG_WAS_WIZ)); *type = CFAPI_INT; break; case CFAPI_OBJECT_PROP_MERGEABLE: { object *op2; op2 = va_arg(args, object *); rint = va_arg(args, int *); *rint = can_merge(op, op2); } *type = CFAPI_INT; break; case CFAPI_OBJECT_PROP_PICKABLE: { object *op2; op2 = va_arg(args, object *); rint = va_arg(args, int *); *rint = can_pick(op2, op); } *type = CFAPI_INT; break; case CFAPI_OBJECT_PROP_FLAGS: { int fl; fl = va_arg(args, int); rint = va_arg(args, int *); *rint = QUERY_FLAG(op, fl); } *type = CFAPI_INT; break; case CFAPI_OBJECT_PROP_STR: rint = va_arg(args, int *); *rint = op->stats.Str; *type = CFAPI_INT; break; case CFAPI_OBJECT_PROP_DEX: rint = va_arg(args, int *); *rint = op->stats.Dex; *type = CFAPI_INT; break; case CFAPI_OBJECT_PROP_CON: rint = va_arg(args, int *); *rint = op->stats.Con; *type = CFAPI_INT; break; case CFAPI_OBJECT_PROP_WIS: rint = va_arg(args, int *); *rint = op->stats.Wis; *type = CFAPI_INT; break; case CFAPI_OBJECT_PROP_INT: rint = va_arg(args, int *); *rint = op->stats.Int; *type = CFAPI_INT; break; case CFAPI_OBJECT_PROP_POW: rint = va_arg(args, int *); *rint = op->stats.Pow; *type = CFAPI_INT; break; case CFAPI_OBJECT_PROP_CHA: rint = va_arg(args, int *); *rint = op->stats.Cha; *type = CFAPI_INT; break; case CFAPI_OBJECT_PROP_WC: rint = va_arg(args, int *); *rint = op->stats.wc; *type = CFAPI_INT; break; case CFAPI_OBJECT_PROP_AC: rint = va_arg(args, int *); *rint = op->stats.ac; *type = CFAPI_INT; break; case CFAPI_OBJECT_PROP_HP: rint = va_arg(args, int *); *rint = op->stats.hp; *type = CFAPI_INT; break; case CFAPI_OBJECT_PROP_SP: rint = va_arg(args, int *); *rint = op->stats.sp; *type = CFAPI_INT; break; case CFAPI_OBJECT_PROP_GP: rint = va_arg(args, int *); *rint = op->stats.grace; *type = CFAPI_INT; break; case CFAPI_OBJECT_PROP_FP: rint = va_arg(args, int *); *rint = op->stats.food; *type = CFAPI_INT; break; case CFAPI_OBJECT_PROP_MAXHP: rint = va_arg(args, int *); *rint = op->stats.maxhp; *type = CFAPI_INT; break; case CFAPI_OBJECT_PROP_MAXSP: rint = va_arg(args, int *); *rint = op->stats.maxsp; *type = CFAPI_INT; break; case CFAPI_OBJECT_PROP_MAXGP: rint = va_arg(args, int *); *rint = op->stats.maxgrace; *type = CFAPI_INT; break; case CFAPI_OBJECT_PROP_DAM: rint = va_arg(args, int *); *rint = op->stats.dam; *type = CFAPI_INT; break; case CFAPI_OBJECT_PROP_GOD: rsstring = va_arg(args, sstring *); *rsstring = determine_god(op); *type = CFAPI_SSTRING; break; case CFAPI_OBJECT_PROP_ARCH_NAME: rsstring = va_arg(args, sstring *); *rsstring = op->arch->name; *type = CFAPI_SSTRING; break; case CFAPI_OBJECT_PROP_INVISIBLE: rint = va_arg(args, int *); *rint = op->invisible; *type = CFAPI_INT; break; case CFAPI_OBJECT_PROP_FACE: rint = va_arg(args, int *); *rint = op->face->number; *type = CFAPI_INT; break; case CFAPI_OBJECT_PROP_ANIMATION: rint = va_arg(args, int *); *rint = op->animation_id; *type = CFAPI_INT; break; case CFAPI_PLAYER_PROP_IP: rsstring = va_arg(args, sstring *); *rsstring = op->contr->socket.host; *type = CFAPI_SSTRING; break; case CFAPI_PLAYER_PROP_MARKED_ITEM: robject = va_arg(args, object **); *robject = find_marked_object(op); *type = CFAPI_POBJECT; break; case CFAPI_PLAYER_PROP_PARTY: rparty = va_arg(args, partylist **); *rparty = (op->contr ? op->contr->party : NULL); *type = CFAPI_PPARTY; break; case CFAPI_PLAYER_PROP_NEXT: robject = va_arg(args, object **); if (op) *robject = op->contr->next ? op->contr->next->ob : NULL; else /* This can be called when there is no player. */ *robject = first_player ? first_player->ob : NULL; *type = CFAPI_POBJECT; break; case CFAPI_PLAYER_PROP_TITLE: rsstring = va_arg(args, sstring *); *rsstring = op->contr->title; *type = CFAPI_SSTRING; break; case CFAPI_OBJECT_PROP_NO_SAVE: rint = va_arg(args, int *); *rint = op->no_save; *type = CFAPI_INT; break; case CFAPI_OBJECT_PROP_MOVE_TYPE: rmove = va_arg(args, MoveType *); *rmove = op->move_type; *type = CFAPI_MOVETYPE; break; case CFAPI_OBJECT_PROP_MOVE_BLOCK: rmove = va_arg(args, MoveType *); *rmove = op->move_block; *type = CFAPI_MOVETYPE; break; case CFAPI_OBJECT_PROP_MOVE_ALLOW: rmove = va_arg(args, MoveType *); *rmove = op->move_allow; *type = CFAPI_MOVETYPE; break; case CFAPI_OBJECT_PROP_MOVE_ON: rmove = va_arg(args, MoveType *); *rmove = op->move_on; *type = CFAPI_MOVETYPE; break; case CFAPI_OBJECT_PROP_MOVE_OFF: rmove = va_arg(args, MoveType *); *rmove = op->move_off; *type = CFAPI_MOVETYPE; break; case CFAPI_OBJECT_PROP_MOVE_SLOW: rmove = va_arg(args, MoveType *); *rmove = op->move_type; *type = CFAPI_MOVETYPE; break; case CFAPI_OBJECT_PROP_MOVE_SLOW_PENALTY: rfloat = va_arg(args, float *); *rfloat = op->move_slow_penalty; *type = CFAPI_FLOAT; break; case CFAPI_PLAYER_PROP_BED_MAP: rbuffer = va_arg(args, char *); rbufsize = va_arg(args, int); snprintf(rbuffer, rbufsize, "%s", op->contr->savebed_map); *type = CFAPI_STRING; break; case CFAPI_PLAYER_PROP_BED_X: rint = va_arg(args, int *); *rint = op->contr->bed_x; *type = CFAPI_INT; break; case CFAPI_PLAYER_PROP_BED_Y: rint = va_arg(args, int *); *rint = op->contr->bed_y; *type = CFAPI_INT; break; case CFAPI_OBJECT_PROP_DURATION: rint = va_arg(args, int *); *rint = op->duration; *type = CFAPI_INT; break; default: *type = CFAPI_NONE; break; } va_end(args); return NULL; } /** * Utility function to copy the string to op->msg and ensure there is a final newline. * * @param op * object to copy to. * @param msg * message to copy. */ static void copy_message(object *op, const char *msg) { char *temp; int size; if (!msg) return; size = strlen(msg); if (msg[0] != 0 && msg[size-1] == '\n') { FREE_AND_COPY(op->msg, msg); return; } temp = malloc(size+2); if (!temp) fatal(OUT_OF_MEMORY); snprintf(temp, size+2, "%s\n", msg); FREE_AND_COPY(op->msg, temp); free(temp); } /** * Sets the property of an object. * Will send changes to client if required. * First argument should be an object*, second an integer.. * Will not change an archetype's object. * @param type * will contain the type of the first argument used to change the property. * @return * NULL. */ void *cfapi_object_set_property(int *type, ...) { va_list args; int iarg; long larg; char *sarg; double darg; object *oparg; object *op; int property; sint64 s64arg; partylist *partyarg; float farg; va_start(args, type); op = va_arg(args, object *); property = va_arg(args, int); *type = CFAPI_NONE; if (op != NULL && (!op->arch || (op != &op->arch->clone))) { switch (property) { case CFAPI_OBJECT_PROP_NAME: sarg = va_arg(args, char *); *type = CFAPI_STRING; FREE_AND_COPY(op->name, sarg); send_changed_object(op); break; case CFAPI_OBJECT_PROP_NAME_PLURAL: sarg = va_arg(args, char *); *type = CFAPI_STRING; FREE_AND_COPY(op->name_pl, sarg); send_changed_object(op); break; case CFAPI_OBJECT_PROP_TITLE: sarg = va_arg(args, char *); *type = CFAPI_STRING; FREE_AND_COPY(op->title, sarg); break; case CFAPI_OBJECT_PROP_RACE: sarg = va_arg(args, char *); *type = CFAPI_STRING; FREE_AND_COPY(op->race, sarg); break; case CFAPI_OBJECT_PROP_SLAYING: sarg = va_arg(args, char *); *type = CFAPI_STRING; FREE_AND_COPY(op->slaying, sarg); break; case CFAPI_OBJECT_PROP_SKILL: sarg = va_arg(args, char *); *type = CFAPI_STRING; FREE_AND_COPY(op->skill, sarg); break; case CFAPI_OBJECT_PROP_MESSAGE: sarg = va_arg(args, char *); *type = CFAPI_STRING; copy_message(op, sarg); break; case CFAPI_OBJECT_PROP_LORE: sarg = va_arg(args, char *); *type = CFAPI_STRING; FREE_AND_COPY(op->lore, sarg); break; case CFAPI_OBJECT_PROP_SPEED: farg = va_arg(args, double); *type = CFAPI_FLOAT; if (farg != op->speed) { op->speed = farg; update_ob_speed(op); } break; case CFAPI_OBJECT_PROP_SPEED_LEFT: farg = va_arg(args, double); *type = CFAPI_FLOAT; op->speed_left = farg; break; case CFAPI_OBJECT_PROP_NROF: iarg = va_arg(args, int); *type = CFAPI_INT; if (iarg < 0) iarg = 0; if (op->nrof > (uint32)iarg) decrease_ob_nr(op, op->nrof-iarg); else if (op->nrof < (uint32)iarg) { object *tmp; player *pl; op->nrof = iarg; if (op->env != NULL) { tmp = get_player_container(op->env); if (!tmp) { for (pl = first_player; pl; pl = pl->next) if (pl->ob->container == op->env) break; if (pl) tmp = pl->ob; else tmp = NULL; } else { sum_weight(tmp); fix_object(tmp); } if (tmp) esrv_update_item(UPD_NROF, tmp, op); } else { object *above = op->above; for (tmp = above; tmp != NULL; tmp = tmp->above) if (tmp->type == PLAYER) tmp->contr->socket.update_look = 1; } } break; case CFAPI_OBJECT_PROP_DIRECTION: iarg = va_arg(args, int); *type = CFAPI_INT; op->direction = iarg; break; case CFAPI_OBJECT_PROP_FACING: iarg = va_arg(args, int); *type = CFAPI_INT; op->facing = iarg; break; case CFAPI_OBJECT_PROP_RESIST: { int iargbis = va_arg(args, int); *type = CFAPI_INT16; iarg = va_arg(args, int); op->resist[iargbis] = iarg; } break; case CFAPI_OBJECT_PROP_ATTACK_TYPE: iarg = va_arg(args, int); *type = CFAPI_INT; op->attacktype = iarg; break; case CFAPI_OBJECT_PROP_PATH_ATTUNED: iarg = va_arg(args, int); *type = CFAPI_INT; op->path_attuned = iarg; break; case CFAPI_OBJECT_PROP_PATH_REPELLED: iarg = va_arg(args, int); *type = CFAPI_INT; op->path_repelled = iarg; break; case CFAPI_OBJECT_PROP_PATH_DENIED: iarg = va_arg(args, int); *type = CFAPI_INT; op->path_denied = iarg; break; case CFAPI_OBJECT_PROP_MATERIAL: iarg = va_arg(args, int); *type = CFAPI_INT; op->material = iarg; break; case CFAPI_OBJECT_PROP_MATERIAL_NAME: break; case CFAPI_OBJECT_PROP_MAGIC: iarg = va_arg(args, int); *type = CFAPI_INT; op->magic = iarg; break; case CFAPI_OBJECT_PROP_VALUE: larg = va_arg(args, long); *type = CFAPI_LONG; op->value = larg; break; case CFAPI_OBJECT_PROP_LEVEL: iarg = va_arg(args, int); *type = CFAPI_INT; op->level = iarg; break; case CFAPI_OBJECT_PROP_LAST_HEAL: iarg = va_arg(args, int); *type = CFAPI_INT; op->last_heal = iarg; break; case CFAPI_OBJECT_PROP_LAST_SP: iarg = va_arg(args, int); *type = CFAPI_INT; op->last_sp = iarg; break; case CFAPI_OBJECT_PROP_LAST_GRACE: iarg = va_arg(args, int); *type = CFAPI_INT; op->last_grace = iarg; break; case CFAPI_OBJECT_PROP_LAST_EAT: iarg = va_arg(args, int); *type = CFAPI_INT; op->last_eat = iarg; break; case CFAPI_OBJECT_PROP_INVISIBLE_TIME: iarg = va_arg(args, int); *type = CFAPI_INT; op->invisible = iarg; break; case CFAPI_OBJECT_PROP_PICK_UP: iarg = va_arg(args, int); *type = CFAPI_INT; op->pick_up = iarg; break; case CFAPI_OBJECT_PROP_ITEM_POWER: iarg = va_arg(args, int); *type = CFAPI_INT; op->item_power = iarg; break; case CFAPI_OBJECT_PROP_GEN_SP_ARMOUR: iarg = va_arg(args, int); *type = CFAPI_INT; op->gen_sp_armour = iarg; break; case CFAPI_OBJECT_PROP_WEIGHT: iarg = va_arg(args, int); *type = CFAPI_INT; if (op->weight != iarg) { object *tmp; player *pl; op->weight = iarg; if (op->env != NULL) { tmp = get_player_container(op->env); if (!tmp) { for (pl = first_player; pl; pl = pl->next) if (pl->ob->container == op->env) break; if (pl) tmp = pl->ob; else tmp = NULL; } else { sum_weight(tmp); fix_object(tmp); } if (tmp) esrv_update_item(UPD_WEIGHT, tmp, op); } else { object *above = op->above; for (tmp = above; tmp != NULL; tmp = tmp->above) if (tmp->type == PLAYER) esrv_update_item(UPD_WEIGHT, tmp, op); } } break; case CFAPI_OBJECT_PROP_WEIGHT_LIMIT: iarg = va_arg(args, int); *type = CFAPI_INT; op->weight_limit = iarg; break; case CFAPI_OBJECT_PROP_GLOW_RADIUS: iarg = va_arg(args, int); *type = CFAPI_INT; if (op->glow_radius != iarg) { object *tmp; op->glow_radius = iarg; tmp = object_get_env_recursive(op); if (tmp->map != NULL) { SET_MAP_FLAGS(tmp->map, tmp->x, tmp->y, P_NEED_UPDATE); update_position(tmp->map, tmp->x, tmp->y); update_all_los(tmp->map, tmp->x, tmp->y); } } break; case CFAPI_OBJECT_PROP_PERM_EXP: s64arg = va_arg(args, sint64); *type = CFAPI_SINT64; op->perm_exp = s64arg; break; case CFAPI_OBJECT_PROP_ENEMY: oparg = va_arg(args, object *); *type = CFAPI_POBJECT; op->enemy = oparg; break; case CFAPI_OBJECT_PROP_RUN_AWAY: iarg = va_arg(args, int); *type = CFAPI_INT; op->run_away = iarg; break; case CFAPI_OBJECT_PROP_CHOSEN_SKILL: oparg = va_arg(args, object *); *type = CFAPI_POBJECT; op->chosen_skill = oparg; break; case CFAPI_OBJECT_PROP_HIDDEN: iarg = va_arg(args, int); *type = CFAPI_INT; op->hide = iarg; break; case CFAPI_OBJECT_PROP_MOVE_STATUS: iarg = va_arg(args, int); *type = CFAPI_INT; op->move_status = iarg; break; case CFAPI_OBJECT_PROP_ATTACK_MOVEMENT: iarg = va_arg(args, int); *type = CFAPI_INT; op->attack_movement = iarg; break; case CFAPI_OBJECT_PROP_SPELL_ITEM: oparg = va_arg(args, object *); *type = CFAPI_POBJECT; op->spellitem = oparg; break; case CFAPI_OBJECT_PROP_EXP_MULTIPLIER: darg = va_arg(args, double); *type = CFAPI_DOUBLE; op->expmul = darg; break; case CFAPI_OBJECT_PROP_CUSTOM_NAME: sarg = va_arg(args, char *); *type = CFAPI_STRING; FREE_AND_COPY(op->custom_name, sarg); send_changed_object(op); break; case CFAPI_OBJECT_PROP_ANIM_SPEED: iarg = va_arg(args, int); *type = CFAPI_INT; op->anim_speed = iarg; break; case CFAPI_OBJECT_PROP_FRIENDLY: iarg = va_arg(args, int); *type = CFAPI_INT; if (iarg == 1 && is_friendly(op) == 0) add_friendly_object(op); else if (iarg == 0 && is_friendly(op) == 1) remove_friendly_object(op); break; case CFAPI_OBJECT_PROP_LUCK: iarg = va_arg(args, int); *type = CFAPI_INT; op->stats.luck = iarg; break; case CFAPI_OBJECT_PROP_EXP: s64arg = va_arg(args, sint64); *type = CFAPI_SINT64; op->stats.exp = s64arg; break; case CFAPI_OBJECT_PROP_OWNER: oparg = va_arg(args, object *); *type = CFAPI_POBJECT; set_owner(op, oparg); break; case CFAPI_OBJECT_PROP_CHEATER: set_cheat(op); *type = CFAPI_NONE; break; case CFAPI_OBJECT_PROP_FLAGS: { int iargbis; iarg = va_arg(args, int); iargbis = va_arg(args, int); *type = CFAPI_INT; if (iargbis == 1) SET_FLAG(op, iarg); else CLEAR_FLAG(op, iarg); } break; case CFAPI_OBJECT_PROP_STR: iarg = va_arg(args, int); *type = CFAPI_INT; op->stats.Str = iarg; break; case CFAPI_OBJECT_PROP_DEX: iarg = va_arg(args, int); *type = CFAPI_INT; op->stats.Dex = iarg; break; case CFAPI_OBJECT_PROP_CON: iarg = va_arg(args, int); *type = CFAPI_INT; op->stats.Con = iarg; break; case CFAPI_OBJECT_PROP_WIS: iarg = va_arg(args, int); *type = CFAPI_INT; op->stats.Wis = iarg; break; case CFAPI_OBJECT_PROP_INT: iarg = va_arg(args, int); *type = CFAPI_INT; op->stats.Int = iarg; break; case CFAPI_OBJECT_PROP_POW: iarg = va_arg(args, int); *type = CFAPI_INT; op->stats.Pow = iarg; break; case CFAPI_OBJECT_PROP_CHA: iarg = va_arg(args, int); *type = CFAPI_INT; op->stats.Cha = iarg; break; case CFAPI_OBJECT_PROP_WC: iarg = va_arg(args, int); *type = CFAPI_INT; op->stats.wc = iarg; break; case CFAPI_OBJECT_PROP_AC: iarg = va_arg(args, int); *type = CFAPI_INT; op->stats.ac = iarg; break; case CFAPI_OBJECT_PROP_HP: iarg = va_arg(args, int); *type = CFAPI_INT; op->stats.hp = iarg; break; case CFAPI_OBJECT_PROP_SP: iarg = va_arg(args, int); *type = CFAPI_INT; op->stats.sp = iarg; break; case CFAPI_OBJECT_PROP_GP: iarg = va_arg(args, int); *type = CFAPI_INT; op->stats.grace = iarg; break; case CFAPI_OBJECT_PROP_FP: iarg = va_arg(args, int); *type = CFAPI_INT; op->stats.food = iarg; break; case CFAPI_OBJECT_PROP_MAXHP: iarg = va_arg(args, int); *type = CFAPI_INT; op->stats.maxhp = iarg; break; case CFAPI_OBJECT_PROP_MAXSP: iarg = va_arg(args, int); *type = CFAPI_INT; op->stats.maxsp = iarg; break; case CFAPI_OBJECT_PROP_MAXGP: iarg = va_arg(args, int); *type = CFAPI_INT; op->stats.maxgrace = iarg; break; case CFAPI_OBJECT_PROP_DAM: iarg = va_arg(args, int); *type = CFAPI_INT; op->stats.dam = iarg; break; case CFAPI_OBJECT_PROP_FACE: iarg = va_arg(args, int); *type = CFAPI_INT; op->face = &new_faces[iarg]; op->state = 0; update_object(op, UP_OBJ_FACE); break; case CFAPI_OBJECT_PROP_ANIMATION: iarg = va_arg(args, int); *type = CFAPI_INT; op->animation_id = iarg; SET_ANIMATION(op, 0); update_object(op, UP_OBJ_FACE); break; case CFAPI_OBJECT_PROP_DURATION: iarg = va_arg(args, int); *type = CFAPI_INT; op->duration = iarg; break; case CFAPI_PLAYER_PROP_MARKED_ITEM: if (op->contr) { oparg = va_arg(args, object *); *type = CFAPI_POBJECT; op->contr->mark = oparg; if (oparg) op->contr->mark_count = oparg->count; } break; case CFAPI_PLAYER_PROP_PARTY: if (op->contr) { partyarg = va_arg(args, partylist *); *type = CFAPI_PPARTY; op->contr->party = partyarg; } break; case CFAPI_OBJECT_PROP_NO_SAVE: iarg = va_arg(args, int); *type = CFAPI_INT; op->no_save = iarg; break; case CFAPI_PLAYER_PROP_BED_MAP: sarg = va_arg(args, char *); *type = CFAPI_STRING; strncpy(op->contr->savebed_map, sarg, MAX_BUF); break; case CFAPI_PLAYER_PROP_BED_X: iarg = va_arg(args, int); *type = CFAPI_INT; op->contr->bed_x = iarg; break; case CFAPI_PLAYER_PROP_BED_Y: iarg = va_arg(args, int); *type = CFAPI_INT; op->contr->bed_y = iarg; break; case CFAPI_PLAYER_PROP_TITLE: sarg = va_arg(args, char *); *type = CFAPI_STRING; strncpy(op->contr->title, sarg, sizeof(op->contr->title)); op->contr->title[sizeof(op->contr->title) - 1]= '\0'; break; default: break; } } va_end(args); return NULL; } /** * Applies an object below. * * @param type * will be CFAPI_NONE. * @return * always NULL. */ void *cfapi_object_apply_below(int *type, ...) { va_list args; object *applier; va_start(args, type); applier = va_arg(args, object *); va_end(args); player_apply_below(applier); *type = CFAPI_NONE; return NULL; } /** * Applies an object. * * @param type * will be CFAPI_INT. * @return * always NULL. */ void *cfapi_object_apply(int *type, ...) { va_list args; object *applied; object *applier; int aflags; int *ret; va_start(args, type); applier = va_arg(args, object *); applied = va_arg(args, object *); aflags = va_arg(args, int); ret = va_arg(args, int *); va_end(args); *type = CFAPI_INT; *ret = manual_apply(applier, applied, aflags); return NULL; } /** * Wrapper for identify(). * @param type * will be CFAPI_NONE. * @return * NULL. */ void *cfapi_object_identify(int *type, ...) { va_list args; object *op; va_start(args, type); op = va_arg(args, object *); va_end(args); identify(op); *type = CFAPI_NONE; return NULL; } /** * Wrapper for describe_item(). * @param type * will be CFAPI_STRING. * @return * NULL. */ void *cfapi_object_describe(int *type, ...) { va_list args; object *op; object *owner; char *desc; int size; va_start(args, type); op = va_arg(args, object *); owner = va_arg(args, object *); desc = va_arg(args, char *); size = va_arg(args, int); va_end(args); *type = CFAPI_STRING; describe_item(op, owner, desc, size); return NULL; } void *cfapi_object_drain(int *type, ...) { va_list args; object *op; int ds; va_start(args, type); op = va_arg(args, object *); ds = va_arg(args, int); va_end(args); drain_specific_stat(op, ds); *type = CFAPI_NONE; return NULL; } void *cfapi_object_fix(int *type, ...) { va_list args; object *op; va_start(args, type); op = va_arg(args, object *); va_end(args); fix_object(op); *type = CFAPI_NONE; return NULL; } void *cfapi_object_give_skill(int *type, ...) { va_list args; object *op; char *skillname; va_start(args, type); op = va_arg(args, object *); skillname = va_arg(args, char *); va_end(args); *type = CFAPI_POBJECT; return give_skill_by_name(op, skillname); } void *cfapi_object_transmute(int *type, ...) { va_list args; object *op; object *chg; va_start(args, type); op = va_arg(args, object *); chg = va_arg(args, object *); va_end(args); transmute_materialname(op, chg); *type = CFAPI_NONE; return NULL; } void *cfapi_object_remove(int *type, ...) { va_list args; object *op; va_start(args, type); op = va_arg(args, object *); if (QUERY_FLAG(op, FLAG_REMOVED)) { LOG(llevError, "Plugin trying to remove removed object %s\n", op->name); *type = CFAPI_NONE; return NULL; } va_end(args); remove_ob(op); *type = CFAPI_NONE; return NULL; } void *cfapi_object_delete(int *type, ...) { va_list args; object *op; va_start(args, type); op = va_arg(args, object *); if (QUERY_FLAG(op, FLAG_FREED) || !QUERY_FLAG(op, FLAG_REMOVED)) { LOG(llevError, "Plugin trying to free freed/non removed object %s\n", op->name); *type = CFAPI_NONE; return NULL; } va_end(args); free_object(op); *type = CFAPI_NONE; return NULL; } /** * Clone an object, either through object_create_clone() or copy_object(). * @param type * will be CFAPI_POBJECT. * @return * NULL. */ void *cfapi_object_clone(int *type, ...) { va_list args; object *op; int kind; object **robj; va_start(args, type); op = va_arg(args, object *); kind = va_arg(args, int); robj = va_arg(args, object **); va_end(args); if (kind == 0) { *type = CFAPI_POBJECT; *robj = object_create_clone(op); } else { object *tmp; tmp = get_object(); copy_object(op, tmp); *type = CFAPI_POBJECT; *robj = tmp; } return NULL; } void *cfapi_object_find(int *type, ...) { va_list args; int ftype; void *rv; int ival; int ival2; char *sval; object *op; va_start(args, type); *type = CFAPI_POBJECT; ftype = va_arg(args, int); switch (ftype) { case 0: ival = va_arg(args, int); rv = find_object(ival); break; case 1: sval = va_arg(args, char *); rv = find_object_name(sval); break; case 2: op = va_arg(args, object *); ival = va_arg(args, int); ival2 = va_arg(args, int); rv = find_obj_by_type_subtype(op, ival, ival2); break; case 3: op = va_arg(args, object *); rv = get_player_container(op); break; default: rv = NULL; *type = CFAPI_NONE; break; } va_end(args); return rv; } /** * Wrapper for get_object(), create_archetype() and create_archetype_by_object_name(). * @param type * will be CFAPI_POBJECT, or CFAPI_NONE if invalid value asked for. * @return * NULL. */ void *cfapi_object_create(int *type, ...) { va_list args; int ival; object **robj; va_start(args, type); ival = va_arg(args, int); *type = CFAPI_POBJECT; switch (ival) { case 0: robj = va_arg(args, object **); *robj = get_object(); break; case 1: { /* Named object. Nearly the old plugin behavior, but we don't add artifact suffixes */ const char *sval; archetype *at; sval = va_arg(args, const char *); robj = va_arg(args, object **); va_end(args); at = try_find_archetype(sval); if (!at) at = find_archetype_by_object_name(sval); if (at) { *robj = object_create_arch(at); } else *robj = NULL; } break; default: *type = CFAPI_NONE; break; } va_end(args); return NULL; } void *cfapi_object_insert(int *type, ...) { va_list args; object *op; object *orig; mapstruct *map; int flag, x, y; int itype; object **robj; va_start(args, type); op = va_arg(args, object *); if (!op) { LOG(llevError, "cfapi_object_insert: called with NULL object!\n"); va_end(args); return NULL; } if (QUERY_FLAG(op, FLAG_FREED)) { LOG(llevError, "cfapi_object_insert: called with FREED object!\n"); va_end(args); return NULL; } if (!QUERY_FLAG(op, FLAG_REMOVED)) { LOG(llevError, "cfapi_object_insert: called with not removed object %s!\n", op->name); remove_ob(op); } itype = va_arg(args, int); switch (itype) { case 0: map = va_arg(args, mapstruct *); orig = va_arg(args, object *); flag = va_arg(args, int); x = va_arg(args, int); y = va_arg(args, int); robj = va_arg(args, object **); if (!map) { LOG(llevError, "cfapi_object_insert (0): called with NULL map, object %s!\n", op->name); free_object(op); *robj = NULL; } else *robj = insert_ob_in_map_at(op, map, orig, flag, x, y); *type = CFAPI_POBJECT; break; case 1: map = va_arg(args, mapstruct *); orig = va_arg(args, object *); flag = va_arg(args, int); robj = va_arg(args, object **); if (!map) { LOG(llevError, "cfapi_object_insert (1): called with NULL map, object %s!\n", op->name); free_object(op); *robj = NULL; } else *robj = insert_ob_in_map(op, map, orig, flag); *type = CFAPI_POBJECT; break; case 3: orig = va_arg(args, object *); robj = va_arg(args, object **); if (!orig) { LOG(llevError, "cfapi_object_insert (3): called with NULL orig, object %s!\n", op->name); free_object(op); *robj = NULL; } else *robj = insert_ob_in_ob(op, orig); *type = CFAPI_POBJECT; break; default: LOG(llevError, "cfapi_object_insert (1): called with itype %d which is not valid, object %s!\n", itype, op->name); free_object(op); *type = CFAPI_NONE; break; } va_end(args); return NULL; } /** * Wrapper for get_split_ob(). * @param type * will be CFAPI_POBJECT. * @return * NULL. */ void *cfapi_object_split(int *type, ...) { va_list args; int nr, size; object *op; char *buf; object **split; va_start(args, type); op = va_arg(args, object *); nr = va_arg(args, int); buf = va_arg(args, char *); size = va_arg(args, int); split = va_arg(args, object **); va_end(args); *type = CFAPI_POBJECT; *split = get_split_ob(op, nr, buf, size); return NULL; } /** * Wrapper for merge_ob(). * @param type * Will be CFAPI_POBJECT. * @return * NULL. */ void *cfapi_object_merge(int *type, ...) { va_list args; object *op; object *op2; object **merge; va_start(args, type); op = va_arg(args, object *); op2 = va_arg(args, object *); merge = va_arg(args, object **); va_end(args); *type = CFAPI_POBJECT; *merge = merge_ob(op, op2); return NULL; } /** * Wrapper for distance(). * @param type * will be CFAPI_INT. * @return * NULL. */ void *cfapi_object_distance(int *type, ...) { va_list args; object *op; object *op2; int *rint; va_start(args, type); op = va_arg(args, object *); op2 = va_arg(args, object *); rint = va_arg(args, int *); va_end(args); *type = CFAPI_INT; *rint = distance(op, op2); return NULL; } /** * Wrapper for update_object(). * @param type * Will be CFAPI_NONE. * @return * NULL. */ void *cfapi_object_update(int *type, ...) { va_list args; int action; object *op; va_start(args, type); op = va_arg(args, object *); action = va_arg(args, int); va_end(args); update_object(op, action); *type = CFAPI_NONE; return NULL; } /** * Wrapper for clear_object(). * @param type * Will be CFAPI_NONE. * @return * NULL. */ void *cfapi_object_clear(int *type, ...) { va_list args; object *op; va_start(args, type); op = va_arg(args, object *); va_end(args); clear_object(op); *type = CFAPI_NONE; return NULL; } /** * Wrapper for clear_reset(). * @param type * Will be CFAPI_NONE. * @return * NULL. */ void *cfapi_object_reset(int *type, ...) { va_list args; object *op; va_start(args, type); op = va_arg(args, object *); va_end(args); reset_object(op); *type = CFAPI_NONE; return NULL; } void *cfapi_object_check_inventory(int *type, ...) { va_list args; object *op; object *op2; int checktype; object *ret = NULL; va_start(args, type); op = va_arg(args, object *); op2 = va_arg(args, object *); checktype = va_arg(args, int); if (checktype == 0) { check_inv(op, op2); *type = CFAPI_NONE; } else { ret = check_inv_recursive(op, op2); *type = CFAPI_POBJECT; } va_end(args); return ret; } void *cfapi_object_clean_object(int *type, ...) { va_list args; object *op; va_start(args, type); op = va_arg(args, object *); clean_object(op); va_end(args); *type = CFAPI_NONE; return NULL; } void *cfapi_object_on_same_map(int *type, ...) { va_list args; object *op1; object *op2; int *rint; va_start(args, type); op1 = va_arg(args, object *); op2 = va_arg(args, object *); rint = va_arg(args, int *); va_end(args); *type = CFAPI_INT; *rint = on_same_map(op1, op2); return NULL; } void *cfapi_object_spring_trap(int *type, ...) { object *trap; object *victim; va_list args; va_start(args, type); trap = va_arg(args, object *); victim = va_arg(args, object *); va_end(args); spring_trap(trap, victim); *type = CFAPI_NONE; return NULL; } /** * Wrapper for check_trigger(). * @param type * Will be CFAPI_INT. * @return * NULL. */ void *cfapi_object_check_trigger(int *type, ...) { object *op; object *cause; va_list args; int *rint; va_start(args, type); op = va_arg(args, object *); cause = va_arg(args, object *); rint = va_arg(args, int *); va_end(args); *rint = check_trigger(op, cause); *type = CFAPI_INT; return NULL; } /** * Wrapper for trigger_connected(). * * Expected parameters after type: * - ::objectlink*: the link to trigger. Can be obtained from map structure * - ::object*: the object that cause this link to trigger, may be NULL * - int: the state to trigger. 0=APPLY_RELEASE other=APPLY_PUSH * * @param[out] type * Will be CFAPI_NONE. * @return * NULL. */ void *cfapi_map_trigger_connected(int *type, ...) { objectlink *ol; object *cause; int state; va_list args; va_start(args, type); ol = va_arg(args, objectlink *); cause = va_arg(args, object *); state = va_arg(args, int); va_end(args); trigger_connected(ol, cause, state); *type = CFAPI_NONE; return NULL; } /** * Wrapper for query_cost(). * @param type * Will be CFAPI_INT. * @return * NULL. */ void *cfapi_object_query_cost(int *type, ...) { object *op; object *who; int flags; va_list args; int *rint; va_start(args, type); op = va_arg(args, object *); who = va_arg(args, object *); flags = va_arg(args, int); rint = va_arg(args, int *); va_end(args); *rint = query_cost(op, who, flags); *type = CFAPI_INT; return NULL; } /** * Wrapper for query_money(). * @param type * Will be CFAPI_INT. * @return * NULL. */ void *cfapi_object_query_money(int *type, ...) { object *op; va_list args; int *rint; va_start(args, type); op = va_arg(args, object *); rint = va_arg(args, int *); va_end(args); *rint = query_money(op); *type = CFAPI_INT; return NULL; } /** * Wrapper for query_money(). * @param type * Will be CFAPI_INT. * @return * NULL. */ void *cfapi_object_cast(int *type, ...) { object *op; object *sp; int dir; char *str; object *caster; va_list args; int *rint; va_start(args, type); op = va_arg(args, object *); caster = va_arg(args, object *); dir = va_arg(args, int); sp = va_arg(args, object *); str = va_arg(args, char *); rint = va_arg(args, int *); va_end(args); *type = CFAPI_INT; if (!op->map) { *rint = -1; return NULL; } *rint = cast_spell(op, caster, dir, sp, str); return NULL; } void *cfapi_object_learn_spell(int *type, ...) { object *op; object *sp; int prayer; va_list args; va_start(args, type); op = va_arg(args, object *); sp = va_arg(args, object *); prayer = va_arg(args, int); va_end(args); do_learn_spell(op, sp, prayer); *type = CFAPI_NONE; return NULL; } void *cfapi_object_forget_spell(int *type, ...) { object *op; object *sp; va_list args; char name[MAX_BUF]; va_start(args, type); op = va_arg(args, object *); sp = va_arg(args, object *); va_end(args); query_name(sp, name, MAX_BUF); do_forget_spell(op, name); *type = CFAPI_NONE; return NULL; } /** * Wrapper for check_spell_known(). * @param type * Will be CFAPI_POBJECT. * @return * NULL. */ void *cfapi_object_check_spell(int *type, ...) { object *op; char *spellname; va_list args; object **robj; va_start(args, type); op = va_arg(args, object *); spellname = va_arg(args, char *); robj = va_arg(args, object **); va_end(args); *robj = check_spell_known(op, spellname); *type = CFAPI_POBJECT; return NULL; } /** * Wrapper for pay_for_amount(). * @param type * will be CFAPI_INT. * @return * NULL. */ void *cfapi_object_pay_amount(int *type, ...) { object *op; uint64 amount; va_list args; int *rint; va_start(args, type); op = va_arg(args, object *); amount = va_arg(args, uint64); rint = va_arg(args, int *); va_end(args); *rint = pay_for_amount(amount, op); *type = CFAPI_INT; return NULL; } /** * Wrapper for pay_for_item(). * @param type * will be CFAPI_INT. * @return * NULL. */ void *cfapi_object_pay_item(int *type, ...) { object *op; object *tobuy; int *rint; va_list args; va_start(args, type); tobuy = va_arg(args, object *); op = va_arg(args, object *); rint = va_arg(args, int *); va_end(args); *rint = pay_for_item(tobuy, op); *type = CFAPI_INT; return NULL; } /** * Object transfer. * Parameters are object*, int meaning: * 0: call to transfer_ob() * 1: call to insert_ob_in_map_at() * 2: call to move_to() * @return * NULL. */ void *cfapi_object_transfer(int *type, ...) { object *op; object *originator; int x, y, randompos, ttype, flag; va_list args; mapstruct *map; int *rint; object **robj; va_start(args, type); op = va_arg(args, object *); ttype = va_arg(args, int); switch (ttype) { case 0: x = va_arg(args, int); y = va_arg(args, int); randompos = va_arg(args, int); originator = va_arg(args, object *); rint = va_arg(args, int *); va_end(args); *rint = transfer_ob(op, x, y, randompos, originator); *type = CFAPI_INT; return NULL; break; case 1: map = va_arg(args, mapstruct *); originator = va_arg(args, object *); flag = va_arg(args, int); x = va_arg(args, int); y = va_arg(args, int); robj = va_arg(args, object **); va_end(args); if (x < 0 || y < 0) { x = map->enter_x; y = map->enter_y; } *robj = insert_ob_in_map_at(op, map, originator, flag, x, y); *type = CFAPI_POBJECT; return NULL; break; case 2: x = va_arg(args, int); y = va_arg(args, int); rint = va_arg(args, int *); va_end(args); *rint = move_to(op, x, y); *type = CFAPI_INT; return NULL; default: *type = CFAPI_NONE; return NULL; break; } } /** * Kinda wrapper for present_arch_in_ob(). */ void *cfapi_object_find_archetype_inside(int *type, ...) { object *op; char *str; va_list args; object **robj; *type = CFAPI_POBJECT; va_start(args, type); op = va_arg(args, object *); str = va_arg(args, char *); robj = va_arg(args, object **); *robj = present_arch_in_ob(try_find_archetype(str), op); if (*robj == NULL) { object *tmp; char name[MAX_BUF]; /* Search by query_name instead */ for (tmp = op->inv; tmp; tmp = tmp->below) { query_name(tmp, name, MAX_BUF); if (!strncmp(name, str, strlen(str))) *robj = tmp; if (!strncmp(tmp->name, str, strlen(str))) *robj = tmp; if (*robj != NULL) break; } } va_end(args); return NULL; } /** * Wrapper for drop(). * @param type * will be CFAPI_NONE. * @return * NULL. */ void *cfapi_object_drop(int *type, ...) { object *op; object *author; va_list args; va_start(args, type); op = va_arg(args, object *); author = va_arg(args, object *); va_end(args); *type = CFAPI_NONE; if (QUERY_FLAG(op, FLAG_NO_DROP)) return NULL; drop(author, op); if (author->type == PLAYER) { author->contr->count = 0; author->contr->socket.update_look = 1; } return NULL; } /** * Wrapper for change_abil(). */ void *cfapi_object_change_abil(int *type, ...) { object *op, *tmp; int *rint; va_list args; va_start(args, type); op = va_arg(args, object *); tmp = va_arg(args, object *); rint = va_arg(args, int *); va_end(args); *type = CFAPI_INT; *rint = change_abil(op, tmp); return NULL; } void *cfapi_object_say(int *type, ...) { object *op; char *msg; va_list args; int *rint; va_start(args, type); op = va_arg(args, object *); msg = va_arg(args, char *); rint = va_arg(args, int *); va_end(args); if (op->type == PLAYER) { *rint = command_say(op, msg); } else { npc_say(op, msg); *rint = 0; } *type = CFAPI_INT; return NULL; } /* PLAYER SUBCLASS */ /** * Wrapper for find_player_partial_name(). * @param type * will be CFAPI_PPLAYER. * @return * NULL. */ void *cfapi_player_find(int *type, ...) { va_list args; char *sval; player **rpl; va_start(args, type); sval = va_arg(args, char *); rpl = va_arg(args, player **); va_end(args); *rpl = find_player_partial_name(sval); *type = CFAPI_PPLAYER; return NULL; } void *cfapi_player_message(int *type, ...) { va_list args; int flags; int pri; object *pl; char *buf; va_start(args, type); flags = va_arg(args, int); pri = va_arg(args, int); pl = va_arg(args, object *); buf = va_arg(args, char *); va_end(args); draw_ext_info(flags, pri, pl, MSG_TYPE_MISC, MSG_SUBTYPE_NONE, buf, buf); *type = CFAPI_NONE; return NULL; } /** * Wrapper for change_exp(). * @param type * will be CFAPI_NONE. * @return * NULL. */ void *cfapi_object_change_exp(int *type, ...) { va_list(args); int flag; object *ob; const char *skill; sint64 exp; va_start(args, type); ob = va_arg(args, object *); exp = va_arg(args, sint64); skill = va_arg(args, const char *); flag = va_arg(args, int); va_end(args); *type = CFAPI_NONE; change_exp(ob, exp, skill, flag); return NULL; } /** * Wrapper for can_pay(). * @param type * will be CFAPI_INT. * @return * NULL. */ void *cfapi_player_can_pay(int *type, ...) { va_list args; object *pl; int *rint; va_start(args, type); pl = va_arg(args, object *); rint = va_arg(args, int *); va_end(args); *rint = can_pay(pl); *type = CFAPI_INT; return NULL; } /** * Teleports an object at a specified destination if possible. * @param type * Will be CFAPI_INT. * @return * NULL. */ void *cfapi_object_teleport(int *type, ...) { mapstruct *map; int x, y; object *who; int *res; va_list args; va_start(args, type); who = va_arg(args, object *); map = va_arg(args, mapstruct *); x = va_arg(args, int); y = va_arg(args, int); res = va_arg(args, int *); *type = CFAPI_INT; if (!out_of_map(map, x, y)) { int k; k = find_first_free_spot(who, map, x, y); if (k == -1) { *res = 1; return NULL; } if (!QUERY_FLAG(who, FLAG_REMOVED)) { remove_ob(who); } insert_ob_in_map_at(who, map, NULL, 0, x, y); if (who->type == PLAYER) map_newmap_cmd(&who->contr->socket); *res = 0; } return NULL; } void *cfapi_object_pickup(int *type, ...) { object *who; object *what; va_list args; va_start(args, type); who = va_arg(args, object *); what = va_arg(args, object *); va_end(args); pick_up(who, what); *type = CFAPI_NONE; return NULL; } /* Archetype-related functions */ void *cfapi_archetype_get_property(int *type, ...) { int prop; archetype *arch; va_list args; sstring *rsstring; archetype **rarch; object **robject; va_start(args, type); arch = va_arg(args, archetype *); prop = va_arg(args, int); switch (prop) { case CFAPI_ARCH_PROP_NAME: *type = CFAPI_SSTRING; rsstring = va_arg(args, sstring *); *rsstring = arch->name; break; case CFAPI_ARCH_PROP_NEXT: *type = CFAPI_PARCH; rarch = va_arg(args, archetype **); *rarch = arch ? arch->next : first_archetype; break; case CFAPI_ARCH_PROP_HEAD: *type = CFAPI_PARCH; rarch = va_arg(args, archetype **); *rarch = arch->head; break; case CFAPI_ARCH_PROP_MORE: *type = CFAPI_PARCH; rarch = va_arg(args, archetype **); *rarch = arch->more; break; case CFAPI_ARCH_PROP_CLONE: *type = CFAPI_POBJECT; robject = va_arg(args, object **); *robject = &arch->clone; break; default: *type = CFAPI_NONE; break; } va_end(args); return NULL; } /** * Party-related functions. * * @param type * data type returned. * @return * NULL. */ void *cfapi_party_get_property(int *type, ...) { partylist *party; int prop; va_list args; object *obarg; sstring *rsstring; player **rplayer; partylist **rparty; va_start(args, type); party = va_arg(args, partylist *); prop = va_arg(args, int); switch (prop) { case CFAPI_PARTY_PROP_NAME: rsstring = va_arg(args, sstring *); *rsstring = party->partyname; *type = CFAPI_SSTRING; break; case CFAPI_PARTY_PROP_NEXT: rparty = va_arg(args, partylist **); *rparty = (party ? party->next : get_firstparty()); *type = CFAPI_PPARTY; break; case CFAPI_PARTY_PROP_PASSWORD: rsstring = va_arg(args, sstring *); *rsstring = party->passwd; *type = CFAPI_SSTRING; break; case CFAPI_PARTY_PROP_PLAYER: *type = CFAPI_PPLAYER; obarg = va_arg(args, object *); rplayer = va_arg(args, player **); *rplayer = (obarg ? obarg->contr : first_player); for (; *rplayer != NULL; (*rplayer) = (*rplayer)->next) if ((*rplayer)->ob->contr->party == party) { break; } break; default: *type = CFAPI_NONE; break; } va_end(args); return NULL; } /** * Regions-related functions. * * @param type * data type returned. * @return * NULL. */ void *cfapi_region_get_property(int *type, ...) { region *reg; int prop; va_list args; /** Return values. */ sstring *rsstring; region **rregion; va_start(args, type); reg = va_arg(args, region *); prop = va_arg(args, int); switch (prop) { case CFAPI_REGION_PROP_NAME: rsstring = va_arg(args, sstring *); *rsstring = reg->name; *type = CFAPI_SSTRING; break; case CFAPI_REGION_PROP_NEXT: rregion = va_arg(args, region **); *rregion = (reg ? reg->next : first_region); *type = CFAPI_PREGION; break; case CFAPI_REGION_PROP_PARENT: rregion = va_arg(args, region **); *rregion = reg->parent; *type = CFAPI_PREGION; break; case CFAPI_REGION_PROP_LONGNAME: rsstring = va_arg(args, sstring *); *rsstring = reg->longname; *type = CFAPI_SSTRING; break; case CFAPI_REGION_PROP_MESSAGE: rsstring = va_arg(args, sstring *); *rsstring = reg->msg; *type = CFAPI_SSTRING; break; default: *type = CFAPI_NONE; break; } va_end(args); return NULL; } /** * Friend list access, to get objects on it. * * Expects one parameter, ob. * * @param type * unused * @return * - if ob is NULL, gets the first object on the friendlylist. * - if not NULL, get next object on the friendlylist after ob. NULL if none or ob not on list. */ void *cfapi_friendlylist_get_next(int *type, ...) { object *ob; va_list args; objectlink *link; object **robject; va_start(args, type); ob = va_arg(args, object *); robject = va_arg(args, object **); va_end(args); *type = CFAPI_POBJECT; *robject = NULL; if (ob) { for (link = first_friendly_object; link; link = link->next) { if (ob == link->ob) { if (link->next) { *robject = link->next->ob; return NULL; } else { return NULL; } } } return NULL; } if (first_friendly_object) *robject = first_friendly_object->ob; return NULL; } /* * Random-map related stuff. */ /** * Wrapper for set_random_map_variable(). * * @param type * unused. * @return * NULL. */ void *cfapi_set_random_map_variable(int *type, ...) { va_list args; RMParms *rp; const char *buf; int *ret; va_start(args, type); rp = va_arg(args, RMParms *); buf = va_arg(args, const char *); ret = va_arg(args, int *); va_end(args); *ret = set_random_map_variable(rp, buf); *type = CFAPI_INT; return NULL; } /** * Wrapper for generate_random_map(). * * @param type * unused. * @return * NULL. */ void *cfapi_generate_random_map(int *type, ...) { va_list args; const char *name; RMParms *rp; char **use_layout; mapstruct **ret; va_start(args, type); name = va_arg(args, const char *); rp = va_arg(args, RMParms *); use_layout = va_arg(args, char **); ret = va_arg(args, mapstruct **); va_end(args); *ret = generate_random_map(name, rp, use_layout); return NULL; } void *cfapi_object_user_event(int *type, ...) { object *op; object *activator; object *third; const char *message; int fix; int *ret; va_list args; va_start(args, type); op = va_arg(args, object *); activator = va_arg(args, object *); third = va_arg(args, object *); message = va_arg(args, const char *); fix = va_arg(args, int); ret = va_arg(args, int *); va_end(args); *ret = user_event(op, activator, third, message, fix); *type = CFAPI_INT; return NULL; } /*****************************************************************************/ /* NEW PLUGIN STUFF ENDS HERE */ /*****************************************************************************/ /*****************************************************************************/ /* Tries to find if a given command is handled by a plugin. */ /* Note that find_plugin_command is called *before *the internal commands are*/ /* checked, meaning that you can "overwrite" them. */ /*****************************************************************************/ /** * @todo * remove static buffer. */ command_array_struct *find_plugin_command(char *cmd, object *op) { int i; crossfire_plugin *cp; static command_array_struct rtn_cmd; if (plugins_list == NULL) return NULL; for (cp = plugins_list; cp != NULL; cp = cp->next) { if (cp->propfunc(&i, "command?", cmd, &rtn_cmd) != NULL) return &rtn_cmd; } return NULL; } /*****************************************************************************/ /* Plugins initialization. Browses the plugins directory and call */ /* initOnePlugin for each file found. */ /* Returns 0 if at least one plugin was successfully loaded, -1 if not */ /*****************************************************************************/ int initPlugins(void) { struct dirent *currentfile; DIR *plugdir; size_t l; char buf[MAX_BUF]; int result; LOG(llevInfo, "Initializing plugins\n"); snprintf(buf, sizeof(buf), "%s/plugins/", LIBDIR); LOG(llevInfo, "Plugins directory is %s\n", buf); plugdir = opendir(buf); if (plugdir == NULL) return -1; result = -1; while ((currentfile = readdir(plugdir)) != NULL) { l = strlen(currentfile->d_name); if (l > strlen(PLUGIN_SUFFIX)) { if (strcmp(currentfile->d_name+l-strlen(PLUGIN_SUFFIX), PLUGIN_SUFFIX) == 0) { snprintf(buf, sizeof(buf), "%s/plugins/%s", LIBDIR, currentfile->d_name); LOG(llevInfo, " -> Loading plugin : %s\n", currentfile->d_name); if (plugins_init_plugin(buf) == 0) result = 0; } } } closedir(plugdir); return result; } /** * Call closePlugin() on the various plugins, used at server shutdown. */ void cleanupPlugins(void) { crossfire_plugin *cp; if (!plugins_list) return; for (cp = plugins_list; cp != NULL; ) { crossfire_plugin *next = cp->next; if (cp->closefunc) cp->closefunc(); /* Don't actually unload plugins, it makes backtraces for memory * debugging (printed at exit) messed up. And it doesn't matter if we * don't free it here. The OS will do it for us. */ /* plugins_dlclose(cp->libptr); */ free(cp); plugin_number--; cp = next; } plugins_list = NULL; }