… | |
… | |
30 | #include <skills.h> |
30 | #include <skills.h> |
31 | #include <tod.h> |
31 | #include <tod.h> |
32 | |
32 | |
33 | #include <sproto.h> |
33 | #include <sproto.h> |
34 | |
34 | |
35 | /* Want this regardless of rplay. */ |
|
|
36 | #include <sounds.h> |
|
|
37 | |
|
|
38 | /** |
35 | /** |
39 | * Check if op should abort moving victim because of it's race or slaying. |
36 | * Check if op should abort moving victim because of it's race or slaying. |
40 | * Returns 1 if it should abort, returns 0 if it should continue. |
37 | * Returns 1 if it should abort, returns 0 if it should continue. |
41 | */ |
38 | */ |
42 | int |
39 | int |
… | |
… | |
1830 | { |
1827 | { |
1831 | spell_skill = find_skill_by_name (op, spell->skill); |
1828 | spell_skill = find_skill_by_name (op, spell->skill); |
1832 | |
1829 | |
1833 | if (!spell_skill) |
1830 | if (!spell_skill) |
1834 | { |
1831 | { |
1835 | op->failmsg (format ("You lack the skill %s to use this spell.", &spell->skill)); |
1832 | op->failmsg (format ("You lack the %s skill to use this spell.", &spell->skill)); |
1836 | return; |
1833 | return; |
1837 | } |
1834 | } |
1838 | |
1835 | |
1839 | if (spell_skill->level < spell->level) |
1836 | if (spell_skill->level < spell->level) |
1840 | { |
1837 | { |
… | |
… | |
2777 | case BOW: |
2774 | case BOW: |
2778 | case RANGED: |
2775 | case RANGED: |
2779 | case BUILDER: |
2776 | case BUILDER: |
2780 | case SKILL_TOOL: |
2777 | case SKILL_TOOL: |
2781 | if (op->env != who) |
2778 | if (op->env != who) |
2782 | return 2; /* not in inventory */ |
2779 | who->failmsg (format ("You must get it first! H<You can only apply the %s if it is in your inventory.>\n", query_name (op))); |
2783 | |
2780 | else |
2784 | apply_special (who, op, aflag); |
2781 | apply_special (who, op, aflag); |
|
|
2782 | |
2785 | return 1; |
2783 | return 1; |
2786 | |
2784 | |
2787 | case DRINK: |
2785 | case DRINK: |
2788 | case FOOD: |
2786 | case FOOD: |
2789 | case FLESH: |
2787 | case FLESH: |
… | |
… | |
2853 | case ITEM_TRANSFORMER: |
2851 | case ITEM_TRANSFORMER: |
2854 | apply_item_transformer (who, op); |
2852 | apply_item_transformer (who, op); |
2855 | return 1; |
2853 | return 1; |
2856 | |
2854 | |
2857 | default: |
2855 | default: |
|
|
2856 | who->statusmsg (format ("I don't know how to apply the %s.", query_name (op))); |
2858 | return 0; |
2857 | return 0; |
2859 | } |
2858 | } |
2860 | } |
2859 | } |
2861 | |
2860 | |
2862 | /* quiet suppresses the "don't know how to apply" and "you must get it first" |
2861 | /* |
2863 | * messages as needed by player_apply_below(). But there can still be |
|
|
2864 | * "but you are floating high above the ground" messages. |
|
|
2865 | * |
|
|
2866 | * Same return value as apply() function. |
2862 | * Same return value as apply() function. |
2867 | */ |
2863 | */ |
2868 | int |
2864 | bool |
2869 | player_apply (object *pl, object *op, int aflag, int quiet) |
2865 | player_apply (object *pl, object *op, int aflag) |
2870 | { |
2866 | { |
2871 | if (!op->env && (pl->move_type & MOVE_FLYING)) |
2867 | if (!op->env && (pl->move_type & MOVE_FLYING)) |
2872 | { |
2868 | { |
2873 | /* player is flying and applying object not in inventory */ |
2869 | /* player is flying and applying object not in inventory */ |
2874 | if (!QUERY_FLAG (pl, FLAG_WIZ) && !(op->move_type & MOVE_FLYING)) |
2870 | if (!QUERY_FLAG (pl, FLAG_WIZ) && !(op->move_type & MOVE_FLYING)) |
… | |
… | |
2880 | } |
2876 | } |
2881 | } |
2877 | } |
2882 | |
2878 | |
2883 | pl->contr->last_used = op; |
2879 | pl->contr->last_used = op; |
2884 | |
2880 | |
2885 | int tmp = manual_apply (pl, op, aflag); |
2881 | return pl->apply (op, aflag); |
2886 | |
|
|
2887 | if (!quiet) |
|
|
2888 | { |
|
|
2889 | if (tmp == 0) |
|
|
2890 | pl->statusmsg (format ("I don't know how to apply the %s.", query_name (op))); |
|
|
2891 | else if (tmp == 2) |
|
|
2892 | pl->failmsg ("You must get it first!\n"); |
|
|
2893 | } |
|
|
2894 | |
|
|
2895 | return tmp; |
|
|
2896 | } |
2882 | } |
2897 | |
2883 | |
2898 | /** |
2884 | /** |
2899 | * player_apply_below attempts to apply the object 'below' the player. |
2885 | * player_apply_below attempts to apply the object 'below' the player. |
2900 | * If the player has an open container, we use that for below, otherwise |
2886 | * If the player has an open container, we use that for below, otherwise |
… | |
… | |
2911 | * we don't use a corrupt pointer for the next object, so we get the |
2897 | * we don't use a corrupt pointer for the next object, so we get the |
2912 | * next object in the stack before applying. This is can only be a |
2898 | * next object in the stack before applying. This is can only be a |
2913 | * problem if player_apply() has a bug in that it uses the object but does |
2899 | * problem if player_apply() has a bug in that it uses the object but does |
2914 | * not return a proper value. |
2900 | * not return a proper value. |
2915 | */ |
2901 | */ |
|
|
2902 | //TODO: currently looks only at the topmost objetc, no longer at multiple floors |
|
|
2903 | // and also not on move_on floors. what was this for, anyways? |
2916 | for (object *next, *tmp = pl->container_ () ? pl->container_ ()->inv : pl->below; tmp; tmp = next) |
2904 | for (object *next, *tmp = pl->container_ () ? pl->container_ ()->inv : pl->below; tmp; tmp = next) |
2917 | { |
2905 | { |
2918 | next = tmp->below; |
2906 | next = tmp->below; |
2919 | |
2907 | |
2920 | if (QUERY_FLAG (tmp, FLAG_IS_FLOOR)) |
|
|
2921 | floors++; |
|
|
2922 | else if (floors > 0) |
|
|
2923 | return; /* process only floor objects after first floor object */ |
|
|
2924 | |
|
|
2925 | /* If it is visible, player can apply it. If it is applied by |
2908 | /* If it is visible, player can apply it. |
2926 | * person moving on it, also activate. Added code to make it |
|
|
2927 | * so that at least one of players movement types be that which |
|
|
2928 | * the item needs. |
|
|
2929 | */ |
2909 | */ |
2930 | if (!tmp->invisible || (tmp->move_on & pl->move_type)) |
2910 | if (!tmp->invisible) |
2931 | if (player_apply (pl, tmp, 0, 1) == 1) |
2911 | if (player_apply (pl, tmp, 0)) |
2932 | return; |
2912 | break; |
2933 | |
2913 | |
2934 | if (floors >= 2) |
2914 | break; |
2935 | return; /* process at most two floor objects */ |
|
|
2936 | } |
2915 | } |
2937 | } |
2916 | } |
2938 | |
2917 | |
2939 | /** |
2918 | /** |
2940 | * Unapplies specified item. |
2919 | * Unapplies specified item. |
… | |
… | |
3054 | static object * |
3033 | static object * |
3055 | get_next_item_from_body_location (int loc, object *start) |
3034 | get_next_item_from_body_location (int loc, object *start) |
3056 | { |
3035 | { |
3057 | for (object *tmp = start; tmp; tmp = tmp->below) |
3036 | for (object *tmp = start; tmp; tmp = tmp->below) |
3058 | if (tmp->flag [FLAG_APPLIED] |
3037 | if (tmp->flag [FLAG_APPLIED] |
3059 | && tmp->slot[loc].info |
3038 | && tmp->slot [loc].info |
3060 | && (!tmp->invisible || tmp->type == SKILL)) |
3039 | && (!tmp->invisible || tmp->type == SKILL || tmp->type == SPELL)) |
3061 | return tmp; |
3040 | return tmp; |
3062 | |
3041 | |
3063 | return 0; |
3042 | return 0; |
3064 | } |
3043 | } |
3065 | |
3044 | |
… | |
… | |
3210 | continue; |
3189 | continue; |
3211 | } |
3190 | } |
3212 | |
3191 | |
3213 | object *tmp1 = get_next_item_from_body_location (i, who->inv); |
3192 | object *tmp1 = get_next_item_from_body_location (i, who->inv); |
3214 | if (!tmp1) |
3193 | if (!tmp1) |
3215 | { |
|
|
3216 | #if 0 |
|
|
3217 | /* This is sort of an error, but happens a lot when old players |
|
|
3218 | * join in with more stuff equipped than they are now allowed. |
|
|
3219 | */ |
|
|
3220 | LOG (llevError, "Can't find object using location %d on %s\n", i, who->name); |
|
|
3221 | #endif |
|
|
3222 | retval |= CAN_APPLY_NEVER; |
3194 | retval |= CAN_APPLY_NEVER; |
3223 | } |
|
|
3224 | else |
3195 | else |
3225 | { |
3196 | { |
3226 | /* need to unapply something. However, if this something |
3197 | /* need to unapply something. However, if this something |
3227 | * is different than we had found before, it means they need |
3198 | * is different than we had found before, it means they need |
3228 | * to apply multiple objects |
3199 | * to apply multiple objects |
… | |
… | |
3285 | |
3256 | |
3286 | // saner interface, returns successful status |
3257 | // saner interface, returns successful status |
3287 | bool |
3258 | bool |
3288 | object::apply (object *ob, int aflags) |
3259 | object::apply (object *ob, int aflags) |
3289 | { |
3260 | { |
3290 | bool want_apply = aflags & AP_APPLY; |
3261 | if (!ob) // simplifies a lot of callers |
3291 | |
|
|
3292 | if (ob->flag [FLAG_APPLIED] == want_apply) |
|
|
3293 | return true; |
3262 | return true; |
3294 | |
3263 | |
|
|
3264 | bool want_apply = |
|
|
3265 | aflags & AP_APPLY ? true |
|
|
3266 | : aflags & AP_UNAPPLY ? false |
|
|
3267 | : !ob->flag [FLAG_APPLIED]; // AP_TOGGLE |
|
|
3268 | |
|
|
3269 | object_ptr *slot = 0; |
|
|
3270 | |
|
|
3271 | // detect the slot, if this is a player |
|
|
3272 | if (contr && !(aflags & AP_NO_SLOT)) |
|
|
3273 | { |
|
|
3274 | switch (ob->type) |
|
|
3275 | { |
|
|
3276 | case WEAPON: |
|
|
3277 | slot = &contr->combat_ob; |
|
|
3278 | break; |
|
|
3279 | |
|
|
3280 | case BOW: |
|
|
3281 | case RANGED: |
|
|
3282 | case SPELL: |
|
|
3283 | case WAND: |
|
|
3284 | case ROD: |
|
|
3285 | case HORN: |
|
|
3286 | case BUILDER: |
|
|
3287 | slot = &contr->ranged_ob; |
|
|
3288 | break; |
|
|
3289 | |
|
|
3290 | // oh, the humanity |
|
|
3291 | case SKILL: |
|
|
3292 | if (aflags & AP_NO_SLOT) |
|
|
3293 | break; |
|
|
3294 | |
|
|
3295 | if (skill_flags [ob->subtype] & SF_NEED_ITEM) |
|
|
3296 | break; |
|
|
3297 | |
|
|
3298 | if (skill_flags [ob->subtype] & SF_COMBAT) |
|
|
3299 | slot = &contr->combat_ob; |
|
|
3300 | else if (skill_flags [ob->subtype] & SF_RANGED) |
|
|
3301 | slot = &contr->ranged_ob; |
|
|
3302 | |
|
|
3303 | break; |
|
|
3304 | } |
|
|
3305 | |
|
|
3306 | // clear item from slot if applied |
|
|
3307 | if (slot && *slot == ob && !want_apply) |
|
|
3308 | { |
|
|
3309 | *slot = 0; |
|
|
3310 | |
|
|
3311 | if (current_weapon == ob) |
|
|
3312 | current_weapon = 0; |
|
|
3313 | } |
|
|
3314 | } |
|
|
3315 | |
|
|
3316 | if (ob->flag [FLAG_APPLIED] != want_apply) |
3295 | manual_apply (this, ob, aflags); |
3317 | manual_apply (this, ob, aflags); |
3296 | |
3318 | |
3297 | return ob->flag [FLAG_APPLIED] == want_apply; |
3319 | if (ob->flag [FLAG_APPLIED] != want_apply) |
|
|
3320 | return false; |
|
|
3321 | |
|
|
3322 | if (slot) |
|
|
3323 | current_weapon = *slot = ob; |
|
|
3324 | |
|
|
3325 | return true; |
3298 | } |
3326 | } |
3299 | |
3327 | |
3300 | /** |
3328 | /** |
3301 | * who is the object using the object. It can be a monster. |
3329 | * who is the object using the object. It can be a monster. |
3302 | * op is the object they are using. op is an equipment type item, |
3330 | * op is the object they are using. op is an equipment type item, |
… | |
… | |
3325 | " H<You lack enough unused item power to use this weapon, see the skills command.>" |
3353 | " H<You lack enough unused item power to use this weapon, see the skills command.>" |
3326 | |
3354 | |
3327 | int |
3355 | int |
3328 | apply_special (object *who, object *op, int aflags) |
3356 | apply_special (object *who, object *op, int aflags) |
3329 | { |
3357 | { |
3330 | int basic_flag = aflags & AP_BASIC_FLAGS; |
3358 | int basic_flag = aflags & AP_MODE; |
3331 | object *tmp, *tmp2, *skop = NULL; |
3359 | object *tmp, *tmp2, *skop = NULL; |
3332 | |
3360 | |
3333 | if (who == NULL) |
3361 | if (who == NULL) |
3334 | { |
3362 | { |
3335 | LOG (llevError, "apply_special() from object without environment.\n"); |
3363 | LOG (llevError, "apply_special() from object without environment.\n"); |
… | |
… | |
3405 | if (!skop) |
3433 | if (!skop) |
3406 | { |
3434 | { |
3407 | who->failmsg (format ("You need the %s skill to use this item!", &op->skill)); |
3435 | who->failmsg (format ("You need the %s skill to use this item!", &op->skill)); |
3408 | return 1; |
3436 | return 1; |
3409 | } |
3437 | } |
3410 | else if (!who->apply (skop, AP_APPLY | AP_HAVE_WEAPON)) |
3438 | else if (!who->apply (skop, AP_APPLY | AP_NO_SLOT)) |
3411 | { |
3439 | { |
3412 | who->failmsg (format ("You can't use the required %s skill!", &op->skill)); |
3440 | who->failmsg (format ("You can't use the required %s skill!", &op->skill)); |
3413 | return 1; |
3441 | return 1; |
3414 | } |
3442 | } |
3415 | } |
3443 | } |
… | |
… | |
3446 | |
3474 | |
3447 | op->flag [FLAG_APPLIED] = true; |
3475 | op->flag [FLAG_APPLIED] = true; |
3448 | |
3476 | |
3449 | if (player *pl = who->contr) |
3477 | if (player *pl = who->contr) |
3450 | { |
3478 | { |
3451 | who->current_weapon = pl->combat_ob = op; |
|
|
3452 | who->statusmsg (format ("You wield %s.", query_name (op))); |
3479 | who->statusmsg (format ("You wield %s.", query_name (op))); |
3453 | change_abil (who, op); |
3480 | change_abil (who, op); |
3454 | } |
3481 | } |
3455 | else |
3482 | else |
3456 | who->change_skill (skop); |
3483 | who->change_skill (skop); |
… | |
… | |
3479 | //TODO: unapplying should unapply the skill, though |
3506 | //TODO: unapplying should unapply the skill, though |
3480 | SET_FLAG (op, FLAG_APPLIED); |
3507 | SET_FLAG (op, FLAG_APPLIED); |
3481 | break; |
3508 | break; |
3482 | |
3509 | |
3483 | case SKILL: |
3510 | case SKILL: |
3484 | if (skill_flags [op->subtype] & SF_NEED_ITEM && !(aflags & AP_HAVE_WEAPON)) |
3511 | if (skill_flags [op->subtype] & SF_NEED_ITEM && !(aflags & AP_NO_SLOT)) |
3485 | { |
3512 | { |
3486 | who->failmsg (format ( |
3513 | who->failmsg (format ( |
3487 | "You feel as if you wanted to do something funny, but you can't remember what. " |
3514 | "You feel as if you wanted to do something funny, but you can't remember what. " |
3488 | "H<The skill %s needs an item to function, it cannot be used on its own.>", |
3515 | "H<The %s skill needs an item to function, it cannot be used on its own.>", |
3489 | &op->skill |
3516 | &op->skill |
3490 | )); |
3517 | )); |
3491 | if (tmp) who->insert (tmp); |
3518 | if (tmp) who->insert (tmp); |
3492 | return 1; |
3519 | return 1; |
3493 | } |
3520 | } |
3494 | |
3521 | |
3495 | if (player *pl = who->contr) |
3522 | if (player *pl = who->contr) |
3496 | { |
3523 | { |
3497 | if (skill_flags [op->subtype] & SF_COMBAT) |
|
|
3498 | who->current_weapon = pl->combat_ob = op; |
|
|
3499 | |
|
|
3500 | if (skill_flags [op->subtype] & SF_RANGED) |
|
|
3501 | who->current_weapon = pl->ranged_ob = op; |
|
|
3502 | |
|
|
3503 | if (op->invisible) |
3524 | if (op->invisible) |
3504 | who->statusmsg (format ("Readied skill: %s.", op->skill ? &op->skill : &op->name)); |
3525 | who->statusmsg (format ("Readied skill: %s.", op->skill ? &op->skill : &op->name)); |
3505 | else |
3526 | else |
3506 | who->statusmsg (format ( |
3527 | who->statusmsg (format ( |
3507 | "You ready %s." |
3528 | "You ready %s." |
… | |
… | |
3526 | } |
3547 | } |
3527 | |
3548 | |
3528 | if (player *pl = who->contr) |
3549 | if (player *pl = who->contr) |
3529 | { |
3550 | { |
3530 | op->flag [FLAG_APPLIED] = true; |
3551 | op->flag [FLAG_APPLIED] = true; |
3531 | who->current_weapon = pl->ranged_ob = op; |
|
|
3532 | who->statusmsg (format ("You wield the %s.", query_name (op))); |
3552 | who->statusmsg (format ("You wield the %s.", query_name (op))); |
3533 | change_abil (who, op); |
3553 | change_abil (who, op); |
3534 | } |
3554 | } |
3535 | break; |
3555 | break; |
3536 | |
3556 | |
3537 | case RANGED: |
3557 | case RANGED: |
3538 | if (player *pl = who->contr) |
3558 | if (player *pl = who->contr) |
3539 | { |
3559 | { |
3540 | op->flag [FLAG_APPLIED] = true; |
3560 | op->flag [FLAG_APPLIED] = true; |
3541 | who->current_weapon = pl->ranged_ob = op; |
|
|
3542 | who->statusmsg (format ("You applied the %s.", query_name (op))); |
3561 | who->statusmsg (format ("You applied the %s.", query_name (op))); |
3543 | } |
3562 | } |
3544 | break; |
3563 | break; |
3545 | |
3564 | |
3546 | case SPELL: |
3565 | case SPELL: |
3547 | if (player *pl = who->contr) |
3566 | if (player *pl = who->contr) |
3548 | { |
3567 | { |
3549 | op->flag [FLAG_APPLIED] = true; |
3568 | op->flag [FLAG_APPLIED] = true; |
3550 | who->current_weapon = pl->ranged_ob = op; |
|
|
3551 | who->statusmsg (format ("You ready the spell %s.", query_name (op))); |
3569 | who->statusmsg (format ("You ready the spell %s.", query_name (op))); |
3552 | } |
3570 | } |
3553 | break; |
3571 | break; |
3554 | |
3572 | |
3555 | /*FALLTHROUGH*/ |
3573 | /*FALLTHROUGH*/ |
… | |
… | |
3568 | op->flag [FLAG_APPLIED] = true; |
3586 | op->flag [FLAG_APPLIED] = true; |
3569 | |
3587 | |
3570 | if (player *pl = who->contr) |
3588 | if (player *pl = who->contr) |
3571 | { |
3589 | { |
3572 | who->statusmsg (format ("You ready %s.", query_name (op))); |
3590 | who->statusmsg (format ("You ready %s.", query_name (op))); |
3573 | who->current_weapon = pl->ranged_ob = op; |
|
|
3574 | |
3591 | |
3575 | if (op->type == BOW) |
3592 | if (op->type == BOW) |
3576 | who->statusmsg (format ("You will now fire %s with %s.", op->race ? &op->race : "nothing", query_name (op))); |
3593 | who->statusmsg (format ("You will now fire %s with %s.", op->race ? &op->race : "nothing", query_name (op))); |
3577 | |
3594 | |
3578 | change_abil (who, op); |
3595 | change_abil (who, op); |
… | |
… | |
3590 | break; |
3607 | break; |
3591 | |
3608 | |
3592 | case BUILDER: |
3609 | case BUILDER: |
3593 | if (player *pl = who->contr) |
3610 | if (player *pl = who->contr) |
3594 | { |
3611 | { |
3595 | who->current_weapon = pl->ranged_ob = op; |
|
|
3596 | who->statusmsg (format ("You ready your %s.", query_name (op))); |
3612 | who->statusmsg (format ("You ready your %s.", query_name (op))); |
3597 | //TODO: change_abil? |
3613 | //TODO: change_abil? |
3598 | } |
3614 | } |
3599 | break; |
3615 | break; |
3600 | |
3616 | |