|
Atrinik Client 2.5
|
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 }
1.7.4