Crossfire Server, Branch 1.12  R12190
cfanim.c
Go to the documentation of this file.
00001 /*****************************************************************************/
00002 /* Crossfire Animator v2.0a                                                  */
00003 /* Contacts: yann.chachkoff@myrealbox.com, tchize@myrealbox.com              */
00004 /*****************************************************************************/
00005 /* That code is placed under the GNU General Public Licence (GPL)            */
00006 /*                                                                           */
00007 /* (C) 2001 David Delbecq for the original code version.                     */
00008 /*****************************************************************************/
00009 /*  CrossFire, A Multiplayer game for X-windows                              */
00010 /*                                                                           */
00011 /*  Copyright (C) 2000 Mark Wedel                                            */
00012 /*  Copyright (C) 1992 Frank Tore Johansen                                   */
00013 /*                                                                           */
00014 /*  This program is free software; you can redistribute it and/or modify     */
00015 /*  it under the terms of the GNU General Public License as published by     */
00016 /*  the Free Software Foundation; either version 2 of the License, or        */
00017 /*  (at your option) any later version.                                      */
00018 /*                                                                           */
00019 /*  This program is distributed in the hope that it will be useful,          */
00020 /*  but WITHOUT ANY WARRANTY; without even the implied warranty of           */
00021 /*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the            */
00022 /*  GNU General Public License for more details.                             */
00023 /*                                                                           */
00024 /*  You should have received a copy of the GNU General Public License        */
00025 /*  along with this program; if not, write to the Free Software              */
00026 /*  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.                */
00027 /*                                                                           */
00028 /*****************************************************************************/
00029 
00030 /* First let's include the header file needed                                */
00031 
00032 #include <assert.h>
00033 #include <cfanim.h>
00034 #include <stdarg.h>
00035 
00036 static CFanimation *first_animation = NULL;  
00038 static int get_boolean(const char *strg, int *bl);
00039 
00045 static int get_dir_from_name(const char *name) {
00046     if (!strcmp(name, "north"))
00047         return 1;
00048     if (!strcmp(name, "north_east"))
00049         return 2;
00050     if (!strcmp(name, "east"))
00051         return 3;
00052     if (!strcmp(name, "south_east"))
00053         return 4;
00054     if (!strcmp(name, "south"))
00055         return 5;
00056     if (!strcmp(name, "south_west"))
00057         return 6;
00058     if (!strcmp(name, "west"))
00059         return 7;
00060     if (!strcmp(name, "north_west"))
00061         return 8;
00062     return -1;
00063 }
00064 
00065 static long int initmovement(const char *name, char *parameters, struct CFmovement_struct *move_entity) {
00066     int dir;
00067 
00068     dir = get_dir_from_name(name);
00069     move_entity->parameters = NULL;
00070     return dir;
00071 }
00072 
00073 static anim_move_result runmovement(struct CFanimation_struct *animation, long int id, void *parameters) {
00074     object *op = animation->victim;
00075     int dir = id;
00076 
00077     if (animation->verbose)
00078         cf_log(llevDebug, "CFAnim: Moving in direction %ld\n", id);
00079     if (op->type == PLAYER)
00080         cf_player_move(op->contr, dir);
00081     else
00082         cf_object_move(op, dir, op);
00083     return mr_finished;
00084 }
00085 
00086 static long int initfire(const char *name, char *parameters, struct CFmovement_struct *move_entity) {
00087     int dir;
00088 
00089     dir = get_dir_from_name(&(name[5]));
00090     move_entity->parameters = NULL;
00091     return dir;
00092 }
00093 
00095 static anim_move_result runfire(struct CFanimation_struct *animation, long int id, void *parameters) {
00096     if (animation->verbose)
00097         cf_log(llevDebug, "CFAnim: Firing in direction %ld\n", id);
00098     return mr_finished;
00099 }
00100 
00101 static long int initturn(const char *name, char *parameters, struct CFmovement_struct *move_entity) {
00102     int dir;
00103 
00104     dir = get_dir_from_name(&(name[5]));
00105     move_entity->parameters = NULL;
00106     return dir;
00107 }
00108 
00109 static anim_move_result runturn(struct CFanimation_struct *animation, long int id, void *parameters) {
00110     object *op = animation->victim;
00111     int dir = id;
00112     int face;
00113 
00114     if (animation->verbose)
00115         cf_log(llevDebug, "CFAnim: Turning in direction %ld\n", id);
00116     op->facing = dir;
00117     cf_object_set_int_property(op, CFAPI_OBJECT_PROP_ANIMATION, face);
00118     return mr_finished;
00119 }
00120 
00121 static long int initcamera(const char *name, char *parameters, struct CFmovement_struct *move_entity) {
00122     int dir;
00123 
00124     dir = get_dir_from_name(&(name[7]));
00125     move_entity->parameters = NULL;
00126     return dir;
00127 }
00128 
00130 static anim_move_result runcamera(struct CFanimation_struct *animation, long int id, void *parameters) {
00131     if (animation->verbose)
00132         cf_log(llevDebug, "CFAnim: Moving the camera in direction %ld\n", id);
00133     return mr_finished;
00134     /*if (animation->victim->type == PLAYER)
00135         hook_scroll_map(animation->victim, id);
00136     else
00137         printf("CFAnim: Not a player\n");
00138     return 1;*/
00139 }
00140 
00141 static long int initvisible(const char *name, char *parameters, struct CFmovement_struct *move_entity) {
00142     int result;
00143 
00144     if (get_boolean(parameters, &result))
00145         return result;
00146     cf_log(llevDebug, "CFAnim: Error in animation - possible values for 'invisible' are 'yes' and 'no'\n");
00147     return -1;
00148 }
00149 
00150 static anim_move_result runvisible(struct CFanimation_struct *animation, long int id, void *parameters) {
00151     if (id == -1)
00152         return mr_finished;
00153     animation->invisible = id;
00154     return mr_finished;
00155 }
00156 
00157 static long int initwizard(const char *name, char *parameters, struct CFmovement_struct *move_entity) {
00158     int result;
00159 
00160     if (get_boolean(parameters, &result))
00161         return result;
00162     cf_log(llevDebug, "CFAnim: Error in animation - possible values for 'wizard' are 'yes' and 'no'\n");
00163     return -1;
00164 }
00165 
00166 static anim_move_result runwizard(struct CFanimation_struct *animation, long int id, void *parameters) {
00167     if (id == -1)
00168         return 1;
00169     animation->wizard = id;
00170     return mr_finished;
00171 }
00172 
00173 static long int initsay(const char *name, char *parameters, struct CFmovement_struct *move_entity) {
00174     if (parameters)
00175         move_entity->parameters = cf_strdup_local(parameters);
00176     else
00177         move_entity->parameters = NULL;
00178     if (move_entity->parent->verbose)
00179         cf_log(llevDebug, "CFAnim: init say: parameters: %s\n", parameters ? parameters : "null");
00180     return 1;
00181 }
00182 
00183 static anim_move_result runsay(struct CFanimation_struct *animation, long int id, void *parameters) {
00184     if (parameters) {
00185         cf_object_say(animation->victim, parameters);
00186         free(parameters);
00187     } else
00188         cf_log(llevDebug, "CFAnim: Error in animation: nothing to say with say function\n");
00189     return mr_finished;
00190 }
00191 
00192 static long int initapply(const char *name, char *parameters, struct CFmovement_struct *move_entity) {
00193     return 1;
00194 }
00195 
00196 static anim_move_result runapply(struct CFanimation_struct *animation, long int id, void *parameters) {
00197     object *current_container;
00198 
00199     if (animation->victim->type != PLAYER)
00200         return mr_finished;
00201     current_container = animation->victim->container;
00202     animation->victim->container = NULL;
00203     cf_object_apply_below(animation->victim);
00204     animation->victim->container = current_container;
00205     return mr_finished;
00206 }
00207 
00208 static long int initapplyobject(const char *name, char *parameters, struct CFmovement_struct *move_entity) {
00209     move_entity->parameters = parameters ? cf_add_string(parameters) : NULL;
00210     return 1;
00211 }
00212 
00213 static anim_move_result runapplyobject(struct CFanimation_struct *animation, long int id, void *parameters) {
00214     object *current;
00215     int aflag;
00216 
00217     if (!parameters)
00218         return mr_finished;
00219     for (current = animation->victim->below; current; current = current->below)
00220         if (current->name == parameters)
00221             break;
00222     if (!current)
00223         for (current = animation->victim->inv; current; current = current->below)
00224             if (current->name == parameters)
00225                 break;
00226     if (!current) {
00227         cf_free_string(parameters);
00228         return mr_finished;
00229     }
00230     aflag = AP_APPLY;
00231     cf_object_apply(animation->victim, current, aflag);
00232     cf_free_string(parameters);
00233     return mr_finished;
00234 }
00235 
00236 static long int initdropobject(const char *name, char *parameters, struct CFmovement_struct *move_entity) {
00237     move_entity->parameters = parameters ? cf_strdup_local(parameters) : NULL;
00238     return 1;
00239 }
00240 
00241 static anim_move_result rundropobject(struct CFanimation_struct *animation, long int id, void *parameters) {
00242     if (!parameters)
00243         return mr_finished;
00244     cf_object_drop(animation->victim, parameters);
00245     cf_free_string(parameters);
00246     return mr_finished;
00247 }
00248 
00249 static long int initpickup(const char *name, char *parameters, struct CFmovement_struct *move_entity) {
00250     return 1;
00251 }
00252 
00253 static anim_move_result runpickup(struct CFanimation_struct *animation, long int id, void *parameters) {
00254     object *current;
00255 
00256     current = animation->victim->below;
00257     if (!current)
00258         return mr_finished;
00259     cf_object_pickup(animation->victim, current);
00260     return mr_finished;
00261 }
00262 
00263 static long int initpickupobject(const char *name, char *parameters, struct CFmovement_struct *move_entity) {
00264     move_entity->parameters = parameters ? cf_add_string(parameters) : NULL;
00265     return 1;
00266 }
00267 
00268 static anim_move_result runpickupobject(struct CFanimation_struct *animation, long int id, void *parameters) {
00269     object *current;
00270 
00271     if (!parameters)
00272         return mr_finished;
00273     for (current = animation->victim->below; current; current = current->below)
00274         if (current->name == parameters)
00275             break;
00276     if (current)
00277         cf_object_pickup(animation->victim, current);
00278     cf_free_string(parameters);
00279     return mr_finished;
00280 }
00281 
00282 static long int initghosted(const char *name, char *parameters, struct CFmovement_struct *move_entity) {
00283     int result;
00284 
00285     if (get_boolean(parameters, &result))
00286         return result;
00287     cf_log(llevDebug, "CFAnim: Error in animation: possible values for 'ghosted' are 'yes' and 'no'\n");
00288     return -1;
00289 }
00290 
00291 static anim_move_result runghosted(struct CFanimation_struct *animation, long int id, void *parameters) {
00292     object *corpse;
00293 
00294     if ((id && animation->ghosted)
00295     || (!id && !animation->ghosted))
00296         runghosted(animation, !id, parameters);
00297     if (id) { /*Create a ghost/corpse pair*/
00298         corpse = cf_object_clone(animation->victim, 1);
00299         corpse->x = animation->victim->x;
00300         corpse->y = animation->victim->y;
00301         corpse->type = 0;
00302         CLEAR_FLAG(corpse, FLAG_WIZ);
00303         corpse->contr = NULL;
00304         cf_map_insert_object_there(corpse, animation->victim->map, NULL, 0);
00305         animation->wizard = 1;
00306         animation->invisible = 1;
00307         animation->corpse = corpse;
00308     } else { /*Remove a corpse, make current player visible*/
00309         animation->wizard = 0;
00310         animation->invisible = 0;
00311         cf_object_remove(animation->corpse);
00312         cf_object_free(animation->corpse);
00313         animation->corpse = NULL;
00314         animation->victim->invisible = 0;
00315         cf_player_move(animation->victim->contr, 0);
00316     }
00317     animation->ghosted = id;
00318     return mr_finished;
00319 }
00320 
00321 typedef struct {
00322     char *mapname;
00323     int mapx;
00324     int mapy;
00325 } teleport_params;
00326 
00327 static long int initteleport(const char *name, char *parameters, struct CFmovement_struct *move_entity) {
00328     char *mapname;
00329     int mapx;
00330     int mapy;
00331     teleport_params *teleport;
00332 
00333     move_entity->parameters = NULL;
00334     cf_log(llevDebug, ".(%s)\n", parameters);
00335     if (!parameters) {
00336         cf_log(llevDebug, "CFAnim: Error - no parameters for teleport\n");
00337         return 0;
00338     }
00339     mapname = strstr(parameters, " ");
00340     cf_log(llevDebug, ".(%s)\n", parameters);
00341     if (!mapname)
00342         return 0;
00343     *mapname = '\0';
00344     mapx = atoi(parameters);
00345     mapname++;
00346     parameters = mapname;
00347     if (!parameters) {
00348         cf_log(llevDebug, "CFAnim: Error - not enough parameters for teleport\n");
00349         return 0;
00350     }
00351     cf_log(llevDebug, ".(%s)\n", parameters);
00352     mapname = strstr(parameters, " ");
00353     cf_log(llevDebug, ".\n");
00354     if (!mapname)
00355         return 0;
00356     *mapname = '\0';
00357     mapy = atoi(parameters);
00358     mapname++;
00359     if (mapname[0] == '\0')
00360         return 0;
00361     teleport = (teleport_params *)malloc(sizeof(teleport_params));
00362     teleport->mapname = cf_strdup_local(mapname);
00363     teleport->mapx = mapx;
00364     teleport->mapy = mapy;
00365     move_entity->parameters = teleport;
00366     return 1;
00367 }
00368 
00369 static anim_move_result runteleport(struct CFanimation_struct *animation, long int id, void *parameters) {
00370     teleport_params *teleport = (teleport_params *)parameters;
00371 
00372     if (!parameters)
00373         return mr_finished;
00374     cf_object_teleport(animation->victim, cf_map_get_map(teleport->mapname, 0), teleport->mapx, teleport->mapy);
00375     free(parameters);
00376     return mr_finished;
00377 }
00378 
00379 static long int initnotice(const char *name, char *parameters, struct CFmovement_struct *move_entity) {
00380     move_entity->parameters = parameters ? cf_strdup_local(parameters) : NULL;
00381     return 1;
00382 }
00383 static  anim_move_result runnotice(struct CFanimation_struct *animation, long int id, void *parameters) {
00384     int val;
00385 
00386     val = NDI_NAVY|NDI_UNIQUE;
00387 
00388     cf_player_message(animation->victim, parameters, val);
00389     return mr_finished;
00390 }
00391 
00392 static long int initstop(const char *name, char *parameters, struct CFmovement_struct *move_entity) {
00393     return 1;
00394 }
00395 
00397 static anim_move_result runstop(struct CFanimation_struct *animation, long int id, void *parameters) {
00398     if (animation->verbose)
00399         cf_log(llevDebug, "CFAnim: stop encountered\n");
00400     return mr_finished;
00401 }
00402 
00404 typedef struct {
00405     int x, y;   
00406 } param_moveto;
00407 
00408 static long int initmoveto(const char *name, char *parameters, struct CFmovement_struct *move_entity) {
00409     param_moveto *moveto;
00410     int x, y;
00411 
00412     if (sscanf(parameters, "%d %d", &x, &y) != 2)
00413         return 0;
00414 
00415     moveto = (param_moveto *)calloc(1, sizeof(param_moveto));
00416     moveto->x = x;
00417     moveto->y = y;
00418     move_entity->parameters = moveto;
00419 
00420     return 1;
00421 }
00422 
00423 static anim_move_result runmoveto(struct CFanimation_struct *animation, long int id, void *parameters) {
00424     int move;
00425     param_moveto *dest = (param_moveto *)parameters;
00426 
00427     if (!dest)
00428         return mr_finished;
00429 
00430     move = cf_object_move_to(animation->victim, dest->x, dest->y);
00431 
00432     if (animation->victim->x == dest->x && animation->victim->y == dest->y) {
00433         free(parameters);
00434         return mr_finished;
00435     }
00436 
00437     if (move == 1)
00438         return mr_again;
00439 
00440     return mr_finished;
00441 }
00442 
00443 static long int initmessage(const char *name, char *parameters, struct CFmovement_struct *move_entity) {
00444     if (parameters)
00445         move_entity->parameters = strdup(parameters);
00446     else
00447         move_entity->parameters = NULL;
00448     return 1;
00449 }
00450 
00451 static anim_move_result runmessage(struct CFanimation_struct *animation, long int id, void *parameters) {
00452     if (parameters && animation->victim->map) {
00453         cf_map_message(animation->victim->map, (const char *)parameters, NDI_UNIQUE|NDI_GREEN);
00454         free(parameters);
00455     }
00456 
00457     return mr_finished;
00458 }
00459 
00461 CFanimationHook animationbox[] = {
00462     { "north", initmovement, runmovement },
00463     { "north_east", initmovement, runmovement },
00464     { "east", initmovement, runmovement },
00465     { "south_east", initmovement, runmovement },
00466     { "south", initmovement, runmovement },
00467     { "south_west", initmovement, runmovement },
00468     { "west", initmovement, runmovement },
00469     { "north_west", initmovement, runmovement },
00470     { "fire_north", initfire, runfire },
00471     { "fire_north_east", initfire, runfire },
00472     { "fire_east", initfire, runfire },
00473     { "fire_south_east", initfire, runfire },
00474     { "fire_south", initfire, runfire },
00475     { "fire_south_west", initfire, runfire },
00476     { "fire_west", initfire, runfire },
00477     { "fire_north_west", initfire, runfire },
00478     { "turn_north", initturn, runturn },
00479     { "turn_north_east", initturn, runturn },
00480     { "turn_east", initturn, runturn },
00481     { "turn_south_east", initturn, runturn },
00482     { "turn_south", initturn, runturn },
00483     { "turn_south_west", initturn, runturn },
00484     { "turn_west", initturn, runturn },
00485     { "turn_north_west", initturn, runturn },
00486     { "camera_north", initcamera, runcamera },
00487     { "camera_north_east", initcamera, runcamera },
00488     { "camera_east", initcamera, runcamera },
00489     { "camera_south_east", initcamera, runcamera },
00490     { "camera_south", initcamera, runcamera },
00491     { "camera_south_west", initcamera, runcamera },
00492     { "camera_west", initcamera, runcamera },
00493     { "camera_north_west", initcamera, runcamera },
00494     { "invisible", initvisible, runvisible },
00495     { "wizard", initwizard, runwizard },
00496     { "say", initsay, runsay },
00497     { "apply", initapply, runapply },
00498     { "apply_object", initapplyobject, runapplyobject },
00499     { "drop_object", initdropobject, rundropobject },
00500     { "pickup", initpickup, runpickup },
00501     { "pickup_object", initpickupobject, runpickupobject },
00502     { "ghosted", initghosted, runghosted },
00503     { "teleport", initteleport, runteleport },
00504     { "notice", initnotice, runnotice },
00505     { "stop", initstop, runstop },
00506     { "moveto", initmoveto, runmoveto },
00507     { "message", initmessage, runmessage }
00508 };
00509 
00510 int animationcount = sizeof(animationbox)/sizeof(CFanimationHook);
00511 
00512 static int ordered_commands = 0;
00513 
00514 static int compareAnims(const void *a, const void *b) {
00515     return strcmp(((const CFanimationHook *)a)->name, ((const CFanimationHook *)b)->name);
00516 }
00517 
00518 static void prepare_commands(void) {
00519     qsort(animationbox, animationcount, sizeof(CFanimationHook), compareAnims);
00520     ordered_commands = 1;
00521 }
00522 
00523 static CFanimationHook *get_command(char *command) {
00524     CFanimationHook dummy;
00525 
00526     dummy.name = command;
00527     if (!ordered_commands)
00528         prepare_commands();
00529     return (CFanimationHook *)bsearch(&dummy, animationbox, animationcount, sizeof(CFanimationHook), compareAnims);
00530 }
00531 
00540 static CFmovement *parse_animation_block(char *buffer, size_t buffer_size, FILE *fichier, CFanimation *parent) {
00541     CFmovement *first = NULL;
00542     CFmovement *current = NULL;
00543     CFmovement *next;
00544     char *time;
00545     char *name;
00546     char *parameters;
00547     int tick;
00548     CFanimationHook *animationhook;
00549 
00550     if (parent->verbose)
00551         cf_log(llevDebug, "CFAnim: In parse block for %s\n", buffer);
00552     while (fgets(buffer, buffer_size, fichier)) {
00553         if (buffer[0] == '[')
00554             break;
00555         if (buffer[0] == '#')
00556             continue;
00557         buffer[strlen(buffer)-strlen("\n")] = '\0';
00558         while (buffer[strlen(buffer)-1] == ' ')
00559             buffer[strlen(buffer)-1] = '\0';
00560         if (strlen(buffer) <= 0)
00561             continue;
00562         time = buffer;
00563 
00564         name = strstr(buffer, " ");
00565         if (!name)
00566             continue;
00567         *name = '\0';
00568         name++;
00569         while (*name == ' ')
00570             name++;
00571 
00572         tick = atoi(time);
00573         if (tick < 0)
00574             continue;
00575 
00576         parameters = strstr(name, " ");
00577         if (parameters) { /*Parameters may be nul*/
00578             *parameters = '\0';
00579             parameters++;
00580             while (*parameters == ' ')
00581                 parameters++;
00582             if (*parameters == '\0')
00583                 parameters = NULL;
00584         }
00585         animationhook = get_command(name);
00586         if (parent->verbose) {
00587             if (!animationhook)
00588                 cf_log(llevDebug, "CFAnim: %s - Unknown animation command\n", name);
00589             else
00590                 cf_log(llevDebug, "CFAnim: Parsed %s -> %p\n", name, animationhook);
00591         }
00592         if (!animationhook) {
00593             if (parent->errors_allowed)
00594                 continue;
00595             else
00596                 break;
00597         }
00598         next = (CFmovement *)malloc(sizeof(CFmovement));
00599         if (!next)
00600             continue;
00601         next->parent = parent;
00602         next->tick = tick;
00603         next->next = NULL;
00604         if (animationhook->funcinit)
00605             next->id = animationhook->funcinit(name, parameters, next);
00606         next->func = animationhook->funcrun;
00607         if (current)
00608             current->next = next;
00609         else
00610             first = next;
00611         current = next;
00612     }
00613     return first;
00614 }
00615 
00626 static int equality_split(char *buffer, char **variable, char **value) {
00627     if (!strcmp(&buffer[strlen(buffer)-strlen("\n")], "\n"))
00628         buffer[strlen(buffer)-strlen("\n")] = '\0';
00629     *value = strstr(buffer, "=");
00630     if (!*value)
00631         return 0;
00632     **value = '\0';
00633     *variable = buffer;
00634     (*value)++;
00635     while ((strlen(*variable) > 0) && ((*variable)[strlen(*variable)-1] == ' '))
00636         (*variable)[strlen(*variable)-1] = '\0';
00637     while ((strlen(*value) > 0) && ((*value)[strlen(*value)-1] == ' '))
00638         (*value)[strlen(*value)-1] = '\0';
00639     while (**value == ' ')
00640         (*value)++;
00641     if ((**variable == '\0') || (**value == '\0'))
00642         return 0;
00643     return 1;
00644 }
00645 
00657 static int get_boolean(const char *strg, int *bl) {
00658     if (!strncmp(strg, "y", 1))
00659         *bl = 1;
00660     else if (!strncmp(strg, "n", 1))
00661         *bl = 0;
00662     else if (!strncmp(strg, "Y", 1))
00663         *bl = 1;
00664     else if (!strncmp(strg, "N", 1))
00665         *bl = 0;
00666     else if (!strncmp(strg, "1", 1))
00667         *bl = 1;
00668     else if (!strncmp(strg, "0", 1))
00669         *bl = 0;
00670     else
00671         return 0;
00672     return 1;
00673 }
00674 
00680 static int is_animated_player(object *pl) {
00681     CFanimation *current;
00682 
00683     for (current = first_animation; current; current++)
00684         if ((current->victim == pl) && (current->paralyze)) {
00685             if (current->verbose)
00686                 cf_log(llevDebug, "CFAnim: Getting a command for a paralyzed player %s.\n", pl->name);
00687             return 1;
00688         }
00689     return 0;
00690 }
00691 
00696 static CFanimation *create_animation(void) {
00697     CFanimation *new;
00698     CFanimation *current;
00699 
00700     new = (CFanimation *)malloc(sizeof(CFanimation));
00701     if (!new)
00702         return NULL;
00703     new->name = NULL;
00704     new->victim = NULL;
00705     new->nextmovement = NULL;
00706     new->nextanimation = NULL;
00707     for (current = first_animation; (current && current->nextanimation); current = current->nextanimation)
00708         ;
00709     if (!current)
00710         first_animation = new;
00711     else
00712         current->nextanimation = new;
00713     return new;
00714 }
00715 
00716 static object *find_by_name(object *origin, const char *name) {
00717     int x, y, w, h;
00718     mapstruct *map;
00719     const char *sname;
00720     object *ob;
00721 
00722     sname = cf_find_string(name);
00723     if (!sname)
00724         return NULL;
00725 
00726     while (origin && !origin->map)
00727         origin = origin->env;
00728 
00729     if (!origin || !origin->map)
00730         return NULL;
00731 
00732     map = origin->map;
00733 
00734     w = cf_map_get_width(map);
00735     h = cf_map_get_height(map);
00736 
00737     for (x = 0; x < w; x++) {
00738         for (y = 0; y < h; y++) {
00739             for (ob = GET_MAP_OB(map, x, y); ob; ob = ob->above) {
00740                 if (/*cf_object_get_sstring_property(ob, CFAPI_OBJECT_PROP_NAME)*/ob->name == sname)
00741                     return ob;
00742             }
00743         }
00744     }
00745 
00746     return NULL;
00747 }
00748 
00760 static int start_animation(object *who, object *activator, object *event, const char *file, const char *message) {
00761     FILE    *fichier;
00762     char    *name = NULL;
00763     int     victimtype = 0;
00764     object  *victim = NULL;
00765     int     unique = 0;
00766     int     always_delete = 0;
00767     int     parallel = 0;
00768     int     paralyzed = 1;
00769     int     invisible = 0;
00770     int     wizard = 0;
00771     enum    time_enum timetype;
00772     int     errors_allowed = 0;
00773     int     verbose = 0;
00774     const char *animationitem;
00775     char    buffer[HUGE_BUF];
00776     char    *variable;
00777     char    *value;
00778     int     errors_found = 0;
00779     CFanimation *current_anim;
00780 
00781     fichier = fopen(file, "r");
00782     if (fichier == NULL) {
00783         cf_log(llevDebug, "CFAnim: Unable to open %s\n", file);
00784         return 0;
00785     }
00786     while (fgets(buffer, HUGE_BUF, fichier)) {
00787         if (buffer[0] == '[')
00788             break;
00789         if (buffer[0] == '#')
00790             continue;
00791         if (!strcmp(buffer, "\n"))
00792             continue;
00793         errors_found = 1;
00794         cf_log(llevDebug, "CFAnim: '%s' has an invalid syntax.\n", buffer);
00795     }
00796     if (feof(fichier))
00797         return 0;
00798     if (strncmp(buffer, "[Config]", 8)) {
00799         cf_log(llevDebug, "CFAnim: Fatal error in %s: [Config] must be the first group defined.\n", file);
00800         return 0;
00801     }
00802     while (fgets(buffer, HUGE_BUF, fichier)) {
00803         if (buffer[0] == '[')
00804             break;
00805         if (buffer[0] == '#')
00806             continue;
00807         if (!strcmp(buffer, "\n"))
00808             continue;
00809         if (!equality_split(buffer, &variable, &value))
00810             errors_found = 1;
00811         else {
00812             if (!strcmp(variable, "name")) {
00813                 if (*value == '"')
00814                     value++;
00815                 if (value[strlen(value)-1] == '"')
00816                     value[strlen(value)-1] = '\0';
00817                 name = cf_strdup_local(value);
00818             } else if (!strcmp(variable, "victimtype")) {
00819                 if (!strcmp(value, "player"))
00820                     victimtype = 0;
00821                 else if (!strcmp(value, "object"))
00822                     victimtype = 1;
00823                 else if (!strcmp(value, "any"))
00824                     victimtype = 2;
00825                 else if (!strcmp(value, "byname"))
00826                     victimtype = 3;
00827                 else
00828                     errors_found = 1;
00829             } else if (!strcmp(variable, "victim")) {
00830                 cf_log(llevDebug, "CFAnim: Setting victim to %s\n", value);
00831                 if (!strcmp(value, "who"))
00832                     victim = who;
00833                 else if (!strcmp(value, "activator"))
00834                     victim = activator;
00835                 else if (!strcmp(value, "who_owner"))
00836                     if (!who) {
00837                         errors_found = 1;
00838                         cf_log(llevDebug, "CFAnim: Warning: object \"who\" doesn't exist and you're victimized it's owner\n");
00839                     } else
00840                         victim = who->env;
00841                 else if (!strcmp(value, "activator_owner"))
00842                     if (!activator) {
00843                         errors_found = 1;
00844                         cf_log(llevDebug, "CFAnim: Warning: object \"activator\" doesn't exist and you're victimized it's owner\n");
00845                     }
00846                     else
00847                         victim = activator->env;
00848                 else if (victimtype == 3) {
00849                     victim = find_by_name(who, value);
00850                 } else
00851                     errors_found = 1;
00852             } else if (!strcmp(variable, "unique")) {
00853                 if (!get_boolean(value, &unique))
00854                     errors_found = 1;
00855             } else if (!strcmp(variable, "always_delete")) {
00856                 if (!get_boolean(value, &always_delete))
00857                     errors_found = 1;
00858             } else if (!strcmp(variable, "parallel")) {
00859                 if (!get_boolean(value, &parallel))
00860                     errors_found = 1;
00861             } else if (!strcmp(variable, "paralyzed")) {
00862                 if (!get_boolean(value, &paralyzed))
00863                     errors_found = 1;
00864             } else if (!strcmp(variable, "invisible")) {
00865                 if (!get_boolean(value, &invisible))
00866                     errors_found = 1;
00867             } else if (!strcmp(variable, "wizard")) {
00868                 if (!get_boolean(value, &wizard))
00869                     errors_found = 1;
00870             } else if (!strcmp(variable, "errors_allowed")) {
00871                 if (!get_boolean(value, &errors_allowed))
00872                     errors_found = 1;
00873             } else if (!strcmp(variable, "verbose")) {
00874                 if (!get_boolean(value, &verbose))
00875                     errors_found = 1;
00876             } else if (!strcmp(variable, "time_representation")) {
00877                 if (!strcmp(value, "second"))
00878                     timetype = time_second;
00879                 else if (!strcmp(value, "tick"))
00880                     timetype = time_tick;
00881                 else
00882                     errors_found = 1;
00883             } else if (!strcmp(variable, "animation")) {
00884                 animationitem = cf_add_string(value);
00885             } else
00886                 errors_found = 1;
00887         }
00888     }
00889 
00890     if (message && message[0] != '\0') {
00891         cf_free_string(animationitem);
00892         animationitem = cf_add_string(message);
00893     }
00894 
00895     if (buffer[0] == '\0') {
00896         if (animationitem)
00897             cf_free_string(animationitem);
00898         cf_log(llevDebug, "CFAnim: Errors occurred during the parsing of %s\n", file);
00899         return 0;
00900     }
00901     if (!victim) {
00902         if (animationitem)
00903             cf_free_string(animationitem);
00904         cf_log(llevDebug,  "CFAnim: Fatal error - victim is NULL");
00905         return 0;
00906     }
00907     if (!(current_anim = create_animation())) {
00908         if (animationitem)
00909             cf_free_string(animationitem);
00910         cf_log(llevDebug, "CFAnim: Fatal error - Not enough memory.\n");
00911         return 0;
00912     }
00913     if (always_delete) {
00914         /*if (verbose) printf("CFAnim: Freeing event nr. %d for %s.\n", current_event, who->name);*/
00915         cf_object_remove(event);
00916     }
00917     if (((victim->type == PLAYER) && (victimtype == 1))
00918     || ((victim->type != PLAYER) && (victimtype == 0))
00919     || (errors_found && !errors_allowed)) {
00920         if (verbose)
00921             cf_log(llevDebug, "CFAnim: No correct victim found or errors found, aborting.\n");
00922         if (animationitem)
00923             cf_free_string(animationitem);
00924         return 0;
00925     }
00926     if (unique && !always_delete) {
00927         /*if (verbose) printf("CFAnim: Freeing event nr. %d for %s.\n", current_event, who->name);*/
00928         cf_object_remove(event);
00929     }
00930     current_anim->name = name;
00931     current_anim->victim = victim;
00932     current_anim->paralyze = paralyzed;
00933     current_anim->invisible = invisible;
00934     current_anim->wizard = wizard;
00935     current_anim->unique = unique;
00936     current_anim->ghosted = 0;
00937     current_anim->corpse = NULL;
00938     current_anim->time_representation = timetype;
00939     current_anim->verbose = verbose;
00940     current_anim->tick_left = 0;
00941     current_anim->errors_allowed = errors_allowed;
00942 
00943     while (buffer[0] == '[') {
00944         while (strncmp(&buffer[1], animationitem, strlen(animationitem))) {
00945             while ((value = fgets(buffer, HUGE_BUF, fichier)) != NULL)
00946                 if (buffer[0] == '[')
00947                     break;
00948             if (value == NULL) {
00949                 cf_log(llevDebug, "CFAnim: no matching animation %s in file.\n", animationitem);
00950                 cf_free_string(animationitem);
00951                 return 0;
00952             }
00953         }
00954         current_anim->nextmovement = parse_animation_block(buffer, HUGE_BUF, fichier, current_anim);
00955         if (current_anim->nextmovement)
00956             break;
00957     }
00958     fclose(fichier);
00959     return 1;
00960 }
00961 
00967 static void animate_one(CFanimation *animation, long int milliseconds) {
00968     CFmovement *current;
00969     int mult = 1;
00970     anim_move_result result;
00971 
00972     if (animation->time_representation == time_second) {
00973         animation->tick_left += milliseconds;
00974         mult = 1000;
00975     }
00976     else
00977         animation->tick_left++;
00978 
00979     if (animation->verbose)
00980         cf_log(llevDebug, "CFAnim: Ticking %s for %s. Tickleft is %ld\n", animation->name, animation->victim->name, animation->tick_left);
00981     if (animation->invisible)
00982         animation->victim->invisible = 10;
00983     if (animation->wizard && animation->victim->type == PLAYER) {
00984         /* setting FLAG_WIZ *on non player leads to issues, as many functions expect contr to not be NULL in this case. */
00985         if (animation->verbose)
00986             cf_log(llevDebug, "CFAnim: Setting wizard flags\n");
00987         cf_object_set_flag(animation->victim, FLAG_WIZPASS, 1);
00988         cf_object_set_flag(animation->victim, FLAG_WIZCAST, 1);
00989         cf_object_set_flag(animation->victim, FLAG_WIZ, 1);
00990         if (animation->verbose)
00991             cf_log(llevDebug, "CFAnim: Setting wizard flags done\n");
00992 
00993     }
00994     if (animation->paralyze)
00995         animation->victim->speed_left = -99999;
00996 
00997     cf_object_update(animation->victim, UP_OBJ_CHANGE);
00998 
00999     if (animation->nextmovement)
01000         while (animation->tick_left > animation->nextmovement->tick*mult) {
01001             animation->tick_left -= animation->nextmovement->tick*mult;
01002             result = animation->nextmovement->func(animation, animation->nextmovement->id, animation->nextmovement->parameters);
01003             if (result == mr_again)
01004                 continue;
01005 
01006             current = animation->nextmovement;
01007             animation->nextmovement = animation->nextmovement->next;
01008             free(current);
01009             if (!animation->nextmovement)
01010                 break;
01011         }
01012     cf_object_set_flag(animation->victim, FLAG_WIZPASS, 0);
01013     cf_object_set_flag(animation->victim, FLAG_WIZCAST, 0);
01014     cf_object_set_flag(animation->victim, FLAG_WIZ, 0);
01015 }
01016 
01020 static void animate(void) {
01021     CFanimation *current;
01022     CFanimation *next;
01023     CFanimation *previous_anim = NULL;
01024     struct timeval now;
01025     static struct timeval yesterday;
01026     static int already_passed = 0;
01027     long int delta_milli;
01028 
01029     (void)GETTIMEOFDAY(&now);
01030     if (!already_passed) {
01031         already_passed = 1;
01032         memcpy(&yesterday, &now, sizeof(struct timeval));
01033         return;
01034     }
01035     delta_milli = (now.tv_sec-yesterday.tv_sec)*1000+(now.tv_usec/1000-yesterday.tv_usec/1000);
01036     /*printf("Working for %ld milli seconds\n", delta_milli);*/
01037     memcpy(&yesterday, &now, sizeof(struct timeval));
01038     for (current = first_animation; current; current = current->nextanimation)
01039         animate_one(current, delta_milli);
01040     current = first_animation;
01041     while (current) {
01042         if (!current->nextmovement) {
01043             if (current->paralyze)
01044                 current->victim->speed_left = current->victim->speed;
01045             next = current->nextanimation;
01046             if (first_animation == current)
01047                 first_animation = next;
01048             else {
01049                 previous_anim->nextanimation = next;
01050             }
01051             if (current->name)
01052                 free(current->name);
01053             free(current);
01054             current = next;
01055         } else {
01056             previous_anim = current;
01057             current = current->nextanimation;
01058         }
01059     }
01060 }
01061 
01068 CF_PLUGIN int initPlugin(const char *iversion, f_plug_api gethooksptr) {
01069     cf_init_plugin(gethooksptr);
01070     cf_log(llevDebug, "CFAnim 2.0a init\n");
01071 
01072     /* Place your initialization code here */
01073     return 0;
01074 }
01075 
01076 CF_PLUGIN void *getPluginProperty(int *type, ...) {
01077     va_list args;
01078     const char *propname;
01079     char *buf;
01080     int size;
01081 
01082     va_start(args, type);
01083     propname = va_arg(args, const char *);
01084 
01085     if (!strcmp(propname, "Identification")) {
01086         buf = va_arg(args, char *);
01087         size = va_arg(args, int);
01088         va_end(args);
01089         snprintf(buf, size, PLUGIN_NAME);
01090         return NULL;
01091     } else if (!strcmp(propname, "FullName")) {
01092         buf = va_arg(args, char *);
01093         size = va_arg(args, int);
01094         va_end(args);
01095         snprintf(buf, size, PLUGIN_VERSION);
01096         return NULL;
01097     }
01098     va_end(args);
01099     return NULL;
01100 }
01101 
01102 CF_PLUGIN anim_move_result cfanim_runPluginCommand(object *op, char *params) {
01103     return -1;
01104 }
01105 
01106 CF_PLUGIN int postInitPlugin(void) {
01107     cf_log(llevDebug, "CFAnim 2.0a post init\n");
01108     /* Pick the global events you want to monitor from this plugin */
01109     cf_system_register_global_event(EVENT_CLOCK, PLUGIN_NAME, cfanim_globalEventListener);
01110     return 0;
01111 }
01112 
01113 CF_PLUGIN void *cfanim_globalEventListener(int *type, ...) {
01114     va_list args;
01115     static int rv = 0;
01116     int event_code;
01117 
01118     va_start(args, type);
01119     event_code = va_arg(args, int);
01120     assert(event_code == EVENT_CLOCK);
01121 
01122     animate();
01123 
01124     va_end(args);
01125 
01126     return &rv;
01127 }
01128 
01129 CF_PLUGIN void *eventListener(int *type, ...) {
01130     static int rv = 0;
01131     va_list args;
01132     char *buf, message[MAX_BUF], script[MAX_BUF];
01133     object *who, *activator, *third, *event;
01134 
01135     va_start(args, type);
01136 
01137     who = va_arg(args, object *);
01138     activator = va_arg(args, object *);
01139     third = va_arg(args, object *);
01140     buf = va_arg(args, char *);
01141 
01142     if (buf != NULL)
01143         strcpy(message, buf);
01144     else
01145         message[0] = '\0';
01146 
01147     va_arg(args, int); /* 'fix', ignored */
01148     event = va_arg(args, object *);
01149 
01151     cf_get_maps_directory(event->slaying, script, sizeof(script));
01152     va_end(args);
01153 
01154     /* Put your plugin action(s) here */
01155     if (activator != NULL) {
01156         cf_log(llevDebug, "CFAnim: %s called animator script %s\n", activator->name, script);
01157     } else if (who != NULL) {
01158         activator = who;
01159         cf_log(llevDebug, "CFAnim: %s called animator script %s\n", who->name, script);
01160     }
01161 
01162     rv = start_animation(who, activator, event, script, message);
01163 
01164     return &rv;
01165 }
01166 
01167 CF_PLUGIN int   closePlugin(void) {
01168     cf_log(llevDebug, "CFAnim 2.0a closing\n");
01169     return 0;
01170 }