server-1.12/plugins/cfanim/cfanim.c

1171 lines
39 KiB
C

/*****************************************************************************/
/* Crossfire Animator v2.0a */
/* Contacts: yann.chachkoff@myrealbox.com, tchize@myrealbox.com */
/*****************************************************************************/
/* That code is placed under the GNU General Public Licence (GPL) */
/* */
/* (C) 2001 David Delbecq for the original code version. */
/*****************************************************************************/
/* CrossFire, A Multiplayer game for X-windows */
/* */
/* Copyright (C) 2000 Mark Wedel */
/* 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. */
/* */
/*****************************************************************************/
/* First let's include the header file needed */
#include <assert.h>
#include <cfanim.h>
#include <stdarg.h>
static CFanimation *first_animation = NULL; /**< Animations we're currently processing. */
static int get_boolean(const char *strg, int *bl);
/**
* Returns the direction from its name.
* @param name direction's name
* @return direction or -1 if unknown.
*/
static int get_dir_from_name(const char *name) {
if (!strcmp(name, "north"))
return 1;
if (!strcmp(name, "north_east"))
return 2;
if (!strcmp(name, "east"))
return 3;
if (!strcmp(name, "south_east"))
return 4;
if (!strcmp(name, "south"))
return 5;
if (!strcmp(name, "south_west"))
return 6;
if (!strcmp(name, "west"))
return 7;
if (!strcmp(name, "north_west"))
return 8;
return -1;
}
static long int initmovement(const char *name, char *parameters, struct CFmovement_struct *move_entity) {
int dir;
dir = get_dir_from_name(name);
move_entity->parameters = NULL;
return dir;
}
static anim_move_result runmovement(struct CFanimation_struct *animation, long int id, void *parameters) {
object *op = animation->victim;
int dir = id;
if (animation->verbose)
cf_log(llevDebug, "CFAnim: Moving in direction %ld\n", id);
if (op->type == PLAYER)
cf_player_move(op->contr, dir);
else
cf_object_move(op, dir, op);
return mr_finished;
}
static long int initfire(const char *name, char *parameters, struct CFmovement_struct *move_entity) {
int dir;
dir = get_dir_from_name(&(name[5]));
move_entity->parameters = NULL;
return dir;
}
/** @todo fix */
static anim_move_result runfire(struct CFanimation_struct *animation, long int id, void *parameters) {
if (animation->verbose)
cf_log(llevDebug, "CFAnim: Firing in direction %ld\n", id);
return mr_finished;
}
static long int initturn(const char *name, char *parameters, struct CFmovement_struct *move_entity) {
int dir;
dir = get_dir_from_name(&(name[5]));
move_entity->parameters = NULL;
return dir;
}
static anim_move_result runturn(struct CFanimation_struct *animation, long int id, void *parameters) {
object *op = animation->victim;
int dir = id;
int face;
if (animation->verbose)
cf_log(llevDebug, "CFAnim: Turning in direction %ld\n", id);
op->facing = dir;
cf_object_set_int_property(op, CFAPI_OBJECT_PROP_ANIMATION, face);
return mr_finished;
}
static long int initcamera(const char *name, char *parameters, struct CFmovement_struct *move_entity) {
int dir;
dir = get_dir_from_name(&(name[7]));
move_entity->parameters = NULL;
return dir;
}
/** @todo fix */
static anim_move_result runcamera(struct CFanimation_struct *animation, long int id, void *parameters) {
if (animation->verbose)
cf_log(llevDebug, "CFAnim: Moving the camera in direction %ld\n", id);
return mr_finished;
/*if (animation->victim->type == PLAYER)
hook_scroll_map(animation->victim, id);
else
printf("CFAnim: Not a player\n");
return 1;*/
}
static long int initvisible(const char *name, char *parameters, struct CFmovement_struct *move_entity) {
int result;
if (get_boolean(parameters, &result))
return result;
cf_log(llevDebug, "CFAnim: Error in animation - possible values for 'invisible' are 'yes' and 'no'\n");
return -1;
}
static anim_move_result runvisible(struct CFanimation_struct *animation, long int id, void *parameters) {
if (id == -1)
return mr_finished;
animation->invisible = id;
return mr_finished;
}
static long int initwizard(const char *name, char *parameters, struct CFmovement_struct *move_entity) {
int result;
if (get_boolean(parameters, &result))
return result;
cf_log(llevDebug, "CFAnim: Error in animation - possible values for 'wizard' are 'yes' and 'no'\n");
return -1;
}
static anim_move_result runwizard(struct CFanimation_struct *animation, long int id, void *parameters) {
if (id == -1)
return 1;
animation->wizard = id;
return mr_finished;
}
static long int initsay(const char *name, char *parameters, struct CFmovement_struct *move_entity) {
if (parameters)
move_entity->parameters = cf_strdup_local(parameters);
else
move_entity->parameters = NULL;
if (move_entity->parent->verbose)
cf_log(llevDebug, "CFAnim: init say: parameters: %s\n", parameters ? parameters : "null");
return 1;
}
static anim_move_result runsay(struct CFanimation_struct *animation, long int id, void *parameters) {
if (parameters) {
cf_object_say(animation->victim, parameters);
free(parameters);
} else
cf_log(llevDebug, "CFAnim: Error in animation: nothing to say with say function\n");
return mr_finished;
}
static long int initapply(const char *name, char *parameters, struct CFmovement_struct *move_entity) {
return 1;
}
static anim_move_result runapply(struct CFanimation_struct *animation, long int id, void *parameters) {
object *current_container;
if (animation->victim->type != PLAYER)
return mr_finished;
current_container = animation->victim->container;
animation->victim->container = NULL;
cf_object_apply_below(animation->victim);
animation->victim->container = current_container;
return mr_finished;
}
static long int initapplyobject(const char *name, char *parameters, struct CFmovement_struct *move_entity) {
move_entity->parameters = parameters ? cf_add_string(parameters) : NULL;
return 1;
}
static anim_move_result runapplyobject(struct CFanimation_struct *animation, long int id, void *parameters) {
object *current;
int aflag;
if (!parameters)
return mr_finished;
for (current = animation->victim->below; current; current = current->below)
if (current->name == parameters)
break;
if (!current)
for (current = animation->victim->inv; current; current = current->below)
if (current->name == parameters)
break;
if (!current) {
cf_free_string(parameters);
return mr_finished;
}
aflag = AP_APPLY;
cf_object_apply(animation->victim, current, aflag);
cf_free_string(parameters);
return mr_finished;
}
static long int initdropobject(const char *name, char *parameters, struct CFmovement_struct *move_entity) {
move_entity->parameters = parameters ? cf_strdup_local(parameters) : NULL;
return 1;
}
static anim_move_result rundropobject(struct CFanimation_struct *animation, long int id, void *parameters) {
if (!parameters)
return mr_finished;
cf_object_drop(animation->victim, parameters);
cf_free_string(parameters);
return mr_finished;
}
static long int initpickup(const char *name, char *parameters, struct CFmovement_struct *move_entity) {
return 1;
}
static anim_move_result runpickup(struct CFanimation_struct *animation, long int id, void *parameters) {
object *current;
current = animation->victim->below;
if (!current)
return mr_finished;
cf_object_pickup(animation->victim, current);
return mr_finished;
}
static long int initpickupobject(const char *name, char *parameters, struct CFmovement_struct *move_entity) {
move_entity->parameters = parameters ? cf_add_string(parameters) : NULL;
return 1;
}
static anim_move_result runpickupobject(struct CFanimation_struct *animation, long int id, void *parameters) {
object *current;
if (!parameters)
return mr_finished;
for (current = animation->victim->below; current; current = current->below)
if (current->name == parameters)
break;
if (current)
cf_object_pickup(animation->victim, current);
cf_free_string(parameters);
return mr_finished;
}
static long int initghosted(const char *name, char *parameters, struct CFmovement_struct *move_entity) {
int result;
if (get_boolean(parameters, &result))
return result;
cf_log(llevDebug, "CFAnim: Error in animation: possible values for 'ghosted' are 'yes' and 'no'\n");
return -1;
}
static anim_move_result runghosted(struct CFanimation_struct *animation, long int id, void *parameters) {
object *corpse;
if ((id && animation->ghosted)
|| (!id && !animation->ghosted))
runghosted(animation, !id, parameters);
if (id) { /*Create a ghost/corpse pair*/
corpse = cf_object_clone(animation->victim, 1);
corpse->x = animation->victim->x;
corpse->y = animation->victim->y;
corpse->type = 0;
CLEAR_FLAG(corpse, FLAG_WIZ);
corpse->contr = NULL;
cf_map_insert_object_there(corpse, animation->victim->map, NULL, 0);
animation->wizard = 1;
animation->invisible = 1;
animation->corpse = corpse;
} else { /*Remove a corpse, make current player visible*/
animation->wizard = 0;
animation->invisible = 0;
cf_object_remove(animation->corpse);
cf_object_free(animation->corpse);
animation->corpse = NULL;
animation->victim->invisible = 0;
cf_player_move(animation->victim->contr, 0);
}
animation->ghosted = id;
return mr_finished;
}
typedef struct {
char *mapname;
int mapx;
int mapy;
} teleport_params;
static long int initteleport(const char *name, char *parameters, struct CFmovement_struct *move_entity) {
char *mapname;
int mapx;
int mapy;
teleport_params *teleport;
move_entity->parameters = NULL;
cf_log(llevDebug, ".(%s)\n", parameters);
if (!parameters) {
cf_log(llevDebug, "CFAnim: Error - no parameters for teleport\n");
return 0;
}
mapname = strstr(parameters, " ");
cf_log(llevDebug, ".(%s)\n", parameters);
if (!mapname)
return 0;
*mapname = '\0';
mapx = atoi(parameters);
mapname++;
parameters = mapname;
if (!parameters) {
cf_log(llevDebug, "CFAnim: Error - not enough parameters for teleport\n");
return 0;
}
cf_log(llevDebug, ".(%s)\n", parameters);
mapname = strstr(parameters, " ");
cf_log(llevDebug, ".\n");
if (!mapname)
return 0;
*mapname = '\0';
mapy = atoi(parameters);
mapname++;
if (mapname[0] == '\0')
return 0;
teleport = (teleport_params *)malloc(sizeof(teleport_params));
teleport->mapname = cf_strdup_local(mapname);
teleport->mapx = mapx;
teleport->mapy = mapy;
move_entity->parameters = teleport;
return 1;
}
static anim_move_result runteleport(struct CFanimation_struct *animation, long int id, void *parameters) {
teleport_params *teleport = (teleport_params *)parameters;
if (!parameters)
return mr_finished;
cf_object_teleport(animation->victim, cf_map_get_map(teleport->mapname, 0), teleport->mapx, teleport->mapy);
free(parameters);
return mr_finished;
}
static long int initnotice(const char *name, char *parameters, struct CFmovement_struct *move_entity) {
move_entity->parameters = parameters ? cf_strdup_local(parameters) : NULL;
return 1;
}
static anim_move_result runnotice(struct CFanimation_struct *animation, long int id, void *parameters) {
int val;
val = NDI_NAVY|NDI_UNIQUE;
cf_player_message(animation->victim, parameters, val);
return mr_finished;
}
static long int initstop(const char *name, char *parameters, struct CFmovement_struct *move_entity) {
return 1;
}
/** @todo fix */
static anim_move_result runstop(struct CFanimation_struct *animation, long int id, void *parameters) {
if (animation->verbose)
cf_log(llevDebug, "CFAnim: stop encountered\n");
return mr_finished;
}
/** Destination for moveto command. */
typedef struct {
int x, y; /**< Coordinates. */
} param_moveto;
static long int initmoveto(const char *name, char *parameters, struct CFmovement_struct *move_entity) {
param_moveto *moveto;
int x, y;
if (sscanf(parameters, "%d %d", &x, &y) != 2)
return 0;
moveto = (param_moveto *)calloc(1, sizeof(param_moveto));
moveto->x = x;
moveto->y = y;
move_entity->parameters = moveto;
return 1;
}
static anim_move_result runmoveto(struct CFanimation_struct *animation, long int id, void *parameters) {
int move;
param_moveto *dest = (param_moveto *)parameters;
if (!dest)
return mr_finished;
move = cf_object_move_to(animation->victim, dest->x, dest->y);
if (animation->victim->x == dest->x && animation->victim->y == dest->y) {
free(parameters);
return mr_finished;
}
if (move == 1)
return mr_again;
return mr_finished;
}
static long int initmessage(const char *name, char *parameters, struct CFmovement_struct *move_entity) {
if (parameters)
move_entity->parameters = strdup(parameters);
else
move_entity->parameters = NULL;
return 1;
}
static anim_move_result runmessage(struct CFanimation_struct *animation, long int id, void *parameters) {
if (parameters && animation->victim->map) {
cf_map_message(animation->victim->map, (const char *)parameters, NDI_UNIQUE|NDI_GREEN);
free(parameters);
}
return mr_finished;
}
/** Available animation commands. */
CFanimationHook animationbox[] = {
{ "north", initmovement, runmovement },
{ "north_east", initmovement, runmovement },
{ "east", initmovement, runmovement },
{ "south_east", initmovement, runmovement },
{ "south", initmovement, runmovement },
{ "south_west", initmovement, runmovement },
{ "west", initmovement, runmovement },
{ "north_west", initmovement, runmovement },
{ "fire_north", initfire, runfire },
{ "fire_north_east", initfire, runfire },
{ "fire_east", initfire, runfire },
{ "fire_south_east", initfire, runfire },
{ "fire_south", initfire, runfire },
{ "fire_south_west", initfire, runfire },
{ "fire_west", initfire, runfire },
{ "fire_north_west", initfire, runfire },
{ "turn_north", initturn, runturn },
{ "turn_north_east", initturn, runturn },
{ "turn_east", initturn, runturn },
{ "turn_south_east", initturn, runturn },
{ "turn_south", initturn, runturn },
{ "turn_south_west", initturn, runturn },
{ "turn_west", initturn, runturn },
{ "turn_north_west", initturn, runturn },
{ "camera_north", initcamera, runcamera },
{ "camera_north_east", initcamera, runcamera },
{ "camera_east", initcamera, runcamera },
{ "camera_south_east", initcamera, runcamera },
{ "camera_south", initcamera, runcamera },
{ "camera_south_west", initcamera, runcamera },
{ "camera_west", initcamera, runcamera },
{ "camera_north_west", initcamera, runcamera },
{ "invisible", initvisible, runvisible },
{ "wizard", initwizard, runwizard },
{ "say", initsay, runsay },
{ "apply", initapply, runapply },
{ "apply_object", initapplyobject, runapplyobject },
{ "drop_object", initdropobject, rundropobject },
{ "pickup", initpickup, runpickup },
{ "pickup_object", initpickupobject, runpickupobject },
{ "ghosted", initghosted, runghosted },
{ "teleport", initteleport, runteleport },
{ "notice", initnotice, runnotice },
{ "stop", initstop, runstop },
{ "moveto", initmoveto, runmoveto },
{ "message", initmessage, runmessage }
};
int animationcount = sizeof(animationbox)/sizeof(CFanimationHook);
static int ordered_commands = 0;
static int compareAnims(const void *a, const void *b) {
return strcmp(((const CFanimationHook *)a)->name, ((const CFanimationHook *)b)->name);
}
static void prepare_commands(void) {
qsort(animationbox, animationcount, sizeof(CFanimationHook), compareAnims);
ordered_commands = 1;
}
static CFanimationHook *get_command(char *command) {
CFanimationHook dummy;
dummy.name = command;
if (!ordered_commands)
prepare_commands();
return (CFanimationHook *)bsearch(&dummy, animationbox, animationcount, sizeof(CFanimationHook), compareAnims);
}
/**
* Parse an animation block in the animation file.
* @param buffer buffer to read data info, will have been modified when function exits.
* @param buffer_size size of buffer.
* @param fichier file to read from.
* @param parent animation we're reading the block for.
* @return one animation frame.
*/
static CFmovement *parse_animation_block(char *buffer, size_t buffer_size, FILE *fichier, CFanimation *parent) {
CFmovement *first = NULL;
CFmovement *current = NULL;
CFmovement *next;
char *time;
char *name;
char *parameters;
int tick;
CFanimationHook *animationhook;
if (parent->verbose)
cf_log(llevDebug, "CFAnim: In parse block for %s\n", buffer);
while (fgets(buffer, buffer_size, fichier)) {
if (buffer[0] == '[')
break;
if (buffer[0] == '#')
continue;
buffer[strlen(buffer)-strlen("\n")] = '\0';
while (buffer[strlen(buffer)-1] == ' ')
buffer[strlen(buffer)-1] = '\0';
if (strlen(buffer) <= 0)
continue;
time = buffer;
name = strstr(buffer, " ");
if (!name)
continue;
*name = '\0';
name++;
while (*name == ' ')
name++;
tick = atoi(time);
if (tick < 0)
continue;
parameters = strstr(name, " ");
if (parameters) { /*Parameters may be nul*/
*parameters = '\0';
parameters++;
while (*parameters == ' ')
parameters++;
if (*parameters == '\0')
parameters = NULL;
}
animationhook = get_command(name);
if (parent->verbose) {
if (!animationhook)
cf_log(llevDebug, "CFAnim: %s - Unknown animation command\n", name);
else
cf_log(llevDebug, "CFAnim: Parsed %s -> %p\n", name, animationhook);
}
if (!animationhook) {
if (parent->errors_allowed)
continue;
else
break;
}
next = (CFmovement *)malloc(sizeof(CFmovement));
if (!next)
continue;
next->parent = parent;
next->tick = tick;
next->next = NULL;
if (animationhook->funcinit)
next->id = animationhook->funcinit(name, parameters, next);
next->func = animationhook->funcrun;
if (current)
current->next = next;
else
first = next;
current = next;
}
return first;
}
/**
* This function take buffer with a value like "blabla= things" and extracts some things.
*
* @param buffer where equality is written
* @param[out] variable will be positionned to where in buffer the
* variable name starts. leading spaces will be converted to \0
* @param[out] value same as above but for the value part
* @note variable and value become pointers to internals of
* buffer. If buffer chages, they will change too and/or become invalid!
*/
static int equality_split(char *buffer, char **variable, char **value) {
if (!strcmp(&buffer[strlen(buffer)-strlen("\n")], "\n"))
buffer[strlen(buffer)-strlen("\n")] = '\0';
*value = strstr(buffer, "=");
if (!*value)
return 0;
**value = '\0';
*variable = buffer;
(*value)++;
while ((strlen(*variable) > 0) && ((*variable)[strlen(*variable)-1] == ' '))
(*variable)[strlen(*variable)-1] = '\0';
while ((strlen(*value) > 0) && ((*value)[strlen(*value)-1] == ' '))
(*value)[strlen(*value)-1] = '\0';
while (**value == ' ')
(*value)++;
if ((**variable == '\0') || (**value == '\0'))
return 0;
return 1;
}
/**
* This function gets a string containing
* [Y/y](es)/[N/n](o), 1/0
* and set bl according to what's read
* if return value is true, strg was set successfully
* else, an error occured and bl was not touched
*
* @param strg string to process.
* @param bl value strg meant.
* @return 1 if strg was processed, 0 else.
*/
static int get_boolean(const char *strg, int *bl) {
if (!strncmp(strg, "y", 1))
*bl = 1;
else if (!strncmp(strg, "n", 1))
*bl = 0;
else if (!strncmp(strg, "Y", 1))
*bl = 1;
else if (!strncmp(strg, "N", 1))
*bl = 0;
else if (!strncmp(strg, "1", 1))
*bl = 1;
else if (!strncmp(strg, "0", 1))
*bl = 0;
else
return 0;
return 1;
}
/**
* Is specified player currently victim of a paralysing animation?
* @param pl player to search for.
* @return 1 if pl is part of animation, 0 else.
*/
static int is_animated_player(object *pl) {
CFanimation *current;
for (current = first_animation; current; current++)
if ((current->victim == pl) && (current->paralyze)) {
if (current->verbose)
cf_log(llevDebug, "CFAnim: Getting a command for a paralyzed player %s.\n", pl->name);
return 1;
}
return 0;
}
/**
* Create a new animation.
* @return new animation pointer inserted in the list of animations.
*/
static CFanimation *create_animation(void) {
CFanimation *new;
CFanimation *current;
new = (CFanimation *)malloc(sizeof(CFanimation));
if (!new)
return NULL;
new->name = NULL;
new->victim = NULL;
new->nextmovement = NULL;
new->nextanimation = NULL;
for (current = first_animation; (current && current->nextanimation); current = current->nextanimation)
;
if (!current)
first_animation = new;
else
current->nextanimation = new;
return new;
}
static object *find_by_name(object *origin, const char *name) {
int x, y, w, h;
mapstruct *map;
const char *sname;
object *ob;
sname = cf_find_string(name);
if (!sname)
return NULL;
while (origin && !origin->map)
origin = origin->env;
if (!origin || !origin->map)
return NULL;
map = origin->map;
w = cf_map_get_width(map);
h = cf_map_get_height(map);
for (x = 0; x < w; x++) {
for (y = 0; y < h; y++) {
for (ob = GET_MAP_OB(map, x, y); ob; ob = ob->above) {
if (/*cf_object_get_sstring_property(ob, CFAPI_OBJECT_PROP_NAME)*/ob->name == sname)
return ob;
}
}
}
return NULL;
}
/**
* Create a new animation object according to file, option and activator (who)
*
* @param who object that raised the event leading to the plugin.
* @param activator object that caused who to get an event.
* @param event actual event object linking who and this plugin. Can be removed.
* @param file file name to read from, should be accessible from the current path.
* @param message if non empty, will be the name of the used animation instead of the one specified in the file.
* @return 1 if the animation was created, 0 else.
* @todo fix memory leaks in case of errors.
*/
static int start_animation(object *who, object *activator, object *event, const char *file, const char *message) {
FILE *fichier;
char *name = NULL;
int victimtype = 0;
object *victim = NULL;
int unique = 0;
int always_delete = 0;
int parallel = 0;
int paralyzed = 1;
int invisible = 0;
int wizard = 0;
enum time_enum timetype;
int errors_allowed = 0;
int verbose = 0;
const char *animationitem;
char buffer[HUGE_BUF];
char *variable;
char *value;
int errors_found = 0;
CFanimation *current_anim;
fichier = fopen(file, "r");
if (fichier == NULL) {
cf_log(llevDebug, "CFAnim: Unable to open %s\n", file);
return 0;
}
while (fgets(buffer, HUGE_BUF, fichier)) {
if (buffer[0] == '[')
break;
if (buffer[0] == '#')
continue;
if (!strcmp(buffer, "\n"))
continue;
errors_found = 1;
cf_log(llevDebug, "CFAnim: '%s' has an invalid syntax.\n", buffer);
}
if (feof(fichier))
return 0;
if (strncmp(buffer, "[Config]", 8)) {
cf_log(llevDebug, "CFAnim: Fatal error in %s: [Config] must be the first group defined.\n", file);
return 0;
}
while (fgets(buffer, HUGE_BUF, fichier)) {
if (buffer[0] == '[')
break;
if (buffer[0] == '#')
continue;
if (!strcmp(buffer, "\n"))
continue;
if (!equality_split(buffer, &variable, &value))
errors_found = 1;
else {
if (!strcmp(variable, "name")) {
if (*value == '"')
value++;
if (value[strlen(value)-1] == '"')
value[strlen(value)-1] = '\0';
name = cf_strdup_local(value);
} else if (!strcmp(variable, "victimtype")) {
if (!strcmp(value, "player"))
victimtype = 0;
else if (!strcmp(value, "object"))
victimtype = 1;
else if (!strcmp(value, "any"))
victimtype = 2;
else if (!strcmp(value, "byname"))
victimtype = 3;
else
errors_found = 1;
} else if (!strcmp(variable, "victim")) {
cf_log(llevDebug, "CFAnim: Setting victim to %s\n", value);
if (!strcmp(value, "who"))
victim = who;
else if (!strcmp(value, "activator"))
victim = activator;
else if (!strcmp(value, "who_owner"))
if (!who) {
errors_found = 1;
cf_log(llevDebug, "CFAnim: Warning: object \"who\" doesn't exist and you're victimized it's owner\n");
} else
victim = who->env;
else if (!strcmp(value, "activator_owner"))
if (!activator) {
errors_found = 1;
cf_log(llevDebug, "CFAnim: Warning: object \"activator\" doesn't exist and you're victimized it's owner\n");
}
else
victim = activator->env;
else if (victimtype == 3) {
victim = find_by_name(who, value);
} else
errors_found = 1;
} else if (!strcmp(variable, "unique")) {
if (!get_boolean(value, &unique))
errors_found = 1;
} else if (!strcmp(variable, "always_delete")) {
if (!get_boolean(value, &always_delete))
errors_found = 1;
} else if (!strcmp(variable, "parallel")) {
if (!get_boolean(value, &parallel))
errors_found = 1;
} else if (!strcmp(variable, "paralyzed")) {
if (!get_boolean(value, &paralyzed))
errors_found = 1;
} else if (!strcmp(variable, "invisible")) {
if (!get_boolean(value, &invisible))
errors_found = 1;
} else if (!strcmp(variable, "wizard")) {
if (!get_boolean(value, &wizard))
errors_found = 1;
} else if (!strcmp(variable, "errors_allowed")) {
if (!get_boolean(value, &errors_allowed))
errors_found = 1;
} else if (!strcmp(variable, "verbose")) {
if (!get_boolean(value, &verbose))
errors_found = 1;
} else if (!strcmp(variable, "time_representation")) {
if (!strcmp(value, "second"))
timetype = time_second;
else if (!strcmp(value, "tick"))
timetype = time_tick;
else
errors_found = 1;
} else if (!strcmp(variable, "animation")) {
animationitem = cf_add_string(value);
} else
errors_found = 1;
}
}
if (message && message[0] != '\0') {
cf_free_string(animationitem);
animationitem = cf_add_string(message);
}
if (buffer[0] == '\0') {
if (animationitem)
cf_free_string(animationitem);
cf_log(llevDebug, "CFAnim: Errors occurred during the parsing of %s\n", file);
return 0;
}
if (!victim) {
if (animationitem)
cf_free_string(animationitem);
cf_log(llevDebug, "CFAnim: Fatal error - victim is NULL");
return 0;
}
if (!(current_anim = create_animation())) {
if (animationitem)
cf_free_string(animationitem);
cf_log(llevDebug, "CFAnim: Fatal error - Not enough memory.\n");
return 0;
}
if (always_delete) {
/*if (verbose) printf("CFAnim: Freeing event nr. %d for %s.\n", current_event, who->name);*/
cf_object_remove(event);
}
if (((victim->type == PLAYER) && (victimtype == 1))
|| ((victim->type != PLAYER) && (victimtype == 0))
|| (errors_found && !errors_allowed)) {
if (verbose)
cf_log(llevDebug, "CFAnim: No correct victim found or errors found, aborting.\n");
if (animationitem)
cf_free_string(animationitem);
return 0;
}
if (unique && !always_delete) {
/*if (verbose) printf("CFAnim: Freeing event nr. %d for %s.\n", current_event, who->name);*/
cf_object_remove(event);
}
current_anim->name = name;
current_anim->victim = victim;
current_anim->paralyze = paralyzed;
current_anim->invisible = invisible;
current_anim->wizard = wizard;
current_anim->unique = unique;
current_anim->ghosted = 0;
current_anim->corpse = NULL;
current_anim->time_representation = timetype;
current_anim->verbose = verbose;
current_anim->tick_left = 0;
current_anim->errors_allowed = errors_allowed;
while (buffer[0] == '[') {
while (strncmp(&buffer[1], animationitem, strlen(animationitem))) {
while ((value = fgets(buffer, HUGE_BUF, fichier)) != NULL)
if (buffer[0] == '[')
break;
if (value == NULL) {
cf_log(llevDebug, "CFAnim: no matching animation %s in file.\n", animationitem);
cf_free_string(animationitem);
return 0;
}
}
current_anim->nextmovement = parse_animation_block(buffer, HUGE_BUF, fichier, current_anim);
if (current_anim->nextmovement)
break;
}
fclose(fichier);
return 1;
}
/**
* Checks if an animation can execute one or more moves, and if so does them.
* @param animation animation to check
* @param milliseconds time elapsed since the last time this function was called.
*/
static void animate_one(CFanimation *animation, long int milliseconds) {
CFmovement *current;
int mult = 1;
anim_move_result result;
if (animation->time_representation == time_second) {
animation->tick_left += milliseconds;
mult = 1000;
}
else
animation->tick_left++;
if (animation->verbose)
cf_log(llevDebug, "CFAnim: Ticking %s for %s. Tickleft is %ld\n", animation->name, animation->victim->name, animation->tick_left);
if (animation->invisible)
animation->victim->invisible = 10;
if (animation->wizard && animation->victim->type == PLAYER) {
/* setting FLAG_WIZ *on non player leads to issues, as many functions expect contr to not be NULL in this case. */
if (animation->verbose)
cf_log(llevDebug, "CFAnim: Setting wizard flags\n");
cf_object_set_flag(animation->victim, FLAG_WIZPASS, 1);
cf_object_set_flag(animation->victim, FLAG_WIZCAST, 1);
cf_object_set_flag(animation->victim, FLAG_WIZ, 1);
if (animation->verbose)
cf_log(llevDebug, "CFAnim: Setting wizard flags done\n");
}
if (animation->paralyze)
animation->victim->speed_left = -99999;
cf_object_update(animation->victim, UP_OBJ_CHANGE);
if (animation->nextmovement)
while (animation->tick_left > animation->nextmovement->tick*mult) {
animation->tick_left -= animation->nextmovement->tick*mult;
result = animation->nextmovement->func(animation, animation->nextmovement->id, animation->nextmovement->parameters);
if (result == mr_again)
continue;
current = animation->nextmovement;
animation->nextmovement = animation->nextmovement->next;
free(current);
if (!animation->nextmovement)
break;
}
cf_object_set_flag(animation->victim, FLAG_WIZPASS, 0);
cf_object_set_flag(animation->victim, FLAG_WIZCAST, 0);
cf_object_set_flag(animation->victim, FLAG_WIZ, 0);
}
/**
* Animates all currently running animations.
*/
static void animate(void) {
CFanimation *current;
CFanimation *next;
CFanimation *previous_anim = NULL;
struct timeval now;
static struct timeval yesterday;
static int already_passed = 0;
long int delta_milli;
(void)GETTIMEOFDAY(&now);
if (!already_passed) {
already_passed = 1;
memcpy(&yesterday, &now, sizeof(struct timeval));
return;
}
delta_milli = (now.tv_sec-yesterday.tv_sec)*1000+(now.tv_usec/1000-yesterday.tv_usec/1000);
/*printf("Working for %ld milli seconds\n", delta_milli);*/
memcpy(&yesterday, &now, sizeof(struct timeval));
for (current = first_animation; current; current = current->nextanimation)
animate_one(current, delta_milli);
current = first_animation;
while (current) {
if (!current->nextmovement) {
if (current->paralyze)
current->victim->speed_left = current->victim->speed;
next = current->nextanimation;
if (first_animation == current)
first_animation = next;
else {
previous_anim->nextanimation = next;
}
if (current->name)
free(current->name);
free(current);
current = next;
} else {
previous_anim = current;
current = current->nextanimation;
}
}
}
/**
* Plugin initialisation function.
* @param iversion server version.
* @param gethooksptr function to get the hooks.
* @return 0
*/
CF_PLUGIN int initPlugin(const char *iversion, f_plug_api gethooksptr) {
cf_init_plugin(gethooksptr);
cf_log(llevDebug, "CFAnim 2.0a init\n");
/* Place your initialization code here */
return 0;
}
CF_PLUGIN void *getPluginProperty(int *type, ...) {
va_list args;
const char *propname;
char *buf;
int size;
va_start(args, type);
propname = va_arg(args, const char *);
if (!strcmp(propname, "Identification")) {
buf = va_arg(args, char *);
size = va_arg(args, int);
va_end(args);
snprintf(buf, size, PLUGIN_NAME);
return NULL;
} else if (!strcmp(propname, "FullName")) {
buf = va_arg(args, char *);
size = va_arg(args, int);
va_end(args);
snprintf(buf, size, PLUGIN_VERSION);
return NULL;
}
va_end(args);
return NULL;
}
CF_PLUGIN anim_move_result cfanim_runPluginCommand(object *op, char *params) {
return -1;
}
CF_PLUGIN int postInitPlugin(void) {
cf_log(llevDebug, "CFAnim 2.0a post init\n");
/* Pick the global events you want to monitor from this plugin */
cf_system_register_global_event(EVENT_CLOCK, PLUGIN_NAME, cfanim_globalEventListener);
return 0;
}
CF_PLUGIN void *cfanim_globalEventListener(int *type, ...) {
va_list args;
static int rv = 0;
int event_code;
va_start(args, type);
event_code = va_arg(args, int);
assert(event_code == EVENT_CLOCK);
animate();
va_end(args);
return &rv;
}
CF_PLUGIN void *eventListener(int *type, ...) {
static int rv = 0;
va_list args;
char *buf, message[MAX_BUF], script[MAX_BUF];
object *who, *activator, *third, *event;
va_start(args, type);
who = va_arg(args, object *);
activator = va_arg(args, object *);
third = va_arg(args, object *);
buf = va_arg(args, char *);
if (buf != NULL)
strcpy(message, buf);
else
message[0] = '\0';
va_arg(args, int); /* 'fix', ignored */
event = va_arg(args, object *);
/** @todo build from current map's path, probably */
cf_get_maps_directory(event->slaying, script, sizeof(script));
va_end(args);
/* Put your plugin action(s) here */
if (activator != NULL) {
cf_log(llevDebug, "CFAnim: %s called animator script %s\n", activator->name, script);
} else if (who != NULL) {
activator = who;
cf_log(llevDebug, "CFAnim: %s called animator script %s\n", who->name, script);
}
rv = start_animation(who, activator, event, script, message);
return &rv;
}
CF_PLUGIN int closePlugin(void) {
cf_log(llevDebug, "CFAnim 2.0a closing\n");
return 0;
}