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
00033 #include <global.h>
00034 #include <living.h>
00035 #include <spells.h>
00036 #include <skills.h>
00037 #include <tod.h>
00038
00039 #ifndef __CEXTRACT__
00040 #include <sproto.h>
00041 #endif
00042
00043
00044 #include <sounds.h>
00045
00046
00047 #include <math.h>
00048
00064 int transport_can_hold(const object *transport, const object *op, int nrof) {
00065 if ((op->weight*nrof+transport->carrying) > transport->weight_limit)
00066 return 0;
00067 else
00068 return 1;
00069 }
00070
00081 int should_director_abort(object *op, object *victim) {
00082 int arch_flag, name_flag, race_flag;
00083
00084
00085
00086
00087
00088
00089
00090
00091
00092
00093 if (op->subtype) {
00094 arch_flag = (op->subtype&1);
00095 name_flag = (op->subtype&2);
00096 race_flag = (op->subtype&4);
00097 } else {
00098 arch_flag = 1;
00099 name_flag = 1;
00100 race_flag = 1;
00101 }
00102
00103
00104
00105 if ((op->race)
00106 && ((!(victim->arch && arch_flag && victim->arch->name) || strcmp(op->race, victim->arch->name)))
00107 && ((!(victim->name && name_flag) || strcmp(op->race, victim->name)))
00108 && ((!(victim->race && race_flag) || strcmp(op->race, victim->race)))) {
00109 return 1;
00110 }
00111
00112
00113
00114
00115 if ((op->slaying)
00116 && (((victim->arch && arch_flag && victim->arch->name && !strcmp(op->slaying, victim->arch->name)))
00117 || ((victim->name && name_flag && !strcmp(op->slaying, victim->name)))
00118 || ((victim->race && race_flag && !strcmp(op->slaying, victim->race))))) {
00119 return 1;
00120 }
00121 return 0;
00122 }
00123
00131 void handle_apply_yield(object *tmp) {
00132 const char *yield;
00133
00134 yield = get_ob_key_value(tmp, "on_use_yield");
00135 if (yield != NULL) {
00136 object *drop = create_archetype(yield);
00137 if (tmp->env) {
00138 drop = insert_ob_in_ob(drop, tmp->env);
00139 } else {
00140 drop->x = tmp->x;
00141 drop->y = tmp->y;
00142 insert_ob_in_map(drop, tmp->map, tmp, INS_BELOW_ORIGINATOR);
00143 }
00144 }
00145 }
00146
00147 int check_weapon_power(const object *who, int improvs);
00148
00160 int set_object_face_main(object *op) {
00161 int newface = op->arch->clone.face->number;
00162 sstring saved = get_ob_key_value(op, "face_closed");
00163
00164 if (saved) {
00165 newface = find_face(saved, newface);
00166 }
00167 if (newface && op->face != &new_faces[newface]) {
00168 op->face = &new_faces[newface];
00169 return TRUE;
00170 }
00171 return FALSE;
00172 }
00173
00185 static int set_object_face_other(object *op) {
00186 sstring custom;
00187 int newface = 0;
00188
00189 if (op->face && op->other_arch && op->other_arch->clone.face)
00190 newface = op->other_arch->clone.face->number;
00191
00192 if (op->face != op->arch->clone.face) {
00193
00194 set_ob_key_value(op, "face_closed", op->face->name, 1);
00195 }
00196
00197 custom = get_ob_key_value(op, "face_opened");
00198 if (custom) {
00199 newface = find_face(custom, newface);
00200 }
00201
00202 if (newface && op->face->number != newface) {
00203 op->face = &new_faces[newface];
00204 return TRUE;
00205 }
00206 return FALSE;
00207 }
00208
00230 int apply_container(object *op, object *sack) {
00231 char name_sack[MAX_BUF], name_tmp[MAX_BUF];
00232 object *tmp = op->container;
00233
00234 if (op->type != PLAYER)
00235 return 0;
00236
00237 if (sack == NULL || sack->type != CONTAINER) {
00238 LOG(llevError, "apply_container: %s is not container!\n", sack ? sack->name : "NULL");
00239 return 0;
00240 }
00241
00242
00243
00244
00245
00246
00247 if (op->container && QUERY_FLAG(sack, FLAG_APPLIED)) {
00248 if (op->container->env != op) {
00249 op->container->move_off = 0;
00250 }
00251
00252 if (execute_event(tmp, EVENT_CLOSE, op, NULL, NULL, SCRIPT_FIX_ALL) != 0)
00253 return 1;
00254
00255 query_name(op->container, name_tmp, MAX_BUF);
00256 draw_ext_info_format(NDI_UNIQUE, 0, op,
00257 MSG_TYPE_APPLY, MSG_TYPE_APPLY_UNAPPLY,
00258 "You close %s.",
00259 "You close %s.",
00260 name_tmp);
00261 CLEAR_FLAG(op->container, FLAG_APPLIED);
00262 op->container = NULL;
00263 if (set_object_face_main(tmp)) {
00264 esrv_update_item(UPD_FLAGS|UPD_FACE, op, tmp);
00265 } else {
00266 esrv_update_item(UPD_FLAGS, op, tmp);
00267 }
00268 if (tmp == sack)
00269 return 1;
00270 }
00271
00272 query_name(sack, name_sack, MAX_BUF);
00273
00274
00275
00276
00277
00278
00279 if (sack->slaying) {
00280 tmp = find_key(op, op, sack);
00281 if (tmp) {
00282 query_name(tmp, name_tmp, MAX_BUF);
00283 draw_ext_info_format(NDI_UNIQUE, 0, op,
00284 MSG_TYPE_APPLY, MSG_TYPE_APPLY_SUCCESS,
00285 "You unlock %s with %s.",
00286 "You unlock %s with %s.",
00287 name_sack, name_tmp);
00288 } else {
00289 draw_ext_info_format(NDI_UNIQUE, 0, op,
00290 MSG_TYPE_APPLY, MSG_TYPE_APPLY_ERROR,
00291 "You don't have the key to unlock %s.",
00292 "You don't have the key to unlock %s.",
00293 name_sack);
00294 return 0;
00295 }
00296 }
00297
00298
00299
00300
00301
00302
00303
00304
00305
00306
00307
00308
00309
00310 if (sack->env != op) {
00311
00312
00313
00314
00315
00316 if (sack->env) {
00317 draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_APPLY, MSG_TYPE_APPLY_ERROR,
00318 "You can't open %s",
00319 "You can't open %s",
00320 name_sack);
00321 return 0;
00322 }
00323
00324 if (sack->nrof > 1) {
00325 object *left = get_split_ob(sack, sack->nrof-1, NULL, 0);
00326
00327 insert_ob_in_map_at(left, sack->map, NULL, INS_NO_MERGE, sack->x, sack->y);
00328
00329 query_name(sack, name_sack, MAX_BUF);
00330 }
00331
00332
00333 sack->move_off = MOVE_ALL;
00334
00335 CLEAR_FLAG(sack, FLAG_APPLIED);
00336 draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_APPLY, MSG_TYPE_APPLY_SUCCESS,
00337 "You open %s.",
00338 "You open %s.",
00339 name_sack);
00340 SET_FLAG(sack, FLAG_APPLIED);
00341 op->container = sack;
00342 if (set_object_face_other(sack)) {
00343 esrv_update_item(UPD_FLAGS|UPD_FACE, op, sack);
00344 } else {
00345 esrv_update_item(UPD_FLAGS, op, sack);
00346 }
00347 esrv_send_inventory(op, sack);
00348 } else {
00349 if (QUERY_FLAG(sack, FLAG_APPLIED)) {
00350 CLEAR_FLAG(sack, FLAG_APPLIED);
00351 draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_APPLY, MSG_TYPE_APPLY_SUCCESS,
00352 "You open %s.",
00353 "You open %s.",
00354 name_sack);
00355 SET_FLAG(sack, FLAG_APPLIED);
00356 op->container = sack;
00357 if (set_object_face_other(sack)) {
00358 esrv_update_item(UPD_FLAGS|UPD_FACE, op, sack);
00359 } else {
00360 esrv_update_item(UPD_FLAGS, op, sack);
00361 }
00362 esrv_send_inventory(op, sack);
00363 } else {
00364 object *left = NULL;
00365
00366 if (sack->nrof > 1) {
00367 left = get_split_ob(sack, sack->nrof-1, NULL, 1);
00368 }
00369
00370 CLEAR_FLAG(sack, FLAG_APPLIED);
00371 draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_APPLY, MSG_TYPE_APPLY_SUCCESS,
00372 "You readied %s.",
00373 "You readied %s.",
00374 name_sack);
00375 SET_FLAG(sack, FLAG_APPLIED);
00376 esrv_update_item(UPD_FLAGS, op, sack);
00377
00378 if (left) {
00379 insert_ob_in_ob(left, sack->env);
00380 esrv_send_item(op, left);
00381 }
00382 }
00383 }
00384 return 1;
00385 }
00386
00398 void do_learn_spell(object *op, object *spell, int special_prayer) {
00399 object *tmp;
00400
00401 if (op->type != PLAYER) {
00402 LOG(llevError, "BUG: do_learn_spell(): not a player\n");
00403 return;
00404 }
00405
00406
00407 if ((tmp = check_spell_known(op, spell->name)) != NULL) {
00408 if (special_prayer && !QUERY_FLAG(tmp, FLAG_STARTEQUIP)) {
00409 LOG(llevError, "BUG: do_learn_spell(): spell already known, but not marked as startequip\n");
00410 return;
00411 }
00412 return;
00413 }
00414
00415 play_sound_player_only(op->contr, SOUND_TYPE_SPELL, spell, 0, "learn");
00416 tmp = get_object();
00417 copy_object(spell, tmp);
00418 insert_ob_in_ob(tmp, op);
00419
00420 if (special_prayer) {
00421 SET_FLAG(tmp, FLAG_STARTEQUIP);
00422 }
00423
00424 draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_APPLY, MSG_TYPE_APPLY_SUCCESS,
00425 "Type 'bind cast %s to store the spell in a key.",
00426 "Type 'bind cast %s to store the spell in a key.",
00427 spell->name);
00428
00429 esrv_add_spells(op->contr, tmp);
00430 }
00431
00440 void do_forget_spell(object *op, const char *spell) {
00441 object *spob;
00442
00443 if (op->type != PLAYER) {
00444 LOG(llevError, "BUG: do_forget_spell(): not a player\n");
00445 return;
00446 }
00447 if ((spob = check_spell_known(op, spell)) == NULL) {
00448 LOG(llevError, "BUG: do_forget_spell(): spell not known\n");
00449 return;
00450 }
00451
00452 draw_ext_info_format(NDI_UNIQUE|NDI_NAVY, 0, op, MSG_TYPE_APPLY, MSG_TYPE_APPLY_CURSED,
00453 "You lose knowledge of %s.",
00454 "You lose knowledge of %s.",
00455 spell);
00456 player_unready_range_ob(op->contr, spob);
00457 esrv_remove_spell(op->contr, spob);
00458 remove_ob(spob);
00459 free_object(spob);
00460 }
00461
00472 static int check_race_restrictions(object *who, object *item) {
00473 char buf[MAX_BUF];
00474 sstring restriction;
00475
00476 if (who->type != PLAYER || QUERY_FLAG(who, FLAG_WIZ))
00477 return 1;
00478
00479 restriction = get_ob_key_value(item, "race_restriction");
00480 if (!restriction)
00481 return 1;
00482
00483 snprintf(buf, sizeof(buf), ":%s:", who->race);
00484 buf[sizeof(buf)-1] = '\0';
00485
00486 if (strstr(restriction, buf) != NULL)
00487 return 1;
00488
00489 query_name(item, buf, sizeof(buf));
00490 draw_ext_info_format(NDI_UNIQUE, 0, who, MSG_TYPE_APPLY, MSG_TYPE_APPLY_PROHIBITION, "Somehow you can't seem to use the %s.", NULL, buf);
00491
00492 return 0;
00493 }
00494
00512 int manual_apply(object *op, object *tmp, int aflag) {
00513 if (tmp->head)
00514 tmp = tmp->head;
00515
00516 if (QUERY_FLAG(tmp, FLAG_UNPAID) && !QUERY_FLAG(tmp, FLAG_APPLIED)) {
00517 if (op->type == PLAYER) {
00518 draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_APPLY, MSG_TYPE_APPLY_ERROR,
00519 "You should pay for it first.", NULL);
00520 return METHOD_SILENT_ERROR;
00521 }
00522 return 0;
00523 }
00524
00525 if (!check_race_restrictions(op, tmp))
00526 return METHOD_SILENT_ERROR;
00527
00528
00529 if (execute_event(tmp, EVENT_APPLY, op, NULL, NULL, SCRIPT_FIX_ALL) != 0)
00530 return METHOD_OK;
00531
00532 if (op->contr)
00533 play_sound_player_only(op->contr, SOUND_TYPE_ITEM, tmp, 0, "apply");
00534
00535 return ob_apply(tmp, op, aflag);
00536 }
00537
00557 int player_apply(object *pl, object *op, int aflag, int quiet) {
00558 int tmp;
00559
00560 if (op->env == NULL && (pl->move_type&MOVE_FLYING)) {
00561
00562 if (!QUERY_FLAG(pl, FLAG_WIZ) && !(op->move_type&MOVE_FLYING)) {
00563 draw_ext_info(NDI_UNIQUE, 0, pl, MSG_TYPE_APPLY, MSG_TYPE_APPLY_ERROR,
00564 "But you are floating high above the ground!", NULL);
00565 return 0;
00566 }
00567 }
00568
00569
00570
00571
00572 if (op->type != PLAYER
00573 && QUERY_FLAG(op, FLAG_WAS_WIZ)
00574 && !QUERY_FLAG(pl, FLAG_WAS_WIZ)) {
00575 play_sound_map(SOUND_TYPE_ITEM, op, 0, "evaporate");
00576 draw_ext_info(NDI_UNIQUE, 0, pl, MSG_TYPE_APPLY, MSG_TYPE_APPLY_ERROR,
00577 "The object disappears in a puff of smoke!", NULL);
00578 draw_ext_info(NDI_UNIQUE, 0, pl, MSG_TYPE_APPLY, MSG_TYPE_APPLY_ERROR,
00579 "It must have been an illusion.", NULL);
00580 remove_ob(op);
00581 free_object(op);
00582 return 1;
00583 }
00584
00585 pl->contr->last_used = op;
00586 pl->contr->last_used_id = op->count;
00587
00588 tmp = manual_apply(pl, op, aflag);
00589 if (!quiet) {
00590 if (tmp == METHOD_UNHANDLED) {
00591 char name[MAX_BUF];
00592
00593 query_name(op, name, MAX_BUF);
00594 draw_ext_info_format(NDI_UNIQUE, 0, pl, MSG_TYPE_APPLY, MSG_TYPE_APPLY_ERROR,
00595 "I don't know how to apply the %s.",
00596 "I don't know how to apply the %s.",
00597 name);
00598 } else if (tmp == METHOD_ERROR)
00599 draw_ext_info_format(NDI_UNIQUE, 0, pl, MSG_TYPE_APPLY, MSG_TYPE_APPLY_ERROR,
00600 "You must get it first!\n", NULL);
00601 else if (tmp == METHOD_SILENT_ERROR)
00602 return tmp;
00603 }
00604 if (tmp == METHOD_OK) {
00605 if (op->anim_suffix != NULL)
00606 apply_anim_suffix(pl, op->anim_suffix);
00607 }
00608 return tmp;
00609 }
00610
00619 void player_apply_below(object *pl) {
00620 object *tmp, *next;
00621 int floors;
00622
00623 if (pl->contr->transport && pl->contr->transport->type == TRANSPORT) {
00624 ob_apply(pl->contr->transport, pl, 0);
00625 return;
00626 }
00627
00628
00629
00630
00631 tmp = (pl->container != NULL) ? pl->container->inv : pl->below;
00632
00633
00634
00635
00636
00637
00638
00639 for (floors = 0; tmp != NULL; tmp = next) {
00640 next = tmp->below;
00641 if (QUERY_FLAG(tmp, FLAG_IS_FLOOR))
00642 floors++;
00643 else if (floors > 0)
00644 return;
00645
00646
00647
00648
00649
00650
00651 if (!tmp->invisible || (tmp->move_on&pl->move_type)) {
00652 if (player_apply(pl, tmp, 0, 1) == METHOD_OK)
00653 return;
00654 }
00655 if (floors >= 2)
00656 return;
00657 }
00658 }
00659
00675 static int unapply_special(object *who, object *op, int aflags) {
00676 char name[MAX_BUF];
00677
00678 if (op->type != LAMP)
00679 CLEAR_FLAG(op, FLAG_APPLIED);
00680 query_name(op, name, MAX_BUF);
00681 switch (op->type) {
00682 case WEAPON:
00683 if (!(aflags&AP_NOPRINT))
00684 draw_ext_info_format(NDI_UNIQUE, 0, who, MSG_TYPE_APPLY, MSG_TYPE_APPLY_UNAPPLY,
00685 "You unwield %s.",
00686 "You unwield %s.",
00687 name);
00688 (void)change_abil(who, op);
00689 if (QUERY_FLAG(who, FLAG_READY_WEAPON))
00690 CLEAR_FLAG(who, FLAG_READY_WEAPON);
00691 who->current_weapon = NULL;
00692 clear_skill(who);
00693 break;
00694
00695 case SKILL:
00696 case SKILL_TOOL:
00697 if (op != who->chosen_skill) {
00698 LOG(llevError, "BUG: apply_special(): applied skill is not a chosen skill\n");
00699 }
00700 if (who->type == PLAYER) {
00701 if (who->contr->shoottype == range_skill)
00702 who->contr->shoottype = range_none;
00703 if (!op->invisible) {
00704 if (!(aflags&AP_NOPRINT))
00705 draw_ext_info_format(NDI_UNIQUE, 0, who, MSG_TYPE_APPLY, MSG_TYPE_APPLY_UNAPPLY,
00706 "You stop using the %s.",
00707 "You stop using the %s.",
00708 name);
00709 } else {
00710 if (!(aflags&AP_NOPRINT))
00711 draw_ext_info_format(NDI_UNIQUE, 0, who, MSG_TYPE_APPLY, MSG_TYPE_APPLY_UNAPPLY,
00712 "You can no longer use the skill: %s.",
00713 "You can no longer use the skill: %s.",
00714 op->skill);
00715 }
00716 }
00717 (void)change_abil(who, op);
00718 who->chosen_skill = NULL;
00719 CLEAR_FLAG(who, FLAG_READY_SKILL);
00720 break;
00721
00722 case ARMOUR:
00723 case HELMET:
00724 case SHIELD:
00725 case RING:
00726 case BOOTS:
00727 case GLOVES:
00728 case AMULET:
00729 case GIRDLE:
00730 case BRACERS:
00731 case CLOAK:
00732 if (!(aflags&AP_NOPRINT))
00733 draw_ext_info_format(NDI_UNIQUE, 0, who, MSG_TYPE_APPLY, MSG_TYPE_APPLY_UNAPPLY,
00734 "You unwear %s.",
00735 "You unwear %s.",
00736 name);
00737 (void)change_abil(who, op);
00738 break;
00739
00740 case BOW:
00741 case WAND:
00742 case ROD:
00743 case HORN:
00744 clear_skill(who);
00745 if (!(aflags&AP_NOPRINT))
00746 draw_ext_info_format(NDI_UNIQUE, 0, who, MSG_TYPE_APPLY, MSG_TYPE_APPLY_UNAPPLY,
00747 "You unready %s.",
00748 "You unready %s.",
00749 name);
00750 if (who->type == PLAYER) {
00751 who->contr->shoottype = range_none;
00752 } else {
00753 if (op->type == BOW)
00754 CLEAR_FLAG(who, FLAG_READY_BOW);
00755 else
00756 CLEAR_FLAG(who, FLAG_READY_RANGE);
00757 }
00758 break;
00759
00760 case BUILDER:
00761 if (!(aflags&AP_NOPRINT))
00762 draw_ext_info_format(NDI_UNIQUE, 0, who, MSG_TYPE_APPLY, MSG_TYPE_APPLY_UNAPPLY,
00763 "You unready %s.",
00764 "You unready %s.",
00765 name);
00766 who->contr->shoottype = range_none;
00767 who->contr->ranges[range_builder] = NULL;
00768 break;
00769
00770 default:
00771 if (!(aflags&AP_NOPRINT))
00772 draw_ext_info_format(NDI_UNIQUE, 0, who, MSG_TYPE_APPLY, MSG_TYPE_APPLY_UNAPPLY,
00773 "You unapply %s.",
00774 "You unapply %s.",
00775 name);
00776 break;
00777 }
00778
00779 fix_object(who);
00780
00781 if (!(aflags&AP_NO_MERGE)) {
00782 object *tmp;
00783
00784 tmp = merge_ob(op, NULL);
00785 if (who->type == PLAYER) {
00786 if (tmp) {
00787 op = tmp;
00788 }
00789 esrv_update_item(UPD_FLAGS, who, op);
00790 }
00791 }
00792 return 0;
00793 }
00794
00814 static object *get_item_from_body_location(object *start, int loc) {
00815 object *tmp;
00816
00817 if (!start)
00818 return NULL;
00819
00820 for (tmp = start; tmp; tmp = tmp->below)
00821 if (QUERY_FLAG(tmp, FLAG_APPLIED)
00822 && tmp->body_info[loc]
00823 && (!tmp->invisible || tmp->type == SKILL))
00824 return tmp;
00825
00826 return NULL;
00827 }
00828
00850 static int unapply_for_ob(object *who, object *op, int aflags) {
00851 int i;
00852 object *tmp = NULL, *last;
00853 char name[MAX_BUF];
00854
00855
00856
00857
00858 if (op->type == WEAPON || op->type == SHIELD) {
00859 for (tmp = who->inv; tmp; tmp = tmp->below) {
00860 if (QUERY_FLAG(tmp, FLAG_APPLIED) && tmp->type == op->type) {
00861 if ((aflags&AP_IGNORE_CURSE)
00862 || (aflags&AP_PRINT)
00863 || (!QUERY_FLAG(tmp, FLAG_CURSED) && !QUERY_FLAG(tmp, FLAG_DAMNED))) {
00864 if (aflags&AP_PRINT) {
00865 query_name(tmp, name, MAX_BUF);
00866 draw_ext_info(NDI_UNIQUE, 0, who, MSG_TYPE_APPLY, MSG_TYPE_APPLY_UNAPPLY,
00867 name, NULL);
00868 } else
00869 unapply_special(who, tmp, aflags);
00870 } else {
00871
00872
00873
00874
00875
00876 if (!(aflags&AP_NOPRINT)) {
00877 query_name(tmp, name, MAX_BUF);
00878 draw_ext_info_format(NDI_UNIQUE, 0, who, MSG_TYPE_APPLY, MSG_TYPE_APPLY_UNAPPLY,
00879 "No matter how hard you try, you just can't remove %s.",
00880 "No matter how hard you try, you just can't remove %s.",
00881 name);
00882 }
00883 return 1;
00884 }
00885
00886 }
00887 }
00888 }
00889
00890 for (i = 0; i < NUM_BODY_LOCATIONS; i++) {
00891
00892 if (op->body_info[i]) {
00893 last = who->inv;
00894
00895
00896
00897
00898 while ((who->body_used[i]+op->body_info[i]) < 0) {
00899 tmp = get_item_from_body_location(last, i);
00900 if (!tmp) {
00901 return 1;
00902 }
00903
00904
00905 if ((aflags&AP_IGNORE_CURSE)
00906 || (aflags&AP_PRINT)
00907 || (!(QUERY_FLAG(tmp, FLAG_CURSED) || QUERY_FLAG(tmp, FLAG_DAMNED)))) {
00908 if (aflags&AP_PRINT) {
00909 query_name(tmp, name, MAX_BUF);
00910 draw_ext_info(NDI_UNIQUE, 0, who, MSG_TYPE_APPLY, MSG_TYPE_APPLY_UNAPPLY,
00911 name, NULL);
00912 } else
00913 unapply_special(who, tmp, aflags);
00914 } else {
00915
00916
00917
00918
00919
00920 if (!(aflags&AP_NOPRINT)) {
00921 query_name(tmp, name, MAX_BUF);
00922 draw_ext_info_format(NDI_UNIQUE, 0, who, MSG_TYPE_APPLY, MSG_TYPE_APPLY_UNAPPLY,
00923 "The %s just won't come off",
00924 "The %s just won't come off",
00925 name);
00926 }
00927 }
00928 last = tmp->below;
00929 }
00930
00931
00932
00933
00934 }
00935 }
00936 return 0;
00937 }
00938
00955 int can_apply_object(object *who, object *op) {
00956 int i, retval = 0;
00957 object *tmp = NULL, *ws = NULL;
00958
00959
00960
00961
00962
00963
00964 if (op->type == WEAPON || op->type == SHIELD) {
00965 for (tmp = who->inv; tmp && !ws; tmp = tmp->below) {
00966 if (QUERY_FLAG(tmp, FLAG_APPLIED) && tmp->type == op->type) {
00967 retval = CAN_APPLY_UNAPPLY;
00968 ws = tmp;
00969 }
00970 }
00971 }
00972
00973 for (i = 0; i < NUM_BODY_LOCATIONS; i++) {
00974 if (op->body_info[i]) {
00975
00976 if (FABS(op->body_info[i]) > who->body_info[i]) {
00977
00978
00979
00980 retval |= CAN_APPLY_NEVER;
00981 } else if ((who->body_used[i]+op->body_info[i]) < 0) {
00982
00983
00984
00985 object *tmp1;
00986
00987
00988
00989
00990
00991
00992
00993
00994
00995
00996 if (ws) {
00997 if ((who->body_used[i]-ws->body_info[i]+op->body_info[i]) >= 0) {
00998 retval |= CAN_APPLY_UNAPPLY;
00999 continue;
01000 }
01001 }
01002
01003 tmp1 = get_item_from_body_location(who->inv, i);
01004 if (!tmp1) {
01005 retval |= CAN_APPLY_NEVER;
01006 } else {
01007
01008
01009
01010
01011 retval |= CAN_APPLY_UNAPPLY;
01012 if (!tmp)
01013 tmp = tmp1;
01014 else if (tmp != tmp1) {
01015 retval |= CAN_APPLY_UNAPPLY_MULT;
01016 }
01017
01018
01019
01020
01021
01022 if (((who->body_used[i]-tmp1->body_info[i]) != who->body_info[i])
01023 && (FABS(op->body_info[i]) < who->body_info[i]))
01024 retval |= CAN_APPLY_UNAPPLY_CHOICE;
01025
01026
01027
01028
01029
01030 if ((who->body_used[i]+op->body_info[i]-tmp1->body_info[i]) < 0)
01031 retval |= CAN_APPLY_UNAPPLY_MULT;
01032 }
01033 }
01034 }
01035 }
01036
01037
01038 if (IS_WEAPON(op) && !QUERY_FLAG(who, FLAG_USE_WEAPON))
01039 retval |= CAN_APPLY_RESTRICTION;
01040 if (IS_SHIELD(op) && !QUERY_FLAG(who, FLAG_USE_SHIELD))
01041 retval |= CAN_APPLY_RESTRICTION;
01042 if (IS_ARMOR(op) && !QUERY_FLAG(who, FLAG_USE_ARMOUR))
01043 retval |= CAN_APPLY_RESTRICTION;
01044
01045 if (who->type != PLAYER) {
01046 if ((op->type == WAND || op->type == HORN || op->type == ROD)
01047 && !QUERY_FLAG(who, FLAG_USE_RANGE))
01048 retval |= CAN_APPLY_RESTRICTION;
01049 if (op->type == BOW && !QUERY_FLAG(who, FLAG_USE_BOW))
01050 retval |= CAN_APPLY_RESTRICTION;
01051 if (op->type == RING && !QUERY_FLAG(who, FLAG_USE_RING))
01052 retval |= CAN_APPLY_RESTRICTION;
01053 if (op->type == BOW && !QUERY_FLAG(who, FLAG_USE_BOW))
01054 retval |= CAN_APPLY_RESTRICTION;
01055 }
01056 return retval;
01057 }
01058
01076 int check_weapon_power(const object *who, int improvs) {
01077
01078
01079
01080
01081
01082 #if 1
01083 if (((who->level/5)+5) >= improvs)
01084 return 1;
01085 else
01086 return 0;
01087
01088 #else
01089 int level = 0;
01090
01091
01092
01093
01094
01095
01096
01097
01098
01099 if (who->type == PLAYER) {
01100 object *wc_obj = NULL;
01101
01102 for (wc_obj = who->inv; wc_obj; wc_obj = wc_obj->below)
01103 if (wc_obj->type == SKILL && IS_COMBAT_SKILL(wc_obj->subtype)
01104 && wc_obj->level > level)
01105 level = wc_obj->level;
01106
01107 if (!level) {
01108 LOG(llevError, "Error: Player: %s lacks wc experience object\n", who->name);
01109 level = who->level;
01110 }
01111 } else
01112 level = who->level;
01113
01114 return (improvs <= ((level/5)+5));
01115 #endif
01116 }
01117
01139 int apply_special(object *who, object *op, int aflags) {
01140 int basic_flag = aflags&AP_BASIC_FLAGS;
01141 object *tmp, *skop = NULL;
01142 int i;
01143 char name_op[MAX_BUF];
01144
01145 if (who == NULL) {
01146 LOG(llevError, "apply_special() from object without environment.\n");
01147 return 1;
01148 }
01149
01150 query_name(op, name_op, MAX_BUF);
01151
01152 if (op->env != who)
01153 return 1;
01154
01155
01156 if (QUERY_FLAG(op, FLAG_APPLIED)) {
01157
01158 if (basic_flag == AP_APPLY)
01159 return 0;
01160
01161 if (!(aflags&AP_IGNORE_CURSE)
01162 && (QUERY_FLAG(op, FLAG_CURSED) || QUERY_FLAG(op, FLAG_DAMNED))) {
01163 if (!(aflags&AP_NOPRINT))
01164 draw_ext_info_format(NDI_UNIQUE, 0, who, MSG_TYPE_APPLY, MSG_TYPE_APPLY_UNAPPLY,
01165 "No matter how hard you try, you just can't remove %s.",
01166 "No matter how hard you try, you just can't remove %s.",
01167 name_op);
01168 return 1;
01169 }
01170 return unapply_special(who, op, aflags);
01171 }
01172
01173 if (basic_flag == AP_UNAPPLY)
01174 return 0;
01175
01176 i = can_apply_object(who, op);
01177
01178
01179 if (i) {
01180 if (i&CAN_APPLY_NEVER) {
01181 if (!(aflags&AP_NOPRINT))
01182 draw_ext_info_format(NDI_UNIQUE, 0, who, MSG_TYPE_APPLY, MSG_TYPE_APPLY_BADBODY,
01183 "You don't have the body to use a %s",
01184 "You don't have the body to use a %s",
01185 name_op);
01186 return 1;
01187 } else if (i&CAN_APPLY_RESTRICTION) {
01188 if (!(aflags&AP_NOPRINT))
01189 draw_ext_info_format(NDI_UNIQUE, 0, who, MSG_TYPE_APPLY, MSG_TYPE_APPLY_PROHIBITION,
01190 "You have a prohibition against using a %s",
01191 "You have a prohibition against using a %s",
01192 name_op);
01193 return 1;
01194 }
01195 if (who->type != PLAYER) {
01196
01197 if (unapply_for_ob(who, op, aflags))
01198 return 1;
01199 } else {
01200 if (who->contr->unapply == unapply_never
01201 || (i&CAN_APPLY_UNAPPLY_CHOICE && who->contr->unapply == unapply_nochoice)) {
01202 if (!(aflags&AP_NOPRINT))
01203 draw_ext_info(NDI_UNIQUE, 0, who, MSG_TYPE_APPLY, MSG_TYPE_APPLY_UNAPPLY,
01204 "You need to unapply some item(s):", NULL);
01205 unapply_for_ob(who, op, AP_PRINT);
01206 return 1;
01207 } else if (who->contr->unapply == unapply_always
01208 || !(i&CAN_APPLY_UNAPPLY_CHOICE)) {
01209 i = unapply_for_ob(who, op, aflags);
01210 if (i)
01211 return 1;
01212 }
01213 }
01214 }
01215 if (op->skill && op->type != SKILL && op->type != SKILL_TOOL) {
01216 skop = find_skill_by_name(who, op->skill);
01217 if (!skop) {
01218 if (!(aflags&AP_NOPRINT))
01219 draw_ext_info_format(NDI_UNIQUE, 0, who, MSG_TYPE_APPLY, MSG_TYPE_APPLY_ERROR,
01220 "You need the %s skill to use this item!",
01221 "You need the %s skill to use this item!",
01222 op->skill);
01223 return 1;
01224 } else {
01225
01226
01227
01228 change_skill(who, skop, (aflags&AP_NOPRINT));
01229 }
01230 }
01231
01232 if (who->type == PLAYER
01233 && op->item_power
01234 && (op->item_power+who->contr->item_power) > (settings.item_power_factor*who->level)) {
01235 if (!(aflags&AP_NOPRINT))
01236 draw_ext_info(NDI_UNIQUE, 0, who, MSG_TYPE_APPLY, MSG_TYPE_APPLY_ERROR,
01237 "Equipping that combined with other items would consume your soul!", NULL);
01238 return 1;
01239 }
01240
01241
01242
01243
01244
01245
01246
01247 if (settings.personalized_blessings) {
01248 const char *owner = get_ob_key_value(op, "item_owner");
01249 if ((owner != NULL) && (strcmp(owner, who->name))) {
01250 const char *will = get_ob_key_value(op, "item_willpower");
01251 long item_will = 0;
01252 long margin = 0;
01253 const char *msg = NULL;
01254 int random_effect = 0;
01255 int damage_percentile = 0;
01256
01257 if (will != NULL)
01258 item_will = atol(will);
01259 if (item_will > who->stats.exp) {
01260 draw_ext_info_format(NDI_UNIQUE, 0, who, MSG_TYPE_APPLY, MSG_TYPE_APPLY_ERROR,
01261 "This %s refuses to serve you - it keeps evading your hand !",
01262 "This %s refuses to serve you - it keeps evading your hand !",
01263 op->name);
01264 return 1;
01265 }
01266 if (item_will != 0)
01267 margin = who->stats.exp/item_will;
01268 else
01269 margin = who->stats.exp;
01270 random_effect = (random_roll(0, 100, who, 1)-(margin*20));
01271 if (random_effect > 80) {
01272 msg = "You don't know why, but you have the feeling that the %s is angry at you !";
01273 damage_percentile = 60;
01274 } else if (random_effect > 60) {
01275 msg = "The %s seems to look at you nastily !";
01276 damage_percentile = 45;
01277 } else if (random_effect > 40) {
01278 msg = "You have the strange feeling that the %s is annoyed...";
01279 damage_percentile = 30;
01280 } else if (random_effect > 20) {
01281 msg = "The %s seems tired, or bored, in a way. Very strange !";
01282 damage_percentile = 15;
01283 } else if (random_effect > 0) {
01284 msg = "You hear the %s sighing !";
01285 damage_percentile = 0;
01286 }
01287 if (msg != NULL)
01288 draw_ext_info_format(NDI_UNIQUE, 0, who, MSG_TYPE_APPLY, MSG_TYPE_APPLY_SUCCESS,
01289 msg, msg, op->name);
01290 if (damage_percentile > 0) {
01291 int weapon_bite = (who->stats.hp*damage_percentile)/100;
01292 if (weapon_bite < 1)
01293 weapon_bite = 1;
01294 who->stats.hp -= weapon_bite;
01295 draw_ext_info_format(NDI_UNIQUE, 0, who, MSG_TYPE_VICTIM, MSG_TYPE_VICTIM_WAS_HIT,
01296 "You get a nasty bite in the hand !",
01297 "You get a nasty bite in the hand !");
01298 }
01299 }
01300 }
01301
01302
01303
01304
01305
01306
01307 if (op->nrof > 1)
01308 tmp = get_split_ob(op, op->nrof-1, NULL, 0);
01309 else
01310 tmp = NULL;
01311
01312 switch (op->type) {
01313 case WEAPON: {
01314 int ownerlen = 0;
01315 char *quotepos = NULL;
01316
01317 if (!check_weapon_power(who, op->last_eat)) {
01318 if (!(aflags&AP_NOPRINT))
01319 draw_ext_info(NDI_UNIQUE, 0, who, MSG_TYPE_APPLY,
01320 MSG_TYPE_APPLY_ERROR,
01321 "That weapon is too powerful for you to use. It would consume your soul!",
01322 NULL);
01323
01324 if (tmp != NULL)
01325 (void)insert_ob_in_ob(tmp, who);
01326 return 1;
01327 }
01328
01329 if ((quotepos = strstr(op->name, "'")) != NULL) {
01330 ownerlen = (strstr(op->name, "'")-op->name);
01331 if (op->level && (strncmp(op->name, who->name, ownerlen))) {
01332
01333
01334
01335 if (!(aflags&AP_NOPRINT))
01336 draw_ext_info(NDI_UNIQUE, 0, who, MSG_TYPE_APPLY, MSG_TYPE_APPLY_ERROR,
01337 "The weapon does not recognize you as its owner.", NULL);
01338 if (tmp != NULL)
01339 (void)insert_ob_in_ob(tmp, who);
01340 return 1;
01341 }
01342 }
01343 SET_FLAG(op, FLAG_APPLIED);
01344
01345 if (skop)
01346 change_skill(who, skop, 1);
01347 if (!QUERY_FLAG(who, FLAG_READY_WEAPON))
01348 SET_FLAG(who, FLAG_READY_WEAPON);
01349
01350 if (!(aflags&AP_NOPRINT))
01351 draw_ext_info_format(NDI_UNIQUE, 0, who, MSG_TYPE_APPLY, MSG_TYPE_APPLY_SUCCESS,
01352 "You wield %s.", "You wield %s.",
01353 name_op);
01354
01355 (void)change_abil(who, op);
01356 break;
01357 }
01358
01359 case ARMOUR:
01360 case HELMET:
01361 case SHIELD:
01362 case BOOTS:
01363 case GLOVES:
01364 case GIRDLE:
01365 case BRACERS:
01366 case CLOAK:
01367 case RING:
01368 case AMULET:
01369 SET_FLAG(op, FLAG_APPLIED);
01370 if (!(aflags&AP_NOPRINT))
01371 draw_ext_info_format(NDI_UNIQUE, 0, who, MSG_TYPE_APPLY, MSG_TYPE_APPLY_SUCCESS,
01372 "You wear %s.",
01373 "You wear %s.",
01374 name_op);
01375 (void)change_abil(who, op);
01376 break;
01377
01378
01379 case SKILL:
01380 case SKILL_TOOL:
01381 if (who->chosen_skill) {
01382 LOG(llevError, "BUG: apply_special(): can't apply two skills\n");
01383 return 1;
01384 }
01385
01386 if (who->type == PLAYER) {
01387 who->contr->shoottype = range_skill;
01388 who->contr->ranges[range_skill] = op;
01389 if (!op->invisible) {
01390 if (!(aflags&AP_NOPRINT)) {
01391 draw_ext_info_format(NDI_UNIQUE, 0, who, MSG_TYPE_APPLY, MSG_TYPE_APPLY_SUCCESS,
01392 "You ready %s.",
01393 "You ready %s.",
01394 name_op);
01395 draw_ext_info_format(NDI_UNIQUE, 0, who, MSG_TYPE_APPLY, MSG_TYPE_APPLY_SUCCESS,
01396 "You can now use the skill: %s.",
01397 "You can now use the skill: %s.",
01398 op->skill);
01399 }
01400 } else {
01401 if (!(aflags&AP_NOPRINT))
01402 draw_ext_info_format(NDI_UNIQUE, 0, who, MSG_TYPE_APPLY, MSG_TYPE_APPLY_SUCCESS,
01403 "Readied skill: %s.",
01404 "Readied skill: %s.",
01405 op->skill ? op->skill : op->name);
01406 }
01407 }
01408 SET_FLAG(op, FLAG_APPLIED);
01409 (void)change_abil(who, op);
01410 who->chosen_skill = op;
01411 SET_FLAG(who, FLAG_READY_SKILL);
01412 break;
01413
01414 case BOW:
01415 if (!check_weapon_power(who, op->last_eat)) {
01416 if (!(aflags&AP_NOPRINT)) {
01417 draw_ext_info(NDI_UNIQUE, 0, who, MSG_TYPE_APPLY, MSG_TYPE_APPLY_ERROR,
01418 "That item is too powerful for you to use.",
01419 NULL);
01420 draw_ext_info(NDI_UNIQUE, 0, who, MSG_TYPE_APPLY, MSG_TYPE_APPLY_ERROR,
01421 "It would consume your soul!.", NULL);
01422 }
01423 if (tmp != NULL)
01424 (void)insert_ob_in_ob(tmp, who);
01425 return 1;
01426 }
01427 if (op->level && (strncmp(op->name, who->name, strlen(who->name)))) {
01428 if (!(aflags&AP_NOPRINT)) {
01429 draw_ext_info(NDI_UNIQUE, 0, who, MSG_TYPE_APPLY, MSG_TYPE_APPLY_ERROR,
01430 "The weapon does not recognize you as its owner.", NULL);
01431 }
01432 if (tmp != NULL)
01433 (void)insert_ob_in_ob(tmp, who);
01434 return 1;
01435 }
01436
01437 case WAND:
01438 case ROD:
01439 case HORN:
01440
01441 SET_FLAG(op, FLAG_APPLIED);
01442 if (skop)
01443 change_skill(who, skop, 0);
01444 if (!(aflags&AP_NOPRINT))
01445 draw_ext_info_format(NDI_UNIQUE, 0, who, MSG_TYPE_APPLY, MSG_TYPE_APPLY_SUCCESS,
01446 "You ready %s.",
01447 "You ready %s.",
01448 name_op);
01449 if (who->type == PLAYER) {
01450 if (op->type == BOW) {
01451 (void)change_abil(who, op);
01452 if (!(aflags&AP_NOPRINT))
01453 draw_ext_info_format(NDI_UNIQUE, 0, who, MSG_TYPE_APPLY, MSG_TYPE_APPLY_SUCCESS,
01454 "You will now fire %s with %s.",
01455 "You will now fire %s with %s.",
01456 op->race ? op->race : "nothing",
01457 name_op);
01458 who->contr->shoottype = range_bow;
01459 } else {
01460 who->contr->shoottype = range_misc;
01461 }
01462 } else {
01463 if (op->type == BOW)
01464 SET_FLAG(who, FLAG_READY_BOW);
01465 else
01466 SET_FLAG(who, FLAG_READY_RANGE);
01467 }
01468 break;
01469
01470 case BUILDER:
01471 if (who->contr->ranges[range_builder])
01472 unapply_special(who, who->contr->ranges[range_builder], 0);
01473 who->contr->shoottype = range_builder;
01474 who->contr->ranges[range_builder] = op;
01475 if (!(aflags&AP_NOPRINT))
01476 draw_ext_info_format(NDI_UNIQUE, 0, who, MSG_TYPE_APPLY, MSG_TYPE_APPLY_SUCCESS,
01477 "You ready your %s.",
01478 "You ready your %s.",
01479 name_op);
01480 break;
01481
01482 default:
01483 draw_ext_info_format(NDI_UNIQUE, 0, who, MSG_TYPE_APPLY, MSG_TYPE_APPLY_SUCCESS,
01484 "You apply %s.",
01485 "You apply %s.",
01486 name_op);
01487 }
01488
01489 SET_FLAG(op, FLAG_APPLIED);
01490
01491 if (tmp != NULL)
01492 tmp = insert_ob_in_ob(tmp, who);
01493
01494 fix_object(who);
01495
01496
01497
01498
01499
01500 if (who->type == PLAYER && op->type != WAND && op->type != HORN && op->type != ROD)
01501 SET_FLAG(op, FLAG_BEEN_APPLIED);
01502
01503 if (QUERY_FLAG(op, FLAG_CURSED) || QUERY_FLAG(op, FLAG_DAMNED)) {
01504 if (who->type == PLAYER) {
01505 draw_ext_info(NDI_UNIQUE, 0, who, MSG_TYPE_APPLY, MSG_TYPE_APPLY_CURSED,
01506 "Oops, it feels deadly cold!", NULL);
01507 SET_FLAG(op, FLAG_KNOWN_CURSED);
01508 }
01509 }
01510 if (who->type == PLAYER) {
01511 esrv_update_item(UPD_NROF|UPD_FLAGS|UPD_WEIGHT, who, op);
01512 }
01513 return 0;
01514 }
01515
01526 int auto_apply(object *op) {
01527 object *tmp = NULL, *tmp2;
01528 int i;
01529
01530 switch (op->type) {
01531 case SHOP_FLOOR:
01532 if (!HAS_RANDOM_ITEMS(op))
01533 return 0;
01534 do {
01535 i = 10;
01536 while ((tmp = generate_treasure(op->randomitems, op->stats.exp ? (int)op->stats.exp : MAX(op->map->difficulty, 5))) == NULL
01537 && --i)
01538 ;
01539 if (tmp == NULL)
01540 return 0;
01541 if (QUERY_FLAG(tmp, FLAG_CURSED) || QUERY_FLAG(tmp, FLAG_DAMNED)) {
01542 free_object(tmp);
01543 tmp = NULL;
01544 }
01545 } while (!tmp);
01546 tmp->x = op->x;
01547 tmp->y = op->y;
01548 SET_FLAG(tmp, FLAG_UNPAID);
01549 insert_ob_in_map(tmp, op->map, NULL, 0);
01550 CLEAR_FLAG(op, FLAG_AUTO_APPLY);
01551 identify(tmp);
01552 break;
01553
01554 case TREASURE:
01555 if (QUERY_FLAG(op, FLAG_IS_A_TEMPLATE))
01556 return 0;
01557 while ((op->stats.hp--) > 0)
01558 create_treasure(op->randomitems, op, op->map ? GT_ENVIRONMENT : 0, op->stats.exp ? (int)op->stats.exp : op->map == NULL ? 14 : op->map->difficulty, 0);
01559
01560
01561
01562
01563
01564
01565 for (tmp = op->inv; tmp; tmp = tmp2) {
01566 tmp2 = tmp->below;
01567 remove_ob(tmp);
01568 if (op->env)
01569 insert_ob_in_ob(tmp, op->env);
01570 else
01571 free_object(tmp);
01572 }
01573 remove_ob(op);
01574 free_object(op);
01575 break;
01576 }
01577 return tmp ? 1 : 0;
01578 }
01579
01590 void fix_auto_apply(mapstruct *m) {
01591 object *tmp, *above = NULL;
01592 int x, y;
01593
01594 if (m == NULL)
01595 return;
01596
01597 for (x = 0; x < MAP_WIDTH(m); x++)
01598 for (y = 0; y < MAP_HEIGHT(m); y++)
01599 for (tmp = GET_MAP_OB(m, x, y); tmp != NULL; tmp = above) {
01600 above = tmp->above;
01601
01602 if (tmp->inv) {
01603 object *invtmp, *invnext;
01604
01605 for (invtmp = tmp->inv; invtmp != NULL; invtmp = invnext) {
01606 invnext = invtmp->below;
01607
01608 if (QUERY_FLAG(invtmp, FLAG_AUTO_APPLY))
01609 auto_apply(invtmp);
01610 else if (invtmp->type == TREASURE && HAS_RANDOM_ITEMS(invtmp)) {
01611 while ((invtmp->stats.hp--) > 0)
01612 create_treasure(invtmp->randomitems, invtmp, 0, m->difficulty, 0);
01613 invtmp->randomitems = NULL;
01614 } else if (invtmp && invtmp->arch
01615 && invtmp->type != TREASURE
01616 && invtmp->type != SPELL
01617 && invtmp->type != CLASS
01618 && HAS_RANDOM_ITEMS(invtmp)) {
01619 create_treasure(invtmp->randomitems, invtmp, 0, m->difficulty, 0);
01620
01621
01622
01623 invtmp->randomitems = NULL;
01624 }
01625 }
01626
01627
01628
01629
01630
01631
01632
01633
01634
01635
01636
01637
01638
01639 if (tmp->type == WAND
01640 || tmp->type == ROD
01641 || tmp->type == SCROLL
01642 || tmp->type == HORN
01643 || tmp->type == FIREWALL
01644 || tmp->type == POTION
01645 || tmp->type == ALTAR
01646 || tmp->type == SPELLBOOK)
01647 tmp->randomitems = NULL;
01648 }
01649
01650 if (QUERY_FLAG(tmp, FLAG_AUTO_APPLY))
01651 auto_apply(tmp);
01652 else if ((tmp->type == TREASURE || (tmp->type == CONTAINER))
01653 && HAS_RANDOM_ITEMS(tmp)) {
01654 while ((tmp->stats.hp--) > 0)
01655 create_treasure(tmp->randomitems, tmp, 0, m->difficulty, 0);
01656 tmp->randomitems = NULL;
01657 } else if (tmp->type == TIMED_GATE) {
01658 object *head = tmp->head != NULL ? tmp->head : tmp;
01659
01660 if (QUERY_FLAG(head, FLAG_IS_LINKED)) {
01661 tmp->speed = 0;
01662 update_ob_speed(tmp);
01663 }
01664 }
01665
01666
01667
01668
01669
01670
01671
01672
01673 else if (tmp
01674 && tmp->arch
01675 && tmp->type != PLAYER
01676 && tmp->type != TREASURE
01677 && tmp->type != SPELL
01678 && tmp->type != PLAYER_CHANGER
01679 && tmp->type != CLASS
01680 && HAS_RANDOM_ITEMS(tmp)) {
01681 create_treasure(tmp->randomitems, tmp, GT_APPLY, m->difficulty, 0);
01682 tmp->randomitems = NULL;
01683 }
01684 }
01685
01686 for (x = 0; x < MAP_WIDTH(m); x++)
01687 for (y = 0; y < MAP_HEIGHT(m); y++)
01688 for (tmp = GET_MAP_OB(m, x, y); tmp != NULL; tmp = tmp->above)
01689 if (tmp->above
01690 && (tmp->type == TRIGGER_BUTTON || tmp->type == TRIGGER_PEDESTAL))
01691 check_trigger(tmp, tmp->above);
01692 }
01693
01708 void scroll_failure(object *op, int failure, int power) {
01709 if (abs(failure/4) > power)
01710 power = abs(failure/4);
01711
01712 if (failure <= -1 && failure > -15) {
01713 object *tmp;
01714
01715 draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_APPLY, MSG_TYPE_APPLY_FAILURE,
01716 "Your spell warps!", NULL);
01717 tmp = create_archetype(SPELL_WONDER);
01718 cast_wonder(op, op, 0, tmp);
01719 if (op->stats.sp < 0)
01720
01721 op->stats.sp = 0;
01722 free_object(tmp);
01723 return;
01724 }
01725
01726 if (settings.spell_failure_effects == TRUE) {
01727 if (failure <= -35 && failure > -60) {
01728 draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_APPLY, MSG_TYPE_APPLY_FAILURE,
01729 "The magic recoils on you!", NULL);
01730 confuse_living(op, op, power);
01731 return;
01732 }
01733
01734 if (failure <= -60 && failure > -70) {
01735 draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_APPLY, MSG_TYPE_APPLY_FAILURE,
01736 "The magic recoils and paralyzes you!", NULL);
01737 paralyze_living(op, op, power);
01738 return;
01739 }
01740
01741 if (failure <= -70 && failure > -80) {
01742 draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_APPLY, MSG_TYPE_APPLY_FAILURE,
01743 "The magic recoils on you!", NULL);
01744 blind_living(op, op, power);
01745 return;
01746 }
01747
01748 if (failure <= -80) {
01749 object *tmp;
01750
01751 tmp = create_archetype(LOOSE_MANA);
01752 cast_magic_storm(op, tmp, power);
01753 draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_APPLY, MSG_TYPE_APPLY_FAILURE,
01754 "You unlease uncontrolled mana!", NULL);
01755 free_object(tmp);
01756 return;
01757 }
01758 }
01759
01760
01761
01762 draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_APPLY, MSG_TYPE_APPLY_FAILURE,
01763 "Your mana is drained!", NULL);
01764 op->stats.sp -= random_roll(0, power-1, op, PREFER_LOW);
01765 if (op->stats.sp < 0)
01766 op->stats.sp = 0;
01767 }
01768
01776 void apply_changes_to_player(object *pl, object *change) {
01777 int excess_stat = 0;
01778
01779
01780
01781
01782 switch (change->type) {
01783 case CLASS: {
01784 living *stats = &(pl->contr->orig_stats);
01785 living *ns = &(change->stats);
01786 object *walk;
01787 int flag_change_face = 1;
01788
01789
01790
01791
01792
01793 int i, j;
01794 for (i = 0; i < NUM_STATS; i++) {
01795 sint8 stat = get_attr_value(stats, i);
01796 int race_bonus = get_attr_value(&(pl->arch->clone.stats), i);
01797
01798 stat += get_attr_value(ns, i);
01799 if (stat > 20+race_bonus) {
01800 excess_stat++;
01801 stat = 20+race_bonus;
01802 }
01803 set_attr_value(stats, i, stat);
01804 }
01805
01806 for (j = 0; excess_stat > 0 && j < 100; j++) {
01807
01808 int i = rndm(0, 6);
01809 int stat = get_attr_value(stats, i);
01810 int race_bonus = get_attr_value(&(pl->arch->clone.stats), i);
01811
01812 if (i == CHA)
01813 continue;
01814 if (stat < 20+race_bonus) {
01815 change_attr_value(stats, i, 1);
01816 excess_stat--;
01817 }
01818 }
01819
01820
01821
01822
01823 if (change->randomitems != NULL)
01824 give_initial_items(pl, change->randomitems);
01825
01826
01827
01828
01829
01830
01831
01832 for (walk = pl->inv; walk != NULL; walk = walk->below)
01833 if (!strcmp(walk->name, "NOCLASSFACECHANGE"))
01834 flag_change_face = 0;
01835
01836 if (flag_change_face) {
01837 pl->animation_id = GET_ANIM_ID(change);
01838 pl->face = change->face;
01839
01840 if (QUERY_FLAG(change, FLAG_ANIMATE))
01841 SET_FLAG(pl, FLAG_ANIMATE);
01842 else
01843 CLEAR_FLAG(pl, FLAG_ANIMATE);
01844 }
01845
01846 if (change->anim_suffix) {
01847 char buf[MAX_BUF];
01848 int anim;
01849
01850 snprintf(buf, MAX_BUF, "%s_%s", animations[pl->animation_id].name, change->anim_suffix);
01851 anim = try_find_animation(buf);
01852 if (anim) {
01853 pl->animation_id = anim;
01854 pl->anim_speed = -1;
01855 CLEAR_FLAG(pl, FLAG_ANIMATE);
01856 animate_object(pl, pl->facing);
01857 }
01858 }
01859
01860
01861
01862
01863
01864 if (!strcmp(change->name, "monk"))
01865 CLEAR_FLAG(pl, FLAG_USE_WEAPON);
01866
01867 break;
01868 }
01869 }
01870 }
01871
01872 void legacy_apply_container(object *op, object *sack) {
01873 apply_container(op, sack);
01874 }