--- deliantra/server/common/anim.C 2006/08/30 16:30:36 1.3
+++ deliantra/server/common/anim.C 2010/03/26 00:59:20 1.35
@@ -1,142 +1,88 @@
/*
- * static char *rcsid_anim_c =
- * "$Id: anim.C,v 1.3 2006/08/30 16:30:36 root Exp $";
+ * This file is part of Deliantra, the Roguelike Realtime MMORPG.
+ *
+ * Copyright (©) 2005,2006,2007,2008 Marc Alexander Lehmann / Robin Redeker / the Deliantra team
+ * Copyright (©) 2002-2003 Mark Wedel & Crossfire Development Team
+ * Copyright (©) 1992 Frank Tore Johansen
+ *
+ * Deliantra is free software: you can redistribute it and/or modify it under
+ * the terms of the Affero GNU General Public License as published by the
+ * Free Software Foundation, either version 3 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 Affero GNU General Public License
+ * and the GNU General Public License along with this program. If not, see
+ * .
+ *
+ * The authors can be reached via e-mail to
*/
-/*
- CrossFire, A Multiplayer game for X-windows
+/* This file contains animation related code. */
- Copyright (C) 2002-2003 Mark Wedel & Crossfire Development Team
- Copyright (C) 1992 Frank Tore Johansen
+#include
+#include
- 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.
+static animhash_t animhash;
+std::vector animations;
- The authors can be reached via e-mail at crossfire-devel@real-time.com
-*/
+void
+animation::resize (int new_size)
+{
+ sfree (faces, num_animations);
+ num_animations = new_size;
+ faces = salloc (num_animations);
+}
-/* This file contains animation related code. */
+animation &
+animation::create (const char *name, uint8 frames, uint8 facings)
+{
+ if (animations.size () == MAXANIMNUM)
+ cleanup ("trying to create new animation, but MAXANIMNUM animations in use.");
-#include
-#include
+ animations.push_back (animation ());
+ animation &anim = animations.back ();
-void free_all_anim(void) {
- int i;
+ anim.number = animations.size () - 1;
+ anim.name = name;
+ anim.num_animations = frames;
+ anim.facings = facings;
+ anim.faces = salloc (frames);
- for (i=0; i<=num_animations; i++) {
- free_string(animations[i].name);
- free(animations[i].faces);
- }
- free(animations);
+ animhash.insert (std::make_pair (anim.name, anim.number));
+
+ return anim;
}
-void init_anim(void) {
- char buf[MAX_BUF];
- FILE *fp;
- static int anim_init=0;
- int num_frames=0,faces[MAX_ANIMATIONS],i;
-
- if (anim_init) return;
- animations_allocated=9;
- num_animations=0;
- /* Make a default. New animations start at one, so if something
- * thinks it is animated but hasn't set the animation_id properly,
- * it will have a default value that should be pretty obvious.
- */
- animations = (Animations *) malloc(10*sizeof(Animations));
- /* set the name so we don't try to dereferance null.
- * Put # at start so it will be first in alphabetical
- * order.
- */
- animations[0].name=add_string("###none");
- animations[0].num_animations=1;
- animations[0].faces = (Fontindex *) malloc(sizeof(Fontindex));
- animations[0].faces[0]=0;
- animations[0].facings=0;
-
- sprintf(buf,"%s/animations", settings.datadir);
- LOG(llevDebug,"Reading animations from %s...", buf);
- if ((fp=fopen(buf,"r")) ==NULL) {
- LOG(llevError, "Cannot open animations file %s: %s\n", buf, strerror(errno));
- exit(-1);
- }
- while (fgets(buf, MAX_BUF-1, fp)!=NULL) {
- if (*buf=='#') continue;
- /* Kill the newline */
- buf[strlen(buf)-1] = '\0';
- if (!strncmp(buf,"anim ", 5)) {
- if (num_frames) {
- LOG(llevError,"Didn't get a mina before %s\n", buf);
- num_frames=0;
- }
- num_animations++;
- if (num_animations==animations_allocated) {
- animations= (Animations *) realloc(animations, sizeof(Animations)*(animations_allocated+10));
- animations_allocated+=10;
- }
- animations[num_animations].name = add_string(buf+5);
- animations[num_animations].num = num_animations; /* for bsearch */
- animations[num_animations].facings = 1;
- }
- else if (!strncmp(buf,"mina",4)) {
- animations[num_animations].faces = (Fontindex *) malloc(sizeof(Fontindex)*num_frames);
- for (i=0; isecond];
}
-static int anim_compare(const Animations *a, const Animations *b) {
- return strcmp(a->name, b->name);
+void
+init_anim ()
+{
+ animation &anim0 = animation::create ("none", 1, 0);
+ anim0.faces [0] = 0;
}
/* Tries to find the animation id that matches name. Returns an integer match
- * 0 if no match found (animation 0 is initialized as the 'bug' face
+ * 0 if no match found (animation 0 is initialised as the 'bug' face
*/
-int find_animation(const char *name)
+//TODO: nuke this function and replace all occurences by animations::find
+int
+find_animation (const char *name)
{
- Animations search, *match;
-
- search.name = name;
-
- match = (Animations*)bsearch(&search, animations, (num_animations+1),
- sizeof(Animations), (int (*)(const void*, const void*))anim_compare);
-
-
- if (match) return match->num;
- LOG(llevError,"Unable to find animation %s\n", name);
- return 0;
+ return animation::find (name).number;
}
/*
@@ -148,83 +94,89 @@
* caller has a better idea which one it really wants to be using,
* so let it pass along the right one.
*/
+void
+animate_object (object *op, int dir)
+{
+ int max_state; /* Max animation state object should be drawn in */
+ int base_state; /* starting index # to draw from */
-void animate_object(object *op, int dir) {
- int max_state; /* Max animation state object should be drawn in */
- int base_state; /* starting index # to draw from */
-
- if(!op->animation_id || !NUM_ANIMATIONS(op)) {
- LOG(llevError,"Object lacks animation.\n");
- dump_object(op);
- return;
- }
- if (op->head) {
- dir=op->head->direction;
-
- if (NUM_ANIMATIONS(op) == NUM_ANIMATIONS(op->head))
- op->state = op->head->state;
- else
- ++op->state;
- }
- else {
- ++op->state; /* increase draw state */
- }
-
- /* If object is turning, then max animation state is half through the
- * animations. Otherwise, we can use all the animations.
- */
- max_state=NUM_ANIMATIONS(op)/ NUM_FACINGS(op);
- base_state=0;
- /* at least in the older aniamtions that used is_turning, the first half
- * of the animations were left facing, the second half right facing.
- * Note in old the is_turning, it was set so that the animation for a monster
- * was always towards the enemy - now it is whatever direction the monster
- * is facing.
- */
- if (NUM_FACINGS(op)==2) {
- if (dir<5) base_state=0;
- else base_state=NUM_ANIMATIONS(op)/2;
- }
- else if (NUM_FACINGS(op)==4) {
- if (dir==0) base_state=0;
- else base_state = ((dir-1)/2) * (NUM_ANIMATIONS(op)/4);
- }
- else if (NUM_FACINGS(op)==8) {
- if (dir==0) base_state=0;
- else base_state = (dir-1)*(NUM_ANIMATIONS(op)/8);
- }
-
- /* If beyond drawable states, reset */
- if (op->state>=max_state) op->state=0;
-
- SET_ANIMATION(op, op->state + base_state);
-
- if(op->face==blank_face)
- op->invisible=1;
-
- /* This block covers monsters (eg, pixies) which are supposed to
- * cycle from visible to invisible and back to being visible.
- * as such, disable it for players, as then players would become
- * visible.
- */
- else if(op->type != PLAYER && QUERY_FLAG((&op->arch->clone),FLAG_ALIVE)) {
- if(op->face->number==0) {
- op->invisible=1;
- CLEAR_FLAG(op, FLAG_ALIVE);
- } else {
- op->invisible=0;
- SET_FLAG(op, FLAG_ALIVE);
+ if (!op->animation_id || !NUM_ANIMATIONS (op))
+ {
+ LOG (llevError, "Object %s lacks animation.\n", op->debug_desc ());
+ CLEAR_FLAG (op, FLAG_ANIMATE);
+ return;
+ }
+
+ if (op->head_ () != op)
+ {
+ dir = op->head->direction;
+
+ if (NUM_ANIMATIONS (op) == NUM_ANIMATIONS (op->head))
+ op->state = op->head->state;
+ else
+ ++op->state;
+ }
+ else
+ ++op->state; /* increase draw state */
+
+ /* If object is turning, then max animation state is half through the
+ * animations. Otherwise, we can use all the animations.
+ */
+ max_state = NUM_ANIMATIONS (op) / NUM_FACINGS (op);
+ base_state = 0;
+ /* at least in the older animations that used is_turning, the first half
+ * of the animations were left facing, the second half right facing.
+ * Note in old the is_turning, it was set so that the animation for a monster
+ * was always towards the enemy - now it is whatever direction the monster
+ * is facing.
+ */
+
+ if (dir > 0)
+ switch (NUM_FACINGS (op))
+ {
+ case 2: base_state = ((dir - 1) / (8 / 2)) * (NUM_ANIMATIONS (op) / 2); break;
+ case 4: base_state = ((dir - 1) / (8 / 4)) * (NUM_ANIMATIONS (op) / 4); break;
+ case 8: base_state = ((dir - 1) / (8 / 8)) * (NUM_ANIMATIONS (op) / 8); break;
+ }
+ else
+ base_state = 0;
+
+ /* If beyond drawable states, reset */
+ if (op->state >= max_state)
+ op->state = 0;
+
+ SET_ANIMATION (op, op->state + base_state);
+
+ if (op->face == blank_face)
+ op->invisible = 1;
+
+ /* This block covers monsters (eg, pixies) which are supposed to
+ * cycle from visible to invisible and back to being visible.
+ * as such, disable it for players, as then players would become
+ * visible.
+ */
+ else if (op->type != PLAYER && op->arch->flag [FLAG_ALIVE])
+ {
+ if (op->face == 0)
+ {
+ op->invisible = 1;
+ CLEAR_FLAG (op, FLAG_ALIVE);
+ }
+ else
+ {
+ op->invisible = 0;
+ SET_FLAG (op, FLAG_ALIVE);
}
}
- if(op->more)
- animate_object(op->more, dir);
+ if (op->more)
+ animate_object (op->more, dir);
- /* update_object will also recursively update all the pieces.
- * as such, we call it last, and only call it for the head
- * piece, and not for the other tail pieces.
- */
- if (!op->head)
- update_object(op, UP_OBJ_FACE);
+ /* update_object will also recursively update all the pieces.
+ * as such, we call it last, and only call it for the head
+ * piece, and not for the other tail pieces.
+ */
+ if (op->head_ () == op)
+ update_object (op, UP_OBJ_FACE);
}