00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00030 #include <global.h>
00031
00032 #ifndef WIN32
00033 #include <stdio.h>
00034 #include <sys/types.h>
00035 #include <sys/uio.h>
00036 #endif
00037
00038 #include <skillist.h>
00039 #include <loader.h>
00040 #include <sproto.h>
00041
00045 struct mempool_chunk *removed_objects;
00046
00048 object *active_objects;
00049
00050
00051 static int static_walk_semaphore = 0;
00052
00054 object void_container;
00055
00061 static const int reduction_dir[SIZEOFFREE][3] =
00062 {
00063 {0, 0, 0},
00064 {0, 0, 0},
00065 {0, 0, 0},
00066 {0, 0, 0},
00067 {0, 0, 0},
00068 {0, 0, 0},
00069 {0, 0, 0},
00070 {0, 0, 0},
00071 {0, 0, 0},
00072 {8, 1, 2},
00073 {1, 2, -1},
00074 {2, 10, 12},
00075 {2, 3, -1},
00076 {2, 3, 4},
00077 {3, 4, -1},
00078 {4, 14, 16},
00079 {5, 4, -1},
00080 {4, 5, 6},
00081 {6, 5, -1},
00082 {6, 20, 18},
00083 {7, 6, -1},
00084 {6, 7, 8},
00085 {7, 8, -1},
00086 {8, 22, 24},
00087 {8, 1, -1},
00088 {24, 9, 10},
00089 {9, 10, -1},
00090 {10, 11, -1},
00091 {27, 11, 29},
00092 {11, 12, -1},
00093 {12, 13, -1},
00094 {12, 13, 14},
00095 {13, 14, -1},
00096 {14, 15, -1},
00097 {33, 15, 35},
00098 {16, 15, -1},
00099 {17, 16, -1},
00100 {18, 17, 16},
00101 {18, 17, -1},
00102 {18, 19, -1},
00103 {41, 19, 39},
00104 {19, 20, -1},
00105 {20, 21, -1},
00106 {20, 21, 22},
00107 {21, 22, -1},
00108 {23, 22, -1},
00109 {45, 47, 23},
00110 {23, 24, -1},
00111 {24, 9, -1}
00112 };
00113
00115 materialtype material[NROFMATERIALS] =
00116 {
00117 {"paper", {15, 10, 17, 9, 5, 7,13, 0, 20, 15, 0, 0, 0, 0, 0, 10, 0, 0, 0, 0, 0, 0, 0, 0}},
00118 {"metal", {2, 12, 3, 12, 2,10, 7, 0, 20, 15, 0, 0, 0, 0, 0, 10, 0, 0, 0, 0, 0, 0, 0, 0}},
00119 {"crystal", {14, 11, 8, 3, 10, 5, 1, 0, 20, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}},
00120 {"leather", {5, 10, 10, 3, 3, 10,10, 0, 20, 15, 0, 0, 0, 0, 0, 12, 0, 0, 0, 0, 0, 0, 0, 0}},
00121 {"wood", {10, 11, 13, 2, 2, 10, 9, 0, 20, 15, 0, 0, 0, 0, 0, 12, 0, 0, 0, 0, 0, 0, 0, 0}},
00122 {"organics", {3, 12, 9, 11, 3, 10, 9, 0, 20, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}},
00123 {"stone", {2, 5, 2, 2, 2, 2, 1, 0, 20, 15, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0}},
00124 {"cloth", {14, 11, 13, 4, 4, 5, 10, 0, 20, 15, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0}},
00125 {"magic material", {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}},
00126 {"liquid", {0, 8, 9, 6, 17, 0, 15, 0, 20, 15, 12, 0, 0, 0, 0, 11, 0, 0, 0, 0, 0, 0, 0, 0}},
00127 {"soft metal", {6, 12, 6, 14, 2, 10, 1, 0, 20, 15, 0, 0, 0, 0, 0, 10, 0, 0, 0, 0, 0, 0, 0, 0}},
00128 {"bone", {10, 9, 4, 5, 3, 10, 10, 0, 20, 15, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0}},
00129 {"ice", {14, 11, 16, 5, 0, 5, 6, 0, 20, 15, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0}}
00130 };
00131
00132 #define NUM_MATERIALS_REAL NROFMATERIALS * NROFMATERIALS_REAL + 1
00133
00137 material_real_struct material_real[NUM_MATERIALS_REAL];
00138
00139 static void sub_weight(object *op, sint32 weight);
00140 static void remove_ob_inv(object *op);
00141 static void add_weight(object *op, sint32 weight);
00142
00145 void init_materials()
00146 {
00147 int i;
00148 char filename[MAX_BUF], buf[MAX_BUF];
00149 FILE *fp;
00150
00151
00152 for (i = 0; i < NUM_MATERIALS_REAL; i++)
00153 {
00154 material_real[i].name[0] = '\0';
00155 material_real[i].quality = 100;
00156 material_real[i].type = M_NONE;
00157 material_real[i].def_race = RACE_TYPE_NONE;
00158 }
00159
00160 snprintf(filename, sizeof(filename), "%s/materials", settings.datadir);
00161
00162 if (!(fp = fopen(filename, "r")))
00163 {
00164 LOG(llevBug, "BUG: Could not open materials file: %s\n", filename);
00165 }
00166
00167 while (fgets(buf, sizeof(buf), fp))
00168 {
00169 if (buf[0] == '#' || buf[0] == '\n')
00170 {
00171 continue;
00172 }
00173
00174 if (sscanf(buf, "material_real %d\n", &i))
00175 {
00176 int def_race = RACE_TYPE_NONE, type = M_NONE, quality = 100;
00177 char name[MAX_BUF];
00178
00179 if (i > NUM_MATERIALS_REAL)
00180 {
00181 LOG(llevError, "ERROR: Materials file contains declaration for material #%d but it doesn't exist.\n", i);
00182 }
00183
00184 name[0] = '\0';
00185
00186 while (fgets(buf, sizeof(buf), fp))
00187 {
00188 if (strcmp(buf, "end\n") == 0)
00189 {
00190 break;
00191 }
00192
00193 if (!sscanf(buf, "quality %d\n", &quality) && !sscanf(buf, "type %d\n", &type) && !sscanf(buf, "def_race %d\n", &def_race) && !sscanf(buf, "name %[^\n]", name))
00194 {
00195 LOG(llevError, "ERROR: Bogus line in materials file: %s\n", buf);
00196 }
00197 }
00198
00199 if (name[0] != '\0')
00200 {
00201 snprintf(material_real[i].name, sizeof(material_real[i].name), "%s ", name);
00202 }
00203
00204 material_real[i].quality = quality;
00205 material_real[i].type = type;
00206 material_real[i].def_race = def_race;
00207 }
00208 else
00209 {
00210 LOG(llevError, "ERROR: Bogus line in materials file: %s\n", buf);
00211 }
00212 }
00213
00214 fclose(fp);
00215 }
00216
00218 int freearr_x[SIZEOFFREE] =
00219 {
00220 0, 0, 1, 1, 1, 0, -1, -1, -1, 0, 1, 2, 2, 2, 2, 2, 1, 0, -1, -2, -2, -2, -2, -2, -1,
00221 0, 1, 2, 3, 3, 3, 3, 3, 3, 3, 2, 1, 0, -1, -2, -3, -3, -3, -3, -3, -3, -3, -2, -1
00222 };
00223
00225 int freearr_y[SIZEOFFREE] =
00226 {
00227 0, -1, -1, 0, 1, 1, 1, 0, -1, -2, -2, -2, -1, 0, 1, 2, 2, 2, 2, 2, 1, 0, -1, -2, -2,
00228 -3, -3, -3, -3, -2, -1, 0, 1, 2, 3, 3, 3, 3, 3, 3, 3, 2, 1, 0, -1, -2, -3, -3, -3
00229 };
00230
00232 int maxfree[SIZEOFFREE] =
00233 {
00234 0, 9, 10, 13, 14, 17, 18, 21, 22, 25, 26, 27, 30, 31, 32, 33, 36, 37, 39, 39, 42, 43, 44, 45,
00235 48, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49
00236 };
00237
00239 int freedir[SIZEOFFREE] =
00240 {
00241 0, 1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 2, 2, 3, 4, 4, 4, 5, 6, 6, 6, 7, 8, 8, 8,
00242 1, 2, 2, 2, 2, 2, 3, 4, 4, 4, 4, 4, 5, 6, 6, 6, 6, 6, 7, 8, 8, 8, 8, 8
00243 };
00244
00251 void mark_object_removed(object *ob)
00252 {
00253 struct mempool_chunk *mem = MEM_POOLDATA(ob);
00254
00255 if (OBJECT_FREE(ob))
00256 {
00257 LOG(llevBug, "BUG: mark_object_removed() called for free object\n");
00258 }
00259
00260 SET_FLAG(ob, FLAG_REMOVED);
00261
00262
00263 if (mem->next != NULL)
00264 {
00265 return;
00266 }
00267
00268 mem->next = removed_objects;
00269 removed_objects = mem;
00270 }
00271
00274 void object_gc()
00275 {
00276 struct mempool_chunk *current, *next;
00277 object *ob;
00278
00279 while ((next = removed_objects) != &end_marker)
00280 {
00281
00282 removed_objects = &end_marker;
00283
00284 while (next != &end_marker)
00285 {
00286 current = next;
00287 next = current->next;
00288 current->next = NULL;
00289
00290 ob = (object *) MEM_USERDATA(current);
00291
00292 if (QUERY_FLAG(ob, FLAG_REMOVED))
00293 {
00294 if (OBJECT_FREE(ob))
00295 {
00296 LOG(llevBug, "BUG: Freed object in remove list: %s\n", STRING_OBJ_NAME(ob));
00297 }
00298 else
00299 {
00300 return_poolchunk(ob, pool_object);
00301 }
00302 }
00303 }
00304 }
00305 }
00306
00313 static int compare_ob_value_lists_one(const object *wants, const object *has)
00314 {
00315 key_value *wants_field;
00316
00317
00318 for (wants_field = wants->key_values; wants_field; wants_field = wants_field->next)
00319 {
00320 key_value *has_field = object_get_key_link(has, wants_field->key);
00321
00322 if (has_field == NULL)
00323 {
00324 return 0;
00325 }
00326
00327
00328 if (has_field->value != wants_field->value)
00329 {
00330 return 0;
00331 }
00332 }
00333
00334 return 1;
00335 }
00336
00342 static int compare_ob_value_lists(const object *ob1, const object *ob2)
00343 {
00344 return compare_ob_value_lists_one(ob1, ob2) && compare_ob_value_lists_one(ob2, ob1);
00345 }
00346
00366 int CAN_MERGE(object *ob1, object *ob2)
00367 {
00368 if (!QUERY_FLAG(ob1, FLAG_CAN_STACK))
00369 {
00370 return 0;
00371 }
00372
00373
00374 if (ob1->type == MONEY && ob1->type == ob2->type && ob1->arch == ob2->arch)
00375 {
00376 return 1;
00377 }
00378
00379
00380
00381
00382
00383
00384
00385
00386 if (((!ob1->nrof || !ob2->nrof) && ob1->type != EVENT_OBJECT) || ob1->glow_radius || ob2->glow_radius)
00387 {
00388 return 0;
00389 }
00390
00391
00392
00393 if (ob1->type != ob2->type || ob1 == ob2 || ob1->arch != ob2->arch || ob1->sub_type1 != ob2->sub_type1 || ob1->material != ob2->material || ob1->material_real != ob2->material_real || ob1->magic != ob2->magic || ob1->item_quality != ob2->item_quality || ob1->item_condition != ob2->item_condition || ob1->item_race != ob2->item_race || ob1->speed != ob2->speed || ob1->value !=ob2->value || ob1->weight != ob2->weight)
00394 {
00395 return 0;
00396 }
00397
00398
00399
00400
00401 if (ob1->inv || ob2->inv)
00402 {
00403 object *tmp1, *tmp2;
00404
00405 if (!ob1->inv || !ob2->inv)
00406 {
00407 return 0;
00408 }
00409
00410
00411 for (tmp1 = ob1->inv, tmp2 = ob2->inv; tmp1 && tmp2; tmp1 = tmp1->below, tmp2 = tmp2->below)
00412 {
00413 if (tmp1->type != EVENT_OBJECT || tmp2->type != EVENT_OBJECT)
00414 {
00415 return 0;
00416 }
00417 }
00418
00419
00420 if (tmp1 || tmp2)
00421 {
00422 return 0;
00423 }
00424
00425 for (tmp1 = ob1->inv; tmp1; tmp1 = tmp1->below)
00426 {
00427 for (tmp2 = ob2->inv; tmp2; tmp2 = tmp2->below)
00428 {
00429 if (CAN_MERGE(tmp1, tmp2))
00430 {
00431 break;
00432 }
00433 }
00434
00435
00436 if (!tmp2)
00437 {
00438 return 0;
00439 }
00440 }
00441 }
00442
00443
00444 if (ob1->name != ob2->name || ob1->title != ob2->title || ob1->race != ob2->race || ob1->slaying != ob2->slaying || ob1->msg != ob2->msg || ob1->artifact != ob2->artifact)
00445 {
00446 return 0;
00447 }
00448
00449
00450 if ((memcmp(&ob1->stats, &ob2->stats, sizeof(living)) != 0) || (memcmp(&ob1->resist, &ob2->resist, sizeof(ob1->resist)) != 0) || (memcmp(&ob1->attack, &ob2->attack, sizeof(ob1->attack)) != 0) || (memcmp(&ob1->protection, &ob2->protection, sizeof(ob1->protection)) != 0))
00451 {
00452 return 0;
00453 }
00454
00455
00456 if (ob1->randomitems != ob2->randomitems || ob1->other_arch != ob2->other_arch || (ob1->flags[0] | 0x300) != (ob2->flags[0] | 0x300) || ob1->flags[1] != ob2->flags[1] || ob1->flags[2] != ob2->flags[2] || ob1->flags[3] != ob2->flags[3] || ob1->path_attuned != ob2->path_attuned || ob1->path_repelled != ob2->path_repelled || ob1->path_denied != ob2->path_denied || ob1->terrain_type != ob2->terrain_type || ob1->terrain_flag != ob2->terrain_flag || ob1->weapon_speed != ob2->weapon_speed || ob1->magic != ob2->magic || ob1->item_level != ob2->item_level || ob1->item_skill != ob2->item_skill || ob1->glow_radius != ob2->glow_radius || ob1->level != ob2->level)
00457 {
00458 return 0;
00459 }
00460
00461
00462 if (ob1->face != ob2->face || ob1->inv_face != ob2->inv_face || ob1->animation_id != ob2->animation_id || ob1->inv_animation_id != ob2->inv_animation_id)
00463 {
00464 return 0;
00465 }
00466
00467
00468 if (ob1->type == CONTAINER)
00469 {
00470 return 0;
00471 }
00472
00473
00474 if (ob1->key_values != NULL || ob2->key_values != NULL)
00475 {
00476
00477 if ((ob1->key_values == NULL) != (ob2->key_values == NULL))
00478 {
00479 return 0;
00480 }
00481 else
00482 {
00483 return compare_ob_value_lists(ob1, ob2);
00484 }
00485 }
00486
00487
00488 return 1;
00489 }
00490
00498 object *merge_ob(object *op, object *top)
00499 {
00500 if (!op->nrof)
00501 {
00502 return 0;
00503 }
00504
00505 if (top == NULL)
00506 {
00507 for (top = op; top != NULL && top->above != NULL; top = top->above)
00508 {
00509 }
00510 }
00511
00512 for (; top != NULL; top = top->below)
00513 {
00514 if (top == op)
00515 {
00516 continue;
00517 }
00518
00519 if (CAN_MERGE(op,top))
00520 {
00521 top->nrof += op->nrof;
00522
00523
00524 op->weight = 0;
00525
00526
00527 remove_ob(op);
00528
00529 return top;
00530 }
00531 }
00532
00533 return NULL;
00534 }
00535
00543 signed long sum_weight(object *op)
00544 {
00545 sint32 sum;
00546 object *inv;
00547
00548 for (sum = 0, inv = op->inv; inv != NULL; inv = inv->below)
00549 {
00550 if (inv->inv)
00551 {
00552 sum_weight(inv);
00553 }
00554
00555 sum += inv->carrying + (inv->nrof ? inv->weight * (int) inv->nrof : inv->weight);
00556 }
00557
00558
00559
00560
00561
00562
00563 if (op->type == CONTAINER && op->weapon_speed != 1.0f)
00564 {
00565 sum = (sint32) ((float) sum * op->weapon_speed);
00566 }
00567
00568 op->carrying = sum;
00569
00570 return sum;
00571 }
00572
00578 static void add_weight(object *op, sint32 weight)
00579 {
00580 while (op != NULL)
00581 {
00582
00583 if (op->type == CONTAINER && op->weapon_speed != 1.0f)
00584 {
00585 weight = (sint32) ((float) weight * op->weapon_speed);
00586 }
00587
00588 op->carrying += weight;
00589
00590 if (op->env && op->env->type == PLAYER)
00591 {
00592 esrv_update_item(UPD_WEIGHT, op->env, op);
00593 }
00594
00595 op = op->env;
00596 }
00597 }
00598
00604 static void sub_weight(object *op, sint32 weight)
00605 {
00606 while (op != NULL)
00607 {
00608
00609 if (op->type == CONTAINER && op->weapon_speed != 1.0f)
00610 {
00611 weight = (sint32) ((float) weight * op->weapon_speed);
00612 }
00613
00614 op->carrying -= weight;
00615
00616 if (op->env && op->env->type == PLAYER)
00617 {
00618 esrv_update_item(UPD_WEIGHT, op->env, op);
00619 }
00620
00621 op = op->env;
00622 }
00623 }
00624
00629 object *is_player_inv(object *op)
00630 {
00631 for (; op != NULL && op->type != PLAYER; op = op->env)
00632 {
00633 if (op->env == op)
00634 {
00635 op->env = NULL;
00636 }
00637 }
00638
00639 return op;
00640 }
00641
00647 void dump_object(object *op, StringBuffer *sb)
00648 {
00649 if (op == NULL)
00650 {
00651 stringbuffer_append_string(sb, "[NULL pointer]");
00652 return;
00653 }
00654
00655 if (op->arch != NULL)
00656 {
00657 stringbuffer_append_printf(sb, "arch %s\n", op->arch->name ? op->arch->name : "(null)");
00658 get_ob_diff(sb, op, &empty_archetype->clone);
00659 stringbuffer_append_string(sb, "end\n");
00660 }
00661 else
00662 {
00663 stringbuffer_append_string(sb, "Object ");
00664 stringbuffer_append_string(sb, op->name == NULL ? "(null)" : op->name);
00665 stringbuffer_append_string(sb, "\nend\n");
00666 }
00667 }
00668
00671 void free_all_object_data()
00672 {
00673 LOG(llevDebug, "%d allocated objects, %d free objects\n", pool_object->nrof_allocated, pool_object->nrof_free);
00674 }
00675
00686 object *get_owner(object *op)
00687 {
00688 if (!op || op->owner == NULL)
00689 {
00690 return NULL;
00691 }
00692
00693 if (!OBJECT_FREE(op) && op->owner->count == op->ownercount)
00694 {
00695 return op->owner;
00696 }
00697
00698 op->owner = NULL, op->ownercount = 0;
00699
00700 return NULL;
00701 }
00702
00706 void clear_owner(object *op)
00707 {
00708 if (!op)
00709 {
00710 return;
00711 }
00712
00713 op->owner = NULL;
00714 op->ownercount = 0;
00715 }
00716
00725 static void set_owner_simple(object *op, object *owner)
00726 {
00727
00728
00729
00730
00731
00732
00733 while (owner->owner && owner != owner->owner && owner->ownercount == owner->owner->count)
00734 {
00735 owner = owner->owner;
00736 }
00737
00738
00739
00740 if (owner->owner)
00741 {
00742 return;
00743 }
00744
00745 op->owner = owner;
00746 op->ownercount = owner->count;
00747 }
00748
00749 static void set_skill_pointers(object *op, object *chosen_skill, object *exp_obj)
00750 {
00751 op->chosen_skill = chosen_skill;
00752 op->exp_obj = exp_obj;
00753
00754
00755
00756
00757
00758 CLEAR_FLAG(op, FLAG_CAN_USE_SKILL);
00759 CLEAR_FLAG(op, FLAG_READY_SKILL);
00760 }
00761
00767 void set_owner(object *op, object *owner)
00768 {
00769 if (owner == NULL || op == NULL)
00770 {
00771 return;
00772 }
00773
00774 set_owner_simple(op, owner);
00775
00776 if (owner->type == PLAYER && owner->chosen_skill)
00777 {
00778 set_skill_pointers(op, owner->chosen_skill, owner->chosen_skill->exp_obj);
00779 }
00780 else if (op->type != PLAYER)
00781 {
00782 CLEAR_FLAG(op, FLAG_READY_SKILL);
00783 }
00784 }
00785
00798 void copy_owner(object *op, object *clone)
00799 {
00800 object *owner = get_owner(clone);
00801
00802 if (owner == NULL)
00803 {
00804
00805
00806 if (clone->type == PLAYER)
00807 {
00808 owner = clone;
00809 }
00810 else
00811 {
00812 return;
00813 }
00814 }
00815
00816 set_owner_simple(op, owner);
00817
00818 if (clone->chosen_skill)
00819 {
00820 set_skill_pointers(op, clone->chosen_skill, clone->exp_obj);
00821 }
00822 else if (op->type != PLAYER)
00823 {
00824 CLEAR_FLAG(op, FLAG_READY_SKILL);
00825 }
00826 }
00827
00832 void initialize_object(object *op)
00833 {
00834
00835
00836 FREE_ONLY_HASH(op->name);
00837 FREE_ONLY_HASH(op->title);
00838 FREE_ONLY_HASH(op->race);
00839 FREE_ONLY_HASH(op->slaying);
00840 FREE_ONLY_HASH(op->msg);
00841 FREE_ONLY_HASH(op->artifact);
00842
00843
00844
00845 memset(op, 0, sizeof(object));
00846
00847
00848
00849 op->anim_enemy_dir = -1;
00850
00851 op->anim_moving_dir = -1;
00852 op->anim_enemy_dir_last = -1;
00853 op->anim_moving_dir_last = -1;
00854 op->anim_last_facing = 4;
00855 op->anim_last_facing_last = -1;
00856
00857 op->face = blank_face;
00858 op->attacked_by_count = -1;
00859
00860
00861 op->count = ++ob_count;
00862 }
00863
00870 void copy_object(object *op2, object *op)
00871 {
00872 int is_removed = QUERY_FLAG(op, FLAG_REMOVED);
00873
00874 FREE_ONLY_HASH(op->name);
00875 FREE_ONLY_HASH(op->title);
00876 FREE_ONLY_HASH(op->race);
00877 FREE_ONLY_HASH(op->slaying);
00878 FREE_ONLY_HASH(op->msg);
00879 FREE_ONLY_HASH(op->artifact);
00880
00881 free_key_values(op);
00882
00883 (void) memcpy((void *)((char *) op + offsetof(object, name)), (void *)((char *) op2 + offsetof(object, name)), sizeof(object) - offsetof(object, name));
00884
00885 if (is_removed)
00886 {
00887 SET_FLAG(op, FLAG_REMOVED);
00888 }
00889
00890 ADD_REF_NOT_NULL_HASH(op->name);
00891 ADD_REF_NOT_NULL_HASH(op->title);
00892 ADD_REF_NOT_NULL_HASH(op->race);
00893 ADD_REF_NOT_NULL_HASH(op->slaying);
00894 ADD_REF_NOT_NULL_HASH(op->msg);
00895 ADD_REF_NOT_NULL_HASH(op->artifact);
00896
00897 if (QUERY_FLAG(op, FLAG_IDENTIFIED))
00898 {
00899 SET_FLAG(op, FLAG_KNOWN_MAGICAL);
00900 SET_FLAG(op, FLAG_KNOWN_CURSED);
00901 }
00902
00903
00904 if (op->speed < 0 && op->speed_left == op->arch->clone.speed_left)
00905 {
00906 op->speed_left += (RANDOM() % 90) / 100.0f;
00907 }
00908
00909
00910 if (op2->key_values)
00911 {
00912 key_value *tail = NULL, *i;
00913
00914 op->key_values = NULL;
00915
00916 for (i = op2->key_values; i; i = i->next)
00917 {
00918 key_value *new_link = malloc(sizeof(key_value));
00919
00920 new_link->next = NULL;
00921 new_link->key = add_refcount(i->key);
00922
00923 if (i->value)
00924 {
00925 new_link->value = add_refcount(i->value);
00926 }
00927 else
00928 {
00929 new_link->value = NULL;
00930 }
00931
00932
00933 if (op->key_values == NULL)
00934 {
00935 op->key_values = new_link;
00936 tail = new_link;
00937 }
00938 else
00939 {
00940 tail->next = new_link;
00941 tail = new_link;
00942 }
00943 }
00944 }
00945
00946 update_ob_speed(op);
00947 }
00948
00953 void copy_object_data(object *op2, object *op)
00954 {
00955 int is_removed = QUERY_FLAG(op, FLAG_REMOVED);
00956
00957 FREE_ONLY_HASH(op->name);
00958 FREE_ONLY_HASH(op->title);
00959 FREE_ONLY_HASH(op->race);
00960 FREE_ONLY_HASH(op->slaying);
00961 FREE_ONLY_HASH(op->msg);
00962 FREE_ONLY_HASH(op->artifact);
00963
00964 free_key_values(op);
00965
00966 (void) memcpy((void *)((char *) op + offsetof(object, name)), (void *)((char *) op2 + offsetof(object, name)), sizeof(object) - offsetof(object, name));
00967
00968 if (is_removed)
00969 {
00970 SET_FLAG(op, FLAG_REMOVED);
00971 }
00972
00973 ADD_REF_NOT_NULL_HASH(op->name);
00974 ADD_REF_NOT_NULL_HASH(op->title);
00975 ADD_REF_NOT_NULL_HASH(op->race);
00976 ADD_REF_NOT_NULL_HASH(op->slaying);
00977 ADD_REF_NOT_NULL_HASH(op->msg);
00978 ADD_REF_NOT_NULL_HASH(op->artifact);
00979
00980 if (QUERY_FLAG(op, FLAG_IDENTIFIED))
00981 {
00982 SET_FLAG(op, FLAG_KNOWN_MAGICAL);
00983 SET_FLAG(op, FLAG_KNOWN_CURSED);
00984 }
00985
00986
00987 if (op2->key_values)
00988 {
00989 key_value *tail = NULL, *i;
00990
00991 op->key_values = NULL;
00992
00993 for (i = op2->key_values; i; i = i->next)
00994 {
00995 key_value *new_link = malloc(sizeof(key_value));
00996
00997 new_link->next = NULL;
00998 new_link->key = add_refcount(i->key);
00999
01000 if (i->value)
01001 {
01002 new_link->value = add_refcount(i->value);
01003 }
01004 else
01005 {
01006 new_link->value = NULL;
01007 }
01008
01009
01010 if (op->key_values == NULL)
01011 {
01012 op->key_values = new_link;
01013 tail = new_link;
01014 }
01015 else
01016 {
01017 tail->next = new_link;
01018 tail = new_link;
01019 }
01020 }
01021 }
01022 }
01023
01030 object *get_object()
01031 {
01032 object *new_obj = (object *) get_poolchunk(pool_object);
01033
01034 mark_object_removed(new_obj);
01035
01036 return new_obj;
01037 }
01038
01045 void update_turn_face(object *op)
01046 {
01047 if (!QUERY_FLAG(op, FLAG_IS_TURNABLE) || op->arch == NULL)
01048 {
01049 return;
01050 }
01051
01052 SET_ANIMATION(op, (NUM_ANIMATIONS(op) / NUM_FACINGS(op)) * op->direction);
01053 update_object(op, UP_OBJ_FACE);
01054 }
01055
01061 void update_ob_speed(object *op)
01062 {
01063 extern int arch_init;
01064
01065
01066
01067 if (OBJECT_FREE(op) && op->speed)
01068 {
01069 LOG(llevBug, "BUG: Object %s is freed but has speed.\n", op->name);
01070 op->speed = 0;
01071 }
01072
01073 if (arch_init)
01074 {
01075 return;
01076 }
01077
01078
01079
01080 if (op->type == SPAWN_POINT_MOB)
01081 {
01082 return;
01083 }
01084
01085 if (FABS(op->speed) > MIN_ACTIVE_SPEED)
01086 {
01087
01088 if (op->active_next || op->active_prev || op == active_objects)
01089 {
01090 return;
01091 }
01092
01093
01094
01095 op->active_next = active_objects;
01096
01097 if (op->active_next != NULL)
01098 {
01099 op->active_next->active_prev = op;
01100 }
01101
01102 active_objects = op;
01103 op->active_prev = NULL;
01104 }
01105 else
01106 {
01107
01108 if (!op->active_next && !op->active_prev && op != active_objects)
01109 {
01110 return;
01111 }
01112
01113 if (op->active_prev == NULL)
01114 {
01115 active_objects = op->active_next;
01116
01117 if (op->active_next != NULL)
01118 {
01119 op->active_next->active_prev = NULL;
01120 }
01121 }
01122 else
01123 {
01124 op->active_prev->active_next = op->active_next;
01125
01126 if (op->active_next)
01127 {
01128 op->active_next->active_prev = op->active_prev;
01129 }
01130 }
01131
01132 op->active_next = NULL;
01133 op->active_prev = NULL;
01134 }
01135 }
01136
01149 void update_object(object *op, int action)
01150 {
01151 MapSpace *msp;
01152 int flags, newflags;
01153
01154 if (op == NULL)
01155 {
01156 LOG(llevError, "ERROR: update_object() called for NULL object.\n");
01157 return;
01158 }
01159
01160 if (op->env != NULL || !op->map || op->map->in_memory == MAP_SAVING)
01161 {
01162 return;
01163 }
01164
01165
01166 if (action == UP_OBJ_FACE)
01167 {
01168 INC_MAP_UPDATE_COUNTER(op->map, op->x, op->y);
01169 return;
01170 }
01171
01172 msp = GET_MAP_SPACE_PTR(op->map, op->x, op->y);
01173 newflags = msp->flags;
01174 flags = newflags & ~P_NEED_UPDATE;
01175
01176
01177 if (action == UP_OBJ_INSERT)
01178 {
01179
01180 newflags |= P_NEED_UPDATE;
01181 msp->update_tile++;
01182
01183
01184 if (op->glow_radius)
01185 {
01186 adjust_light_source(op->map, op->x, op->y, op->glow_radius);
01187 }
01188
01189
01190 if (QUERY_FLAG(op, FLAG_NO_PASS) || QUERY_FLAG(op, FLAG_PASS_THRU))
01191 {
01192 newflags |= P_FLAGS_UPDATE;
01193 }
01194
01195 else if (QUERY_FLAG(op, FLAG_IS_FLOOR))
01196 {
01197 newflags |= P_FLAGS_UPDATE;
01198 msp->light_value += op->last_sp;
01199 }
01200
01201 else
01202 {
01203 if (op->type == CHECK_INV)
01204 {
01205 newflags |= P_CHECK_INV;
01206 }
01207 else if (op->type == MAGIC_EAR)
01208 {
01209 newflags|= P_MAGIC_EAR;
01210 }
01211
01212 if (QUERY_FLAG(op, FLAG_ALIVE))
01213 {
01214 newflags |= P_IS_ALIVE;
01215 }
01216
01217 if (QUERY_FLAG(op, FLAG_IS_PLAYER))
01218 {
01219 newflags |= P_IS_PLAYER;
01220 }
01221
01222 if (QUERY_FLAG(op, FLAG_PLAYER_ONLY))
01223 {
01224 newflags |= P_PLAYER_ONLY;
01225 }
01226
01227 if (QUERY_FLAG(op, FLAG_BLOCKSVIEW))
01228 {
01229 newflags |= P_BLOCKSVIEW;
01230 }
01231
01232 if (QUERY_FLAG(op, FLAG_NO_MAGIC))
01233 {
01234 newflags |= P_NO_MAGIC;
01235 }
01236
01237 if (QUERY_FLAG(op, FLAG_NO_CLERIC))
01238 {
01239 newflags |= P_NO_CLERIC;
01240 }
01241
01242 if (QUERY_FLAG(op, FLAG_WALK_ON))
01243 {
01244 newflags |= P_WALK_ON;
01245 }
01246
01247 if (QUERY_FLAG(op, FLAG_FLY_ON))
01248 {
01249 newflags |= P_FLY_ON;
01250 }
01251
01252 if (QUERY_FLAG(op, FLAG_WALK_OFF))
01253 {
01254 newflags |= P_WALK_OFF;
01255 }
01256
01257 if (QUERY_FLAG(op, FLAG_FLY_OFF))
01258 {
01259 newflags |= P_FLY_OFF;
01260 }
01261
01262 if (QUERY_FLAG(op, FLAG_DOOR_CLOSED))
01263 {
01264 newflags |= P_DOOR_CLOSED;
01265 }
01266
01267 if (QUERY_FLAG(op, FLAG_CAN_REFL_SPELL))
01268 {
01269 newflags |= P_REFL_SPELLS;
01270 }
01271
01272 if (QUERY_FLAG(op, FLAG_CAN_REFL_MISSILE))
01273 {
01274 newflags |= P_REFL_MISSILE;
01275 }
01276 }
01277 }
01278 else if (action == UP_OBJ_REMOVE)
01279 {
01280
01281 newflags |= P_NEED_UPDATE;
01282 msp->update_tile++;
01283
01284
01285 if (op->glow_radius)
01286 {
01287 adjust_light_source(op->map, op->x, op->y, -(op->glow_radius));
01288 }
01289
01290
01291 if (QUERY_FLAG(op, FLAG_ALIVE) || QUERY_FLAG(op, FLAG_IS_PLAYER) || QUERY_FLAG(op, FLAG_BLOCKSVIEW) || QUERY_FLAG(op, FLAG_DOOR_CLOSED) || QUERY_FLAG(op, FLAG_PASS_THRU) || QUERY_FLAG(op, FLAG_NO_PASS) || QUERY_FLAG(op, FLAG_PLAYER_ONLY) || QUERY_FLAG(op, FLAG_NO_MAGIC) || QUERY_FLAG(op, FLAG_NO_CLERIC) || QUERY_FLAG(op, FLAG_WALK_ON) || QUERY_FLAG(op, FLAG_FLY_ON) || QUERY_FLAG(op, FLAG_WALK_OFF) || QUERY_FLAG(op, FLAG_FLY_OFF) || QUERY_FLAG(op, FLAG_CAN_REFL_SPELL) || QUERY_FLAG(op, FLAG_CAN_REFL_MISSILE) || QUERY_FLAG(op, FLAG_IS_FLOOR) || op->type == CHECK_INV || op->type == MAGIC_EAR)
01292 {
01293 newflags |= P_FLAGS_UPDATE;
01294 }
01295 }
01296 else if (action == UP_OBJ_FLAGS)
01297 {
01298
01299 newflags |= P_FLAGS_UPDATE;
01300 }
01301 else if (action == UP_OBJ_FLAGFACE)
01302 {
01303
01304 newflags |= P_FLAGS_UPDATE;
01305 msp->update_tile++;
01306 }
01307 else if (action == UP_OBJ_LAYER)
01308 {
01309
01310 newflags |= P_NEED_UPDATE;
01311 msp->update_tile++;
01312 }
01313 else if (action == UP_OBJ_ALL)
01314 {
01315
01316 newflags |= (P_FLAGS_UPDATE | P_NEED_UPDATE);
01317 msp->update_tile++;
01318 }
01319 else
01320 {
01321 LOG(llevError, "ERROR: update_object called with invalid action: %d\n", action);
01322 return;
01323 }
01324
01325 if (flags != newflags)
01326 {
01327
01328 if (newflags & (P_FLAGS_UPDATE))
01329 {
01330 msp->flags |= (newflags | P_NO_ERROR | P_FLAGS_ONLY);
01331 update_position(op->map, op->x, op->y);
01332 }
01333 else
01334 {
01335 msp->flags |= newflags;
01336 }
01337 }
01338
01339 if (op->more != NULL)
01340 {
01341 update_object(op->more, action);
01342 }
01343 }
01344
01351 void drop_ob_inv(object *ob)
01352 {
01353 object *corpse = NULL, *enemy = NULL, *tmp_op = NULL, *tmp = NULL;
01354
01355
01356 if (ob->type == PLAYER)
01357 {
01358 LOG(llevBug, "BUG: drop_ob_inv() - tried to drop items of %s\n", ob->name);
01359 return;
01360 }
01361
01362
01363 if (ob->env == NULL && (ob->map == NULL || ob->map->in_memory != MAP_IN_MEMORY))
01364 {
01365 LOG(llevDebug, "BUG: drop_ob_inv() - can't drop inventory of objects not in map yet: %s (%x)\n", ob->name, ob->map);
01366 return;
01367 }
01368
01369 if (ob->enemy && ob->enemy->type == PLAYER)
01370 {
01371 enemy = ob->enemy;
01372 }
01373 else
01374 {
01375 enemy = get_owner(ob->enemy);
01376 }
01377
01378
01379 if ((QUERY_FLAG(ob, FLAG_CORPSE) && !QUERY_FLAG(ob, FLAG_STARTEQUIP)) || QUERY_FLAG(ob, FLAG_CORPSE_FORCED))
01380 {
01381 racelink *race_corpse = find_racelink(ob->race);
01382
01383 if (race_corpse)
01384 {
01385 corpse = arch_to_object(race_corpse->corpse);
01386 corpse->x = ob->x;
01387 corpse->y = ob->y;
01388 corpse->map = ob->map;
01389 corpse->weight = ob->weight;
01390 }
01391 }
01392
01393 tmp_op = ob->inv;
01394
01395 while (tmp_op != NULL)
01396 {
01397 tmp = tmp_op->below;
01398
01399 remove_ob(tmp_op);
01400
01401 if (tmp_op->type == QUEST_CONTAINER)
01402 {
01403
01404 if (enemy && enemy->type == PLAYER && enemy->count == ob->enemy_count)
01405 {
01406 check_quest(enemy, tmp_op);
01407 }
01408 }
01409 else if (!(QUERY_FLAG(ob, FLAG_STARTEQUIP) || (tmp_op->type != RUNE && (QUERY_FLAG(tmp_op, FLAG_SYS_OBJECT) || QUERY_FLAG(tmp_op, FLAG_STARTEQUIP) || QUERY_FLAG(tmp_op, FLAG_NO_DROP)))))
01410 {
01411 tmp_op->x = ob->x, tmp_op->y = ob->y;
01412
01413
01414 CLEAR_FLAG(tmp_op, FLAG_APPLIED);
01415 CLEAR_FLAG(tmp_op, FLAG_BEEN_APPLIED);
01416
01417
01418 if (corpse)
01419 {
01420 insert_ob_in_ob(tmp_op, corpse);
01421 }
01422 else
01423 {
01424
01425
01426
01427
01428 if (tmp_op->type != RUNE)
01429 {
01430 if (ob->env)
01431 {
01432 insert_ob_in_ob(tmp_op, ob->env);
01433
01434
01435 if (ob->env->type == PLAYER)
01436 {
01437 esrv_send_item(ob->env, tmp_op);
01438 }
01439 else if (ob->env->type == CONTAINER)
01440 {
01441 esrv_send_item(ob->env, tmp_op);
01442 }
01443 }
01444
01445 else
01446 {
01447 insert_ob_in_map(tmp_op, ob->map, NULL, 0);
01448 }
01449 }
01450 }
01451 }
01452
01453 tmp_op = tmp;
01454 }
01455
01456
01457 if (corpse || QUERY_FLAG(ob, FLAG_CORPSE_FORCED))
01458 {
01459 if (enemy && enemy->type == PLAYER)
01460 {
01461 if (enemy->count == ob->enemy_count)
01462 {
01463 FREE_AND_ADD_REF_HASH(corpse->slaying, enemy->name);
01464 }
01465 }
01466 else if (QUERY_FLAG(ob, FLAG_CORPSE_FORCED))
01467 {
01468 corpse->stats.food = 3;
01469 }
01470
01471
01472 if (corpse->slaying)
01473 {
01474 if (CONTR(enemy)->party)
01475 {
01476 FREE_AND_ADD_REF_HASH(corpse->slaying, CONTR(enemy)->party->name);
01477 corpse->sub_type1 = ST1_CONTAINER_CORPSE_party;
01478 }
01479 else
01480 {
01481 corpse->sub_type1 = ST1_CONTAINER_CORPSE_player;
01482 }
01483 }
01484
01485 if (ob->env)
01486 {
01487 insert_ob_in_ob(corpse, ob->env);
01488
01489
01490 if (ob->env->type == PLAYER)
01491 {
01492 esrv_send_item(ob->env, corpse);
01493 }
01494 else if (ob->env->type == CONTAINER)
01495 {
01496 esrv_send_item(ob->env, corpse);
01497 }
01498 }
01499 else
01500 {
01501 insert_ob_in_map(corpse, ob->map, NULL, 0);
01502 }
01503 }
01504 }
01505
01515 void destroy_object(object *ob)
01516 {
01517 if (OBJECT_FREE(ob))
01518 {
01519 StringBuffer *sb = stringbuffer_new();
01520 char *diff;
01521
01522 dump_object(ob, sb);
01523 diff = stringbuffer_finish(sb);
01524 LOG(llevBug, "BUG: Trying to destroy freed object.\n%s\n", diff);
01525 free(diff);
01526 return;
01527 }
01528
01529 if (!QUERY_FLAG(ob, FLAG_REMOVED))
01530 {
01531 StringBuffer *sb = stringbuffer_new();
01532 char *diff;
01533
01534 dump_object(ob, sb);
01535 diff = stringbuffer_finish(sb);
01536 LOG(llevBug, "BUG: Destroy object called with non removed object\n:%s\n", diff);
01537 free(diff);
01538 }
01539
01540 free_key_values(ob);
01541
01542
01543 if (QUERY_FLAG(ob, FLAG_IS_LINKED))
01544 {
01545 remove_button_link(ob);
01546 }
01547
01548 if (ob->type == CONTAINER && ob->attacked_by)
01549 {
01550 container_unlink(NULL, ob);
01551 }
01552
01553
01554
01555 remove_ob_inv(ob);
01556
01557
01558 ob->speed = 0;
01559 update_ob_speed(ob);
01560
01561
01562 if (ob->custom_attrset)
01563 {
01564 switch (ob->type)
01565 {
01566 case PLAYER:
01567
01568 case DEAD_OBJECT:
01569 return_poolchunk(ob->custom_attrset, pool_player);
01570 break;
01571
01572 default:
01573 LOG(llevBug, "BUG: destroy_object() custom attrset found in unsupported object %s (type %d)\n", STRING_OBJ_NAME(ob), ob->type);
01574 }
01575
01576 ob->custom_attrset = NULL;
01577 }
01578
01579 if (ob->type == BEACON)
01580 {
01581 beacon_remove(ob);
01582 }
01583
01584 FREE_AND_CLEAR_HASH2(ob->name);
01585 FREE_AND_CLEAR_HASH2(ob->title);
01586 FREE_AND_CLEAR_HASH2(ob->race);
01587 FREE_AND_CLEAR_HASH2(ob->slaying);
01588 FREE_AND_CLEAR_HASH2(ob->msg);
01589 FREE_AND_CLEAR_HASH2(ob->artifact);
01590
01591
01592 ob->count = 0;
01593 }
01594
01600 void destruct_ob(object *op)
01601 {
01602 if (op->inv)
01603 {
01604 drop_ob_inv(op);
01605 }
01606
01607 remove_ob(op);
01608 check_walk_off(op, NULL, MOVE_APPLY_DEFAULT);
01609 }
01610
01622 void remove_ob(object *op)
01623 {
01624 MapSpace *msp;
01625 object *otmp;
01626
01627 if (QUERY_FLAG(op, FLAG_REMOVED))
01628 {
01629
01630 LOG(llevBug, "BUG: Trying to remove removed object.:%s map:%s (%d,%d)\n", query_name(op, NULL), op->map ? (op->map->path ? op->map->path : "op->map->path == NULL") : "op->map == NULL", op->x, op->y);
01631 return;
01632 }
01633
01634
01635 if (op->more != NULL)
01636 {
01637 remove_ob(op->more);
01638 }
01639
01640 mark_object_removed(op);
01641 SET_FLAG(op, FLAG_OBJECT_WAS_MOVED);
01642
01643
01644
01645 if (op->env)
01646 {
01647 sub_weight(op->env, WEIGHT_NROF(op));
01648
01649
01650
01651 if ((otmp = is_player_inv(op->env)) != NULL && CONTR(otmp) && !QUERY_FLAG(otmp, FLAG_NO_FIX_PLAYER))
01652 {
01653 fix_player(otmp);
01654 }
01655
01656 if (op->above)
01657 {
01658 op->above->below = op->below;
01659 }
01660 else
01661 {
01662 op->env->inv = op->below;
01663 }
01664
01665 if (op->below)
01666 {
01667 op->below->above = op->above;
01668 }
01669
01670
01671
01672
01673 op->x = op->env->x, op->y = op->env->y;
01674
01675 #ifdef POSITION_DEBUG
01676 op->ox = op->x, op->oy = op->y;
01677 #endif
01678
01679 op->map = op->env->map;
01680 op->above = NULL, op->below = NULL;
01681 op->env = NULL;
01682 return;
01683 }
01684
01685
01686 if (!op->map)
01687 {
01688 LOG(llevBug, "BUG: remove_ob(): object %s (%s) not on map or env.\n", query_short_name(op, NULL), op->arch ? (op->arch->name ? op->arch->name : "<nor arch name!>") : "<no arch!>");
01689 return;
01690 }
01691
01692
01693 msp = GET_MAP_SPACE_PTR(op->map, op->x, op->y);
01694
01695 if (op->layer)
01696 {
01697 if (GET_MAP_SPACE_LAYER(msp, op->layer - 1) == op)
01698 {
01699
01700 if (op->above && op->above->layer == op->layer && GET_MAP_SPACE_LAYER(msp, op->layer + 6) != op->above)
01701 {
01702 SET_MAP_SPACE_LAYER(msp, op->layer - 1, op->above);
01703 }
01704 else
01705 {
01706 SET_MAP_SPACE_LAYER(msp, op->layer - 1, NULL);
01707 }
01708 }
01709
01710 else if (GET_MAP_SPACE_LAYER(msp, op->layer + 6) == op)
01711 {
01712 if (op->above && op->above->layer == op->layer)
01713 {
01714 SET_MAP_SPACE_LAYER(msp, op->layer + 6, op->above);
01715 }
01716 else
01717 {
01718 SET_MAP_SPACE_LAYER(msp, op->layer + 6, NULL);
01719 }
01720 }
01721 }
01722
01723
01724 if (op->above)
01725 {
01726 op->above->below = op->below;
01727 }
01728
01729 else
01730 {
01731 SET_MAP_SPACE_LAST(msp, op->below);
01732 }
01733
01734
01735 if (op->below)
01736 {
01737 op->below->above = op->above;
01738 }
01739
01740 else
01741 {
01742 SET_MAP_SPACE_FIRST(msp, op->above);
01743 }
01744
01745 op->above = NULL;
01746 op->below = NULL;
01747
01748
01749 if (op->map->in_memory == MAP_SAVING)
01750 {
01751 return;
01752 }
01753
01754
01755 msp->update_tile++;
01756
01757
01758
01759 if (op->type == PLAYER)
01760 {
01761 struct pl_player *pltemp = CONTR(op);
01762
01763
01764 if (pltemp->map_below)
01765 {
01766 CONTR(pltemp->map_below)->map_above = pltemp->map_above;
01767 }
01768 else
01769 {
01770 op->map->player_first = pltemp->map_above;
01771 }
01772
01773 if (pltemp->map_above)
01774 {
01775 CONTR(pltemp->map_above)->map_below = pltemp->map_below;
01776 }
01777
01778 pltemp->map_below = pltemp->map_above = NULL;
01779 pltemp->update_los = 1;
01780
01781
01782 if (pltemp->container && pltemp->container->env != op)
01783 {
01784 container_unlink(pltemp, NULL);
01785 }
01786 }
01787
01788 update_object(op, UP_OBJ_REMOVE);
01789 op->env = NULL;
01790 }
01791
01795 static void remove_ob_inv(object *op)
01796 {
01797 object *tmp, *tmp2;
01798
01799 for (tmp = op->inv; tmp; tmp = tmp2)
01800 {
01801
01802 tmp2 = tmp->below;
01803
01804 if (tmp->inv)
01805 {
01806 remove_ob_inv(tmp);
01807 }
01808
01809
01810 remove_ob(tmp);
01811 }
01812 }
01813
01822 object *insert_ob_in_map(object *op, mapstruct *m, object *originator, int flag)
01823 {
01824 object *tmp = NULL, *top;
01825 MapSpace *mc;
01826 int x, y, lt, layer, layer_inv;
01827
01828
01829
01830 if (OBJECT_FREE(op))
01831 {
01832 LOG(llevBug, "BUG: insert_ob_in_map(): Trying to insert freed object %s in map %s!\n", query_name(op, NULL), m->name);
01833 return NULL;
01834 }
01835
01836 if (m == NULL)
01837 {
01838 LOG(llevBug, "BUG: insert_ob_in_map(): Trying to insert object %s in null-map!\n", query_name(op, NULL));
01839 return NULL;
01840 }
01841
01842 if (!QUERY_FLAG(op, FLAG_REMOVED))
01843 {
01844 LOG(llevBug, "BUG: insert_ob_in_map(): Trying to insert non removed object %s in map %s.\n", query_name(op, NULL), m->name);
01845 return NULL;
01846 }
01847
01848
01849 if (op->head && !(flag & INS_TAIL_MARKER))
01850 {
01851 LOG(llevBug, "BUG: insert_ob_in_map(): inserting op->more WITHOUT INS_TAIL_MARKER! OB:%s (ARCH: %s) (MAP: %s (%d,%d))\n", query_name(op, NULL), op->arch->name, m->path, op->x, op->y);
01852 return NULL;
01853 }
01854
01855 if (op->more)
01856 {
01857 if (insert_ob_in_map(op->more, op->more->map, originator, flag | INS_TAIL_MARKER) == NULL)
01858 {
01859 if (!op->head)
01860 {
01861 LOG(llevBug, "BUG: insert_ob_in_map(): inserting op->more killed op %s in map %s\n", query_name(op, NULL), m->name);
01862 }
01863
01864 return NULL;
01865 }
01866 }
01867
01868 CLEAR_FLAG(op, FLAG_REMOVED);
01869
01870 #ifdef POSITION_DEBUG
01871 op->ox = op->x;
01872 op->oy = op->y;
01873 #endif
01874
01875
01876
01877 x = op->x;
01878 y = op->y;
01879 op->map = m;
01880
01881 if (!(m = get_map_from_coord(m, &x, &y)))
01882 {
01883 LOG(llevBug, "BUG: insert_ob_in_map(): Trying to insert object %s outside the map %s (%d,%d).\n\n", query_name(op, NULL), op->map->path, op->x, op->y);
01884 return NULL;
01885 }
01886
01887
01888 if (op->map != m)
01889 {
01890 op->map = m;
01891 op->x = x;
01892 op->y = y;
01893 }
01894
01895 if (op->nrof && !(flag & INS_NO_MERGE))
01896 {
01897 for (tmp = GET_MAP_OB(m, x, y); tmp; tmp = tmp->above)
01898 {
01899 if (CAN_MERGE(op,tmp))
01900 {
01901 op->nrof += tmp->nrof;
01902 remove_ob(tmp);
01903 }
01904 }
01905 }
01906
01907
01908 SET_FLAG(op, FLAG_OBJECT_WAS_MOVED);
01909
01910 CLEAR_FLAG(op, FLAG_APPLIED);
01911
01912 CLEAR_FLAG(op, FLAG_INV_LOCKED);
01913
01914
01915 mc = GET_MAP_SPACE_PTR(op->map, op->x, op->y);
01916
01917
01918 if (op->layer)
01919 {
01920 layer = op->layer - 1;
01921 layer_inv = layer + 7;
01922
01923
01924 if (!QUERY_FLAG(op, FLAG_IS_INVISIBLE))
01925 {
01926
01927 if ((top = GET_MAP_SPACE_LAYER(mc, layer)) == NULL && (top = GET_MAP_SPACE_LAYER(mc, layer_inv)) == NULL)
01928 {
01929
01930 for (lt = op->layer; lt < MAX_ARCH_LAYERS && (top = GET_MAP_SPACE_LAYER(mc, lt)) == NULL && (top = GET_MAP_SPACE_LAYER(mc, lt + 7)) == NULL; lt++)
01931 {
01932 }
01933 }
01934
01935 SET_MAP_SPACE_LAYER(mc, layer, op);
01936
01937
01938 if (top)
01939 {
01940 if (top->below)
01941 {
01942 top->below->above = op;
01943 }
01944
01945 else
01946 {
01947 SET_MAP_SPACE_FIRST(mc, op);
01948 }
01949
01950 op->below = top->below;
01951 top->below = op;
01952 op->above = top;
01953 }
01954
01955 else
01956 {
01957 if ((top = GET_MAP_SPACE_LAST(mc)) != NULL)
01958 {
01959 top->above = op;
01960 op->below = top;
01961
01962 }
01963
01964 else
01965 {
01966 SET_MAP_SPACE_FIRST(mc, op);
01967 }
01968
01969 SET_MAP_SPACE_LAST(mc, op);
01970 }
01971 }
01972
01973 else
01974 {
01975 int tmp_flag;
01976
01977
01978 if ((top = GET_MAP_SPACE_LAYER(mc, layer_inv)) != NULL)
01979 {
01980 tmp_flag = 1;
01981 }
01982 else if ((top = GET_MAP_SPACE_LAYER(mc, layer)) != NULL)
01983 {
01984
01985
01986
01987 for (lt = op->layer; lt < MAX_ARCH_LAYERS && (tmp = GET_MAP_SPACE_LAYER(mc, lt)) == NULL && (tmp = GET_MAP_SPACE_LAYER(mc, lt + 7)) == NULL; lt++)
01988 {
01989 }
01990
01991 tmp_flag = 2;
01992 }
01993 else
01994 {
01995
01996 for (lt = op->layer; lt < MAX_ARCH_LAYERS && (top = GET_MAP_SPACE_LAYER(mc, lt)) == NULL && (top = GET_MAP_SPACE_LAYER(mc, lt + 7)) == NULL; lt++)
01997 {
01998 }
01999
02000 tmp_flag = 3;
02001 }
02002
02003
02004 SET_MAP_SPACE_LAYER(mc, layer_inv, op);
02005
02006 if (top)
02007 {
02008
02009
02010
02011
02012
02013
02014
02015
02016
02017 if (tmp_flag == 2)
02018 {
02019 if (tmp)
02020 {
02021
02022 tmp->below->above = op;
02023 op->below = tmp->below;
02024
02025 tmp->below = op;
02026 op->above = tmp;
02027 }
02028 else
02029 {
02030
02031 tmp = GET_MAP_SPACE_LAST(mc);
02032
02033 SET_MAP_SPACE_LAST(mc, op);
02034 op->below = tmp;
02035 tmp->above = op;
02036 }
02037 }
02038
02039 else
02040 {
02041 if (top->below)
02042 {
02043 top->below->above = op;
02044 }
02045
02046 else
02047 {
02048 SET_MAP_SPACE_FIRST(mc, op);
02049 }
02050
02051 op->below = top->below;
02052 top->below = op;
02053 op->above = top;
02054 }
02055 }
02056
02057 else
02058 {
02059
02060 if ((top = GET_MAP_SPACE_LAST(mc)) != NULL)
02061 {
02062
02063 top->above = op;
02064 op->below = top;
02065
02066 }
02067
02068 else
02069 {
02070 SET_MAP_SPACE_FIRST(mc, op);
02071 }
02072
02073 SET_MAP_SPACE_LAST(mc, op);
02074 }
02075 }
02076 }
02077
02078 else
02079 {
02080
02081 if ((top = GET_MAP_SPACE_FIRST(mc)) != NULL)
02082 {
02083
02084 top->below = op;
02085 op->above = top;
02086 }
02087
02088 else
02089 {
02090 SET_MAP_SPACE_LAST(mc, op);
02091 }
02092
02093 SET_MAP_SPACE_FIRST(mc, op);
02094 }
02095
02096
02097
02098 if (op->type == PLAYER)
02099 {
02100 CONTR(op)->socket.update_tile = 0;
02101 CONTR(op)->update_los = 1;
02102
02103 if (op->map->player_first)
02104 {
02105 CONTR(op->map->player_first)->map_below = op;
02106 CONTR(op)->map_above = op->map->player_first;
02107 }
02108
02109 op->map->player_first = op;
02110 }
02111
02112
02113 mc->update_tile++;
02114
02115 update_object(op, UP_OBJ_INSERT);
02116
02117 if (!(flag & INS_NO_WALK_ON) && (mc->flags & (P_WALK_ON | P_FLY_ON) || op->more) && !op->head)
02118 {
02119 int event;
02120
02121
02122 if (QUERY_FLAG(op, FLAG_FLY_ON))
02123 {
02124 if (!(mc->flags & P_FLY_ON))
02125 {
02126 goto check_walk_loop;
02127 }
02128 }
02129
02130 else
02131 {
02132 if (!(mc->flags & P_WALK_ON))
02133 {
02134 goto check_walk_loop;
02135 }
02136 }
02137
02138 if ((event = check_walk_on(op, originator, MOVE_APPLY_MOVE)))
02139 {
02140
02141 if (event == CHECK_WALK_MOVED)
02142 {
02143 return op;
02144 }
02145 else
02146 {
02147 return NULL;
02148 }
02149 }
02150
02151
02152 check_walk_loop:
02153 for (tmp = op->more; tmp; tmp = tmp->more)
02154 {
02155 mc = GET_MAP_SPACE_PTR(tmp->map, tmp->x, tmp->y);
02156
02157
02158 if (QUERY_FLAG(op, FLAG_FLY_ON))
02159 {
02160 if (!(mc->flags & P_FLY_ON))
02161 {
02162 continue;
02163 }
02164 }
02165
02166 else
02167 {
02168 if (!(mc->flags & P_WALK_ON))
02169 {
02170 continue;
02171 }
02172 }
02173
02174 if ((event = check_walk_on(tmp, originator, MOVE_APPLY_MOVE)))
02175 {
02176
02177 if (event == CHECK_WALK_MOVED)
02178 {
02179 return op;
02180 }
02181 else
02182 {
02183 return NULL;
02184 }
02185 }
02186 }
02187 }
02188
02189 return op;
02190 }
02191
02197 void replace_insert_ob_in_map(char *arch_string, object *op)
02198 {
02199 object *tmp, *tmp1;
02200
02201
02202 for (tmp = GET_MAP_OB(op->map, op->x, op->y); tmp; tmp = tmp->above)
02203 {
02204 if (!strcmp(tmp->arch->name, arch_string))
02205 {
02206 remove_ob(tmp);
02207 tmp->speed = 0;
02208
02209 update_ob_speed(tmp);
02210 }
02211 }
02212
02213 tmp1 = arch_to_object(find_archetype(arch_string));
02214 tmp1->x = op->x;
02215 tmp1->y = op->y;
02216 insert_ob_in_map(tmp1, op->map, op, 0);
02217 }
02218
02229 object *get_split_ob(object *orig_ob, int nr, char *err, size_t size)
02230 {
02231 object *newob, *tmp, *event;
02232 int is_removed = (QUERY_FLAG(orig_ob, FLAG_REMOVED) != 0);
02233
02234 if ((int) orig_ob->nrof < nr)
02235 {
02236 if (err)
02237 {
02238 snprintf(err, size, "There are only %d %ss.", orig_ob->nrof ? orig_ob->nrof : 1, query_name(orig_ob, NULL));
02239 }
02240
02241 return NULL;
02242 }
02243
02244 newob = get_object();
02245 copy_object(orig_ob, newob);
02246
02247
02248 for (tmp = orig_ob->inv; tmp; tmp = tmp->below)
02249 {
02250 if (tmp->type == EVENT_OBJECT)
02251 {
02252 event = get_object();
02253 copy_object(tmp, event);
02254 insert_ob_in_ob(event, newob);
02255 }
02256 }
02257
02258 orig_ob->nrof -= nr;
02259
02260 if (orig_ob->nrof < 1)
02261 {
02262 if (!is_removed)
02263 {
02264 remove_ob(orig_ob);
02265 }
02266
02267 check_walk_off(orig_ob, NULL, MOVE_APPLY_VANISHED);
02268 }
02269 else if (!is_removed)
02270 {
02271 if (orig_ob->env)
02272 {
02273 sub_weight(orig_ob->env, orig_ob->weight * nr);
02274 }
02275
02276 if (orig_ob->env == NULL && orig_ob->map->in_memory != MAP_IN_MEMORY)
02277 {
02278 strncpy(err, "Tried to split object whose map is not in memory.", size);
02279 LOG(llevDebug, "Error, Tried to split object whose map is not in memory.\n");
02280 return NULL;
02281 }
02282 }
02283
02284 newob->nrof = nr;
02285 return newob;
02286 }
02287
02297 object *decrease_ob_nr(object *op, uint32 i)
02298 {
02299 object *tmp;
02300
02301
02302 if (i == 0)
02303 {
02304 return op;
02305 }
02306
02307 if (i > op->nrof)
02308 {
02309 i = op->nrof;
02310 }
02311
02312 if (QUERY_FLAG(op, FLAG_REMOVED))
02313 {
02314 op->nrof -= i;
02315 }
02316 else if (op->env)
02317 {
02318
02319
02320 tmp = is_player_inv(op->env);
02321
02322 if (!tmp)
02323 {
02324 if (op->env->type == CONTAINER && op->env->attacked_by && CONTR(op->env->attacked_by) && CONTR(op->env->attacked_by)->container == op->env)
02325 {
02326 tmp = op->env->attacked_by;
02327 }
02328 }
02329
02330 if (i < op->nrof)
02331 {
02332 sub_weight (op->env, op->weight * i);
02333 op->nrof -= i;
02334
02335 if (tmp)
02336 {
02337 esrv_send_item(tmp, op);
02338 esrv_update_item(UPD_WEIGHT, tmp, tmp);
02339 }
02340 }
02341 else
02342 {
02343 remove_ob(op);
02344 check_walk_off(op, NULL, MOVE_APPLY_VANISHED);
02345 op->nrof = 0;
02346
02347 if (tmp)
02348 {
02349 esrv_del_item(CONTR(tmp), op->count, op->env);
02350 esrv_update_item(UPD_WEIGHT, tmp, tmp);
02351 }
02352 }
02353 }
02354 else
02355 {
02356 object *above = op->above;
02357
02358 if (i < op->nrof)
02359 {
02360 op->nrof -= i;
02361 }
02362 else
02363 {
02364 remove_ob(op);
02365 check_walk_off(op, NULL, MOVE_APPLY_VANISHED);
02366 op->nrof = 0;
02367 }
02368
02369
02370 for (tmp = above; tmp; tmp = tmp->above)
02371 {
02372 if (tmp->type == PLAYER)
02373 {
02374 if (op->nrof)
02375 {
02376 esrv_send_item(tmp, op);
02377 }
02378 else
02379 {
02380 esrv_del_item(CONTR(tmp), op->count, op->env);
02381 }
02382 }
02383 }
02384 }
02385
02386 if (op->nrof)
02387 {
02388 return op;
02389 }
02390
02391 return NULL;
02392 }
02393
02404 object *insert_ob_in_ob(object *op, object *where)
02405 {
02406 object *tmp, *otmp;
02407
02408 if (!QUERY_FLAG(op, FLAG_REMOVED))
02409 {
02410 StringBuffer *sb;
02411 char *diff;
02412
02413 sb = stringbuffer_new();
02414 dump_object(op, sb);
02415 diff = stringbuffer_finish(sb);
02416 LOG(llevBug, "BUG: Trying to insert (ob) inserted object.\n%s\n", diff);
02417 free(diff);
02418 return op;
02419 }
02420
02421 if (where == NULL)
02422 {
02423 StringBuffer *sb;
02424 char *diff;
02425
02426 sb = stringbuffer_new();
02427 dump_object(op, sb);
02428 diff = stringbuffer_finish(sb);
02429 LOG(llevBug, "BUG: Trying to put object in NULL.\n%s\n", diff);
02430 free(diff);
02431 return op;
02432 }
02433
02434 if (where->head)
02435 {
02436 LOG(llevBug, "BUG: Tried to insert object wrong part of multipart object.\n");
02437 where = where->head;
02438 }
02439
02440 if (op->more)
02441 {
02442 LOG(llevError, "ERROR: Tried to insert multipart object %s (%d)\n", query_name(op, NULL), op->count);
02443 return op;
02444 }
02445
02446 CLEAR_FLAG(op, FLAG_REMOVED);
02447
02448 for (tmp = where->inv; tmp; tmp = tmp->below)
02449 {
02450 if (CAN_MERGE(tmp, op))
02451 {
02452
02453
02454 tmp->nrof += op->nrof;
02455
02456
02457
02458 add_weight(where, WEIGHT_NROF(op));
02459
02460
02461 SET_FLAG(op, FLAG_REMOVED);
02462
02463 op = tmp;
02464
02465 remove_ob(op);
02466
02467 CLEAR_FLAG(op, FLAG_REMOVED);
02468 break;
02469 }
02470 }
02471
02472
02473
02474
02475
02476
02477 add_weight(where, WEIGHT_NROF(op));
02478
02479 SET_FLAG(op, FLAG_OBJECT_WAS_MOVED);
02480 op->map = NULL;
02481 op->env = where;
02482 op->above = NULL;
02483 op->below = NULL;
02484 op->x = 0, op->y = 0;
02485
02486 #ifdef POSITION_DEBUG
02487 op->ox = 0, op->oy = 0;
02488 #endif
02489
02490
02491
02492 if (where->inv == NULL)
02493 {
02494 where->inv = op;
02495 }
02496 else
02497 {
02498 op->below = where->inv;
02499 op->below->above = op;
02500 where->inv = op;
02501 }
02502
02503
02504
02505 if (op->type == EVENT_OBJECT && op->sub_type1)
02506 {
02507 where->event_flags |= (1U << (op->sub_type1 - 1));
02508 }
02509
02510
02511
02512 otmp = is_player_inv(where);
02513
02514 if (otmp && CONTR(otmp) != NULL)
02515 {
02516 if (QUERY_FLAG(op, FLAG_ONE_DROP))
02517 {
02518 SET_FLAG(op, FLAG_STARTEQUIP);
02519 }
02520
02521 if (!QUERY_FLAG(otmp, FLAG_NO_FIX_PLAYER))
02522 {
02523 fix_player(otmp);
02524 }
02525 }
02526
02527 return op;
02528 }
02529
02532 int check_walk_on(object *op, object *originator, int flags)
02533 {
02534 object *tmp;
02535
02536 int local_walk_semaphore = 0;
02537 tag_t tag;
02538 int fly;
02539
02540 if (QUERY_FLAG(op, FLAG_NO_APPLY))
02541 {
02542 return 0;
02543 }
02544
02545 fly = QUERY_FLAG(op, FLAG_FLYING);
02546
02547 if (fly)
02548 {
02549 flags |= MOVE_APPLY_FLY_ON;
02550 }
02551 else
02552 {
02553 flags |= MOVE_APPLY_WALK_ON;
02554 }
02555
02556 tag = op->count;
02557
02558
02559
02560
02561
02562 if (!static_walk_semaphore)
02563 {
02564 local_walk_semaphore = 1;
02565 static_walk_semaphore = 1;
02566 CLEAR_FLAG(op, FLAG_OBJECT_WAS_MOVED);
02567 }
02568
02569 for (tmp = GET_MAP_OB(op->map, op->x, op->y); tmp; tmp = tmp->above)
02570 {
02571
02572 if (tmp == op)
02573 {
02574 continue;
02575 }
02576
02577 if (fly ? QUERY_FLAG(tmp, FLAG_FLY_ON) : QUERY_FLAG(tmp, FLAG_WALK_ON))
02578 {
02579 move_apply(tmp, op, originator,flags);
02580
02581
02582 if (was_destroyed(op, tag))
02583 {
02584 if (local_walk_semaphore)
02585 {
02586 static_walk_semaphore = 0;
02587 }
02588
02589 return CHECK_WALK_DESTROYED;
02590 }
02591
02592
02593 if (QUERY_FLAG(op, FLAG_OBJECT_WAS_MOVED))
02594 {
02595 if (local_walk_semaphore)
02596 {
02597 static_walk_semaphore = 0;
02598 }
02599
02600 return CHECK_WALK_MOVED;
02601 }
02602 }
02603 }
02604
02605 if (local_walk_semaphore)
02606 {
02607 static_walk_semaphore = 0;
02608 }
02609
02610 return CHECK_WALK_OK;
02611 }
02612
02615 int check_walk_off(object *op, object *originator, int flags)
02616 {
02617 MapSpace *mc;
02618 object *tmp, *part;
02619
02620 int local_walk_semaphore = 0;
02621 int fly;
02622 tag_t tag;
02623
02624
02625 if (!op || !op->map)
02626 {
02627 return CHECK_WALK_OK;
02628 }
02629
02630 if (!QUERY_FLAG(op, FLAG_REMOVED))
02631 {
02632 LOG(llevBug, "BUG: check_walk_off: object %s is not removed when called\n", query_name(op, NULL));
02633 return CHECK_WALK_OK;
02634 }
02635
02636 if (QUERY_FLAG(op, FLAG_NO_APPLY))
02637 {
02638 return CHECK_WALK_OK;
02639 }
02640
02641 tag = op->count;
02642 fly = QUERY_FLAG(op, FLAG_FLYING);
02643
02644 if (fly)
02645 {
02646 flags |= MOVE_APPLY_FLY_OFF;
02647 }
02648 else
02649 {
02650 flags |= MOVE_APPLY_WALK_OFF;
02651 }
02652
02653
02654 for (part = op; part; part = part->more)
02655 {
02656 mc = GET_MAP_SPACE_PTR(part->map, part->x, part->y);
02657
02658
02659 if (!(mc->flags & (P_WALK_OFF | P_FLY_OFF)))
02660 {
02661 continue;
02662 }
02663
02664
02665
02666
02667
02668 if (!static_walk_semaphore)
02669 {
02670 local_walk_semaphore = 1;
02671 static_walk_semaphore = 1;
02672 CLEAR_FLAG(op, FLAG_OBJECT_WAS_MOVED);
02673 }
02674
02675
02676 for (tmp = mc->first; tmp != NULL; tmp = tmp->above)
02677 {
02678
02679 if (tmp == part)
02680 {
02681 continue;
02682 }
02683
02684
02685 if (fly ? QUERY_FLAG(tmp, FLAG_FLY_OFF) : QUERY_FLAG(tmp, FLAG_WALK_OFF))
02686 {
02687 move_apply(tmp, part, originator, flags);
02688
02689 if (OBJECT_FREE(part) || tag != op->count)
02690 {
02691 if (local_walk_semaphore)
02692 {
02693 static_walk_semaphore = 0;
02694 }
02695
02696 return CHECK_WALK_DESTROYED;
02697 }
02698
02699
02700 if (!QUERY_FLAG(part, FLAG_REMOVED) || QUERY_FLAG(part, FLAG_OBJECT_WAS_MOVED))
02701 {
02702 if (local_walk_semaphore)
02703 {
02704 static_walk_semaphore = 0;
02705 }
02706
02707 return CHECK_WALK_MOVED;
02708 }
02709 }
02710 }
02711
02712 if (local_walk_semaphore)
02713 {
02714 local_walk_semaphore = 0;
02715 static_walk_semaphore = 0;
02716 }
02717
02718 }
02719
02720 if (local_walk_semaphore)
02721 {
02722 static_walk_semaphore = 0;
02723 }
02724
02725 return CHECK_WALK_OK;
02726 }
02727
02736 object *present_arch(archetype *at, mapstruct *m, int x, int y)
02737 {
02738 object *tmp;
02739
02740 if (!(m = get_map_from_coord(m, &x, &y)))
02741 {
02742 LOG(llevError, "ERROR: present_arch() called outside map.\n");
02743 return NULL;
02744 }
02745
02746 for (tmp = GET_MAP_OB(m, x, y); tmp; tmp = tmp->above)
02747 {
02748 if (tmp->arch == at)
02749 {
02750 return tmp;
02751 }
02752 }
02753
02754 return NULL;
02755 }
02756
02765 object *present(uint8 type, mapstruct *m, int x, int y)
02766 {
02767 object *tmp;
02768
02769 if (!(m = get_map_from_coord(m, &x, &y)))
02770 {
02771 LOG(llevError, "ERROR: Present called outside map.\n");
02772 return NULL;
02773 }
02774
02775 for (tmp = GET_MAP_OB(m, x, y); tmp; tmp = tmp->above)
02776 {
02777 if (tmp->type == type)
02778 {
02779 return tmp;
02780 }
02781 }
02782
02783 return NULL;
02784 }
02785
02792 object *present_in_ob(uint8 type, object *op)
02793 {
02794 object *tmp;
02795
02796 for (tmp = op->inv; tmp; tmp = tmp->below)
02797 {
02798 if (tmp->type == type)
02799 {
02800 return tmp;
02801 }
02802 }
02803
02804 return NULL;
02805 }
02806
02813 object *present_arch_in_ob(archetype *at, object *op)
02814 {
02815 object *tmp;
02816
02817 for (tmp = op->inv; tmp; tmp = tmp->below)
02818 {
02819 if (tmp->arch == at)
02820 {
02821 return tmp;
02822 }
02823 }
02824
02825 return NULL;
02826 }
02827
02842 int find_free_spot(archetype *at, object *op, mapstruct *m, int x, int y, int start, int stop)
02843 {
02844 int i, index = 0;
02845 static int altern[SIZEOFFREE];
02846
02847 for (i = start; i < stop; i++)
02848 {
02849 if (!arch_blocked(at, op, m, x + freearr_x[i], y + freearr_y[i]))
02850 {
02851 altern[index++] = i;
02852 }
02853 else if (wall(m, x + freearr_x[i], y + freearr_y[i]) && maxfree[i] < stop)
02854 {
02855 stop = maxfree[i];
02856 }
02857 }
02858
02859 if (!index)
02860 {
02861 return -1;
02862 }
02863
02864 return altern[RANDOM() % index];
02865 }
02866
02867
02873 int find_first_free_spot(archetype *at, object *op, mapstruct *m, int x, int y)
02874 {
02875 int i;
02876
02877 for (i = 0; i < SIZEOFFREE; i++)
02878 {
02879 if (!arch_blocked(at, op, m, x + freearr_x[i], y + freearr_y[i]))
02880 {
02881 return i;
02882 }
02883 }
02884
02885 return -1;
02886 }
02887
02890 int find_first_free_spot2(archetype *at, mapstruct *m, int x, int y, int start, int range)
02891 {
02892 int i;
02893
02894 for (i = start; i < range; i++)
02895 {
02896 if (!arch_blocked(at, NULL, m, x + freearr_x[i], y + freearr_y[i]))
02897 {
02898 return i;
02899 }
02900 }
02901
02902 return -1;
02903 }
02904
02910 static void permute(int *arr, int begin, int end)
02911 {
02912 int i, j, tmp, len;
02913
02914 len = end - begin;
02915
02916 for (i = begin; i < end; i++)
02917 {
02918 j = begin + RANDOM() % len;
02919
02920 tmp = arr[i];
02921 arr[i] = arr[j];
02922 arr[j] = tmp;
02923 }
02924 }
02925
02935 void get_search_arr(int *search_arr)
02936 {
02937 int i;
02938
02939 for (i = 0; i < SIZEOFFREE; i++)
02940 {
02941 search_arr[i] = i;
02942 }
02943
02944 permute(search_arr, 1, SIZEOFFREE1 + 1);
02945 permute(search_arr, SIZEOFFREE1 + 1, SIZEOFFREE2 + 1);
02946 permute(search_arr, SIZEOFFREE2 + 1, SIZEOFFREE);
02947 }
02948
02958 int find_dir(mapstruct *m, int x, int y, object *exclude)
02959 {
02960 int i, xt, yt, max = SIZEOFFREE;
02961 mapstruct *mt;
02962 object *tmp;
02963
02964 if (exclude && exclude->head)
02965 {
02966 exclude = exclude->head;
02967 }
02968
02969 for (i = 1; i < max; i++)
02970 {
02971 xt = x + freearr_x[i];
02972 yt = y + freearr_y[i];
02973
02974 if (wall(m, xt, yt))
02975 {
02976 max = maxfree[i];
02977 }
02978 else
02979 {
02980 if (!(mt = get_map_from_coord(m, &xt, &yt)))
02981 {
02982 continue;
02983 }
02984
02985 tmp = GET_MAP_OB(mt, xt, yt);
02986
02987 while (tmp != NULL && ((tmp != NULL && !QUERY_FLAG(tmp, FLAG_MONSTER) && tmp->type != PLAYER) || (tmp == exclude || (tmp->head && tmp->head == exclude))))
02988 {
02989 tmp = tmp->above;
02990 }
02991
02992 if (tmp != NULL)
02993 {
02994 return freedir[i];
02995 }
02996 }
02997 }
02998
02999 return 0;
03000 }
03001
03007 int find_dir_2(int x, int y)
03008 {
03009 int q;
03010
03011 if (!y)
03012 {
03013 q = -300 * x;
03014 }
03015 else
03016 {
03017 q = x * 100 / y;
03018 }
03019
03020 if (y > 0)
03021 {
03022 if (q < -242)
03023 {
03024 return 3;
03025 }
03026
03027 if (q < -41)
03028 {
03029 return 2;
03030 }
03031
03032 if (q < 41)
03033 {
03034 return 1;
03035 }
03036
03037 if (q < 242)
03038 {
03039 return 8;
03040 }
03041
03042 return 7;
03043 }
03044
03045 if (q < -242)
03046 {
03047 return 7;
03048 }
03049
03050 if (q < -41)
03051 {
03052 return 6;
03053 }
03054
03055 if (q < 41)
03056 {
03057 return 5;
03058 }
03059
03060 if (q < 242)
03061 {
03062 return 4;
03063 }
03064
03065 return 3;
03066 }
03067
03074 int absdir(int d)
03075 {
03076 while (d < 1)
03077 {
03078 d += 8;
03079 }
03080
03081 while (d > 8)
03082 {
03083 d -= 8;
03084 }
03085
03086 return d;
03087 }
03088
03089
03096 int dirdiff(int dir1, int dir2)
03097 {
03098 int d = abs(dir1 - dir2);
03099
03100 if (d > 4)
03101 {
03102 d = 8 - d;
03103 }
03104
03105 return d;
03106 }
03107
03117 int get_dir_to_target(object *op, object *target, rv_vector *range_vector)
03118 {
03119 int dir;
03120
03121 get_rangevector(op, target, range_vector, 0);
03122 dir = range_vector->direction;
03123
03124 if (op->type == PLAYER)
03125 {
03126 if (op->head)
03127 {
03128 op->head->anim_enemy_dir = dir;
03129 op->head->facing = dir;
03130 }
03131 else
03132 {
03133 op->anim_enemy_dir = dir;
03134 op->facing = dir;
03135 }
03136 }
03137
03138 return dir;
03139 }
03140
03141
03148 int can_pick(object *who, object *item)
03149 {
03150 if (item->weight <= 0)
03151 {
03152 return 0;
03153 }
03154
03155 if (QUERY_FLAG(item, FLAG_NO_PICK) && !QUERY_FLAG(item, FLAG_UNPAID))
03156 {
03157 return 0;
03158 }
03159
03160 if (QUERY_FLAG(item, FLAG_ALIVE))
03161 {
03162 return 0;
03163 }
03164
03165 if (IS_INVISIBLE(item, who) && !QUERY_FLAG(who, FLAG_SEE_INVISIBLE))
03166 {
03167 return 0;
03168 }
03169
03170
03171 if (who->type != PLAYER && item->weight > (who->weight / 3))
03172 {
03173 return 0;
03174 }
03175
03176
03177 if (item->head || item->more)
03178 {
03179 return 0;
03180 }
03181
03182 return 1;
03183 }
03184
03189 object *object_create_clone(object *asrc)
03190 {
03191 object *dst = NULL, *tmp, *src, *part, *prev, *item;
03192
03193 if (!asrc)
03194 {
03195 return NULL;
03196 }
03197
03198 src = asrc;
03199
03200 if (src->head)
03201 {
03202 src = src->head;
03203 }
03204
03205 prev = NULL;
03206
03207 for (part = src; part; part = part->more)
03208 {
03209 tmp = get_object();
03210 copy_object(part, tmp);
03211 tmp->x -= src->x;
03212 tmp->y -= src->y;
03213
03214 if (!part->head)
03215 {
03216 dst = tmp;
03217 tmp->head = NULL;
03218 }
03219 else
03220 {
03221 tmp->head = dst;
03222 }
03223
03224 tmp->more = NULL;
03225
03226 if (prev)
03227 {
03228 prev->more = tmp;
03229 }
03230
03231 prev = tmp;
03232 }
03233
03234
03235 for (item = src->inv; item; item = item->below)
03236 {
03237 insert_ob_in_ob(object_create_clone(item), dst);
03238 }
03239
03240 return dst;
03241 }
03242
03249 int was_destroyed(object *op, tag_t old_tag)
03250 {
03251 return (QUERY_FLAG(op, FLAG_REMOVED) || (op->count != old_tag) || OBJECT_FREE(op));
03252 }
03253
03261 object *load_object_str(char *obstr)
03262 {
03263 object *op;
03264 FILE *tempfile;
03265 void *mybuffer;
03266 char filename[MAX_BUF];
03267
03268 snprintf(filename, sizeof(filename), "%s/cfloadobstr2044", settings.tmpdir);
03269 tempfile = fopen(filename, "w+");
03270
03271 if (tempfile == NULL)
03272 {
03273 LOG(llevError, "ERROR: load_object_str(): Unable to access load object temp file\n");
03274 return NULL;
03275 }
03276
03277 fprintf(tempfile, "%s", obstr);
03278 op = get_object();
03279 rewind(tempfile);
03280 mybuffer = create_loader_buffer(tempfile);
03281 load_object(tempfile, op, mybuffer, LO_REPEAT, 0);
03282 delete_loader_buffer(mybuffer);
03283 fclose(tempfile);
03284 return op;
03285 }
03286
03294 int auto_apply(object *op)
03295 {
03296 object *tmp = NULL, *tmp2;
03297 int i, level, a_chance;
03298
03299
03300
03301 CLEAR_FLAG(op, FLAG_AUTO_APPLY);
03302
03303 if (op->env && op->env->type == PLAYER)
03304 {
03305 LOG(llevDebug, "DEBUG: Object with auto_apply (%s, %s) found in %s.\n", op->name, op->arch->name, op->env->name);
03306 return 0;
03307 }
03308
03309 switch (op->type)
03310 {
03311 case SHOP_FLOOR:
03312 if (op->randomitems == NULL)
03313 {
03314 return 0;
03315 }
03316
03317 a_chance = op->randomitems->artifact_chance;
03318
03319
03320 if (QUERY_FLAG(op, FLAG_DAMNED))
03321 {
03322 a_chance = 0;
03323 }
03324
03325 do
03326 {
03327
03328 i = 10;
03329 level = op->stats.exp ? (int) op->stats.exp : get_enviroment_level(op);
03330
03331 while ((tmp = generate_treasure(op->randomitems, level, a_chance)) == NULL && --i)
03332 {
03333 }
03334
03335 if (tmp == NULL)
03336 {
03337 return 0;
03338 }
03339
03340 if (QUERY_FLAG(tmp, FLAG_CURSED) || QUERY_FLAG(tmp, FLAG_DAMNED))
03341 {
03342 tmp = NULL;
03343 }
03344 }
03345 while (!tmp);
03346
03347 tmp->x = op->x, tmp->y = op->y;
03348 SET_FLAG(tmp, FLAG_UNPAID);
03349
03350
03351
03352 if (!QUERY_FLAG(op, FLAG_CURSED))
03353 {
03354 SET_FLAG(tmp, FLAG_NO_PICK);
03355 }
03356
03357 insert_ob_in_map(tmp, op->map, NULL, INS_NO_MERGE | INS_NO_WALK_ON);
03358 identify(tmp);
03359
03360 break;
03361
03362 case TREASURE:
03363 level = op->stats.exp ? (int) op->stats.exp : get_enviroment_level(op);
03364 create_treasure(op->randomitems, op, op->map ? GT_ENVIRONMENT : 0, level, T_STYLE_UNSET, ART_CHANCE_UNSET, 0, NULL);
03365
03366
03367
03368
03369
03370 for (tmp = op->inv; tmp; tmp = tmp2)
03371 {
03372 tmp2 = tmp->below;
03373 remove_ob(tmp);
03374
03375 if (op->env)
03376 {
03377 insert_ob_in_ob(tmp, op->env);
03378 }
03379 }
03380
03381
03382 remove_ob(op);
03383 break;
03384 }
03385
03386 return tmp ? 1 : 0;
03387 }
03388
03396 int can_see_monsterP(mapstruct *m, int x, int y, int dir)
03397 {
03398 int dx, dy;
03399
03400
03401 if (dir < 0)
03402 {
03403 return 0;
03404 }
03405
03406 dx = x + freearr_x[dir];
03407 dy = y + freearr_y[dir];
03408
03409 if (!(m = get_map_from_coord(m, &dx, &dy)))
03410 {
03411 return 0;
03412 }
03413
03414 if (wall(m, dx, dy))
03415 {
03416 return 0;
03417 }
03418
03419
03420 if (dir < 9)
03421 {
03422 return 1;
03423 }
03424
03425 return can_see_monsterP(m, x, y, reduction_dir[dir][0]) | can_see_monsterP(m, x, y, reduction_dir[dir][1]) | can_see_monsterP(m, x, y, reduction_dir[dir][2]);
03426 }
03427
03432 void free_key_values(object *op)
03433 {
03434 key_value *i, *next = NULL;
03435
03436 if (op->key_values == NULL)
03437 {
03438 return;
03439 }
03440
03441 for (i = op->key_values; i; i = next)
03442 {
03443
03444 next = i->next;
03445
03446 if (i->key)
03447 {
03448 FREE_AND_CLEAR_HASH(i->key);
03449 }
03450
03451 if (i->value)
03452 {
03453 FREE_AND_CLEAR_HASH(i->value);
03454 }
03455
03456 i->next = NULL;
03457 free(i);
03458 }
03459
03460 op->key_values = NULL;
03461 }
03462
03469 key_value *object_get_key_link(const object *ob, const char *key)
03470 {
03471 key_value *link;
03472
03473 for (link = ob->key_values; link; link = link->next)
03474 {
03475 if (link->key == key)
03476 {
03477 return link;
03478 }
03479 }
03480
03481 return NULL;
03482 }
03483
03491 const char *object_get_value(const object *op, const char *const key)
03492 {
03493 key_value *link;
03494 const char *canonical_key = find_string(key);
03495
03496 if (canonical_key == NULL)
03497 {
03498 return NULL;
03499 }
03500
03501
03502
03503 for (link = op->key_values; link; link = link->next)
03504 {
03505 if (link->key == canonical_key)
03506 {
03507 return link->value;
03508 }
03509 }
03510
03511 return NULL;
03512 }
03513
03521 static int object_set_value_s(object *op, const char *canonical_key, const char *value, int add_key)
03522 {
03523 key_value *field = NULL, *last = NULL;
03524
03525 for (field = op->key_values; field; field = field->next)
03526 {
03527 if (field->key != canonical_key)
03528 {
03529 last = field;
03530 continue;
03531 }
03532
03533 if (field->value)
03534 {
03535 FREE_AND_CLEAR_HASH(field->value);
03536 }
03537
03538 if (value)
03539 {
03540 field->value = add_string(value);
03541 }
03542 else
03543 {
03544
03545
03546
03547
03548 if (object_get_key_link(&op->arch->clone, canonical_key))
03549 {
03550 field->value = NULL;
03551 }
03552 else
03553 {
03554
03555 if (field->key)
03556 {
03557 FREE_AND_CLEAR_HASH(field->key);
03558 }
03559
03560 if (field->value)
03561 {
03562 FREE_AND_CLEAR_HASH(field->value);
03563 }
03564
03565 if (last)
03566 {
03567 last->next = field->next;
03568 }
03569 else
03570 {
03571 op->key_values = field->next;
03572 }
03573
03574 free(field);
03575 }
03576 }
03577
03578 return 1;
03579 }
03580
03581 if (!add_key)
03582 {
03583 return 0;
03584 }
03585
03586
03587
03588
03589
03590 if (value == NULL)
03591 {
03592 return 1;
03593 }
03594
03595 field = malloc(sizeof(key_value));
03596
03597 field->key = add_refcount(canonical_key);
03598 field->value = add_string(value);
03599
03600 field->next = op->key_values;
03601 op->key_values = field;
03602
03603 return 1;
03604 }
03605
03615 int object_set_value(object *op, const char *key, const char *value, int add_key)
03616 {
03617 const char *canonical_key = find_string(key);
03618 int floating_ref = 0, ret;
03619
03620 if (canonical_key == NULL)
03621 {
03622 canonical_key = add_string(key);
03623 floating_ref = 1;
03624 }
03625
03626 ret = object_set_value_s(op, canonical_key, value, add_key);
03627
03628 if (floating_ref)
03629 {
03630 FREE_ONLY_HASH(canonical_key);
03631 }
03632
03633 return ret;
03634 }
03635
03638 void init_object_initializers()
03639 {
03640 object_initializers[BEACON] = beacon_add;
03641 }