Atrinik Client 2.5
client/item.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 
00033 static object *free_objects = NULL;
00034 
00038 static object *object_new()
00039 {
00040     object *op = calloc(1, sizeof(object));
00041 
00042     if (!op)
00043     {
00044         LOG(llevError, "object_new(): Out of memory.\n");
00045     }
00046 
00047     return op;
00048 }
00049 
00054 static object *objects_alloc(int nrof)
00055 {
00056     object *op, *list;
00057     int i;
00058 
00059     list = op = object_new();
00060 
00061     for (i = 1; i < nrof; i++)
00062     {
00063         op->next = object_new();
00064         op->next->prev = op;
00065         op = op->next;
00066     }
00067 
00068     return list;
00069 }
00070 
00074 void objects_free(object *op)
00075 {
00076     object *next;
00077 
00078     while (op)
00079     {
00080         if (op->inv)
00081         {
00082             objects_free(op->inv);
00083         }
00084 
00085         next = op->next;
00086         free(op);
00087         op = next;
00088     }
00089 }
00095 object *object_find_object_inv(object *op, sint32 tag)
00096 {
00097     object *tmp;
00098 
00099     for (tmp = op->inv; tmp; tmp = tmp->next)
00100     {
00101         if (tmp->tag == tag)
00102         {
00103             return op;
00104         }
00105     }
00106 
00107     return NULL;
00108 }
00109 
00115 object *object_find_object(object *op, sint32 tag)
00116 {
00117     for (; op; op = op->next)
00118     {
00119         if (op->tag == tag)
00120         {
00121             return op;
00122         }
00123         else if (op->inv)
00124         {
00125             object *tmp = object_find_object(op->inv, tag);
00126 
00127             if (tmp)
00128             {
00129                 return tmp;
00130             }
00131         }
00132     }
00133 
00134     return NULL;
00135 }
00136 
00141 object *object_find(sint32 tag)
00142 {
00143     object *op;
00144 
00145     if (tag == 0)
00146     {
00147         return cpl.below;
00148     }
00149 
00150     if (tag == -1)
00151     {
00152         return cpl.sack;
00153     }
00154 
00155     /* Below the player. */
00156     if (cpl.below)
00157     {
00158         op = object_find_object(cpl.below->inv, tag);
00159 
00160         if (op)
00161         {
00162             return op;
00163         }
00164     }
00165 
00166     /* Open container. */
00167     if (cpl.sack)
00168     {
00169         op = object_find_object(cpl.sack->inv, tag);
00170 
00171         if (op)
00172         {
00173             return op;
00174         }
00175     }
00176 
00177     /* Last attempt, inside the player. */
00178     return object_find_object(cpl.ob, tag);
00179 }
00180 
00184 void object_remove(object *op)
00185 {
00186     if (!op || op == cpl.ob || op == cpl.below || op == cpl.sack)
00187     {
00188         return;
00189     }
00190 
00191     if (op->inv)
00192     {
00193         object_remove_inventory(op);
00194     }
00195 
00196     if (op->prev)
00197     {
00198         op->prev->next = op->next;
00199     }
00200     else
00201     {
00202         op->env->inv = op->next;
00203     }
00204 
00205     if (op->next)
00206     {
00207         op->next->prev = op->prev;
00208     }
00209 
00210     /* Add object to the list of free objects. */
00211     op->next = free_objects;
00212 
00213     if (op->next)
00214     {
00215         op->next->prev = op;
00216     }
00217 
00218     free_objects = op;
00219 
00220     /* Clear the object so it can be reused. */
00221     memset((void *) ((char *) op + offsetof(object, prev)), 0, sizeof(object) - offsetof(object, prev));
00222 }
00223 
00227 void object_remove_inventory(object *op)
00228 {
00229     if (!op)
00230     {
00231         return;
00232     }
00233 
00234     while (op->inv)
00235     {
00236         object_remove(op->inv);
00237     }
00238 }
00239 
00246 static void object_add(object *env, object *op, int bflag)
00247 {
00248     object *tmp;
00249 
00250     if (!op)
00251     {
00252         return;
00253     }
00254 
00255     if (!bflag)
00256     {
00257         op->next = env->inv;
00258 
00259         if (op->next)
00260         {
00261             op->next->prev = op;
00262         }
00263 
00264         op->prev = NULL;
00265         env->inv = op;
00266         op->env = env;
00267     }
00268     else
00269     {
00270         for (tmp = env->inv; tmp && tmp->next; tmp = tmp->next)
00271         {
00272         }
00273 
00274         op->next = NULL;
00275         op->prev = tmp;
00276         op->env = env;
00277 
00278         if (!tmp)
00279         {
00280             env->inv = op;
00281         }
00282         else
00283         {
00284             if (tmp->next)
00285             {
00286                 tmp->next->prev = op;
00287             }
00288 
00289             tmp->next = op;
00290         }
00291     }
00292 }
00293 
00302 object *object_create(object *env, sint32 tag, int bflag)
00303 {
00304     object *op;
00305 
00306     /* Allocate more objects if needed. */
00307     if (!free_objects)
00308     {
00309         free_objects = objects_alloc(NROF_ITEMS);
00310     }
00311 
00312     op = free_objects;
00313     free_objects = free_objects->next;
00314 
00315     if (free_objects)
00316     {
00317         free_objects->prev = NULL;
00318     }
00319 
00320     op->tag = tag;
00321 
00322     if (env)
00323     {
00324         object_add(env, op, bflag);
00325     }
00326 
00327     return op;
00328 }
00329 
00333 void object_set_values(object *op, const char *name, sint32 weight, uint16 face, int flags, uint16 anim, uint16 animspeed, sint32 nrof, uint8 itype, uint8 stype, uint8 qual, uint8 cond, uint8 skill, uint8 level, uint8 dir)
00334 {
00335     if (!op)
00336     {
00337         LOG (-1, "Error in object_set_values(): object pointer is NULL.\n");
00338         return;
00339     }
00340 
00341     if (nrof < 0)
00342     {
00343         op->nrof = 1;
00344         strncpy(op->s_name, "Warning: Old name cmd! This is a bug.", sizeof(op->s_name) - 1);
00345         op->s_name[sizeof(op->s_name) - 1] = '\0';
00346     }
00347     /* we have a nrof - object1 command */
00348     else
00349     {
00350         /* Program always expect at least 1 object internal */
00351         if (nrof == 0)
00352         {
00353             nrof = 1;
00354         }
00355 
00356         op->nrof = nrof;
00357 
00358         if (*name != '\0')
00359         {
00360             strncpy(op->s_name, name, sizeof(op->s_name) - 1);
00361             op->s_name[sizeof(op->s_name) - 1] = '\0';
00362         }
00363     }
00364 
00365     op->weight = (float) weight / 1000;
00366 
00367     if (itype != 254)
00368     {
00369         op->itype = itype;
00370     }
00371 
00372     if (stype != 254)
00373     {
00374         op->stype = stype;
00375     }
00376 
00377     if (qual != 254)
00378     {
00379         op->item_qua = qual;
00380     }
00381 
00382     if (cond != 254)
00383     {
00384         op->item_con = cond;
00385     }
00386 
00387     if (skill != 254)
00388     {
00389         op->item_skill = skill;
00390     }
00391 
00392     if (level != 254)
00393     {
00394         op->item_level = level;
00395     }
00396 
00397     op->face = face;
00398     op->animation_id = anim;
00399     op->anim_speed = animspeed;
00400     op->direction = dir;
00401     op->flags = flags;
00402 }
00403 
00407 void toggle_locked(object *op)
00408 {
00409     SockList sl;
00410     char buf[MAX_BUF];
00411 
00412     /* If object is on the ground, don't lock it. */
00413     if (!op || !op->env || op->env->tag == 0)
00414     {
00415         return;
00416     }
00417 
00418     sl.buf = (unsigned char *) buf;
00419     strcpy((char *) sl.buf, "lock ");
00420     sl.len = 5;
00421     sl.buf[sl.len++] = !(op->flags & F_LOCKED);
00422     SockList_AddInt(&sl, op->tag);
00423     send_socklist(sl);
00424 }
00425 
00429 void object_send_mark(object *op)
00430 {
00431     SockList sl;
00432     char buf[MAX_BUF];
00433 
00434     /* If object is on the ground, don't mark it. */
00435     if (!op || !op->env || op->env->tag == 0)
00436     {
00437         return;
00438     }
00439 
00440     if (cpl.mark_count == op->tag)
00441     {
00442         cpl.mark_count = -1;
00443     }
00444     else
00445     {
00446         cpl.mark_count = op->tag;
00447     }
00448 
00449     sl.buf = (unsigned char *) buf;
00450     strcpy((char *) sl.buf, "mark ");
00451     sl.len = 5;
00452     SockList_AddInt(&sl, op->tag);
00453     send_socklist(sl);
00454 }
00455 
00459 void ready_object(object *op)
00460 {
00461     SockList sl;
00462     char buf[MAX_BUF];
00463 
00464     /* If object is on the ground, don't ready it. */
00465     if (!op || !op->env || op->env->tag == 0)
00466     {
00467         return;
00468     }
00469 
00470     sl.buf = (unsigned char *) buf;
00471     strcpy((char *) sl.buf, "rd ");
00472     sl.len = 3;
00473     SockList_AddInt(&sl, op->tag);
00474     send_socklist(sl);
00475 }
00476 
00480 void objects_init()
00481 {
00482     objects_free(cpl.sack);
00483     objects_free(cpl.below);
00484     objects_free(cpl.ob);
00485 
00486     cpl.ob = object_new();
00487     cpl.below = object_new();
00488     cpl.sack = object_new();
00489 
00490     cpl.below->weight = -111;
00491     cpl.sack->weight = -111;
00492 }
00493 
00498 void update_object(int tag, int loc, const char *name, int weight, int face, int flags, int anim, int animspeed, int nrof, uint8 itype, uint8 stype, uint8 qual, uint8 cond, uint8 skill, uint8 level, uint8 direction, int bflag)
00499 {
00500     object *ip, *env;
00501 
00502     ip = object_find(tag);
00503     env = object_find(loc);
00504 
00505     /* Need to do some special handling if this is the player that is
00506      * being updated. */
00507     if (cpl.ob->tag == tag)
00508     {
00509         cpl.ob->nrof = 1;
00510         cpl.ob->weight = (float) weight / 1000;
00511         cpl.ob->face = face;
00512         cpl.ob->flags = flags;
00513 
00514         cpl.ob->animation_id = anim;
00515         cpl.ob->anim_speed = animspeed;
00516         cpl.ob->nrof = nrof;
00517         cpl.ob->direction = direction;
00518     }
00519     else
00520     {
00521         if (ip && ip->env != env)
00522         {
00523             object_remove(ip);
00524             ip = NULL;
00525         }
00526 
00527         object_set_values(ip ? ip : object_create(env, tag, bflag), name, weight, (uint16) face, flags, (uint16) anim, (uint16) animspeed, nrof, itype, stype, qual, cond, skill, level, direction);
00528     }
00529 }
00530 
00534 static void animate_object(object *ob)
00535 {
00536     if (ob->animation_id > 0)
00537     {
00538         check_animation_status(ob->animation_id);
00539     }
00540 
00541     if (ob->animation_id > 0 && ob->anim_speed)
00542     {
00543         ob->last_anim++;
00544 
00545         if (ob->last_anim >= ob->anim_speed)
00546         {
00547             if (++ob->anim_state >= animations[ob->animation_id].frame)
00548             {
00549                 ob->anim_state = 0;
00550             }
00551 
00552             if (ob->direction > animations[ob->animation_id].facings)
00553             {
00554                 ob->face = animations[ob->animation_id].faces[ob->anim_state];
00555             }
00556             else
00557             {
00558                 ob->face = animations[ob->animation_id].faces[animations[ob->animation_id].frame * ob->direction + ob->anim_state];
00559             }
00560 
00561             ob->last_anim = 0;
00562         }
00563     }
00564 }
00565 
00568 void animate_objects()
00569 {
00570     object *ob;
00571 
00572     if (cpl.ob)
00573     {
00574         /* For now, only the players inventory needs to be animated */
00575         for (ob = cpl.ob->inv; ob; ob = ob->next)
00576         {
00577             animate_object(ob);
00578         }
00579     }
00580 
00581     if (cpl.below)
00582     {
00583         for (ob = cpl.below->inv; ob; ob = ob->next)
00584         {
00585             animate_object(ob);
00586         }
00587     }
00588 
00589     if (cpl.container)
00590     {
00591         for (ob = cpl.sack->inv; ob; ob = ob->next)
00592         {
00593             animate_object(ob);
00594         }
00595     }
00596 }