Crossfire Server, Branch 1.12
R12190
|
00001 /* 00002 * static char *rcsid_anim_c = 00003 * "$Id: anim.c 11578 2009-02-23 22:02:27Z lalo $"; 00004 */ 00005 00006 /* 00007 CrossFire, A Multiplayer game for X-windows 00008 00009 Copyright (C) 2002-2003 Mark Wedel & Crossfire Development Team 00010 Copyright (C) 1992 Frank Tore Johansen 00011 00012 This program is free software; you can redistribute it and/or modify 00013 it under the terms of the GNU General Public License as published by 00014 the Free Software Foundation; either version 2 of the License, or 00015 (at your option) any later version. 00016 00017 This program is distributed in the hope that it will be useful, 00018 but WITHOUT ANY WARRANTY; without even the implied warranty of 00019 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00020 GNU General Public License for more details. 00021 00022 You should have received a copy of the GNU General Public License 00023 along with this program; if not, write to the Free Software 00024 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 00025 00026 The authors can be reached via e-mail at crossfire-devel@real-time.com 00027 */ 00028 00034 #include <global.h> 00035 #include <stdio.h> 00036 #include <assert.h> 00037 00041 void free_all_anim(void) { 00042 int i; 00043 00044 for (i = 0; i <= num_animations; i++) { 00045 free_string(animations[i].name); 00046 free(animations[i].faces); 00047 } 00048 free(animations); 00049 } 00050 00055 void init_anim(void) { 00056 char buf[MAX_BUF]; 00057 FILE *fp; 00058 int num_frames = 0, faces[MAX_ANIMATIONS], i; 00059 00060 animations_allocated = 9; 00061 num_animations = 0; 00062 /* Make a default. New animations start at one, so if something 00063 * thinks it is animated but hasn't set the animation_id properly, 00064 * it will have a default value that should be pretty obvious. 00065 */ 00066 animations = malloc(10*sizeof(Animations)); 00067 /* set the name so we don't try to dereferance null. 00068 * Put # at start so it will be first in alphabetical 00069 * order. 00070 */ 00071 animations[0].name = add_string("###none"); 00072 animations[0].num_animations = 1; 00073 animations[0].faces = malloc(sizeof(Fontindex)); 00074 animations[0].faces[0] = 0; 00075 animations[0].facings = 0; 00076 00077 snprintf(buf, sizeof(buf), "%s/animations", settings.datadir); 00078 LOG(llevDebug, "Reading animations from %s...\n", buf); 00079 if ((fp = fopen(buf, "r")) == NULL) { 00080 LOG(llevError, "Cannot open animations file %s: %s\n", buf, strerror_local(errno, buf, sizeof(buf))); 00081 exit(-1); 00082 } 00083 while (fgets(buf, MAX_BUF-1, fp) != NULL) { 00084 if (*buf == '#') 00085 continue; 00086 if (strlen(buf) == 0) 00087 break; 00088 /* Kill the newline */ 00089 buf[strlen(buf)-1] = '\0'; 00090 if (!strncmp(buf, "anim ", 5)) { 00091 if (num_frames) { 00092 LOG(llevError, "Didn't get a mina before %s\n", buf); 00093 num_frames = 0; 00094 } 00095 num_animations++; 00096 if (num_animations == animations_allocated) { 00097 animations = realloc(animations, sizeof(Animations)*(animations_allocated+10)); 00098 animations_allocated += 10; 00099 } 00100 animations[num_animations].name = add_string(buf+5); 00101 animations[num_animations].num = num_animations; /* for bsearch */ 00102 animations[num_animations].facings = 1; 00103 } else if (!strncmp(buf, "mina", 4)) { 00104 animations[num_animations].faces = malloc(sizeof(Fontindex)*num_frames); 00105 for (i = 0; i < num_frames; i++) 00106 animations[num_animations].faces[i] = faces[i]; 00107 animations[num_animations].num_animations = num_frames; 00108 if (num_frames%animations[num_animations].facings) { 00109 LOG(llevDebug, "Animation %s frame numbers (%d) is not a multiple of facings (%d)\n", 00110 animations[num_animations].name, num_frames, animations[num_animations].facings); 00111 } 00112 num_frames = 0; 00113 } else if (!strncmp(buf, "facings", 7)) { 00114 if (!(animations[num_animations].facings = atoi(buf+7))) { 00115 LOG(llevDebug, "Animation %s has 0 facings, line=%s\n", 00116 animations[num_animations].name, buf); 00117 animations[num_animations].facings = 1; 00118 } 00119 00120 } else { 00121 if (!(faces[num_frames++] = find_face(buf, 0))) 00122 LOG(llevDebug, "Could not find face %s for animation %s\n", 00123 buf, animations[num_animations].name); 00124 } 00125 } 00126 fclose(fp); 00127 LOG(llevDebug, "done. got (%d)\n", num_animations); 00128 } 00129 00134 static int anim_compare(const Animations *a, const Animations *b) { 00135 return strcmp(a->name, b->name); 00136 } 00137 00146 int find_animation(const char *name) { 00147 int face = try_find_animation(name); 00148 if (!face) 00149 LOG(llevError, "Unable to find animation %s\n", name); 00150 return face; 00151 } 00152 00161 int try_find_animation(const char *name) { 00162 Animations search, *match; 00163 00164 search.name = name; 00165 00166 match = (Animations *)bsearch(&search, animations, (num_animations+1), sizeof(Animations), (int (*)(const void *, const void *))anim_compare); 00167 00168 00169 if (match) 00170 return match->num; 00171 return 0; 00172 } 00173 00186 void animate_object(object *op, int dir) { 00187 int max_state; /* Max animation state object should be drawn in */ 00188 int base_state; /* starting index # to draw from */ 00189 int oldface = op->face->number; 00190 00191 if (!op->animation_id || !NUM_ANIMATIONS(op)) { 00192 StringBuffer *sb; 00193 char *diff; 00194 00195 LOG(llevError, "Object lacks animation.\n"); 00196 sb = stringbuffer_new(); 00197 dump_object(op, sb); 00198 diff = stringbuffer_finish(sb); 00199 LOG(llevError, diff); 00200 free(diff); 00201 return; 00202 } 00203 00204 if (op->head) { 00205 dir = op->head->direction; 00206 00207 if (NUM_ANIMATIONS(op) == NUM_ANIMATIONS(op->head)) 00208 op->state = op->head->state; 00209 } 00210 00211 /* If object is turning, then max animation state is half through the 00212 * animations. Otherwise, we can use all the animations. 00213 */ 00214 max_state = NUM_ANIMATIONS(op)/NUM_FACINGS(op); 00215 base_state = 0; 00216 /* at least in the older aniamtions that used is_turning, the first half 00217 * of the animations were left facing, the second half right facing. 00218 * Note in old the is_turning, it was set so that the animation for a monster 00219 * was always towards the enemy - now it is whatever direction the monster 00220 * is facing. 00221 */ 00222 if (NUM_FACINGS(op) == 2) { 00223 if (dir < 5) 00224 base_state = 0; 00225 else 00226 base_state = NUM_ANIMATIONS(op)/2; 00227 } else if (NUM_FACINGS(op) == 4) { 00228 if (dir == 0) 00229 base_state = 0; 00230 else 00231 base_state = ((dir-1)/2)*(NUM_ANIMATIONS(op)/4); 00232 } else if (NUM_FACINGS(op) == 8) { 00233 if (dir == 0) 00234 base_state = 0; 00235 else 00236 base_state = (dir-1)*(NUM_ANIMATIONS(op)/8); 00237 } 00238 00239 /* If beyond drawable states, reset */ 00240 if (op->state >= max_state) { 00241 op->state = 0; 00242 if (op->temp_animation_id) { 00243 op->temp_animation_id = 0; 00244 /* op->last_anim = 0; */ 00245 /* update_object(op, UP_OBJ_FACE); */ 00246 animate_object(op, dir); 00247 return; 00248 } 00249 } 00250 SET_ANIMATION(op, op->state+base_state); 00251 00252 if (op->face == blank_face) 00253 op->invisible = 1; 00254 00255 /* This block covers monsters (eg, pixies) which are supposed to 00256 * cycle from visible to invisible and back to being visible. 00257 * as such, disable it for players, as then players would become 00258 * visible. 00259 */ 00260 else if (op->type != PLAYER && QUERY_FLAG((&op->arch->clone), FLAG_ALIVE)) { 00261 if (op->face->number == 0) { 00262 op->invisible = 1; 00263 CLEAR_FLAG(op, FLAG_ALIVE); 00264 } else { 00265 op->invisible = 0; 00266 SET_FLAG(op, FLAG_ALIVE); 00267 } 00268 } 00269 00270 if (op->more) 00271 animate_object(op->more, dir); 00272 00273 /* update_object will also recursively update all the pieces. 00274 * as such, we call it last, and only call it for the head 00275 * piece, and not for the other tail pieces. 00276 */ 00277 if (!op->head && (oldface != op->face->number)) 00278 update_object(op, UP_OBJ_FACE); 00279 } 00280 00289 void apply_anim_suffix(object *who, sstring suffix) { 00290 int anim; 00291 object *head, *orig; 00292 char buf[MAX_BUF]; 00293 00294 assert(who); 00295 assert(suffix); 00296 00297 if (who->temp_animation_id != 0) 00298 /* don't overlap animation, let the current one finish. */ 00299 return; 00300 00301 if (who->head != NULL) 00302 head = who->head; 00303 else 00304 head = who; 00305 orig = head; 00306 snprintf(buf, MAX_BUF, "%s_%s", animations[head->animation_id].name, suffix); 00307 anim = try_find_animation(buf); 00308 if (anim) { 00309 for (; head != NULL; head = head->more) { 00310 head->temp_animation_id = anim; 00311 head->temp_anim_speed = animations[anim].num_animations/animations[anim].facings; 00312 head->temp_last_anim = 0; 00313 head->last_anim = 0; 00314 head->state = 0; 00315 } 00316 animate_object(orig, orig->facing); 00317 } 00318 }