/*****************************************************************************/ /* 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 #include #include 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, ¶llel)) errors_found = 1; } else if (!strcmp(variable, "paralyzed")) { if (!get_boolean(value, ¶lyzed)) 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; }