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
00026
00027
00028
00035 #include <global.h>
00036 #include <spells.h>
00037 #ifndef __CEXTRACT__
00038 #include <sproto.h>
00039 #endif
00040
00051 void remove_door(object *op) {
00052 int i;
00053 object *tmp;
00054
00055 for (i = 1; i < 9; i += 2)
00056 if ((tmp = present(DOOR, op->map, op->x+freearr_x[i], op->y+freearr_y[i])) != NULL) {
00057 tmp->speed = 0.1;
00058 update_ob_speed(tmp);
00059 tmp->speed_left = -0.2;
00060 }
00061
00062 if (op->other_arch) {
00063 tmp = arch_to_object(op->other_arch);
00064 tmp->x = op->x;
00065 tmp->y = op->y;
00066 tmp->map = op->map;
00067 tmp->level = op->level;
00068 insert_ob_in_map(tmp, op->map, op, 0);
00069 }
00070 remove_ob(op);
00071 free_object(op);
00072 }
00073
00080 void remove_locked_door(object *op) {
00081 int i;
00082 object *tmp;
00083
00084 for (i = 1; i < 9; i += 2) {
00085 tmp = present(LOCKED_DOOR, op->map, op->x+freearr_x[i], op->y+freearr_y[i]);
00086 if (tmp && tmp->slaying == op->slaying) {
00087 tmp->speed = 0.1;
00088 update_ob_speed(tmp);
00089 tmp->speed_left = -0.2;
00090 }
00091 }
00092 if (op->other_arch) {
00093 tmp = arch_to_object(op->other_arch);
00094 tmp->x = op->x;
00095 tmp->y = op->y;
00096 tmp->map = op->map;
00097 tmp->level = op->level;
00098 insert_ob_in_map(tmp, op->map, op, 0);
00099 }
00100 remove_ob(op);
00101 free_object(op);
00102 }
00103
00114 static void generate_monster_inv(object *gen) {
00115 int i;
00116 int nx, ny;
00117 object *op, *head = NULL;
00118 const char *code;
00119 int qty = 0;
00120
00121
00122
00123
00124
00125 if (gen->map == NULL) {
00126 LOG(llevError,"Generator (%s) not on a map?\n", gen->name);
00127 return;
00128 }
00129
00130
00131 for (op = gen->inv; op; op = op->below)
00132 qty++;
00133 if (!qty) {
00134 LOG(llevError,"Generator (%s) has no inventory in generate_monster_inv?\n", gen->name);
00135 return;
00136 }
00137 qty=rndm(0,qty-1);
00138 for (op=gen->inv;qty;qty--)
00139 op=op->below;
00140 i=find_multi_free_spot_within_radius(op, gen, &nx, &ny);
00141 if (i==-1)
00142 return;
00143 head=object_create_clone(op);
00144 CLEAR_FLAG(head, FLAG_IS_A_TEMPLATE);
00145 unflag_inv(head, FLAG_IS_A_TEMPLATE);
00146 if (rndm(0, 9))
00147 generate_artifact(head, gen->map->difficulty);
00148 code = get_ob_key_value(gen, "generator_code");
00149 if (code) {
00150 set_ob_key_value(head, "generator_code", code, 1);
00151 }
00152 insert_ob_in_map_at(head,gen->map,gen,0,nx,ny);
00153 if (QUERY_FLAG(head, FLAG_FREED)) return;
00154 fix_multipart_object(head);
00155 if (HAS_RANDOM_ITEMS(head))
00156 create_treasure(head->randomitems, head, GT_APPLY,
00157 gen->map->difficulty, 0);
00158 }
00159
00168 static void generate_monster_arch(object *gen) {
00169 int i;
00170 int nx, ny;
00171 object *op, *head = NULL, *prev = NULL;
00172 archetype *at = gen->other_arch;
00173 const char *code;
00174
00175 if(gen->other_arch == NULL) {
00176 LOG(llevError, "Generator without other_arch: %s\n", gen->name);
00177 return;
00178 }
00179
00180
00181
00182
00183 if (gen->map == NULL) {
00184 LOG(llevError,"Generator (%s) not on a map?\n", gen->name);
00185 return;
00186 }
00187 i = find_multi_free_spot_within_radius(&at->clone, gen, &nx, &ny);
00188 if (i == -1) return;
00189 while (at != NULL) {
00190 op = arch_to_object(at);
00191 op->x = nx + at->clone.x;
00192 op->y = ny + at->clone.y;
00193
00194 if (head != NULL)
00195 op->head = head, prev->more=op;
00196
00197 if (rndm(0, 9)) generate_artifact(op, gen->map->difficulty);
00198
00199 code = get_ob_key_value(gen, "generator_code");
00200 if (code) {
00201 set_ob_key_value(head, "generator_code", code, 1);
00202 }
00203
00204 insert_ob_in_map(op, gen->map, gen,0);
00205 if (QUERY_FLAG(op, FLAG_FREED)) return;
00206 if(HAS_RANDOM_ITEMS(op))
00207 create_treasure(op->randomitems, op, GT_APPLY,
00208 gen->map->difficulty, 0);
00209 if(head == NULL)
00210 head = op;
00211 prev = op;
00212 at = at->more;
00213 }
00214 }
00215
00222 static void generate_monster(object *gen) {
00223 sint8 children;
00224 sint8 max_children;
00225 sint8 x, y;
00226 object *tmp;
00227 const char *code, *value;
00228
00229 if (GENERATE_SPEED(gen)&&rndm(0, GENERATE_SPEED(gen)-1))
00230 return;
00231
00232 value = get_ob_key_value(gen, "generator_max_map");
00233 if (value) {
00234 max_children = (sint8)strtol(value, NULL, 10);
00235 if (max_children < 1)
00236 return;
00237 code = get_ob_key_value(gen, "generator_code");
00238 if (code) {
00239
00240
00241
00242 children = 0;
00243 for (x = 0; x < MAP_WIDTH(gen->map); x++) {
00244 for (y = 0; y < MAP_HEIGHT(gen->map); y++) {
00245 for (tmp = GET_MAP_OB(gen->map, x, y); tmp != NULL; tmp = tmp->above) {
00246 value = get_ob_key_value(tmp, "generator_code");
00247 if (value && value == code) {
00248 children++;
00249 }
00250 }
00251 }
00252 }
00253
00254 if (children >= max_children+1)
00255 return;
00256 } else {
00257
00258
00259
00260 value = get_ob_key_value(gen, "generator_name");
00261 if (value) {
00262 set_ob_key_value(gen, "generator_code", value, 1);
00263 } else if (gen->name) {
00264 set_ob_key_value(gen, "generator_code", gen->name, 1);
00265 } else {
00266 set_ob_key_value(gen, "generator_code", "generator", 1);
00267 }
00268 }
00269 }
00270
00271 if (QUERY_FLAG(gen, FLAG_CONTENT_ON_GEN))
00272 generate_monster_inv(gen);
00273 else
00274 generate_monster_arch(gen);
00275 }
00276
00284 static void remove_force(object *op) {
00285 if (--op->duration > 0) {
00286 check_spell_expiry(op);
00287 return;
00288 }
00289
00290 switch (op->subtype) {
00291 case FORCE_CONFUSION:
00292 if (op->env != NULL) {
00293 CLEAR_FLAG(op->env, FLAG_CONFUSED);
00294 draw_ext_info(NDI_UNIQUE, 0, op->env,
00295 MSG_TYPE_ATTRIBUTE, MSG_TYPE_ATTRIBUTE_BAD_EFFECT_END,
00296 "You regain your senses.", NULL);
00297 }
00298 break;
00299
00300 case FORCE_TRANSFORMED_ITEM:
00301
00302 if (op->env != NULL && op->inv != NULL) {
00303 object *inv = op->inv;
00304 object *pl = get_player_container(op);
00305
00306 remove_ob(inv);
00307 inv->weight = (inv->nrof ? (sint32)(op->env->weight/inv->nrof) : op->env->weight);
00308 if (op->env->env) {
00309 insert_ob_in_ob(inv, op->env->env);
00310 if (pl) {
00311 char name[HUGE_BUF];
00312
00313 query_short_name(inv, name, HUGE_BUF);
00314 draw_ext_info_format(NDI_UNIQUE, 0, pl, MSG_TYPE_ITEM, MSG_TYPE_ITEM_CHANGE,
00315 "Your %s recovers its original form.",
00316 "Your %s recovers its original form.",
00317 name);
00318 }
00319 } else {
00320
00321 inv->x = op->env->x;
00322 inv->y = op->env->y;
00323 insert_ob_in_map(inv, op->env->map, NULL, 0);
00324 }
00325 inv = op->env;
00326 remove_ob(op);
00327 free_object(op);
00328 remove_ob(inv);
00329 }
00330 return;
00331
00332 default:
00333 break;
00334 }
00335
00336 if (op->env != NULL) {
00337 CLEAR_FLAG(op, FLAG_APPLIED);
00338 change_abil(op->env, op);
00339 fix_object(op->env);
00340 }
00341 remove_ob(op);
00342 free_object(op);
00343 }
00344
00351 static void animate_trigger(object *op) {
00352 if ((unsigned char)++op->stats.wc >= NUM_ANIMATIONS(op)) {
00353 op->stats.wc = 0;
00354 check_trigger(op, NULL);
00355 } else {
00356 SET_ANIMATION(op, op->stats.wc);
00357 update_object(op, UP_OBJ_FACE);
00358 }
00359 }
00360
00367 static void move_hole(object *op) {
00368 object *next, *tmp;
00369
00370 if (op->value) {
00371 if (--op->stats.wc <= 0) {
00372 op->stats.wc = 0;
00373 op->speed = 0;
00374 update_ob_speed(op);
00375
00376
00377 op->move_on = MOVE_WALK;
00378 for (tmp = op->above; tmp != NULL; tmp = next) {
00379 next = tmp->above;
00380 ob_move_on(op, tmp, tmp);
00381 }
00382 }
00383
00384 op->state = op->stats.wc;
00385 animate_object(op, 0);
00386 update_object(op, UP_OBJ_FACE);
00387 return;
00388 }
00389
00390 op->move_on = 0;
00391
00392 op->stats.wc++;
00393 if ((int)op->stats.wc >= NUM_ANIMATIONS(op))
00394 op->stats.wc = NUM_ANIMATIONS(op)-1;
00395
00396 op->state = op->stats.wc;
00397 animate_object(op, 0);
00398 update_object(op, UP_OBJ_FACE);
00399 if ((unsigned char)op->stats.wc == (NUM_ANIMATIONS(op)-1)) {
00400 op->speed = 0;
00401 update_ob_speed(op);
00402 return;
00403 }
00404 }
00405
00426 object *stop_item(object *op) {
00427 if (free_no_drop(op))
00428 return NULL;
00429
00430 if (op->map == NULL)
00431 return op;
00432
00433 switch (op->type) {
00434 case THROWN_OBJ: {
00435 object *payload = op->inv;
00436
00437 if (payload == NULL)
00438 return NULL;
00439 remove_ob(payload);
00440 remove_ob(op);
00441 free_object(op);
00442 return payload;
00443 }
00444
00445 case ARROW:
00446 if (op->speed >= MIN_ACTIVE_SPEED)
00447 op = fix_stopped_arrow(op);
00448 return op;
00449
00450 default:
00451 return op;
00452 }
00453 }
00454
00466 void fix_stopped_item(object *op, mapstruct *map, object *originator) {
00467 if (map == NULL)
00468 return;
00469 if (QUERY_FLAG(op, FLAG_REMOVED))
00470 insert_ob_in_map(op, map, originator, 0);
00471 else if (op->type == ARROW)
00472 merge_ob(op, NULL);
00473 }
00474
00483 object *fix_stopped_arrow(object *op) {
00484 if (free_no_drop(op))
00485 return NULL;
00486
00487 if (rndm(0, 99) < op->stats.food) {
00488
00489 remove_ob(op);
00490 free_object(op);
00491 return NULL;
00492 }
00493
00494 op->direction = 0;
00495 op->move_on = 0;
00496 op->move_type = 0;
00497 op->speed = 0;
00498 update_ob_speed(op);
00499 op->stats.wc = op->stats.sp;
00500 op->stats.dam = op->stats.hp;
00501 op->attacktype = op->stats.grace;
00502 if (op->slaying != NULL)
00503 FREE_AND_CLEAR_STR(op->slaying);
00504
00505 if (op->skill != NULL)
00506 FREE_AND_CLEAR_STR(op->skill);
00507
00508 if (op->spellarg != NULL) {
00509 op->slaying = add_string(op->spellarg);
00510 free(op->spellarg);
00511 op->spellarg = NULL;
00512 } else
00513 op->slaying = NULL;
00514
00515
00516 op->spellarg = NULL;
00517 op->stats.sp = 0;
00518 op->stats.hp = 0;
00519 op->stats.grace = 0;
00520 op->level = 0;
00521 op->face = op->arch->clone.face;
00522 op->owner = NULL;
00523 update_object(op, UP_OBJ_FACE);
00524 return op;
00525 }
00526
00536 int free_no_drop(object *op) {
00537 if (!QUERY_FLAG(op, FLAG_NO_DROP)) {
00538 return 0;
00539 }
00540
00541 if (!QUERY_FLAG(op, FLAG_REMOVED)) {
00542 remove_ob(op);
00543 }
00544
00545 free_object2(op, 1);
00546 return 1;
00547 }
00548
00559 static void change_object(object *op) {
00560 object *tmp, *env;
00561 int i, j;
00562
00563 if (op->other_arch == NULL) {
00564 LOG(llevError, "Change object (%s) without other_arch error.\n", op->name);
00565 return;
00566 }
00567
00568
00569 if (!QUERY_FLAG(op, FLAG_ALIVE)) {
00570 if (op->stats.food-- > 0)
00571 return;
00572 else
00573 op->stats.food = 1;
00574 }
00575 env = op->env;
00576 remove_ob(op);
00577 for (i = 0; i < NROFNEWOBJS(op); i++) {
00578 tmp = arch_to_object(op->other_arch);
00579 if (op->type == LAMP)
00580 tmp->stats.food = op->stats.food-1;
00581 tmp->stats.hp = op->stats.hp;
00582 if (env) {
00583 tmp->x = env->x,
00584 tmp->y = env->y;
00585 tmp = insert_ob_in_ob(tmp, env);
00586 } else {
00587 j = find_first_free_spot(tmp, op->map, op->x, op->y);
00588 if (j == -1)
00589 free_object(tmp);
00590 else {
00591 tmp->x = op->x+freearr_x[j],
00592 tmp->y = op->y+freearr_y[j];
00593 insert_ob_in_map(tmp, op->map, op, 0);
00594 }
00595 }
00596 }
00597 free_object(op);
00598 }
00599
00610 void move_firewall(object *op) {
00611 object *spell;
00612
00613 if (!op->map)
00614 return;
00615
00616 spell = op->inv;
00617 if (!spell) {
00618 LOG(llevError, "move_firewall: no spell specified (%s, %s, %d, %d)\n", op->name, op->map->name, op->x, op->y);
00619 return;
00620 }
00621
00622 cast_spell(op, op, op->stats.sp ? op->stats.sp : rndm(1, 8), spell, NULL);
00623 }
00624
00625
00639 void move_player_mover(object *op) {
00640 object *victim, *nextmover;
00641 int dir = op->stats.sp;
00642 sint16 nx, ny;
00643 mapstruct *m;
00644
00645
00646 if (!dir)
00647 dir = rndm(1, 8);
00648
00649 for (victim = GET_MAP_OB(op->map, op->x, op->y); victim != NULL; victim = victim->above) {
00650 if (QUERY_FLAG(victim, FLAG_ALIVE)
00651 && !QUERY_FLAG(victim, FLAG_WIZPASS)
00652 && (victim->move_type&op->move_type || !victim->move_type)) {
00653
00654 if (victim->head)
00655 victim = victim->head;
00656
00657 if (QUERY_FLAG(op, FLAG_LIFESAVE)&&op->stats.hp-- < 0) {
00658 remove_ob(op);
00659 free_object(op);
00660 return;
00661 }
00662 nx = op->x+freearr_x[dir];
00663 ny = op->y+freearr_y[dir];
00664 m = op->map;
00665 if (get_map_flags(m, &m, nx, ny, &nx, &ny)&P_OUT_OF_MAP) {
00666 LOG(llevError, "move_player_mover: Trying to push player off the map! map=%s (%d, %d)\n", m->path, op->x, op->y);
00667 return;
00668 }
00669
00670 if (should_director_abort(op, victim))
00671 return;
00672
00673 for (nextmover = GET_MAP_OB(m, nx, ny); nextmover != NULL; nextmover = nextmover->above) {
00674 if (nextmover->type == PLAYERMOVER)
00675 nextmover->speed_left = -.99;
00676 if (QUERY_FLAG(nextmover, FLAG_ALIVE)) {
00677 op->speed_left = -1.1;
00678 }
00679 }
00680
00681 if (victim->type == PLAYER) {
00682
00683 if (op->level) {
00684
00685
00686
00687
00688
00689 victim->contr->fire_on = 0;
00690 victim->speed_left = -FABS(victim->speed);
00691 move_player(victim, dir);
00692 } else
00693 return;
00694 } else
00695 move_object(victim, dir);
00696
00697 if (!op->stats.maxsp && op->attacktype)
00698 op->stats.maxsp = 2.0;
00699
00700 if (op->attacktype) {
00701 victim->speed_left = -FABS(op->stats.maxsp*victim->speed/op->speed);
00702
00703
00704
00705
00706
00707
00708 if (victim->speed_left < -5.0)
00709 victim->speed_left = -5.0;
00710 }
00711 }
00712 }
00713 }
00714
00724 int process_object(object *op) {
00725 if (QUERY_FLAG(op, FLAG_IS_A_TEMPLATE))
00726 return 0;
00727
00728
00729 if (execute_event(op, EVENT_TIME, NULL, NULL, NULL, SCRIPT_FIX_NOTHING) != 0)
00730 return 0;
00731
00732 if (QUERY_FLAG(op, FLAG_MONSTER))
00733 if (move_monster(op) || QUERY_FLAG(op, FLAG_FREED))
00734 return 1;
00735
00736 if ((QUERY_FLAG(op, FLAG_ANIMATE) && op->anim_speed == 0)
00737 || (op->temp_animation_id && op->temp_anim_speed == 0)) {
00738 op->state++;
00739 if (op->type == PLAYER)
00740 animate_object(op, op->facing);
00741 else
00742 animate_object(op, op->direction);
00743
00744 if (QUERY_FLAG(op, FLAG_SEE_ANYWHERE))
00745 make_sure_seen(op);
00746 }
00747 if (QUERY_FLAG(op, FLAG_CHANGING) && !op->state) {
00748 change_object(op);
00749 return 1;
00750 }
00751 if (QUERY_FLAG(op, FLAG_GENERATOR) && !QUERY_FLAG(op, FLAG_FRIENDLY))
00752 generate_monster(op);
00753
00754 if (QUERY_FLAG(op, FLAG_IS_USED_UP) && --op->stats.food <= 0) {
00755 if (QUERY_FLAG(op, FLAG_APPLIED))
00756 remove_force(op);
00757 else {
00758 remove_ob(op);
00759 if (QUERY_FLAG(op, FLAG_SEE_ANYWHERE))
00760 make_sure_not_seen(op);
00761 free_object(op);
00762 }
00763 return 1;
00764 }
00765 return (ob_process(op) == METHOD_OK ? 1 : 0);
00766 }
00767
00768 void legacy_remove_force(object *op) {
00769 remove_force(op);
00770 }
00771
00772 void legacy_animate_trigger(object *op) {
00773 animate_trigger(op);
00774 }
00775
00776 void legacy_move_hole(object *op) {
00777 move_hole(op);
00778 }