Atrinik Server 2.5
server/anim.c
Go to the documentation of this file.
00001 /************************************************************************
00002 *            Atrinik, a Multiplayer Online Role Playing Game            *
00003 *                                                                       *
00004 *    Copyright (C) 2009-2011 Alex Tokar and Atrinik Development Team    *
00005 *                                                                       *
00006 * Fork from Daimonin (Massive Multiplayer Online Role Playing Game)     *
00007 * and Crossfire (Multiplayer game for X-windows).                       *
00008 *                                                                       *
00009 * This program is free software; you can redistribute it and/or modify  *
00010 * it under the terms of the GNU General Public License as published by  *
00011 * the Free Software Foundation; either version 2 of the License, or     *
00012 * (at your option) any later version.                                   *
00013 *                                                                       *
00014 * This program is distributed in the hope that it will be useful,       *
00015 * but WITHOUT ANY WARRANTY; without even the implied warranty of        *
00016 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
00017 * GNU General Public License for more details.                          *
00018 *                                                                       *
00019 * You should have received a copy of the GNU General Public License     *
00020 * along with this program; if not, write to the Free Software           *
00021 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.             *
00022 *                                                                       *
00023 * The author can be reached at admin@atrinik.org                        *
00024 ************************************************************************/
00025 
00030 #include <global.h>
00031 
00034 void free_all_anim()
00035 {
00036     int i;
00037 
00038     for (i = 0; i <= num_animations; i++)
00039     {
00040         FREE_AND_CLEAR_HASH(animations[i].name);
00041         free(animations[i].faces);
00042     }
00043 
00044     free(animations);
00045 }
00046 
00050 void init_anim()
00051 {
00052     char buf[MAX_BUF];
00053     FILE *fp;
00054     static int anim_init = 0;
00055     int num_frames = 0, faces[MAX_ANIMATIONS], i;
00056 
00057     if (anim_init)
00058     {
00059         return;
00060     }
00061 
00062     animations_allocated = 9;
00063     num_animations = 0;
00064 
00065     /* Make a default.  New animations start at one, so if something
00066      * thinks it is animated but hasn't set the animation_id properly,
00067      * it will have a default value that should be pretty obvious. */
00068     animations = malloc(10 * sizeof(Animations));
00069     /* set the name so we don't try to dereference null.
00070      * Put # at start so it will be first in alphabetical
00071      * order. */
00072     animations[0].name = NULL;
00073     FREE_AND_COPY_HASH(animations[0].name, "###none" );
00074     animations[0].num_animations = 1;
00075     animations[0].faces = malloc(sizeof(Fontindex));
00076     animations[0].faces[0] = 0;
00077     animations[0].facings = 0;
00078 
00079     snprintf(buf, sizeof(buf), "%s/animations", settings.datadir);
00080     LOG(llevDebug, "Reading animations from %s...\n", buf);
00081 
00082     if ((fp = fopen(buf, "r")) == NULL)
00083     {
00084         LOG(llevError, "Can not open animations file Filename=%s\n", buf);
00085     }
00086 
00087     while (fgets(buf, MAX_BUF - 1, fp) != NULL)
00088     {
00089         if (*buf == '#')
00090         {
00091             continue;
00092         }
00093 
00094         /* Kill the newline */
00095         buf[strlen(buf) - 1] = '\0';
00096 
00097         if (!strncmp(buf, "anim ", 5))
00098         {
00099             if (num_frames)
00100             {
00101                 LOG(llevError, "Didn't get a mina before %s\n", buf);
00102                 num_frames = 0;
00103             }
00104 
00105             num_animations++;
00106 
00107             if (num_animations == animations_allocated)
00108             {
00109                 animations = realloc(animations, sizeof(Animations) * (animations_allocated + 10));
00110                 animations_allocated += 10;
00111             }
00112 
00113             animations[num_animations].name = NULL;
00114             FREE_AND_COPY_HASH(animations[num_animations].name, buf + 5);
00115             /* for bsearch */
00116             animations[num_animations].num = num_animations;
00117             animations[num_animations].facings = 1;
00118         }
00119         else if (!strncmp(buf, "mina", 4))
00120         {
00121             animations[num_animations].faces = malloc(sizeof(Fontindex) * num_frames);
00122 
00123             for (i = 0; i < num_frames; i++)
00124             {
00125                 animations[num_animations].faces[i] = faces[i];
00126             }
00127 
00128             animations[num_animations].num_animations = num_frames;
00129 
00130             if (num_frames % animations[num_animations].facings)
00131             {
00132                 LOG(llevDebug, "Animation %s frame numbers (%d) is not a multiple of facings (%d)\n", STRING_SAFE(animations[num_animations].name), num_frames, animations[num_animations].facings);
00133             }
00134 
00135             num_frames = 0;
00136         }
00137         else if (!strncmp(buf, "facings", 7))
00138         {
00139             if (!(animations[num_animations].facings = atoi(buf + 7)))
00140             {
00141                 LOG(llevDebug, "Animation %s has 0 facings, line=%s\n", STRING_SAFE(animations[num_animations].name), buf);
00142                 animations[num_animations].facings = 1;
00143             }
00144 
00145             if (animations[num_animations].facings != 9 && animations[num_animations].facings != 25)
00146             {
00147                 LOG(llevDebug, "Animation %s has invalid facings parameter (%d - allowed are 9 or 25 only).", STRING_SAFE(animations[num_animations].name), animations[num_animations].facings);
00148                 animations[num_animations].facings = 1;
00149             }
00150         }
00151         else
00152         {
00153             if (!(faces[num_frames++] = find_face(buf, 0)))
00154             {
00155                 LOG(llevBug, "Could not find face %s for animation %s\n", buf, STRING_SAFE(animations[num_animations].name));
00156             }
00157         }
00158     }
00159 
00160     fclose(fp);
00161 
00162     LOG(llevDebug, "done. (got %d)\n", num_animations);
00163 }
00164 
00172 static int anim_compare(Animations *a, Animations *b)
00173 {
00174     return strcmp(a->name, b->name);
00175 }
00176 
00182 int find_animation(char *name)
00183 {
00184     Animations search, *match;
00185 
00186     search.name = name;
00187 
00188     match = (Animations *) bsearch(&search, animations, (num_animations + 1), sizeof(Animations), (void *) (int (*)()) anim_compare);
00189 
00190     if (match)
00191     {
00192         return match->num;
00193     }
00194 
00195     LOG(llevBug, "Unable to find animation %s\n", STRING_SAFE(name));
00196     return 0;
00197 }
00198 
00204 void animate_object(object *op, int count)
00205 {
00206     int numfacing, numanim;
00207     /* Max animation state object should be drawn in */
00208     int max_state;
00209     /* starting index # to draw from */
00210     int base_state;
00211     int dir;
00212 
00213     numanim = NUM_ANIMATIONS(op);
00214     numfacing = NUM_FACINGS(op);
00215 
00216     if (!op->animation_id || !numanim || op->head)
00217     {
00218 #if 0
00219         /* ONLY activate for active debugging */
00220         if (op->animation_id)
00221             LOG(llevBug,"Object %s (arch %s) lacks animation. (is tail: %s)\n", STRING_OBJ_NAME(op), STRING_OBJ_ARCH_NAME(op), op->head ? "yes" : "no");
00222 #endif
00223         return;
00224     }
00225 
00226     /* An animation is not only changed by anim_speed.
00227      * If we turn the object by a teleporter for example, the direction & facing can
00228      * change - outside the normal animation loop.
00229      * We have then to change the frame and not increase the state */
00230     if ((!QUERY_FLAG(op, FLAG_SLEEP) && !QUERY_FLAG(op, FLAG_PARALYZED)))
00231     {
00232         op->state += count;
00233     }
00234 
00235     if (!count)
00236     {
00237         if (op->type == PLAYER)
00238         {
00239             if (!CONTR(op)->anim_flags && op->anim_moving_dir == op->anim_moving_dir_last && op->anim_last_facing == op->anim_last_facing_last)
00240             {
00241                 return;
00242             }
00243         }
00244         else
00245         {
00246             /* Object needs no update for moving */
00247             if (op->anim_enemy_dir == op->anim_enemy_dir_last && op->anim_moving_dir == op->anim_moving_dir_last && op->anim_last_facing == op->anim_last_facing_last)
00248             {
00249                 return;
00250             }
00251         }
00252     }
00253 
00254     dir = op->direction;
00255 
00256     /* If object is turning, then max animation state is half through the
00257      * animations.  Otherwise, we can use all the animations. */
00258     max_state= numanim / numfacing;
00259     base_state = 0;
00260 
00261     /* 0: "stay" "non direction" face
00262      * 1-8: point of the compass the object is facing. */
00263     if (numfacing == 9)
00264     {
00265         base_state = dir * (numanim / 9);
00266 
00267         /* If beyond drawable states, reset */
00268         if (op->state >= max_state)
00269         {
00270             op->state = 0;
00271         }
00272     }
00273 
00274     /* that's the new extended animation: base_state is */
00275     /* 0:     that's the dying anim - "non direction" facing */
00276     /* 1-8:   guard/stand_still anim frames */
00277     /* 9-16:  move anim frames */
00278     /* 17-24: close fight anim frames */
00279     /* TODO: allow different number of faces in each frame */
00280     else if (numfacing >= 25)
00281     {
00282         if (op->type == PLAYER)
00283         {
00284             /* Check flags - perhaps we have hit something in close fight */
00285             if ((CONTR(op)->anim_flags & PLAYER_AFLAG_ADDFRAME || CONTR(op)->anim_flags & PLAYER_AFLAG_ENEMY) && !(CONTR(op)->anim_flags & PLAYER_AFLAG_FIGHT))
00286             {
00287                 /* Do swing animation, starting at frame 0 */
00288                 op->state = 0;
00289 
00290                 if (CONTR(op)->anim_flags & PLAYER_AFLAG_ENEMY)
00291                 {
00292                     /* So we do one more swing */
00293                     CONTR(op)->anim_flags |= PLAYER_AFLAG_ADDFRAME;
00294                     /* So we do one swing */
00295                     CONTR(op)->anim_flags |= PLAYER_AFLAG_FIGHT;
00296                 }
00297                 else
00298                 {
00299                     /* Only do ADDFRAME if we are still fighting something */
00300                     if (op->enemy && is_melee_range(op, op->enemy))
00301                     {
00302                         CONTR(op)->anim_flags |= PLAYER_AFLAG_FIGHT;
00303                     }
00304 
00305                     /* We do our additional frame*/
00306                     CONTR(op)->anim_flags &=~PLAYER_AFLAG_ADDFRAME;
00307                 }
00308 
00309                 /* Clear enemy, set fight */
00310                 CONTR(op)->anim_flags &=~PLAYER_AFLAG_ENEMY;
00311             }
00312 
00313             /* Now setup the best animation for our action */
00314             if (CONTR(op)->anim_flags & PLAYER_AFLAG_FIGHT)
00315             {
00316                 op->anim_enemy_dir_last = op->anim_enemy_dir;
00317 
00318                 /* Test of moving when swing */
00319                 if (op->anim_moving_dir != -1)
00320                 {
00321                     /* Face in moving direction */
00322                     dir = op->anim_moving_dir;
00323                     op->anim_moving_dir_last = op->anim_moving_dir;
00324                 }
00325                 else
00326                 {
00327                     /* Face to last direction we had done something */
00328                     if (op->anim_enemy_dir != -1)
00329                     {
00330                         dir = op->anim_enemy_dir;
00331                     }
00332                     else
00333                     {
00334                         dir = op->anim_last_facing;
00335                     }
00336                 }
00337 
00338                 /* If we have no idea where we faced, we face to enemy */
00339                 if (!dir || dir == -1)
00340                 {
00341                     dir = 4;
00342                 }
00343 
00344                 op->anim_last_facing = dir;
00345                 op->anim_last_facing_last = -1;
00346                 dir += 16;
00347             }
00348             /* Test of moving */
00349             else if (op->anim_moving_dir != -1)
00350             {
00351                 /* Face in moving direction */
00352                 dir = op->anim_moving_dir;
00353                 op->anim_moving_dir_last = op->anim_moving_dir;
00354                 op->anim_enemy_dir_last = -1;
00355 
00356                 /* Same spot will be mapped to south dir */
00357                 if (!dir)
00358                 {
00359                     dir = 4;
00360                 }
00361 
00362                 op->anim_last_facing = dir;
00363                 op->anim_last_facing_last = -1;
00364                 dir += 8;
00365             }
00366             /* If nothing to do: object is doing nothing. Use original facing */
00367             else
00368             {
00369                 /* Face to last direction we had done something */
00370                 if (op->anim_enemy_dir != -1)
00371                 {
00372                     dir = op->anim_enemy_dir;
00373                 }
00374                 else
00375                 {
00376                     dir = op->anim_last_facing;
00377                 }
00378 
00379                 op->anim_last_facing_last = dir;
00380 
00381                 /* Same spot will be mapped to south dir */
00382                 if (!dir || dir == -1)
00383                 {
00384                     op->anim_last_facing = dir = 4;
00385                 }
00386             }
00387 
00388             base_state = dir * (numanim / numfacing);
00389 
00390             /* If beyond drawable states, reset */
00391             if (op->state >= max_state)
00392             {
00393                 op->state = 0;
00394                 /* Always clear fighting flag */
00395                 CONTR(op)->anim_flags &= ~PLAYER_AFLAG_FIGHT;
00396             }
00397         }
00398         /* Monster and non player animations */
00399         else
00400         {
00401             /* Mob has targeted an enemy and faces him. When me move, we strafe sidewards */
00402             if (op->anim_enemy_dir != -1 && (!QUERY_FLAG(op, FLAG_RUN_AWAY) && !QUERY_FLAG(op, FLAG_SCARED)))
00403             {
00404                 /* Face to the enemy position */
00405                 dir = op->anim_enemy_dir;
00406                 op->anim_enemy_dir_last = op->anim_enemy_dir;
00407                 op->anim_moving_dir_last = -1;
00408 
00409                 /* Same spot will be mapped to south dir */
00410                 if (!dir)
00411                 {
00412                     dir = 4;
00413                 }
00414 
00415                 op->anim_last_facing = dir;
00416                 op->anim_last_facing_last = -1;
00417                 dir += 16;
00418             }
00419             /* Test of moving */
00420             else if (op->anim_moving_dir != -1)
00421             {
00422                 /* Face in moving direction */
00423                 dir = op->anim_moving_dir;
00424                 op->anim_moving_dir_last = op->anim_moving_dir;
00425                 op->anim_enemy_dir_last = -1;
00426 
00427                 /* Same spot will be mapped to south dir */
00428                 if (!dir)
00429                 {
00430                     dir = 4;
00431                 }
00432 
00433                 op->anim_last_facing = dir;
00434                 op->anim_last_facing_last = -1;
00435                 dir += 8;
00436             }
00437             else
00438             {
00439                 /* Face to last direction we had done something */
00440                 dir = op->anim_last_facing;
00441                 op->anim_last_facing_last = dir;
00442 
00443                 /* Same spot will be mapped to south dir */
00444                 if (!dir || dir == -1)
00445                 {
00446                     op->anim_last_facing = dir = 4;
00447                 }
00448             }
00449 
00450             base_state = dir * (numanim / numfacing);
00451 
00452             /* If beyond drawable states, reset */
00453             if (op->state >= max_state)
00454             {
00455                 op->state = 0;
00456             }
00457         }
00458     }
00459     else
00460     {
00461         /* If beyond drawable states, reset */
00462         if (op->state >= max_state)
00463         {
00464             op->state = 0;
00465         }
00466     }
00467 
00468     SET_ANIMATION(op, op->state + base_state);
00469 
00470     update_object(op, UP_OBJ_FACE);
00471 }