Changeset 316

Show
Ignore:
Timestamp:
07/09/07 20:08:24 (1 year ago)
Author:
takkaria
Message:

Unify a lot of cmd6.c and use-obj.c, resulting in more understandable (IMO) code and much less duplication.

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • trunk/src/cmd6.c

    r291 r316  
    1 /* File: cmd6.c */ 
    2  
    3 /* 
    4  * Copyright (c) 1997 Ben Harrison, James E. Wilson, Robert A. Koeneke 
    5  * 
    6  * This software may be copied and distributed for educational, research, 
    7  * and not for profit purposes provided that this copyright and statement 
    8  * are included in all such copies.  Other copyrights may also apply. 
    9  */ 
    10  
     1/* 
     2 * File: cmd6.c 
     3 * Purpose: Eating/quaffing/reading/aiming/staving/zapping/activating 
     4 * 
     5 * Copyright (c) 1997-2007 Andrew Sidwell, Ben Harrison, James E. Wilson, 
     6 * Robert A. Koeneke 
     7 * 
     8 * This work is free software; you can redistribute it and/or modify it 
     9 * under the terms of either: 
     10 * 
     11 * a) the GNU General Public License as published by the Free Software 
     12 *    Foundation, version 2, or 
     13 * 
     14 * b) the "Angband licence": 
     15 *    This software may be copied and distributed for educational, research, 
     16 *    and not for profit purposes provided that this copyright and statement 
     17 *    are included in all such copies.  Other copyrights may also apply. 
     18 */ 
    1119#include "angband.h" 
    12  
    1320#include "script.h" 
    1421 
    15  
    16 /* 
    17  * This file includes code for eating food, drinking potions, 
    18  * reading scrolls, aiming wands, using staffs, zapping rods, 
    19  * and activating artifacts. 
    20  * 
    21  * In all cases, if the player becomes "aware" of the item's use 
    22  * by testing it, mark it as "aware" and reward some experience 
    23  * based on the object's level, always rounding up.  If the player 
    24  * remains "unaware", mark that object "kind" as "tried". 
    25  * 
    26  * This code now correctly handles the unstacking of wands, staffs, 
    27  * and rods.  Note the overly paranoid warning about potential pack 
    28  * overflow, which allows the player to use and drop a stacked item. 
    29  * 
    30  * In all "unstacking" scenarios, the "used" object is "carried" as if 
    31  * the player had just picked it up.  In particular, this means that if 
    32  * the use of an item induces pack overflow, that item will be dropped. 
    33  * 
    34  * For simplicity, these routines induce a full "pack reorganization" 
    35  * which not only combines similar items, but also reorganizes various 
    36  * items to obey the current "sorting" method.  This may require about 
    37  * 400 item comparisons, but only occasionally. 
     22/* Types of item use */ 
     23typedef enum 
     24
     25        USE_TIMEOUT, 
     26        USE_CHARGE, 
     27        USE_SINGLE 
     28} use_type; 
     29 
     30 
     31/* 
     32 * Hook to determine if an object is activatable 
     33 */ 
     34static bool item_tester_hook_activate(const object_type *o_ptr) 
     35
     36        u32b f1, f2, f3; 
     37 
     38        /* Not known */ 
     39        if (!object_known_p(o_ptr)) return (FALSE); 
     40 
     41        /* Extract the flags */ 
     42        object_flags(o_ptr, &f1, &f2, &f3); 
     43         
     44        /* Check the recharge */ 
     45        if (o_ptr->timeout) return (FALSE); 
     46 
     47        /* Check activation flag */ 
     48        if (f3 & (TR3_ACTIVATE)) return (TRUE); 
     49 
     50        /* Assume not */ 
     51        return (FALSE); 
     52
     53 
     54 
     55/* 
     56 * Hook to determine if an object is zappable 
     57 */ 
     58static bool item_tester_hook_zap(const object_type *o_ptr) 
     59
     60        const object_kind *k_ptr = &k_info[o_ptr->k_idx]; 
     61 
     62        /* Non-rods are out */ 
     63        if (o_ptr->tval != TV_ROD) return FALSE; 
     64 
     65        /* All still charging? */ 
     66        if (o_ptr->timeout > (o_ptr->pval - k_ptr->pval)) return FALSE; 
     67 
     68        /* Otherwise OK */ 
     69        return TRUE; 
     70
     71 
     72 
     73/* 
     74 * Determine if the player can read scrolls. 
     75 */ 
     76static bool can_read_scroll(void) 
     77
     78        if (p_ptr->timed[TMD_BLIND]) 
     79        { 
     80                msg_print("You can't see anything."); 
     81                return FALSE; 
     82        } 
     83 
     84        if (no_lite()) 
     85        { 
     86                msg_print("You have no light to read by."); 
     87                return FALSE; 
     88        } 
     89 
     90        if (p_ptr->timed[TMD_CONFUSED]) 
     91        { 
     92                msg_print("You are too confused to read!"); 
     93                return FALSE; 
     94        } 
     95 
     96        if (p_ptr->timed[TMD_AMNESIA]) 
     97        { 
     98                msg_print("You can't remember how to read!"); 
     99                return FALSE; 
     100        } 
     101 
     102        return TRUE; 
     103
     104 
     105 
     106/* 
     107 * Check to see if the player can use a rod/wand/staff/activatable object. 
     108 */ 
     109static int check_devices(object_type *o_ptr) 
     110
     111        int lev, chance; 
     112        const char *msg; 
     113        const char *what = NULL; 
     114 
     115        /* Get the right string */ 
     116        switch (o_ptr->tval) 
     117        { 
     118                case TV_ROD:   msg = "zap the rod";   break; 
     119                case TV_WAND:  msg = "use the wand";  what = "wand";  break; 
     120                case TV_STAFF: msg = "use the staff"; what = "staff"; break; 
     121                default:       msg = "active it";     break; 
     122        } 
     123 
     124        /* Extract the item level */ 
     125        if (artifact_p(o_ptr)) 
     126                lev = a_info[o_ptr->name1].level; 
     127        else 
     128                lev = k_info[o_ptr->k_idx].level; 
     129 
     130        /* Base chance of success */ 
     131        chance = p_ptr->skills[SKILL_DEV]; 
     132 
     133        /* Confusion hurts skill */ 
     134        if (p_ptr->timed[TMD_CONFUSED] || p_ptr->timed[TMD_AMNESIA]) 
     135                chance = chance / 2; 
     136 
     137        /* High level objects are harder */ 
     138        chance -= MIN(lev, 50); 
     139 
     140        /* Give everyone a (slight) chance */ 
     141        if ((chance < USE_DEVICE) && (rand_int(USE_DEVICE - chance + 1) == 0)) 
     142        { 
     143                chance = USE_DEVICE; 
     144        } 
     145 
     146        /* Roll for usage */ 
     147        if ((chance < USE_DEVICE) || (randint(chance) < USE_DEVICE)) 
     148        { 
     149                if (flush_failure) flush(); 
     150                msg_format("You failed to %s properly.", msg); 
     151                return FALSE; 
     152        } 
     153 
     154        /* Notice empty staffs */ 
     155        if (what && o_ptr->pval <= 0) 
     156        { 
     157                if (flush_failure) flush(); 
     158                msg_format("The %s has no charges left.", what); 
     159                o_ptr->ident |= (IDENT_EMPTY); 
     160                return FALSE; 
     161        } 
     162 
     163        return TRUE; 
     164
     165 
     166 
     167/* 
     168 * Use an object the right way. 
    38169 * 
    39170 * There may be a BIG problem with any "effect" that can cause "changes" 
     
    49180 * item causes the inducer of that action to "move", causing "o_ptr" to 
    50181 * no longer point at the correct item, with horrifying results. 
    51  * 
    52  * Note that food/potions/scrolls no longer use bit-flags for effects, 
    53  * but instead use the "sval" (which is also used to sort the objects). 
    54  */ 
    55  
    56  
    57  
    58  
    59  
    60  
    61 /* 
    62  * Eat some food (from the pack or floor) 
    63  */ 
    64 void do_cmd_eat_food(void) 
    65 
    66         int item, lev; 
    67         bool ident; 
    68  
     182 */ 
     183static void do_cmd_use(const char *q, const char *s, int flag, int snd, use_type use) 
     184
     185        int item; 
    69186        object_type *o_ptr; 
    70  
    71         cptr q, s; 
    72  
    73  
    74         /* Restrict choices to food */ 
    75         item_tester_tval = TV_FOOD; 
    76  
    77         /* Get an item */ 
    78         q = "Eat which item? "; 
    79         s = "You have nothing to eat."; 
    80         if (!get_item(&item, q, s, (USE_INVEN | USE_FLOOR))) return; 
    81  
    82         /* Get the item (in the pack) */ 
    83         if (item >= 0) 
    84         { 
    85                 o_ptr = &inventory[item]; 
    86         } 
    87  
    88         /* Get the item (on the floor) */ 
    89         else 
    90         { 
    91                 o_ptr = &o_list[0 - item]; 
    92         } 
    93  
    94  
    95         /* Sound */ 
    96         sound(MSG_EAT); 
    97  
    98  
    99         /* Take a turn */ 
     187        bool ident = FALSE, used; 
     188        int dir = 5; 
     189 
     190        /* Get the item */ 
     191        if (!get_item(&item, q, s, flag)) 
     192                return; 
     193 
     194        /* Get the item (in the pack/on the floor) */ 
     195        if (item >= 0) o_ptr = &inventory[item]; 
     196        else o_ptr = &o_list[0 - item]; 
     197 
     198        /* If the item requires a direction, get one (allow cancelling) */ 
     199        if ((o_ptr->tval == TV_WAND) ||  
     200            (o_ptr->tval == TV_ROD && (o_ptr->sval >= SV_ROD_MIN_DIRECTION || !object_aware_p(o_ptr)))) 
     201        { 
     202                /* Get a direction, allow cancel */ 
     203                if (!get_aim_dir(&dir)) 
     204                        return; 
     205        } 
     206 
     207        /* Use energy regardless of failure */   
    100208        p_ptr->energy_use = 100; 
    101209 
    102         /* Identity not known yet */ 
    103         ident = FALSE; 
    104  
    105         /* Object level */ 
    106         lev = k_info[o_ptr->k_idx].level; 
    107  
    108         /* Eat the food */ 
    109         use_object(o_ptr, &ident); 
    110  
    111         /* Combine / Reorder the pack (later) */ 
     210        /* Check for use */ 
     211        if (use == USE_CHARGE || use == USE_TIMEOUT) 
     212        { 
     213                if (!check_devices(o_ptr)) 
     214                        return; 
     215        } 
     216 
     217        /* Make a noise! */ 
     218        sound(snd); 
     219 
     220        /* Use the object */ 
     221        used = use_object(o_ptr, &ident, dir); 
     222        if (!used && !ident) return; 
     223 
     224        /* Mark as tried and redisplay */ 
    112225        p_ptr->notice |= (PN_COMBINE | PN_REORDER); 
    113  
    114         /* We have tried it */ 
    115         object_tried(o_ptr); 
    116  
    117         /* The player is now aware of the object */ 
     226        p_ptr->window |= (PW_INVEN | PW_EQUIP); 
     227 
     228 
     229        /* 
     230         * If the player becomes aware of the item's function, then mark it as 
     231         * aware and reward the player with some experience.  Otherwise, mark 
     232         * it as "tried". 
     233         */ 
    118234        if (ident && !object_aware_p(o_ptr)) 
    119235        { 
     236                /* Object level */ 
     237                int lev = k_info[o_ptr->k_idx].level; 
     238 
    120239                object_aware(o_ptr); 
    121240                gain_exp((lev + (p_ptr->lev / 2)) / p_ptr->lev); 
    122241                p_ptr->notice |= PN_SQUELCH; 
    123242        } 
    124  
    125         /* Window stuff */ 
    126         p_ptr->window |= (PW_INVEN | PW_EQUIP); 
    127  
    128  
    129         /* Destroy a food in the pack */ 
    130         if (item >= 0) 
    131         { 
    132                 inven_item_increase(item, -1); 
    133                 inven_item_describe(item); 
    134                 inven_item_optimize(item); 
    135         } 
    136  
    137         /* Destroy a food on the floor */ 
    138243        else 
    139244        { 
    140                 floor_item_increase(0 - item, -1); 
    141                 floor_item_describe(0 - item); 
    142                 floor_item_optimize(0 - item); 
    143         } 
    144 
    145  
    146  
     245                object_tried(o_ptr); 
     246        } 
     247 
     248         
     249        /* Some uses are "free" */ 
     250        if (!used) return; 
     251 
     252        /* Chargeables act differently to single-used items when not used up */ 
     253        if (use == USE_CHARGE) 
     254        { 
     255                /* Use a single charge */ 
     256                o_ptr->pval--; 
     257 
     258                /* Describe charges in the pack */ 
     259                if (item >= 0) 
     260                        inven_item_charges(item); 
     261 
     262                /* Describe charges on the floor */ 
     263                else 
     264                        floor_item_charges(0 - item); 
     265        } 
     266        else if (use == USE_TIMEOUT && o_ptr->tval == TV_ROD) 
     267        { 
     268                const object_kind *k_ptr = &k_info[o_ptr->k_idx]; 
     269 
     270                /* Drain the charge */ 
     271                o_ptr->timeout += k_ptr->pval; 
     272        } 
     273        else if (use == USE_SINGLE) 
     274        { 
     275                /* Destroy a potion in the pack */ 
     276                if (item >= 0) 
     277                { 
     278                        inven_item_increase(item, -1); 
     279                        inven_item_describe(item); 
     280                        inven_item_optimize(item); 
     281                } 
     282 
     283                /* Destroy a potion on the floor */ 
     284                else 
     285                { 
     286                        floor_item_increase(0 - item, -1); 
     287                        floor_item_describe(0 - item); 
     288                        floor_item_optimize(0 - item); 
     289                } 
     290        } 
     291
     292 
     293 
     294/* 
     295 * Eat some food (from the pack or floor) 
     296 */ 
     297void do_cmd_eat_food(void) 
     298
     299        /* Restrict choices to food */ 
     300        item_tester_tval = TV_FOOD; 
     301 
     302        /* Use the object */ 
     303        do_cmd_use("Eat which item? ", "You have nothing to eat.", (USE_INVEN | USE_FLOOR), MSG_EAT, USE_SINGLE); 
     304
    147305 
    148306 
     
    152310void do_cmd_quaff_potion(void) 
    153311{ 
    154         int item, lev; 
    155         bool ident; 
    156         object_type *o_ptr; 
    157         cptr q, s; 
    158  
    159  
    160312        /* Restrict choices to potions */ 
    161313        item_tester_tval = TV_POTION; 
    162314 
    163         /* Get an item */ 
    164         q = "Quaff which potion? "; 
    165         s = "You have no potions to quaff."; 
    166         if (!get_item(&item, q, s, (USE_INVEN | USE_FLOOR))) return; 
    167  
    168         /* Get the item (in the pack) */ 
    169         if (item >= 0) 
    170         { 
    171                 o_ptr = &inventory[item]; 
    172         } 
    173  
    174         /* Get the item (on the floor) */ 
    175         else 
    176         { 
    177                 o_ptr = &o_list[0 - item]; 
    178         } 
    179  
    180  
    181         /* Sound */ 
    182         sound(MSG_QUAFF); 
    183  
    184  
    185         /* Take a turn */ 
    186         p_ptr->energy_use = 100; 
    187  
    188         /* Not identified yet */ 
    189         ident = FALSE; 
    190  
    191         /* Object level */ 
    192         lev = k_info[o_ptr->k_idx].level; 
    193  
    194         /* Quaff the potion */ 
    195         use_object(o_ptr, &ident); 
    196  
    197         /* Combine / Reorder the pack (later) */ 
    198         p_ptr->notice |= (PN_COMBINE | PN_REORDER); 
    199  
    200         /* The item has been tried */ 
    201         object_tried(o_ptr); 
    202  
    203         /* An identification was made */ 
    204         if (ident && !object_aware_p(o_ptr)) 
    205         { 
    206                 object_aware(o_ptr); 
    207                 gain_exp((lev + (p_ptr->lev / 2)) / p_ptr->lev); 
    208                 p_ptr->notice |= PN_SQUELCH; 
    209         } 
    210  
    211         /* Window stuff */ 
    212         p_ptr->window |= (PW_INVEN | PW_EQUIP); 
    213  
    214         /* Destroy a potion in the pack */ 
    215         if (item >= 0) 
    216         { 
    217                 inven_item_increase(item, -1); 
    218                 inven_item_describe(item); 
    219                 inven_item_optimize(item); 
    220         } 
    221  
    222         /* Destroy a potion on the floor */ 
    223         else 
    224         { 
    225                 floor_item_increase(0 - item, -1); 
    226                 floor_item_describe(0 - item); 
    227                 floor_item_optimize(0 - item); 
    228         } 
     315        /* Use the object */ 
     316        do_cmd_use("Quaff which potion? ", "You have no potions to quaff.", (USE_INVEN | USE_FLOOR), MSG_QUAFF, USE_SINGLE); 
    229317} 
    230318 
     
    232320/* 
    233321 * Read a scroll (from the pack or floor). 
    234  * 
    235  * Certain scrolls can be "aborted" without losing the scroll.  These 
    236  * include scrolls with no effects but recharge or identify, which are 
    237  * cancelled before use.  XXX Reading them still takes a turn, though. 
    238322 */ 
    239323void do_cmd_read_scroll(void) 
    240324{ 
    241         int item, used_up, lev; 
    242         bool ident; 
    243  
    244         object_type *o_ptr; 
    245  
    246         cptr q, s; 
    247  
    248  
    249325        /* Check some conditions */ 
    250         if (p_ptr->timed[TMD_BLIND]) 
    251         { 
    252                 msg_print("You can't see anything."); 
    253                 return; 
    254         } 
    255         if (no_lite()) 
    256         { 
    257                 msg_print("You have no light to read by."); 
    258                 return; 
    259         } 
    260  
    261         if (p_ptr->timed[TMD_CONFUSED]) 
    262         { 
    263                 msg_print("You are too confused!"); 
    264                 return; 
    265         } 
     326        if (!can_read_scroll()) return; 
    266327 
    267328        /* Restrict choices to scrolls */ 
    268329        item_tester_tval = TV_SCROLL; 
    269330 
    270         /* Get an item */ 
    271         q = "Read which scroll? "; 
    272         s = "You have no scrolls to read."; 
    273         if (!get_item(&item, q, s, (USE_INVEN | USE_FLOOR))) return; 
    274  
    275         /* Get the item (in the pack) */ 
    276         if (item >= 0) 
    277         { 
    278                 o_ptr = &inventory[item]; 
    279         } 
    280  
    281         /* Get the item (on the floor) */ 
    282         else 
    283         { 
    284                 o_ptr = &o_list[0 - item]; 
    285         } 
    286  
    287  
    288         /* Take a turn */ 
    289         p_ptr->energy_use = 100; 
    290  
    291         /* Check for amnesia */ 
    292         if (rand_int(2) != 0 && p_ptr->timed[TMD_AMNESIA]) 
    293         { 
    294                 /* Can't remember how */ 
    295                 msg_print("You can't remember how to read!"); 
    296                 return; 
    297         } 
    298  
    299         /* Not identified yet */ 
    300         ident = FALSE; 
    301  
    302         /* Object level */ 
    303         lev = k_info[o_ptr->k_idx].level; 
    304  
    305         /* Read the scroll */ 
    306         used_up = use_object(o_ptr, &ident); 
    307  
    308         /* Combine / Reorder the pack (later) */ 
    309         p_ptr->notice |= (PN_COMBINE | PN_REORDER); 
    310  
    311         /* The item was tried */ 
    312         object_tried(o_ptr); 
    313  
    314         /* An identification was made */ 
    315         if (ident && !object_aware_p(o_ptr)) 
    316         { 
    317                 object_aware(o_ptr); 
    318                 gain_exp((lev + (p_ptr->lev / 2)) / p_ptr->lev); 
    319                 p_ptr->notice |= PN_SQUELCH; 
    320         } 
    321  
    322         /* Window stuff */ 
    323         p_ptr->window |= (PW_INVEN | PW_EQUIP); 
    324  
    325  
    326         /* Hack -- allow certain scrolls to be "preserved" */ 
    327         if (!used_up) return; 
    328  
    329  
    330         /* Destroy a scroll in the pack */ 
    331         if (item >= 0) 
    332         { 
    333                 inven_item_increase(item, -1); 
    334                 inven_item_describe(item); 
    335                 inven_item_optimize(item); 
    336         } 
    337  
    338         /* Destroy a scroll on the floor */ 
    339         else 
    340         { 
    341                 floor_item_increase(0 - item, -1); 
    342                 floor_item_describe(0 - item); 
    343                 floor_item_optimize(0 - item); 
    344         } 
    345 
    346  
    347  
    348  
    349  
    350  
     331        /* Use the object */ 
     332        do_cmd_use("Read which scroll? ", "You have no scrolls to read.", (USE_INVEN | USE_FLOOR), MSG_GENERIC, USE_SINGLE); 
     333
    351334 
    352335 
    353336/* 
    354337 * Use a staff 
    355  * 
    356  * One charge of one staff disappears. 
    357  * 
    358  * Hack -- staffs of identify can be "cancelled". 
    359338 */ 
    360339void do_cmd_use_staff(void) 
    361340{ 
    362         int item, chance, lev; 
    363  
    364         bool ident; 
    365          
    366         object_type *o_ptr; 
    367  
    368         bool use_charge; 
    369  
    370         cptr q, s; 
    371  
    372  
    373341        /* Restrict choices to staves */ 
    374342        item_tester_tval = TV_STAFF; 
    375343 
    376         /* Get an item */ 
    377         q = "Use which staff? "; 
    378         s = "You have no staff to use."; 
    379         if (!get_item(&item, q, s, (USE_INVEN | USE_FLOOR))) return; 
    380  
    381         /* Get the item (in the pack) */ 
    382         if (item >= 0) 
    383         { 
    384                 o_ptr = &inventory[item]; 
    385         } 
    386  
    387         /* Get the item (on the floor) */ 
    388         else 
    389         { 
    390                 o_ptr = &o_list[0 - item]; 
    391         } 
    392  
    393         /* Take a turn */ 
    394         p_ptr->energy_use = 100; 
    395  
    396  
    397         /* Not identified yet */ 
    398         ident = FALSE; 
    399  
    400         /* Extract the item level */ 
    401         lev = k_info[o_ptr->k_idx].level; 
    402  
    403         /* Base chance of success */ 
    404         chance = p_ptr->skills[SKILL_DEV]; 
    405  
    406         /* Confusion hurts skill */ 
    407         if (p_ptr->timed[TMD_CONFUSED]) chance = chance / 2; 
    408  
    409         /* High level objects are harder */ 
    410         chance = chance - ((lev > 50) ? 50 : lev); 
    411  
    412         /* Give everyone a (slight) chance */ 
    413         if ((chance < USE_DEVICE) && (rand_int(USE_DEVICE - chance + 1) == 0)) 
    414         { 
    415                 chance = USE_DEVICE; 
    416         } 
    417  
    418         /* Roll for usage */ 
    419         if ((chance < USE_DEVICE) || (randint(chance) < USE_DEVICE)) 
    420         { 
    421                 if (flush_failure) flush(); 
    422                 msg_print("You failed to use the staff properly."); 
    423                 return; 
    424         } 
    425  
    426         /* Notice empty staffs */ 
    427         if (o_ptr->pval <= 0) 
    428         { 
    429                 if (flush_failure) flush(); 
    430                 msg_print("The staff has no charges left."); 
    431                 o_ptr->ident |= (IDENT_EMPTY); 
    432                 p_ptr->notice |= (PN_COMBINE | PN_REORDER); 
    433                 p_ptr->window |= (PW_INVEN); 
    434                 return; 
    435         } 
    436  
    437  
    438         /* Sound */ 
    439         sound(MSG_USE_STAFF); 
    440  
    441  
    442         /* Use the staff */ 
    443         use_charge = use_object(o_ptr, &ident); 
    444  
    445  
    446         /* Combine / Reorder the pack (later) */ 
    447         p_ptr->notice |= (PN_COMBINE | PN_REORDER); 
    448  
    449         /* Tried the item */ 
    450         object_tried(o_ptr); 
    451  
    452         /* An identification was made */ 
    453         if (ident && !object_aware_p(o_ptr)) 
    454         { 
    455                 object_aware(o_ptr); 
    456                 gain_exp((lev + (p_ptr->lev / 2)) / p_ptr->lev); 
    457                 p_ptr->notice |= PN_SQUELCH; 
    458         } 
    459  
    460         /* Window stuff */ 
    461         p_ptr->window |= (PW_INVEN | PW_EQUIP); 
    462  
    463  
    464         /* Hack -- some uses are "free" */ 
    465         if (!use_charge) return; 
    466  
    467  
    468         /* Use a single charge */ 
    469         o_ptr->pval--; 
    470  
    471         /* Describe charges in the pack */ 
    472         if (item >= 0) 
    473         { 
    474                 inven_item_charges(item); 
    475         } 
    476  
    477         /* Describe charges on the floor */ 
    478         else 
    479         { 
    480                 floor_item_charges(0 - item); 
    481         } 
    482 
    483  
    484  
    485 /* 
    486  * Aim a wand (from the pack or floor). 
    487  * 
    488  * Use a single charge from a single item. 
    489  * Handle "unstacking" in a logical manner. 
    490  * 
    491  * For simplicity, you cannot use a stack of items from the 
    492  * ground.  This would require too much nasty code. 
    493  * 
    494  * There are no wands which can "destroy" themselves, in the inventory 
    495  * or on the ground, so we can ignore this possibility.  Note that this 
    496  * required giving "wand of wonder" the ability to ignore destruction 
    497  * by electric balls. 
    498  * 
    499  * All wands can be "cancelled" at the "Direction?" prompt for free. 
    500  * 
    501  * Note that the basic "bolt" wands do slightly less damage than the 
    502  * basic "bolt" rods, but the basic "ball" wands do the same damage 
    503  * as the basic "ball" rods. 
     344        /* Use the object */ 
     345        do_cmd_use("Use which staff? ", "You have no staff to use.", (USE_INVEN | USE_FLOOR), MSG_USE_STAFF, USE_CHARGE); 
     346
     347 
     348 
     349/* 
     350 * Aim a wand 
    504351 */ 
    505352void do_cmd_aim_wand(void) 
    506353{ 
    507         int item, lev; 
    508  
    509         bool ident; 
    510  
    511         object_type *o_ptr; 
    512  
    513         cptr q, s; 
    514  
    515  
    516354        /* Restrict choices to wands */ 
    517355        item_tester_tval = TV_WAND; 
    518356 
    519         /* Get an item */ 
    520         q = "Aim which wand? "; 
    521         s = "You have no wand to aim."; 
    522         if (!get_item(&item, q, s, (USE_INVEN | USE_FLOOR))) return; 
    523  
    524         /* Get the item (in the pack) */ 
    525         if (item >= 0) 
    526         { 
    527                 o_ptr = &inventory[item]; 
    528         } 
    529  
    530         /* Get the item (on the floor) */ 
    531         else 
    532         { 
    533                 o_ptr = &o_list[0 - item]; 
    534         } 
    535  
    536  
    537  
    538         /* Aim the wand */ 
    539         if (!use_object(o_ptr, &ident)) return; 
    540  
    541  
    542         /* Combine / Reorder the pack (later) */ 
    543         p_ptr->notice |= (PN_COMBINE | PN_REORDER); 
    544  
    545         /* Mark it as tried */ 
    546         object_tried(o_ptr); 
    547  
    548         /* Object level */ 
    549         lev = k_info[o_ptr->k_idx].level; 
    550  
    551         /* Apply identification */ 
    552         if (ident && !object_aware_p(o_ptr)) 
    553         { 
    554                 object_aware(o_ptr); 
    555                 gain_exp((lev + (p_ptr->lev / 2)) / p_ptr->lev); 
    556                 p_ptr->notice |= PN_SQUELCH; 
    557         } 
    558  
    559         /* Window stuff */ 
    560         p_ptr->window |= (PW_INVEN | PW_EQUIP); 
    561  
    562  
    563         /* Use a single charge */ 
    564         o_ptr->pval--; 
    565  
    566         /* Describe the charges in the pack */ 
    567         if (item >= 0) 
    568         { 
    569                 inven_item_charges(item); 
    570         } 
    571  
    572         /* Describe the charges on the floor */ 
    573         else 
    574         { 
    575                 floor_item_charges(0 - item); 
    576         } 
    577 
    578  
    579  
    580  
     357        /* Use the object */ 
     358        do_cmd_use("Aim which wand? ", "You have no wand to aim.", (USE_INVEN | USE_FLOOR), MSG_ZAP_ROD, USE_CHARGE); 
     359
    581360 
    582361 
    583362/* 
    584363 * Zap a Rod 
    585  * 
    586  * Unstack fully charged rods as needed. 
    587  * 
    588  * Hack -- rods of perception can be "cancelled" 
    589  * All rods can be cancelled at the "Direction?" prompt 
    590364 */ 
    591365void do_cmd_zap_rod(void) 
    592366{ 
    593         int item; 
    594         bool ident; 
    595         object_type *o_ptr; 
    596         cptr q, s; 
    597  
    598  
    599367        /* Restrict choices to rods */ 
    600         item_tester_tval = TV_ROD; 
    601  
    602         /* Get an item */ 
    603         q = "Zap which rod? "; 
    604         s = "You have no rod to zap."; 
    605         if (!get_item(&item, q, s, (USE_INVEN | USE_FLOOR))) return; 
    606  
    607         /* Get the item (in the pack) */ 
    608         if (item >= 0) 
    609         { 
    610                 o_ptr = &inventory[item]; 
    611         } 
    612  
    613         /* Get the item (on the floor) */ 
    614         else 
    615         { 
    616                 o_ptr = &o_list[0 - item]; 
    617         } 
    618  
    619         /* Zap the rod */ 
    620         if (!use_object(o_ptr, &ident)) return; 
    621  
    622         /* Combine / Reorder the pack (later) */ 
    623         p_ptr->notice |= (PN_COMBINE | PN_REORDER); 
    624  
    625         /* Tried the object */ 
    626         object_tried(o_ptr); 
    627  
    628         /* Successfully determined the object function */ 
    629         if (ident && !object_aware_p(o_ptr)) 
    630         { 
    631                 /* Object level */ 
    632                 int lev = k_info[o_ptr->k_idx].level; 
    633  
    634                 object_aware(o_ptr); 
    635                 gain_exp((lev + (p_ptr->lev / 2)) / p_ptr->lev); 
    636                 p_ptr->notice |= PN_SQUELCH; 
    637         } 
    638  
    639         /* Window stuff */ 
    640         p_ptr->window |= (PW_INVEN | PW_EQUIP); 
    641 
    642  
    643  
    644  
    645  
    646 /* 
    647  * Hook to determine if an object is activatable 
    648  */ 
    649 static bool item_tester_hook_activate(const object_type *o_ptr) 
    650 
    651         u32b f1, f2, f3; 
    652  
    653         /* Not known */ 
    654         if (!object_known_p(o_ptr)) return (FALSE); 
    655  
    656         /* Extract the flags */ 
    657         object_flags(o_ptr, &f1, &f2, &f3); 
    658  
    659         /* Check activation flag */ 
    660         if (f3 & (TR3_ACTIVATE)) return (TRUE); 
    661  
    662         /* Assume not */ 
    663         return (FALSE); 
    664 
    665  
    666  
    667 /* 
    668  * Activate a wielded object.  Wielded objects never stack. 
    669  * And even if they did, activatable objects never stack. 
    670  * 
    671  * Note that it always takes a turn to activate an artifact, even if 
    672  * the user hits "escape" at the "direction" prompt. 
     368        item_tester_hook = item_tester_hook_zap; 
     369 
     370        /* Use the object */ 
     371        do_cmd_use("Zap which rod? ", "You have no charged rods to zap.", (USE_INVEN | USE_FLOOR), MSG_ZAP_ROD, USE_TIMEOUT); 
     372
     373 
     374 
     375/* 
     376 * Activate a wielded object. 
    673377 */ 
    674378void do_cmd_activate(void) 
    675379{ 
    676         int item, lev, chance; 
    677         bool ident; 
    678         object_type *o_ptr; 
    679  
    680         cptr q, s; 
    681  
    682  
    683380        /* Prepare the hook */ 
    684381        item_tester_hook = item_tester_hook_activate; 
    685382 
    686         /* Get an item */ 
    687         q = "Activate which item? "; 
    688         s = "You have nothing to activate."; 
    689         if (!get_item(&item, q, s, (USE_EQUIP))) return; 
    690  
    691         /* Get the item (in the pack) */ 
    692         if (item >= 0) 
    693         { 
    694                 o_ptr = &inventory[item]; 
    695         } 
    696  
    697         /* Get the item (on the floor) */ 
    698         else 
    699         { 
    700                 o_ptr = &o_list[0 - item]; 
    701         } 
    702  
    703  
    704         /* Take a turn */ 
    705         p_ptr->energy_use = 100; 
    706  
    707  
    708         /* Extract the item level */ 
    709         lev = k_info[o_ptr->k_idx].level; 
    710  
    711         /* Hack -- use artifact level instead */ 
    712         if (artifact_p(o_ptr)) lev = a_info[o_ptr->name1].level; 
    713  
    714         /* Base chance of success */ 
    715         chance = p_ptr->skills[SKILL_DEV]; 
    716  
    717         /* Confusion hurts skill */ 
    718         if (p_ptr->timed[TMD_CONFUSED]) chance = chance / 2; 
    719  
    720         /* High level objects are harder */ 
    721         chance = chance - ((lev > 50) ? 50 : lev); 
    722  
    723  
    724         /* Give everyone a (slight) chance */ 
    725         if ((chance < USE_DEVICE) && (rand_int(USE_DEVICE - chance + 1) == 0)) 
    726         { 
    727                 chance = USE_DEVICE; 
    728         } 
    729  
    730         /* Check for amnesia */ 
    731         if (rand_int(2) != 0 && p_ptr->timed[TMD_AMNESIA]) 
    732         { 
    733                 if (flush_failure) flush(); 
    734                 msg_print("You can't remember how to activate it."); 
    735                 return; 
    736         } 
    737  
    738         /* Roll for usage */ 
    739         if ((chance < USE_DEVICE) || (randint(chance) < USE_DEVICE)) 
    740         { 
    741                 if (flush_failure) flush(); 
    742                 msg_print("You failed to activate it properly."); 
    743                 return; 
    744         } 
    745  
    746         /* Activate the object */ 
    747         (void)use_object(o_ptr, &ident); 
    748 
     383        /* Use the object */ 
     384        do_cmd_use("Activate which item? ", "You have nothing to activate.", USE_EQUIP, MSG_GENERIC, USE_TIMEOUT); 
     385
  • trunk/src/script.h

    r136 r316  
    88/* Object and spell useage.  To be put somewhere else eventually. */ 
    99/* Right now they're fine here.  -AS- */ 
    10 extern bool use_object(object_type *o_ptr, bool *ident); 
     10extern bool use_object(object_type *o_ptr, bool *ident, int dir); 
    1111extern int get_spell_index(const object_type *o_ptr, int index); 
    1212extern cptr get_spell_name(int tval, int index); 
  • trunk/src/types.h

    r303 r316  
    956956        s16b command_rep;               /* Gives repetition of current command */ 
    957957        s16b command_dir;               /* Gives direction of current command */ 
     958        int  command_inv;               /* Gives item of current command */ 
    958959        event_type command_cmd_ex; /* Gives additional information of current command */ 
    959960 
  • trunk/src/use-obj.c

    r250 r316  
    12831283} 
    12841284 
    1285  
    1286 static bool aim_wand(object_type *o_ptr, bool *ident) 
     1285/* 
     1286 * There are no wands which can "destroy" themselves, in the inventory 
     1287 * or on the ground, so we can ignore this possibility.  Note that this 
     1288 * required giving "wand of wonder" the ability to ignore destruction 
     1289 * by electric balls. 
     1290 * 
     1291 * All wands can be "cancelled" at the "Direction?" prompt for free. 
     1292 * 
     1293 * Note that the basic "bolt" wands do slightly less damage than the 
     1294 * basic "bolt" rods, but the basic "ball" wands do the same damage 
     1295 * as the basic "ball" rods. 
     1296 */ 
     1297static bool aim_wand(object_type *o_ptr, bool *ident, int dir) 
    12871298{ 
    1288         int lev, chance, dir, sval; 
    1289  
    1290  
    1291         /* Allow direction to be cancelled for free */ 
    1292         if (!get_aim_dir(&dir)) return (FALSE); 
    1293  
    1294         /* Take a turn */ 
    1295         p_ptr->energy_use = 100; 
    1296  
    1297         /* Not identified yet */ 
    1298         *ident = FALSE; 
    1299  
    1300         /* Get the level */ 
    1301         lev = k_info[o_ptr->k_idx].level; 
    1302  
    1303         /* Base chance of success */ 
    1304         chance = p_ptr->skills[SKILL_DEV]; 
    1305  
    1306         /* Confusion hurts skill */ 
    1307         if (p_ptr->timed[TMD_CONFUSED]) chance = chance / 2; 
    1308  
    1309         /* High level objects are harder */ 
    1310         chance = chance - ((lev > 50) ? 50 : lev); 
    1311  
    1312         /* Give everyone a (slight) chance */ 
    1313         if ((chance < USE_DEVICE) && (rand_int(USE_DEVICE - chance + 1) == 0)) 
    1314         { 
    1315                 chance = USE_DEVICE; 
    1316         } 
    1317  
    1318         /* Roll for usage */ 
    1319         if ((chance < USE_DEVICE) || (randint(chance) < USE_DEVICE)) 
    1320         { 
    1321                 if (flush_failure) flush(); 
    1322                 msg_print("You failed to use the wand properly."); 
    1323                 return (FALSE); 
    1324         } 
    1325  
    1326         /* The wand is already empty! */ 
    1327         if (o_ptr->pval <= 0) 
    1328         { 
    1329                 if (flush_failure) flush(); 
    1330                 msg_print("The wand has no charges left."); 
    1331                 o_ptr->ident |= (IDENT_EMPTY); 
    1332                 p_ptr->notice |= (PN_COMBINE | PN_REORDER); 
    1333                 p_ptr->window |= (PW_INVEN); 
    1334                 return (FALSE); 
    1335         } 
    1336  
    1337  
    1338         /* Sound */ 
    1339         /* TODO: Create wand sound?  Do the individual effects have sounds? */ 
    1340         /* sound(MSG_ZAP_ROD); */ 
    1341  
     1299        int sval; 
    13421300 
    13431301        /* XXX Hack -- Extract the "sval" effect */ 
     
    15761534 
    15771535 
    1578 static bool zap_rod(object_type *o_ptr, bool *ident
     1536static bool zap_rod(object_type *o_ptr, bool *ident, int dir
    15791537{ 
    1580         int chance, dir, lev; 
    1581         bool used_charge = TRUE; 
    1582         object_kind *k_ptr = &k_info[o_ptr->k_idx]; 
    1583  
    1584  
    1585         /* Get a direction (unless KNOWN not to need it) */ 
    1586         if ((o_ptr->sval >= SV_ROD_MIN_DIRECTION) || !object_aware_p(o_ptr)) 
    1587         { 
    1588                 /* Get a direction, allow cancel */ 
    1589                 if (!get_aim_dir(&dir)) return FALSE; 
    1590         } 
    1591  
    1592  
    1593         /* Take a turn */ 
    1594         p_ptr->energy_use = 100; 
    1595  
    1596         /* Not identified yet */ 
    1597