server-1.12/server/plugins.c

4644 lines
114 KiB
C

/*
* 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 <plugin.h>
#ifndef __CEXTRACT__
#include <sproto.h>
#include <timers.h>
#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;
}