#include "iuse.h" #include "game.h" #include "mapdata.h" #include "keypress.h" #include "output.h" #include "rng.h" #include "line.h" #include "mutation.h" #include "player.h" #include "vehicle.h" #include #include #define RADIO_PER_TURN 25 // how many characters per turn of radio // mfb(n) converts a flag to its appropriate position in covers's bitfield #ifndef mfb #define mfb(n) long(1 << (n)) #endif static void add_or_drop_item(game *g, player *p, item *it) { item replacement(g->itypes[it->type->id], int(g->turn), g->nextinv); bool drop = false; int iter = 0; // Should this vary based on how many charges get consumed by default? if (replacement.charges >= 0) { replacement.charges = 1; } if( replacement.is_drink() ) { it->charges++; return; } while (p->has_item(replacement.invlet)) { replacement.invlet = g->nextinv; g->advance_nextinv(); iter++; } if (!drop && (iter == inv_chars.size() || p->volume_carried() >= p->volume_capacity())) drop = true; if (drop) g->m.add_item_or_charges(p->posx, p->posy, replacement); else p->i_add(replacement, g); } static bool use_fire(game *g, player *p, item *it) { if (!p->use_charges_if_avail("fire", 1)) { add_or_drop_item(g, p, it); g->add_msg_if_player(p, _("You need a lighter!")); return false; } return true; } // Returns false if the inscription failed or if the player canceled the action. Otherwise, returns true. static bool inscribe_item( game *g, player *p, std::string verb, std::string gerund, bool carveable ) { //Note: this part still strongly relies on English grammar. //Although it can be easily worked around in language like Chinese, //but might need to be reworked for some European languages that have more verb forms char ch = g->inv(string_format(_("%s on what?"), verb.c_str())); item* cut = &(p->i_at(ch)); if (cut->type->id == "null") { g->add_msg(_("You do not have that item!")); return false; } if (!cut->made_of(SOLID)) { std::string lower_verb = verb; std::transform(lower_verb.begin(), lower_verb.end(), lower_verb.begin(), ::tolower); g->add_msg(_("You can't %s an item that's not solid!"), lower_verb.c_str()); return false; } if(carveable && !(cut->made_of("wood") || cut->made_of("plastic") || cut->made_of("glass") || cut->made_of("chitin") || cut->made_of("iron") || cut->made_of("steel") || cut->made_of("silver"))) { std::string lower_verb = verb; std::transform(lower_verb.begin(), lower_verb.end(), lower_verb.begin(), ::tolower); std::string mat = cut->get_material(1); material_type* mt = material_type::find_material(mat); std::string mtname = "null"; if(mt!=NULL) { mtname = mt->name(); } std::transform(mtname.begin(), mtname.end(), mtname.begin(), ::tolower); g->add_msg(_("You can't %1$s an item made of %2$s!"), lower_verb.c_str(), mtname.c_str()); return false; } std::map::iterator ent = cut->item_vars.find("item_note"); std::string message = string_format(_("%1$s on this %2$s is a note saying: "), gerund.c_str(), cut->type->name.c_str()); message = string_input_popup(string_format(_("%s what?"), verb.c_str()), 64, (ent != cut->item_vars.end() ? cut->item_vars["item_note"] : message )); if( message.size() > 0 ) { cut->item_vars["item_note"] = message; } return true; } void iuse::none(game *g, player *p, item *it, bool t) { g->add_msg(_("You can't do anything interesting with your %s."), it->tname(g).c_str()); } /* To mark an item as "removed from inventory", set its invlet to 0 This is useful for traps (placed on ground), inactive bots, etc */ void iuse::sewage(game *g, player *p, item *it, bool t) { p->vomit(g); if (one_in(4)) p->mutate(g); } void iuse::honeycomb(game *g, player *p, item *it, bool t) { g->m.spawn_item(p->posx, p->posy, "wax",0, 2); } void iuse::royal_jelly(game *g, player *p, item *it, bool t) { // TODO: Add other diseases here; royal jelly is a cure-all! p->pkill += 5; std::string message; if (p->has_disease("fungus")) { message = _("You feel cleansed inside!"); p->rem_disease("fungus"); } if (p->has_disease("blind")) { message = _("Your sight returns!"); p->rem_disease("blind"); } if (p->has_disease("poison") || p->has_disease("foodpoison") || p->has_disease("badpoison")) { message = _("You feel much better!"); p->rem_disease("poison"); p->rem_disease("badpoison"); p->rem_disease("foodpoison"); } if (p->has_disease("asthma")) { message = _("Your breathing clears up!"); p->rem_disease("asthma"); } if (p->has_disease("common_cold") || p->has_disease("flu")) { message = _("You feel healthier!"); p->rem_disease("common_cold"); p->rem_disease("flu"); } g->add_msg_if_player(p,message.c_str()); } // returns true if we want to use the special action bool use_healing_item(game *g, player *p, item *it, int normal_power, int head_power, int torso_power, std::string item_name, std::string special_action) { int bonus = p->skillLevel("firstaid"); hp_part healed; if (p->is_npc()) { // NPCs heal whichever has sustained the most damage int highest_damage = 0; for (int i = 0; i < num_hp_parts; i++) { int damage = p->hp_max[i] - p->hp_cur[i]; if (i == hp_head) damage *= 1.5; if (i == hp_torso) damage *= 1.2; if (damage > highest_damage) { highest_damage = damage; healed = hp_part(i); } } } else { // Player--present a menu WINDOW* hp_window = newwin(11, 22, (TERMY-10)/2, (TERMX-22)/2); wborder(hp_window, LINE_XOXO, LINE_XOXO, LINE_OXOX, LINE_OXOX, LINE_OXXO, LINE_OOXX, LINE_XXOO, LINE_XOOX ); mvwprintz(hp_window, 1, 1, c_ltred, _("Use %s:"), item_name.c_str()); if(p->hp_cur[hp_head] < p->hp_max[hp_head]) { mvwprintz(hp_window, 2, 1, c_ltgray, _("1: Head")); } if(p->hp_cur[hp_torso] < p->hp_max[hp_torso]) { mvwprintz(hp_window, 3, 1, c_ltgray, _("2: Torso")); } if(p->hp_cur[hp_arm_l] < p->hp_max[hp_arm_l]) { mvwprintz(hp_window, 4, 1, c_ltgray, _("3: Left Arm")); } if(p->hp_cur[hp_arm_r] < p->hp_max[hp_arm_r]) { mvwprintz(hp_window, 5, 1, c_ltgray, _("4: Right Arm")); } if(p->hp_cur[hp_leg_l] < p->hp_max[hp_leg_l]) { mvwprintz(hp_window, 6, 1, c_ltgray, _("5: Left Leg")); } if(p->hp_cur[hp_leg_r] < p->hp_max[hp_leg_r]) { mvwprintz(hp_window, 7, 1, c_ltgray, _("6: Right Leg")); } if(special_action != "") { mvwprintz(hp_window, 8, 1, c_ltgray, _("7: %s"), special_action.c_str()); } mvwprintz(hp_window, 9, 1, c_ltgray, _("8: Exit")); nc_color color; std::string asterisks = ""; for (int i = 0; i < num_hp_parts; i++) { if (p->hp_cur[i] < p->hp_max[i]) { int current_hp = p->hp_cur[i]; int temporary_bonus = bonus; if (current_hp != 0) { switch (hp_part(i)) { case hp_head: current_hp += head_power; temporary_bonus *= .8; break; case hp_torso: current_hp += torso_power; temporary_bonus *= 1.5; break; default: current_hp += normal_power; break; } current_hp += temporary_bonus; if (current_hp > p->hp_max[i]) { current_hp = p->hp_max[i]; } if (current_hp == p->hp_max[i]) { color = c_green; asterisks = "***"; } else if (current_hp > p->hp_max[i] * .8) { color = c_ltgreen; asterisks = "***"; } else if (current_hp > p->hp_max[i] * .5) { color = c_yellow; asterisks = "** "; } else if (current_hp > p->hp_max[i] * .3) { color = c_ltred; asterisks = "** "; } else { color = c_red; asterisks = "* "; } if (p->has_trait(PF_SELFAWARE)) { if (current_hp >= 100) { mvwprintz(hp_window, i + 2, 16, color, "%d", current_hp); } else if (current_hp >= 10) { mvwprintz(hp_window, i + 2, 17, color, "%d", current_hp); } else { mvwprintz(hp_window, i + 2, 19, color, "%d", current_hp); } } else { mvwprintz(hp_window, i + 2, 16, color, asterisks.c_str()); } } else { // curhp is 0; requires surgical attention mvwprintz(hp_window, i + 2, 16, c_dkgray, "---"); } } } wrefresh(hp_window); char ch; do { ch = getch(); if (ch == '1'){ healed = hp_head; } else if (ch == '2'){ healed = hp_torso; } else if (ch == '3') { if (p->hp_cur[hp_arm_l] == 0) { g->add_msg_if_player(p,_("That arm is broken. It needs surgical attention.")); add_or_drop_item(g, p, it); return false; } else { healed = hp_arm_l; } } else if (ch == '4') { if (p->hp_cur[hp_arm_r] == 0) { g->add_msg_if_player(p,_("That arm is broken. It needs surgical attention.")); add_or_drop_item(g, p, it); return false; } else { healed = hp_arm_r; } } else if (ch == '5') { if (p->hp_cur[hp_leg_l] == 0) { g->add_msg_if_player(p,_("That leg is broken. It needs surgical attention.")); add_or_drop_item(g, p, it); return false; } else { healed = hp_leg_l; } } else if (ch == '6') { if (p->hp_cur[hp_leg_r] == 0) { g->add_msg_if_player(p,_("That leg is broken. It needs surgical attention.")); add_or_drop_item(g, p, it); return false; } else { healed = hp_leg_r; } } else if (ch == '8' || special_action == "") { g->add_msg_if_player(p,_("Never mind.")); add_or_drop_item(g, p, it); return false; } else if (ch == '7') { return true; } } while (ch < '1' || ch > '8'); werase(hp_window); wrefresh(hp_window); delwin(hp_window); refresh(); } p->practice(g->turn, "firstaid", 8); int dam = 0; if (healed == hp_head){ dam = head_power + bonus * .8; } else if (healed == hp_torso){ dam = torso_power + bonus * 1.5; } else { dam = normal_power + bonus; } p->heal(healed, dam); return false; } void iuse::bandage(game *g, player *p, item *it, bool t) { if (use_healing_item(g, p, it, 3, 1, 4, _("Bandage"), p->has_disease("bleed") ? _("Stop Bleeding") : "")) { g->add_msg_if_player(p,_("You stopped the bleeding.")); p->rem_disease("bleed"); } } void iuse::firstaid(game *g, player *p, item *it, bool t) { if (use_healing_item(g, p, it, 14, 10, 18, _("First Aid"), p->has_disease("bite") ? _("Clean Wound") : "")) { g->add_msg_if_player(p,_("You clean the bite wound.")); p->rem_disease("bite"); } } void iuse::disinfectant(game *g, player *p, item *it, bool t) { if (use_healing_item(g, p, it, 6, 5, 9, _("Disinfectant"), p->has_disease("bite") ? _("Clean Wound") : "")) { g->add_msg_if_player(p,_("You disinfect the bite wound.")); p->rem_disease("bite"); } } void iuse::pkill(game *g, player *p, item *it, bool t) { // Aspirin if (it->has_flag("PKILL_1")) { g->add_msg_if_player(p,_("You take some %s."), it->tname().c_str()); if (!p->has_disease("pkill1")) { p->add_disease("pkill1", 120); } else { for (int i = 0; i < p->illness.size(); i++) { if (p->illness[i].type == "pkill1") { p->illness[i].duration = 120; i = p->illness.size(); } } } // Codeine } else if (it->has_flag("PKILL_2")) { g->add_msg_if_player(p,_("You take some %s."), it->tname().c_str()); p->add_disease("pkill2", 180); } else if (it->has_flag("PKILL_3")) { g->add_msg_if_player(p,_("You take some %s."), it->tname().c_str()); p->add_disease("pkill3", 20); p->add_disease("pkill2", 200); } else if (it->has_flag("PKILL_4")) { g->add_msg_if_player(p,_("You shoot up.")); p->add_disease("pkill3", 80); p->add_disease("pkill2", 200); } else if (it->has_flag("PKILL_L")) { g->add_msg_if_player(p,_("You take some %s."), it->tname().c_str()); p->add_disease("pkill_l", rng(12, 18) * 300); } } void iuse::xanax(game *g, player *p, item *it, bool t) { g->add_msg_if_player(p,_("You take some %s."), it->tname().c_str()); if (!p->has_disease("took_xanax")) p->add_disease("took_xanax", 900); else p->add_disease("took_xanax", 200); } void iuse::caff(game *g, player *p, item *it, bool t) { it_comest *food = dynamic_cast (it->type); p->fatigue -= food->stim * 3; } void iuse::alcohol(game *g, player *p, item *it, bool t) { int duration = 680 - (10 * p->str_max); // Weaker characters are cheap drunks if (p->has_trait(PF_LIGHTWEIGHT)) duration += 300; p->pkill += 8; p->add_disease("drunk", duration); } void iuse::alcohol_weak(game *g, player *p, item *it, bool t) { int duration = 340 - (6 * p->str_max); if (p->has_trait(PF_LIGHTWEIGHT)) duration += 120; p->pkill += 4; p->add_disease("drunk", duration); } void iuse::cig(game *g, player *p, item *it, bool t) { if (!use_fire(g, p, it)) return; if (it->type->id == "cig") g->add_msg_if_player(p,_("You light a cigarette and smoke it.")); else //cigar g->add_msg_if_player(p,_("You take a few puffs from your cigar.")); p->add_disease("cig", 200); for (int i = 0; i < p->illness.size(); i++) { if (p->illness[i].type == "cig" && p->illness[i].duration > 600) g->add_msg_if_player(p,_("Ugh, too much smoke... you feel gross.")); } } void iuse::antibiotic(game *g, player *p, item *it, bool t) { if (p->has_disease("infected")){ g->add_msg_if_player(p,_("You took some antibiotics.")); p->rem_disease("infected"); p->add_disease("recover", 1200); } else { g->add_msg_if_player(p,_("You took some antibiotics.")); } } void iuse::weed(game *g, player *p, item *it, bool t) { if (!use_fire(g, p, it)) return; g->add_msg_if_player(p,_("Good stuff, man!")); int duration = 60; if (p->has_trait(PF_LIGHTWEIGHT)) duration = 90; p->hunger += 8; if (p->pkill < 15) p->pkill += 5; p->add_disease("high", duration); } void iuse::coke(game *g, player *p, item *it, bool t) { g->add_msg_if_player(p,_("You snort a bump.")); int duration = 21 - p->str_cur; if (p->has_trait(PF_LIGHTWEIGHT)) duration += 20; p->hunger -= 8; p->add_disease("high", duration); } void iuse::crack(game *g, player *p, item *it, bool t) { // Crack requires a fire source AND a pipe. if (!use_fire(g, p, it)) return; g->add_msg_if_player(p,_("You smoke some rocks.")); int duration = 10; if (p->has_trait(PF_LIGHTWEIGHT)) { duration += 10; } p->hunger -= 8; p->add_disease("high", duration); } void iuse::grack(game *g, player *p, item *it, bool t) { // Grack requires a fire source AND a pipe. if (!use_fire(g, p, it)) return; g->add_msg_if_player(p,_("You smoke some Grack Cocaine. Time seems to stop.")); int duration = 1000; if (p->has_trait(PF_LIGHTWEIGHT)) duration += 10; p->hunger -= 8; p->add_disease("grack", duration); } void iuse::meth(game *g, player *p, item *it, bool t) { int duration = 10 * (40 - p->str_cur); if (p->has_amount("apparatus", 1) && p->use_charges_if_avail("fire", 1)) { g->add_msg_if_player(p,_("You smoke some crystals.")); duration *= 1.5; } else { g->add_msg_if_player(p,_("You snort some crystals.")); } if (!p->has_disease("meth")) {duration += 600;} if (duration > 0) { int hungerpen = (p->str_cur < 10 ? 20 : 30 - p->str_cur); p->hunger -= hungerpen; p->add_disease("meth", duration); } } void iuse::vitamins(game *g, player *p, item *it, bool t) { g->add_msg_if_player(p,_("You take some vitamins.")); if (p->health >= 10) { return; } else if (p->health >= 0) { p->health = 10; } else { p->health += 10; } } void iuse::vaccine(game *g, player *p, item *it, bool t) { g->add_msg_if_player(p,_("You inject the vaccine, and feel much healthier.")); if (p->health >= 100) { return; } else if (p->health >= 0) { p->health = 100; } else { p->health += 100; } } void iuse::poison(game *g, player *p, item *it, bool t) { p->add_disease("poison", 600); p->add_disease("foodpoison", 1800); } void iuse::hallu(game *g, player *p, item *it, bool t) { p->add_disease("hallu", 2400); } void iuse::thorazine(game *g, player *p, item *it, bool t) { p->fatigue += 15; p->rem_disease("hallu"); p->rem_disease("visuals"); p->rem_disease("high"); if (!p->has_disease("dermatik")) p->rem_disease("formication"); g->add_msg_if_player(p,_("You feel somewhat sedated.")); } void iuse::prozac(game *g, player *p, item *it, bool t) { if (!p->has_disease("took_prozac") && p->morale_level() < 0) p->add_disease("took_prozac", 7200); else p->stim += 3; } void iuse::sleep(game *g, player *p, item *it, bool t) { p->fatigue += 40; g->add_msg_if_player(p,_("You feel very sleepy...")); } void iuse::iodine(game *g, player *p, item *it, bool t) { p->add_disease("iodine", 1200); g->add_msg_if_player(p,_("You take an iodine tablet.")); } void iuse::flumed(game *g, player *p, item *it, bool t) { p->add_disease("took_flumed", 6000); g->add_msg_if_player(p,_("You take some %s"), it->tname().c_str()); } void iuse::flusleep(game *g, player *p, item *it, bool t) { p->add_disease("took_flumed", 7200); p->fatigue += 30; g->add_msg_if_player(p,_("You feel very sleepy...")); } void iuse::inhaler(game *g, player *p, item *it, bool t) { p->rem_disease("asthma"); g->add_msg_if_player(p,_("You take a puff from your inhaler.")); } void iuse::blech(game *g, player *p, item *it, bool t) { // TODO: Add more effects? g->add_msg_if_player(p,_("Blech, that burns your throat!")); p->vomit(g); } void iuse::mutagen(game *g, player *p, item *it, bool t) { if( it->has_flag("MUTAGEN_STRONG") ) { p->mutate(g); if (!one_in(3)) p->mutate(g); if (one_in(2)) p->mutate(g); } else if( it->has_flag("MUTAGEN_PLANT") ) { g->add_msg_if_player(p, _("You feel much closer to nature.")); p->mutate_category(g, MUTCAT_PLANT); } else if( it->has_flag("MUTAGEN_INSECT") ) { g->add_msg_if_player(p, _("You hear buzzing, and feel your body harden.")); p->mutate_category(g, MUTCAT_INSECT); } else if( it->has_flag("MUTAGEN_SPIDER") ) { g->add_msg_if_player(p, _("You feel insidious.")); p->mutate_category(g, MUTCAT_SPIDER); } else if( it->has_flag("MUTAGEN_SLIME") ) { g->add_msg_if_player(p, _("Your body loses all rigidity for a moment.")); p->mutate_category(g, MUTCAT_SLIME); } else if( it->has_flag("MUTAGEN_FISH") ) { g->add_msg_if_player(p, _("You are overcome by an overwhelming longing for the ocean.")); p->mutate_category(g, MUTCAT_FISH); } else if( it->has_flag("MUTAGEN_RAT") ) { g->add_msg_if_player(p, _("You feel a momentary nausea.")); p->mutate_category(g, MUTCAT_RAT); } else if( it->has_flag("MUTAGEN_BEAST") ) { g->add_msg_if_player(p, _("Your heart races and you see blood for a moment.")); p->mutate_category(g, MUTCAT_BEAST); } else if( it->has_flag("MUTAGEN_CATTLE") ) { g->add_msg_if_player(p, _("Your mind and body slow down. You feel peaceful.")); p->mutate_category(g, MUTCAT_CATTLE); } else if( it->has_flag("MUTAGEN_CEPHALOPOD") ) { g->add_msg_if_player(p, _("Your mind is overcome by images of eldritch horrors...and then they pass.")); p->mutate_category(g, MUTCAT_CEPHALOPOD); } else if( it->has_flag("MUTAGEN_BIRD") ) { g->add_msg_if_player(p, _("Your body lightens and you long for the sky.")); p->mutate_category(g, MUTCAT_BIRD); } else if( it->has_flag("MUTAGEN_LIZARD") ) { g->add_msg_if_player(p, _("For a heartbeat, your body cools down.")); p->mutate_category(g, MUTCAT_LIZARD); } else if( it->has_flag("MUTAGEN_TROGLOBITE") ) { g->add_msg_if_player(p, _("You yearn for a cool, dark place to hide.")); p->mutate_category(g, MUTCAT_TROGLO); } else { if (!one_in(3)) { p->mutate(g); } } } void iuse::purifier(game *g, player *p, item *it, bool t) { std::vector valid; // Which flags the player has for (int i = PF_NULL+1; i < PF_MAX2; i++) { if (p->has_trait(pl_flag(i)) && !p->has_base_trait(pl_flag(i))) //Looks for active mutation valid.push_back(i); } if (valid.size() == 0) { g->add_msg_if_player(p,_("You feel cleansed.")); return; } int num_cured = rng(1, valid.size()); if (num_cured > 4) num_cured = 4; for (int i = 0; i < num_cured && valid.size() > 0; i++) { int index = rng(0, valid.size() - 1); p->remove_mutation(g, pl_flag(valid[index]) ); valid.erase(valid.begin() + index); } } void iuse::marloss(game *g, player *p, item *it, bool t) { if (p->is_npc()) return; // If we have the marloss in our veins, we are a "breeder" and will spread // alien lifeforms. if (p->has_trait(PF_MARLOSS)) { g->add_msg_if_player(p,_("As you eat the berry, you have a near-religious experience, feeling at one with your surroundings...")); p->add_morale(MORALE_MARLOSS, 100, 1000); p->hunger = -100; monster goo(g->mtypes[mon_blob]); goo.friendly = -1; int goo_spawned = 0; for (int x = p->posx - 4; x <= p->posx + 4; x++) { for (int y = p->posy - 4; y <= p->posy + 4; y++) { if (rng(0, 10) > trig_dist(x, y, p->posx, p->posy) && rng(0, 10) > trig_dist(x, y, p->posx, p->posy) ) g->m.marlossify(x, y); if (one_in(10 + 5 * trig_dist(x, y, p->posx, p->posy)) && (goo_spawned == 0 || one_in(goo_spawned * 2))) { goo.spawn(x, y); g->z.push_back(goo); goo_spawned++; } } } return; } /* If we're not already carriers of Marloss, roll for a random effect: * 1 - Mutate * 2 - Mutate * 3 - Mutate * 4 - Purify * 5 - Purify * 6 - Cleanse radiation + Purify * 7 - Fully satiate * 8 - Vomit * 9 - Give Marloss mutation */ int effect = rng(1, 9); if (effect <= 3) { g->add_msg_if_player(p,_("This berry tastes extremely strange!")); p->mutate(g); } else if (effect <= 6) { // Radiation cleanse is below g->add_msg_if_player(p,_("This berry makes you feel better all over.")); p->pkill += 30; this->purifier(g, p, it, t); } else if (effect == 7) { g->add_msg_if_player(p,_("This berry is delicious, and very filling!")); p->hunger = -100; } else if (effect == 8) { g->add_msg_if_player(p,_("You take one bite, and immediately vomit!")); p->vomit(g); } else if (!p->has_trait(PF_MARLOSS)) { g->add_msg_if_player(p,_("You feel a strange warmth spreading throughout your body...")); p->toggle_mutation(PF_MARLOSS); } if (effect == 6) p->radiation = 0; } void iuse::dogfood(game *g, player *p, item *it, bool t) { int dirx, diry; if(!g->choose_adjacent(_("Put the dog food"),dirx,diry)) return; p->moves -= 15; int mon_dex = g->mon_at(dirx,diry); if (mon_dex != -1) { if (g->z[mon_dex].type->id == mon_dog) { g->add_msg_if_player(p,_("The dog seems to like you!")); g->z[mon_dex].friendly = -1; } else g->add_msg_if_player(p,_("The %s seems quite unimpressed!"),g->z[mon_dex].type->name.c_str()); } else g->add_msg_if_player(p,_("You spill the dogfood all over the ground.")); } // TOOLS below this point! bool prep_firestarter_use(game *g, player *p, item *it, int &posx, int &posy) { if (!g->choose_adjacent(_("Light"),posx,posy)) { it->charges++; return false; } if (posx == p->posx && posy == p->posy) { g->add_msg_if_player(p, _("You would set yourself on fire.")); g->add_msg_if_player(p, _("But you're already smokin' hot.")); it->charges++; return false; } if (!(g->m.flammable_items_at(posx, posy) || g->m.has_flag(flammable, posx, posy) || g->m.has_flag(flammable2, posx, posy))) { g->add_msg_if_player(p,_("There's nothing to light there.")); it->charges++; return false; } else { return true; } } void resolve_firestarter_use(game *g, player *p, item *it, int posx, int posy) { // this should have already been checked, but double-check to make sure if (g->m.flammable_items_at(posx, posy) || g->m.has_flag(flammable, posx, posy) || g->m.has_flag(flammable2, posx, posy)) { if (g->m.add_field(g, posx, posy, fd_fire, 1)) { field ¤t_field = g->m.field_at(posx, posy); current_field.findField(fd_fire)->setFieldAge(current_field.findField(fd_fire)->getFieldAge() + 100); g->add_msg_if_player(p, _("You successfully light a fire.")); } } else { debugmsg(_("Flammable items disappeared while lighting a fire!")); } } void iuse::lighter(game *g, player *p, item *it, bool t) { int dirx, diry; if (prep_firestarter_use(g, p, it, dirx, diry)) { p->moves -= 15; resolve_firestarter_use(g, p, it, dirx, diry); } } void iuse::primitive_fire(game *g, player *p, item *it, bool t) { int posx, posy; if (prep_firestarter_use(g, p, it, posx, posy)) { p->moves -= 500; const int skillLevel = p->skillLevel("survival"); const int sides = 10; const int base_dice = 3; // aiming for ~50% success at skill level 3, and possible but unheard of at level 0 const int difficulty = (base_dice + 3) * sides / 2; if (dice(skillLevel+base_dice, 10) >= difficulty) { resolve_firestarter_use(g, p, it, posx, posy); } else { g->add_msg_if_player(p, _("You try to light a fire, but fail.")); } p->practice(g->turn, "survival", 10); } } void iuse::sew(game *g, player *p, item *it, bool t) { if(p->fine_detail_vision_mod(g) > 2.5) { g->add_msg(_("You can't see to sew!")); it->charges++; return; } char ch = g->inv_type(_("Repair what?"), IC_ARMOR); item* fix = &(p->i_at(ch)); if (fix == NULL || fix->is_null()) { g->add_msg_if_player(p,_("You do not have that item!")); it->charges++; return; } if (!fix->is_armor()) { g->add_msg_if_player(p,_("That isn't clothing!")); it->charges++; return; } //some items are made from more than one material. we should try to use both items if one type of repair item is missing itype_id repair_item = "none"; std::vector plurals; std::vector repair_items; std::string plural = ""; //translation note: add tag to keep them unique if (fix->made_of("cotton") || fix->made_of("wool")) { repair_items.push_back("rag"); plurals.push_back(_("rags")); } if (fix->made_of("leather")) { repair_items.push_back("leather"); plurals.push_back(rm_prefix(_("leather"))); } if (fix->made_of("fur")) { repair_items.push_back("fur"); plurals.push_back(rm_prefix(_("fur"))); } if(repair_items.empty()) { g->add_msg_if_player(p,_("Your %s is not made of cotton, wool, leather or fur."), fix->tname().c_str()); it->charges++; return; } int items_needed=(fix->damage>2||fix->damage==0)?1:0; // this will cause issues if/when NPCs start being able to sew. // but, then again, it'll cause issues when they start crafting, too. inventory crafting_inv = g->crafting_inventory(p); bool bFound = false; //go through all discovered repair items and see if we have any of them available for(unsigned int i = 0; i< repair_items.size(); i++) { if (crafting_inv.has_amount(repair_items[i], items_needed)) { //we've found enough of a material, use this one repair_item = repair_items[i]; bFound = true; } } if (!bFound) { for(unsigned int i = 0; i< repair_items.size(); i++) { g->add_msg_if_player(p,_("You don't have enough %s to do that."), plurals[i].c_str()); } it->charges++; return; } if (fix->damage < 0) { g->add_msg_if_player(p,_("Your %s is already enhanced."), fix->tname().c_str()); it->charges++; return; } std::vector comps; comps.push_back(component(repair_item, items_needed)); comps.back().available = true; if (fix->damage == 0) { p->moves -= 500 * p->fine_detail_vision_mod(g); p->practice(g->turn, "tailor", 10); int rn = dice(4, 2 + p->skillLevel("tailor")); if (p->dex_cur < 8 && one_in(p->dex_cur)) {rn -= rng(2, 6);} if (p->dex_cur >= 16 || (p->dex_cur > 8 && one_in(16 - p->dex_cur))) {rn += rng(2, 6);} if (p->dex_cur > 16) {rn += rng(0, p->dex_cur - 16);} if (rn <= 4) { g->add_msg_if_player(p,_("You damage your %s!"), fix->tname().c_str()); fix->damage++; } else if (rn >= 12 && p->i_at(ch).has_flag("VARSIZE") && !p->i_at(ch).has_flag("FIT")) { g->add_msg_if_player(p,_("You take your %s in, improving the fit."), fix->tname().c_str()); (p->i_at(ch).item_tags.insert("FIT")); } else if (rn >= 12 && (p->i_at(ch).has_flag("FIT") || !p->i_at(ch).has_flag("VARSIZE"))) { g->add_msg_if_player(p, _("You make your %s extra sturdy."), fix->tname().c_str()); fix->damage--; g->consume_items(p, comps); } else { g->add_msg_if_player(p,_("You practice your sewing.")); } } else { p->moves -= 500 * p->fine_detail_vision_mod(g); p->practice(g->turn, "tailor", 8); int rn = dice(4, 2 + p->skillLevel("tailor")); rn -= rng(fix->damage, fix->damage * 2); if (p->dex_cur < 8 && one_in(p->dex_cur)) {rn -= rng(2, 6);} if (p->dex_cur >= 8 && (p->dex_cur >= 16 || one_in(16 - p->dex_cur))) {rn += rng(2, 6);} if (p->dex_cur > 16) {rn += rng(0, p->dex_cur - 16);} if (rn <= 4) { g->add_msg_if_player(p,_("You damage your %s further!"), fix->tname().c_str()); fix->damage++; if (fix->damage >= 5) { g->add_msg_if_player(p,_("You destroy it!")); p->i_rem(ch); } } else if (rn <= 6) { g->add_msg_if_player(p,_("You don't repair your %s, but you waste lots of thread."), fix->tname().c_str()); int waste = rng(1, 8); if (waste > it->charges) {it->charges = 1;} else {it->charges -= waste;} } else if (rn <= 8) { g->add_msg_if_player(p,_("You repair your %s, but waste lots of thread."), fix->tname().c_str()); if (fix->damage>=3) {g->consume_items(p, comps);} fix->damage--; int waste = rng(1, 8); if (waste > it->charges) {it->charges = 1;} else {it->charges -= waste;} } else if (rn <= 16) { g->add_msg_if_player(p,_("You repair your %s!"), fix->tname().c_str()); if (fix->damage>=3) {g->consume_items(p, comps);} fix->damage--; } else { g->add_msg_if_player(p,_("You repair your %s completely!"), fix->tname().c_str()); if (fix->damage>=3) {g->consume_items(p, comps);} fix->damage = 0; } } //iuse::sew uses up 1 charge when called, if less than 1, set to 1, and use that one up. if (it->charges < 1) {it->charges = 1;} } void iuse::extra_battery(game *g, player *p, item *it, bool t) { char ch = g->inv_type(_("Modify what?"), IC_TOOL); item* modded = &(p->i_at(ch)); if (modded == NULL || modded->is_null()) { g->add_msg_if_player(p,_("You do not have that item!")); return; } if (!modded->is_tool()) { g->add_msg_if_player(p,_("You can only mod tools with this battery mod.")); return; } it_tool *tool = dynamic_cast(modded->type); if (tool->ammo != "battery") { g->add_msg_if_player(p,_("That item does not use batteries!")); return; } if (modded->has_flag("DOUBLE_AMMO")) { g->add_msg_if_player(p,_("That item has already had its battery capacity doubled.")); return; } modded->item_tags.insert("DOUBLE_AMMO"); g->add_msg_if_player(p,_("You double the battery capacity of your %s!"), tool->name.c_str()); it->invlet = 0; } void iuse::scissors(game *g, player *p, item *it, bool t) { char ch = g->inv(_("Chop up what?")); item* cut = &(p->i_at(ch)); if (cut->type->id == "null") { g->add_msg_if_player(p,_("You do not have that item!")); return; } if (cut->type->id == "string_6" || cut->type->id == "string_36" || cut->type->id == "rope_30" || cut->type->id == "rope_6") { g->add_msg(_("You cannot cut that, you must disassemble it using the disassemble key")); return; } if (cut->type->id == "rag" || cut->type->id == "rag_bloody" || cut->type->id == "leather") { g->add_msg_if_player(p, _("There's no point in cutting a %s."), cut->type->name.c_str()); return; } if (!cut->made_of("cotton") && !cut->made_of("leather")) { g->add_msg(_("You can only slice items made of cotton or leather.")); return; } p->moves -= 25 * cut->volume(); int count = cut->volume(); if (p->skillLevel("tailor") == 0) { count = rng(0, count); } else if (p->skillLevel("tailor") == 1 && count >= 2) { count -= rng(0, 2); } if (dice(3, 3) > p->dex_cur) { count -= rng(1, 3); } if (cut->damage>2 || cut->damage<0) { count-= cut->damage; } //scrap_text is result string of worthless scraps //sliced_text is result on a success std::string scrap_text, sliced_text, type; if (cut->made_of("cotton")) { scrap_text = _("You clumsily cut the %s into useless ribbons."); sliced_text = ngettext("You slice the %s into a rag.", "You slice the %1$s into %2$d rags.", count); type = "rag"; } else { scrap_text = _("You clumsily cut the %s into useless scraps."); sliced_text = ngettext("You slice the %s into a piece of leather.", "You slice the %1$s into %2$d pieces of leather.", count); type = "leather"; } if (count <= 0) { g->add_msg_if_player(p, scrap_text.c_str(), cut->tname().c_str()); p->i_rem(ch); return; } g->add_msg_if_player(p, sliced_text.c_str(), cut->tname().c_str(), count); item result(g->itypes[type], int(g->turn), g->nextinv); p->i_rem(ch); bool drop = false; for (int i = 0; i < count; i++) { int iter = 0; while (p->has_item(result.invlet) && iter < inv_chars.size()) { result.invlet = g->nextinv; g->advance_nextinv(); iter++; } if (!drop && (iter == inv_chars.size() || p->volume_carried() >= p->volume_capacity())) drop = true; if (drop) g->m.add_item_or_charges(p->posx, p->posy, result); else p->i_add(result, g); } return; } void iuse::extinguisher(game *g, player *p, item *it, bool t) { g->draw(); int x, y; // If anyone other than the player wants to use one of these, // they're going to need to figure out how to aim it. if (!g->choose_adjacent("Spray", x, y)) return; p->moves -= 140; field ¤t_field = g->m.field_at(x, y); if (current_field.findField(fd_fire)) { current_field.findField(fd_fire)->setFieldDensity(current_field.findField(fd_fire)->getFieldDensity() - rng(2, 3)); if (current_field.findField(fd_fire)->getFieldDensity() <= 0) { //g->m.field_at(x, y).density = 1; g->m.remove_field(x, y, fd_fire); } } int mondex = g->mon_at(x, y); if (mondex != -1) { g->z[mondex].moves -= 150; if (g->u_see(&(g->z[mondex]))) g->add_msg_if_player(p,_("The %s is sprayed!"), g->z[mondex].name().c_str()); if (g->z[mondex].made_of(LIQUID)) { if (g->u_see(&(g->z[mondex]))) g->add_msg_if_player(p,_("The %s is frozen!"), g->z[mondex].name().c_str()); if (g->z[mondex].hurt(rng(20, 60))) g->kill_mon(mondex, (p == &(g->u))); else g->z[mondex].speed /= 2; } } if (g->m.move_cost(x, y) != 0) { x += (x - p->posx); y += (y - p->posy); if (current_field.findField(fd_fire)) { current_field.findField(fd_fire)->setFieldDensity(current_field.findField(fd_fire)->getFieldDensity() - rng(0, 1) + rng(0, 1)); if (current_field.findField(fd_fire)->getFieldDensity() <= 0) { //g->m.field_at(x, y).density = 1; g->m.remove_field(x, y,fd_fire); } } } } void iuse::hammer(game *g, player *p, item *it, bool t) { g->draw(); int x, y; // If anyone other than the player wants to use one of these, // they're going to need to figure out how to aim it. if (!g->choose_adjacent(_("Pry"), x, y)) return; if (x == p->posx && y == p->posy) { g->add_msg_if_player(p, _("You try to hit yourself with the hammer.")); g->add_msg_if_player(p, _("But you can't touch this.")); return; } int nails = 0, boards = 0; ter_id newter; switch (g->m.ter(x, y)) { case t_fence_h: case t_fence_v: nails = 6; boards = 3; newter = t_fence_post; break; case t_window_boarded: nails = 8; boards = 4; newter = t_window_empty; break; case t_door_boarded: nails = 12; boards = 4; newter = t_door_b; break; default: g->add_msg_if_player(p,_("Hammers can only remove boards from windows, doors and fences.")); g->add_msg_if_player(p,_("To board up a window or door, press *")); return; } p->moves -= 500; g->m.spawn_item(p->posx, p->posy, "nail", 0, 0, nails); g->m.spawn_item(p->posx, p->posy, "2x4", 0, boards); g->m.ter_set(x, y, newter); } void iuse::gasoline_lantern_off(game *g, player *p, item *it, bool t) { if (it->charges == 0) { g->add_msg_if_player(p,_("The lantern is empty.")); } else if(!p->use_charges_if_avail("fire", 1)) { g->add_msg_if_player(p,_("You need a lighter!")); } else { g->add_msg_if_player(p,_("You turn the lantern on.")); it->make(g->itypes["gasoline_lantern_on"]); it->active = true; it->charges --; } } void iuse::gasoline_lantern_on(game *g, player *p, item *it, bool t) { if (t) // Normal use { // Do nothing... player::active_light and the lightmap::generate deal with this } else // Turning it off { g->add_msg_if_player(p,_("The lantern is extinguished.")); it->make(g->itypes["gasoline_lantern"]); it->active = false; } } void iuse::light_off(game *g, player *p, item *it, bool t) { if (it->charges == 0) g->add_msg_if_player(p,_("The flashlight's batteries are dead.")); else { g->add_msg_if_player(p,_("You turn the flashlight on.")); it->make(g->itypes["flashlight_on"]); it->active = true; it->charges --; } } void iuse::light_on(game *g, player *p, item *it, bool t) { if (t) { // Normal use // Do nothing... player::active_light and the lightmap::generate deal with this } else { // Turning it off g->add_msg_if_player(p,_("The flashlight flicks off.")); it->make(g->itypes["flashlight"]); it->active = false; } } // this function only exists because we need to set it->active = true // otherwise crafting would just give you the active version directly void iuse::lightstrip(game *g, player *p, item *it, bool t) { g->add_msg_if_player(p,_("You irreversibly activate the lightstrip.")); it->make(g->itypes["lightstrip"]); it->active = true; } void iuse::lightstrip_active(game *g, player *p, item *it, bool t) { if (t) { // Normal use // Do nothing... player::active_light and the lightmap::generate deal with this } else { // Turning it off g->add_msg_if_player(p,_("The lightstrip dies.")); it->make(g->itypes["lightstrip_dead"]); it->active = false; } } void iuse::glowstick(game *g, player *p, item *it, bool t) { g->add_msg_if_player(p,_("You activate the glowstick.")); it->make(g->itypes["glowstick_lit"]); it->active = true; } void iuse::glowstick_active(game *g, player *p, item *it, bool t) { if (t) { // Normal use // Do nothing... player::active_light and the lightmap::generate deal with this } else { if (it->charges > 0) { g->add_msg_if_player(p,_("You can't turn off a glowstick.")); } else { g->add_msg_if_player(p,_("The glowstick fades out.")); it->active = false; } } } void iuse::cauterize_elec(game *g, player *p, item *it, bool t) { if (it->charges == 0) g->add_msg_if_player(p,_("You need batteries to cauterize wounds.")); else if (!p->has_disease("bite") && !p->has_disease("bleed")) g->add_msg_if_player(p,_("You are not bleeding or bitten, there is no need to cauterize yourself.")); else if (p->is_npc() || query_yn(_("Cauterize any open wounds?"))) { it->charges -= 1; p->cauterize(g); } } void iuse::solder_weld(game *g, player *p, item *it, bool t) { it->charges += (dynamic_cast(it->type))->charges_per_use; int choice = menu(true, _("Using soldering item:"), _("Cauterize wound"), _("Repair plastic/metal/kevlar item"), _("Cancel"), NULL); switch (choice) { case 1: { iuse::cauterize_elec(g, p, it, t); } break; case 2: { if(it->charges <= 0) { g->add_msg_if_player(p,_("You don't have enough batteries!")); return; } char ch = g->inv_type(_("Repair what?"), IC_ARMOR); item* fix = &(p->i_at(ch)); if (fix == NULL || fix->is_null()) { g->add_msg_if_player(p,_("You do not have that item!")); return; } if (!fix->is_armor()) { g->add_msg_if_player(p,_("That isn't clothing!")); return; } itype_id repair_item = "none"; std::vector repairitem_names; std::vector repair_items; if (fix->made_of("kevlar")) { repair_items.push_back("kevlar_plate"); repairitem_names.push_back(_("kevlar plates")); } if (fix->made_of("plastic")) { repair_items.push_back("plastic_chunk"); repairitem_names.push_back(_("plastic chunks")); } if (fix->made_of("iron") || fix->made_of("steel")) { repair_items.push_back("scrap"); repairitem_names.push_back(_("scrap metal")); } if(repair_items.empty()) { g->add_msg_if_player(p,_("Your %s is not made of kevlar, plastic or metal."), fix->tname().c_str()); return; } //repairing or modifying items requires at least 1 repair item, otherwise number is related to size of item int items_needed=ceil( fix->volume() * 0.25); // this will cause issues if/when NPCs start being able to sew. // but, then again, it'll cause issues when they start crafting, too. inventory crafting_inv = g->crafting_inventory(p); bool bFound = false; //go through all discovered repair items and see if we have any of them available for(unsigned int i = 0; i< repair_items.size(); i++) { if (crafting_inv.has_amount(repair_items[i], items_needed)) { //we've found enough of a material, use this one repair_item = repair_items[i]; bFound = true; } } if (!bFound) { for(unsigned int i = 0; i< repair_items.size(); i++) { g->add_msg_if_player(p,_("You don't have enough %s to do that."), repairitem_names[i].c_str()); } return; } if (fix->damage < 0) { g->add_msg_if_player(p,_("Your %s is already enhanced."), fix->tname().c_str()); return; } std::vector comps; comps.push_back(component(repair_item, items_needed)); comps.back().available = true; if (fix->damage == 0) { p->moves -= 500 * p->fine_detail_vision_mod(g); p->practice(g->turn, "mechanics", 10); int rn = dice(4, 2 + p->skillLevel("mechanics")); if (p->dex_cur < 8 && one_in(p->dex_cur)) {rn -= rng(2, 6);} if (p->dex_cur >= 16 || (p->dex_cur > 8 && one_in(16 - p->dex_cur))) {rn += rng(2, 6);} if (p->dex_cur > 16) {rn += rng(0, p->dex_cur - 16);} if (rn <= 4) { g->add_msg_if_player(p,_("You damage your %s!"), fix->tname().c_str()); fix->damage++; } else if (rn >= 12 && p->i_at(ch).has_flag("VARSIZE") && !p->i_at(ch).has_flag("FIT")) { g->add_msg_if_player(p,_("You take your %s in, improving the fit."), fix->tname().c_str()); (p->i_at(ch).item_tags.insert("FIT")); } else if (rn >= 12 && (p->i_at(ch).has_flag("FIT") || !p->i_at(ch).has_flag("VARSIZE"))) { g->add_msg_if_player(p, _("You make your %s extra sturdy."), fix->tname().c_str()); fix->damage--; g->consume_items(p, comps); } else { g->add_msg_if_player(p,_("You practice your soldering.")); } } else { p->moves -= 500 * p->fine_detail_vision_mod(g); p->practice(g->turn, "mechanics", 8); int rn = dice(4, 2 + p->skillLevel("mechanics")); rn -= rng(fix->damage, fix->damage * 2); if (p->dex_cur < 8 && one_in(p->dex_cur)) {rn -= rng(2, 6);} if (p->dex_cur >= 8 && (p->dex_cur >= 16 || one_in(16 - p->dex_cur))) {rn += rng(2, 6);} if (p->dex_cur > 16) {rn += rng(0, p->dex_cur - 16);} if (rn <= 4) { g->add_msg_if_player(p,_("You damage your %s further!"), fix->tname().c_str()); fix->damage++; if (fix->damage >= 5) { g->add_msg_if_player(p,_("You destroy it!")); p->i_rem(ch); } } else if (rn <= 6) { g->add_msg_if_player(p,_("You don't repair your %s, and you waste lots of charge."), fix->tname().c_str()); int waste = rng(1, 8); if (waste > it->charges) {it->charges = 1;} else {it->charges -= waste;} } else if (rn <= 8) { g->add_msg_if_player(p,_("You repair your %s, but you waste lots of charge."), fix->tname().c_str()); if (fix->damage>=3) {g->consume_items(p, comps);} fix->damage--; int waste = rng(1, 8); if (waste > it->charges) {it->charges = 1;} else {it->charges -= waste;} } else if (rn <= 16) { g->add_msg_if_player(p,_("You repair your %s!"), fix->tname().c_str()); if (fix->damage>=3) {g->consume_items(p, comps);} fix->damage--; } else { g->add_msg_if_player(p,_("You repair your %s completely!"), fix->tname().c_str()); if (fix->damage>=3) {g->consume_items(p, comps);} fix->damage = 0; } } it->charges -= 1; } break; case 3: { } break; default: break; }; } void iuse::water_purifier(game *g, player *p, item *it, bool t) { it->charges++; char ch = g->inv_type(_("Purify what?"), IC_COMESTIBLE); if (!p->has_item(ch)) { g->add_msg_if_player(p,_("You do not have that item!")); return; } if (p->i_at(ch).contents.size() == 0) { g->add_msg_if_player(p,_("You can only purify water.")); return; } item *pure = &(p->i_at(ch).contents[0]); if (pure->type->id != "water" && pure->type->id != "salt_water") { g->add_msg_if_player(p,_("You can only purify water.")); return; } if (pure->charges > it->charges) { g->add_msg_if_player(p,_("You don't have enough battery power to purify all the water.")); return; } it->charges -= pure->charges; p->moves -= 150; pure->make(g->itypes["water_clean"]); pure->poison = 0; } void iuse::two_way_radio(game *g, player *p, item *it, bool t) { WINDOW* w = newwin(6, 36, (TERMY-6)/2, (TERMX-36)/2); wborder(w, LINE_XOXO, LINE_XOXO, LINE_OXOX, LINE_OXOX, LINE_OXXO, LINE_OOXX, LINE_XXOO, LINE_XOOX ); // TODO: More options here. Thoughts... // > Respond to the SOS of an NPC // > Report something to a faction // > Call another player fold_and_print(w, 1, 1, 999, c_white, _( "1: Radio a faction for help...\n" "2: Call Acquaintance...\n" "3: General S.O.S.\n" "0: Cancel")); wrefresh(w); char ch = getch(); if (ch == '1') { p->moves -= 300; faction* fac = g->list_factions(_("Call for help...")); if (fac == NULL) { it->charges++; return; } int bonus = 0; if (fac->goal == FACGOAL_CIVILIZATION) bonus += 2; if (fac->has_job(FACJOB_MERCENARIES)) bonus += 4; if (fac->has_job(FACJOB_DOCTORS)) bonus += 2; if (fac->has_value(FACVAL_CHARITABLE)) bonus += 3; if (fac->has_value(FACVAL_LONERS)) bonus -= 3; if (fac->has_value(FACVAL_TREACHERY)) bonus -= rng(0, 8); bonus += fac->respects_u + 3 * fac->likes_u; if (bonus >= 25) { popup(_("They reply, \"Help is on the way!\"")); g->add_event(EVENT_HELP, int(g->turn) + fac->response_time(g), fac->id, -1, -1); fac->respects_u -= rng(0, 8); fac->likes_u -= rng(3, 5); } else if (bonus >= -5) { popup(_("They reply, \"Sorry, you're on your own!\"")); fac->respects_u -= rng(0, 5); } else { popup(_("They reply, \"Hah! We hope you die!\"")); fac->respects_u -= rng(1, 8); } } else if (ch == '2') { // Call Acquaitance // TODO: Implement me! } else if (ch == '3') { // General S.O.S. p->moves -= 150; std::vector in_range; for (int i = 0; i < g->cur_om->npcs.size(); i++) { if (g->cur_om->npcs[i]->op_of_u.value >= 4 && rl_dist(g->levx, g->levy, g->cur_om->npcs[i]->mapx, g->cur_om->npcs[i]->mapy) <= 30) in_range.push_back((g->cur_om->npcs[i])); } if (in_range.size() > 0) { npc* coming = in_range[rng(0, in_range.size() - 1)]; popup(_("A reply! %s says, \"I'm on my way; give me %d minutes!\""), coming->name.c_str(), coming->minutes_to_u(g)); coming->mission = NPC_MISSION_RESCUE_U; } else popup(_("No-one seems to reply...")); } else it->charges++; // Canceled the call, get our charge back werase(w); wrefresh(w); delwin(w); refresh(); } void iuse::radio_off(game *g, player *p, item *it, bool t) { if (it->charges == 0) g->add_msg_if_player(p,_("It's dead.")); else { g->add_msg_if_player(p,_("You turn the radio on.")); it->make(g->itypes["radio_on"]); it->active = true; } } static radio_tower *find_radio_station( game *g, int frequency ) { radio_tower *tower = NULL; for (int k = 0; k < g->cur_om->radios.size(); k++) { tower = &g->cur_om->radios[k]; if( 0 < tower->strength - rl_dist(tower->x, tower->y, g->levx, g->levy) && tower->frequency == frequency ) { return tower; } } return NULL; } void iuse::directional_antenna(game *g, player *p, item *it, bool t) { // Find out if we have an active radio item radio = p->i_of_type("radio_on"); if( radio.typeId() != "radio_on" ) { g->add_msg( _("Must have an active radio to check for signal sirection.") ); return; } // Find the radio station its tuned to (if any) radio_tower *tower = find_radio_station( g, radio.frequency ); if( tower == NULL ) { g->add_msg( _("You can't find the direction if your radio isn't tuned.") ); return; } // Report direction. direction angle = direction_from( g->levx, g->levy, tower->x, tower->y ); g->add_msg( _("The signal seems strongest to the %s."), direction_name(angle).c_str()); } void iuse::radio_on(game *g, player *p, item *it, bool t) { if (t) { // Normal use std::string message = _("Radio: Kssssssssssssh."); radio_tower *selected_tower = find_radio_station( g, it->frequency ); if( selected_tower != NULL ) { if( selected_tower->type == MESSAGE_BROADCAST ) { message = selected_tower->message; } else if (selected_tower->type == WEATHER_RADIO) { message = weather_forecast(g, *selected_tower); } int signal_strength = selected_tower->strength - rl_dist(selected_tower->x, selected_tower->y, g->levx, g->levy); for (int j = 0; j < message.length(); j++) { if (dice(10, 100) > dice(10, signal_strength * 3)) { if (!one_in(10)) { message[j] = '#'; } else { message[j] = char(rng('a', 'z')); } } } std::vector segments = foldstring(message, RADIO_PER_TURN); int index = g->turn % (segments.size()); std::stringstream messtream; messtream << _("radio: ") << segments[index]; message = messtream.str(); } point pos = g->find_item(it); g->sound(pos.x, pos.y, 6, message.c_str()); } else { // Activated int ch = menu( true, _("Radio:"), _("Scan"), _("Turn off"), NULL ); switch (ch) { case 1: { int old_frequency = it->frequency; radio_tower *tower = NULL; radio_tower *lowest_tower = NULL; radio_tower *lowest_larger_tower = NULL; for (int k = 0; k < g->cur_om->radios.size(); k++) { tower = &g->cur_om->radios[k]; if( 0 < tower->strength - rl_dist(tower->x, tower->y, g->levx, g->levy) && tower->frequency != old_frequency ) { if( tower->frequency > old_frequency && (lowest_larger_tower == NULL || tower->frequency < lowest_larger_tower->frequency) ) { lowest_larger_tower = tower; } else if( lowest_tower == NULL || tower->frequency < lowest_tower->frequency ) { lowest_tower = tower; } } } if( lowest_larger_tower != NULL ) { it->frequency = lowest_larger_tower->frequency; } else if( lowest_tower != NULL ) { it->frequency = lowest_tower->frequency; } } break; case 2: g->add_msg_if_player(p,_("The radio dies.")); it->make(g->itypes["radio"]); it->active = false; break; case 3: break; } } } void iuse::noise_emitter_off(game *g, player *p, item *it, bool t) { if (it->charges == 0) { g->add_msg_if_player(p,_("It's dead.")); } else { g->add_msg_if_player(p,_("You turn the noise emitter on.")); it->make(g->itypes["noise_emitter_on"]); it->active = true; } } void iuse::noise_emitter_on(game *g, player *p, item *it, bool t) { if (t) // Normal use { point pos = g->find_item(it); g->sound(pos.x, pos.y, 30, _("KXSHHHHRRCRKLKKK!")); } else // Turning it off { g->add_msg_if_player(p,_("The infernal racket dies as you turn off the noise emitter.")); it->make(g->itypes["noise_emitter"]); it->active = false; } } void iuse::roadmap(game *g, player *p, item *it, bool t) { if (it->charges < 1) { g->add_msg_if_player(p, _("There isn't anything new on the map.")); return; } // Show roads roadmap_targets(g, p, it, t, (int)ot_hiway_ns, 2, 0, 0); roadmap_targets(g, p, it, t, (int)ot_road_ns, 12, 0, 0); roadmap_targets(g, p, it, t, (int)ot_bridge_ns, 2, 0, 0); // Show evac shelters roadmap_targets(g, p, it, t, (int)ot_shelter, 1, 0, 0); // Show hospital(s) roadmap_targets(g, p, it, t, (int)ot_hospital_entrance, 2, 0, 0); // Show megastores roadmap_targets(g, p, it, t, (int)ot_megastore_entrance, 2, 0, 0); // Show police stations roadmap_targets(g, p, it, t, (int)ot_police_north, 4, 0, 0); // Show pharmacies roadmap_targets(g, p, it, t, (int)ot_s_pharm_north, 4, 0, 0); g->add_msg_if_player(p, _("You add roads and points of interest to your map.")); it->charges = 0; } void iuse::roadmap_a_target(game *g, player *p, item *it, bool t, int target) { int dist = 0; oter_t oter_target = oterlist[target]; point place = g->cur_om->find_closest(g->om_location(), (oter_id)target, 1, dist, false); int pomx = (g->levx + int(MAPSIZE / 2)) / 2; //overmap loc int pomy = (g->levy + int(MAPSIZE / 2)) / 2; //overmap loc if (g->debugmon) debugmsg("Map: %s at %d,%d found! You @ %d %d",oter_target.name.c_str(), place.x, place.y, pomx,pomy); if (place.x >= 0 && place.y >= 0) { for (int x = place.x - 3; x <= place.x + 3; x++) { for (int y = place.y - 3; y <= place.y + 3; y++) g->cur_om->seen(x, y, g->levz) = true; } direction to_hospital = direction_from(pomx,pomy, place.x, place.y); int distance = trig_dist(pomx,pomy, place.x, place.y); g->add_msg_if_player(p, _("You add a %s location to your map."), oterlist[target].name.c_str()); g->add_msg_if_player(p, _("It's %d squares to the %s"), distance, direction_name(to_hospital).c_str()); } else { g->add_msg_if_player(p, _("You can't find a hospital near your location.")); } } void iuse::roadmap_targets(game *g, player *p, item *it, bool t, int target, int target_range, int distance, int reveal_distance) { oter_t oter_target = oterlist[target]; point place; point origin = g->om_location(); std::vector places = g->cur_om->find_all(tripoint(origin.x, origin.y, g->levz), (oter_id)target, target_range, distance, false); for (std::vector::iterator iter = places.begin(); iter != places.end(); ++iter) { place = *iter; if (place.x >= 0 && place.y >= 0) { if (reveal_distance == 0) { g->cur_om->seen(place.x,place.y,g->levz) = true; } else { for (int x = place.x - reveal_distance; x <= place.x + reveal_distance; x++) { for (int y = place.y - reveal_distance; y <= place.y + reveal_distance; y++) g->cur_om->seen(x, y,g->levz) = true; } } } } } void iuse::picklock(game *g, player *p, item *it, bool t) { int dirx, diry; if(!g->choose_adjacent(_("Use your pick lock"), dirx, diry)) return; if (dirx == p->posx && diry == p->posy) { g->add_msg_if_player(p, _("You pick your nose and your sinuses swing open.")); return; } ter_id type = g->m.ter(dirx, diry); int npcdex = g->npc_at(dirx, diry); if (npcdex != -1) { g->add_msg_if_player(p, _("You can pick your friends, and you can\npick your nose, but you can't pick\nyour friend's nose")); return; } int pick_quality = 1; if( it->typeId() == "picklock" ) { pick_quality = 5; } else if( it->typeId() == "crude_picklock" ) { pick_quality = 3; } std::string door_name; ter_id new_type; if (type == t_chaingate_l) { door_name = rm_prefix(_("gate")); new_type = t_chaingate_c; } else if (type == t_door_locked || type == t_door_locked_alarm || type == t_door_locked_interior) { door_name = rm_prefix(_("door")); new_type = t_door_c; } else if (type == t_door_bar_locked) { door_name = rm_prefix(_("door")); new_type = t_door_bar_o; g->add_msg_if_player(p, _("The door swings open...")); } else { g->add_msg(_("That cannot be picked.")); return; } p->practice(g->turn, "mechanics", 1); p->moves -= (1000 - (pick_quality * 100)) - (p->dex_cur + p->skillLevel("mechanics")) * 5; int pick_roll = (dice(2, p->skillLevel("mechanics")) + dice(2, p->dex_cur) - it->damage / 2) * pick_quality; int door_roll = dice(4, 30); if (pick_roll >= door_roll) { p->practice(g->turn, "mechanics", 1); g->add_msg_if_player(p,_("With a satisfying click, the lock on the %s opens."), door_name.c_str()); g->m.ter_set(dirx, diry, new_type); } else if (door_roll > (1.5 * pick_roll) && it->damage < 100) { it->damage++; std::string sStatus = rm_prefix(_("damage")); if (it->damage >= 5) { sStatus = rm_prefix(_("destroy")); it->invlet = 0; // no copy to inventory in player.cpp:4472 -> } g->add_msg_if_player(p,"The lock stumps your efforts to pick it, and you %s your tool.", sStatus.c_str()); } else { g->add_msg_if_player(p,_("The lock stumps your efforts to pick it.")); } if ( type == t_door_locked_alarm && (door_roll + dice(1, 30)) > pick_roll && it->damage < 100) { g->sound(p->posx, p->posy, 40, _("An alarm sounds!")); if (!g->event_queued(EVENT_WANTED)) { g->add_event(EVENT_WANTED, int(g->turn) + 300, 0, g->levx, g->levy); } } } void iuse::crowbar(game *g, player *p, item *it, bool t) { int dirx, diry; if(!g->choose_adjacent(_("Pry"), dirx,diry)) return; if (dirx == p->posx && diry == p->posy) { g->add_msg_if_player(p, _("You attempt to pry open your wallet")); g->add_msg_if_player(p, _("but alas. You are just too miserly.")); return; } ter_id type = g->m.ter(dirx, diry); const char *succ_action; const char *fail_action; ter_id new_type; bool noisy; int difficulty; if (type == t_door_c || type == t_door_locked || type == t_door_locked_alarm || type == t_door_locked_interior) { succ_action = _("You pry open the door."); fail_action = _("You pry, but cannot pry open the door."); new_type = t_door_o; noisy = true; difficulty = 6; } else if (type == t_door_bar_locked) { succ_action = _("You pry open the door."); fail_action = _("You pry, but cannot pry open the door."); new_type = t_door_bar_o; noisy = false; difficulty = 10; } else if (type == t_manhole_cover) { succ_action = _("You lift the manhole cover."); fail_action = _("You pry, but cannot lift the manhole cover."); new_type = t_manhole; noisy = false; difficulty = 12; } else if (g->m.furn(dirx, diry) == f_crate_c) { succ_action = _("You pop open the crate."); fail_action = _("You pry, but cannot pop open the crate."); noisy = true; difficulty = 6; } else if (type == t_window_domestic || type == t_curtains) { succ_action = _("You pry open the window."); fail_action = _("You pry, but cannot pry open the window."); new_type = t_window_open; noisy = true; difficulty = 6; } else { int nails = 0, boards = 0; ter_id newter; switch (g->m.ter(dirx, diry)) { case t_window_boarded: nails = 8; boards = 4; newter = t_window_empty; break; case t_door_boarded: nails = 12; boards = 4; newter = t_door_b; break; case t_fence_h: nails = 6; boards = 3; newter = t_fence_post; break; case t_fence_v: nails = 6; boards = 3; newter = t_fence_post; break; default: g->add_msg_if_player(p,_("There's nothing to pry there.")); return; } if(p->skillLevel("carpentry") < 1) p->practice(g->turn, "carpentry", 1); p->moves -= 500; g->m.spawn_item(p->posx, p->posy, "nail", 0, 0, nails); g->m.spawn_item(p->posx, p->posy, "2x4", 0, boards); g->m.ter_set(dirx, diry, newter); return; } p->practice(g->turn, "mechanics", 1); p->moves -= (difficulty * 25) - ((p->str_cur + p->skillLevel("mechanics")) * 5); if (dice(4, difficulty) < dice(2, p->skillLevel("mechanics")) + dice(2, p->str_cur)) { p->practice(g->turn, "mechanics", 1); g->add_msg_if_player(p, succ_action); if (g->m.furn(dirx, diry) == f_crate_c) g->m.furn_set(dirx, diry, f_crate_o); else g->m.ter_set(dirx, diry, new_type); if (noisy) g->sound(dirx, diry, 12, _("crunch!")); if ( type == t_door_locked_alarm ) { g->sound(p->posx, p->posy, 40, _("An alarm sounds!")); if (!g->event_queued(EVENT_WANTED)) { g->add_event(EVENT_WANTED, int(g->turn) + 300, 0, g->levx, g->levy); } } } else { if (type == t_window_domestic || type == t_curtains) { //chance of breaking the glass if pry attempt fails if (dice(4, difficulty) > dice(2, p->skillLevel("mechanics")) + dice(2, p->str_cur)) { g->add_msg_if_player(p,_("You break the glass.")); g->sound(dirx, diry, 24, _("glass breaking!")); g->m.ter_set(dirx, diry, t_window_frame); g->m.spawn_item(dirx, diry, "sheet", 0, 2); g->m.spawn_item(dirx, diry, "stick", 0); g->m.spawn_item(dirx, diry, "string_36", 0); return; } } g->add_msg_if_player(p, fail_action); } } void iuse::makemound(game *g, player *p, item *it, bool t) { if (g->m.has_flag(diggable, p->posx, p->posy)) { g->add_msg_if_player(p,_("You churn up the earth here.")); p->moves = -300; g->m.ter_set(p->posx, p->posy, t_dirtmound); } else g->add_msg_if_player(p,_("You can't churn up this ground.")); } //TODO remove this? void iuse::dig(game *g, player *p, item *it, bool t) { g->add_msg_if_player(p,_("You can dig a pit via the construction menu--hit *")); } void iuse::siphon(game *g, player *p, item *it, bool t) { int posx = 0; int posy = 0; if(!g->choose_adjacent(_("Siphon from"), posx, posy)) return; vehicle* veh = g->m.veh_at(posx, posy); if (veh == NULL) { g->add_msg_if_player(p,_("There's no vehicle there.")); return; } if (veh->fuel_left("gasoline") == 0) { g->add_msg_if_player(p, _("That vehicle has no fuel to siphon.")); return; } p->siphon(g, veh, "gasoline"); p->moves -= 200; return; } void iuse::chainsaw_off(game *g, player *p, item *it, bool t) { p->moves -= 80; if (rng(0, 10) - it->damage > 5 && it->charges > 0) { g->sound(p->posx, p->posy, 20, _("With a roar, the chainsaw leaps to life!")); it->make(g->itypes["chainsaw_on"]); it->active = true; } else g->add_msg_if_player(p,_("You yank the cord, but nothing happens.")); } void iuse::chainsaw_on(game *g, player *p, item *it, bool t) { if (t) { // Effects while simply on if (one_in(15)) g->sound(p->posx, p->posy, 12, _("Your chainsaw rumbles.")); } else { // Toggling g->add_msg_if_player(p,_("Your chainsaw dies.")); it->make(g->itypes["chainsaw_off"]); it->active = false; } } void iuse::jackhammer(game *g, player *p, item *it, bool t) { int dirx, diry; if(!g->choose_adjacent(_("Drill"),dirx,diry)) return; if (dirx == p->posx && diry == p->posy) { g->add_msg_if_player(p,_("My god! Let's talk it over OK?")); g->add_msg_if_player(p,_("Don't do anything rash..")); return; } if (g->m.is_destructable(dirx, diry) && g->m.has_flag(supports_roof, dirx, diry) && g->m.ter(dirx, diry) != t_tree) { g->m.destroy(g, dirx, diry, false); p->moves -= 500; g->sound(dirx, diry, 45, _("TATATATATATATAT!")); } else if (g->m.move_cost(dirx, diry) == 2 && g->levz != -1 && g->m.ter(dirx, diry) != t_dirt && g->m.ter(dirx, diry) != t_grass) { g->m.destroy(g, dirx, diry, false); p->moves -= 500; g->sound(dirx, diry, 45, _("TATATATATATATAT!")); } else { g->add_msg_if_player(p,_("You can't drill there.")); it->charges += (dynamic_cast(it->type))->charges_per_use; } } void iuse::jacqueshammer(game *g, player *p, item *it, bool t) { int dirx, diry; g->draw(); mvprintw(0, 0, _("Percer dans quelle direction?")); get_direction(g, dirx, diry, input()); if (dirx == -2) { g->add_msg_if_player(p,_("Direction invalide")); return; } if (dirx == 0 && diry == 0) { g->add_msg_if_player(p,_("Mon dieu! Nous allons en parler OK?")); g->add_msg_if_player(p,_("Ne pas faire eruption rien..")); return; } dirx += p->posx; diry += p->posy; if (g->m.is_destructable(dirx, diry) && g->m.has_flag(supports_roof, dirx, diry) && g->m.ter(dirx, diry) != t_tree) { g->m.destroy(g, dirx, diry, false); p->moves -= 500; g->sound(dirx, diry, 45, _("OHOHOHOHOHOHOHOHO!")); } else if (g->m.move_cost(dirx, diry) == 2 && g->levz != -1 && g->m.ter(dirx, diry) != t_dirt && g->m.ter(dirx, diry) != t_grass) { g->m.destroy(g, dirx, diry, false); p->moves -= 500; g->sound(dirx, diry, 45, _("OHOHOHOHOHOHOHOHO!")); } else { g->add_msg_if_player(p,_("Vous ne pouvez pas percer la-bas..")); it->charges += (dynamic_cast(it->type))->charges_per_use; } } void iuse::pickaxe(game *g, player *p, item *it, bool t) { g->add_msg_if_player(p,_("Whoa buddy! You can't go cheating in items and")); g->add_msg_if_player(p,_("just expect them to work! Now put the pickaxe")); g->add_msg_if_player(p,_("down and go play the game.")); } void iuse::set_trap(game *g, player *p, item *it, bool t) { int dirx, diry; if(!g->choose_adjacent(_("Place trap"),dirx,diry)) return; if (dirx == p->posx && diry == p->posy) { g->add_msg_if_player(p,_("Yeah. Place the %s at your feet."), it->tname().c_str()); g->add_msg_if_player(p,_("Real damn smart move.")); return; } int posx = dirx; int posy = diry; if (g->m.move_cost(posx, posy) != 2) { g->add_msg_if_player(p,_("You can't place a %s there."), it->tname().c_str()); return; } if (g->m.tr_at(posx, posy) != tr_null) { g->add_msg_if_player(p, _("You can't place a %s there. It contains a trap already."), it->tname().c_str()); return; } trap_id type = tr_null; ter_id ter; bool buried = false; bool set = false; std::stringstream message; int practice; if(it->type->id == "cot"){ message << _("You unfold the cot and place it on the ground."); type = tr_cot; practice = 0; } else if(it->type->id == "rollmat"){ message << _("You unroll the mat and lay it on the ground."); type = tr_rollmat; practice = 0; } else if(it->type->id == "brazier"){ message << _("You place the brazier securely."); type = tr_brazier; practice = 0; } else if(it->type->id == "boobytrap"){ message << _("You set the boobytrap up and activate the grenade."); type = tr_boobytrap; practice = 4; } else if(it->type->id == "bubblewrap"){ message << _("You set the bubblewrap on the ground, ready to be popped."); type = tr_bubblewrap; practice = 2; } else if(it->type->id == "beartrap"){ buried = (p->has_amount("shovel", 1) && g->m.has_flag(diggable, posx, posy) && query_yn(_("Bury the beartrap?"))); type = (buried ? tr_beartrap_buried : tr_beartrap); message << (buried ? _("You bury the beartrap.") : _("You set the beartrap.")) ; practice = (buried ? 7 : 4); } else if(it->type->id == "board_trap"){ message << string_format("You set the board trap on the %s, nails facing up.", g->m.tername(posx, posy).c_str()); type = tr_nailboard; practice = 2; } else if(it->type->id == "funnel"){ message << _("You place the funnel, waiting to collect rain."); type = tr_funnel; practice = 0; } else if(it->type->id == "tripwire"){ // Must have a connection between solid squares. if ((g->m.move_cost(posx , posy - 1) != 2 && g->m.move_cost(posx , posy + 1) != 2 ) || (g->m.move_cost(posx + 1, posy ) != 2 && g->m.move_cost(posx - 1, posy ) != 2 ) || (g->m.move_cost(posx - 1, posy - 1) != 2 && g->m.move_cost(posx + 1, posy + 1) != 2 ) || (g->m.move_cost(posx + 1, posy - 1) != 2 && g->m.move_cost(posx - 1, posy + 1) != 2 )) { message << _("You string up the tripwire."); type= tr_tripwire; practice = 3; } else { g->add_msg_if_player(p,_("You must place the tripwire between two solid tiles.")); return; } } else if(it->type->id == "crossbow_trap"){ message << _("You set the crossbow trap."); type = tr_crossbow; practice = 4; } else if(it->type->id == "shotgun_trap"){ message << _("You set the shotgun trap."); type = tr_shotgun_2; practice = 5; } else if(it->type->id == "blade_trap"){ posx = (dirx - p->posx)*2 + p->posx; //math correction for blade trap posy = (diry - p->posy)*2 + p->posy; for (int i = -1; i <= 1; i++) { for (int j = -1; j <= 1; j++) { if (g->m.move_cost(posx + i, posy + j) != 2) { g->add_msg_if_player(p,_("That trap needs a 3x3 space to be clear, centered two tiles from you.")); return; } } } message << _("You set the blade trap two squares away."); type = tr_engine; practice = 12; } else if(it->type->id == "light_snare_kit"){ for(int i = -1; i <= 1; i++) { for(int j = -1; j <= 1; j++){ ter = g->m.ter(posx+j, posy+i); if(ter == t_tree_young && !set) { message << _("You set the snare trap."); type = tr_light_snare; practice = 2; set = true; } } } if(!set) { g->add_msg_if_player(p, _("Invalid Placement.")); return; } } else if(it->type->id == "heavy_snare_kit"){ for(int i = -1; i <= 1; i++) { for(int j = -1; j <= 1; j++){ ter = g->m.ter(posx+j, posy+i); if(ter == t_tree && !set) { message << _("You set the snare trap."); type = tr_heavy_snare; practice = 4; set = true; } } } if(!set) { g->add_msg_if_player(p, _("Invalid Placement.")); return; } } else if(it->type->id == "landmine"){ buried = (p->has_amount("shovel", 1) && g->m.has_flag(diggable, posx, posy) && query_yn(_("Bury the landmine?"))); type = (buried ? tr_landmine_buried : tr_landmine); message << (buried ? _("You bury the landmine.") : _("You set the landmine.")); practice = (buried ? 7 : 4); } else { g->add_msg_if_player(p,_("Tried to set a trap. But got confused! %s"), it->tname().c_str()); } if (buried) { if (!p->has_amount("shovel", 1)) { g->add_msg_if_player(p,_("You need a shovel.")); return; } else if (!g->m.has_flag(diggable, posx, posy)) { g->add_msg_if_player(p,_("You can't dig in that %s"), g->m.tername(posx, posy).c_str()); return; } } g->add_msg_if_player(p,message.str().c_str()); p->practice(g->turn, "traps", practice); g->m.add_trap(posx, posy, type); p->moves -= 100 + practice * 25; if (type == tr_engine) { for (int i = -1; i <= 1; i++) { for (int j = -1; j <= 1; j++) { if (i != 0 || j != 0) g->m.add_trap(posx + i, posy + j, tr_blade); } } } it->invlet = 0; // Remove the trap from the player's inv } void iuse::geiger(game *g, player *p, item *it, bool t) { if (t) { // Every-turn use when it's on int rads = g->m.radiation(p->posx, p->posy); if (rads == 0) return; g->sound(p->posx, p->posy, 6, ""); if (rads > 50) g->add_msg(_("The geiger counter buzzes intensely.")); else if (rads > 35) g->add_msg(_("The geiger counter clicks wildly.")); else if (rads > 25) g->add_msg(_("The geiger counter clicks rapidly.")); else if (rads > 15) g->add_msg(_("The geiger counter clicks steadily.")); else if (rads > 8) g->add_msg(_("The geiger counter clicks slowly.")); else if (rads > 4) g->add_msg(_("The geiger counter clicks intermittantly.")); else g->add_msg(_("The geiger counter clicks once.")); return; } // Otherwise, we're activating the geiger counter it_tool *type = dynamic_cast(it->type); bool is_on = (type->id == "geiger_on"); if (is_on) { g->add_msg(_("The geiger counter's SCANNING LED flicks off.")); it->make(g->itypes["geiger_off"]); it->active = false; return; } std::string toggle_text = is_on ? _("Turn continuous scan off") : _("Turn continuous scan on"); int ch = menu(true, _("Geiger counter:"), _("Scan yourself"), _("Scan the ground"), toggle_text.c_str(), _("Cancel"), NULL); switch (ch) { case 1: g->add_msg_if_player(p,_("Your radiation level: %d"), p->radiation); break; case 2: g->add_msg_if_player(p,_("The ground's radiation level: %d"), g->m.radiation(p->posx, p->posy)); break; case 3: g->add_msg_if_player(p,_("The geiger counter's scan LED flicks on.")); it->make(g->itypes["geiger_on"]); it->active = true; break; case 4: it->charges++; break; } } void iuse::teleport(game *g, player *p, item *it, bool t) { p->moves -= 100; g->teleport(p); } void iuse::can_goo(game *g, player *p, item *it, bool t) { it->make(g->itypes["canister_empty"]); int tries = 0, goox, gooy; do { goox = p->posx + rng(-2, 2); gooy = p->posy + rng(-2, 2); tries++; } while (g->m.move_cost(goox, gooy) == 0 && tries < 10); if (tries == 10) return; int mondex = g->mon_at(goox, gooy); if (mondex != -1) { if (g->u_see(goox, gooy)) g->add_msg(_("Black goo emerges from the canister and envelopes a %s!"), g->z[mondex].name().c_str()); g->z[mondex].poly(g->mtypes[mon_blob]); g->z[mondex].speed -= rng(5, 25); g->z[mondex].hp = g->z[mondex].speed; } else { if (g->u_see(goox, gooy)) g->add_msg(_("Living black goo emerges from the canister!")); monster goo(g->mtypes[mon_blob]); goo.friendly = -1; goo.spawn(goox, gooy); g->z.push_back(goo); } tries = 0; while (!one_in(4) && tries < 10) { tries = 0; do { goox = p->posx + rng(-2, 2); gooy = p->posy + rng(-2, 2); tries++; } while (g->m.move_cost(goox, gooy) == 0 && g->m.tr_at(goox, gooy) == tr_null && tries < 10); if (tries < 10) { if (g->u_see(goox, gooy)) g->add_msg(_("A nearby splatter of goo forms into a goo pit.")); g->m.tr_at(goox, gooy) = tr_goo; } } } void iuse::pipebomb(game *g, player *p, item *it, bool t) { if (!p->use_charges_if_avail("fire", 1)) { g->add_msg_if_player(p,_("You need a lighter!")); return; } g->add_msg_if_player(p,_("You light the fuse on the pipe bomb.")); it->make(g->itypes["pipebomb_act"]); it->charges = 3; it->active = true; } void iuse::pipebomb_act(game *g, player *p, item *it, bool t) { point pos = g->find_item(it); if (pos.x == -999 || pos.y == -999) return; if (t) // Simple timer effects g->sound(pos.x, pos.y, 0, _("Ssssss")); // Vol 0 = only heard if you hold it else { // The timer has run down if (one_in(10) && g->u_see(pos.x, pos.y)) g->add_msg(_("The pipe bomb fizzles out.")); else g->explosion(pos.x, pos.y, rng(6, 14), rng(0, 4), false); } } void iuse::grenade(game *g, player *p, item *it, bool t) { g->add_msg_if_player(p,_("You pull the pin on the grenade.")); it->make(g->itypes["grenade_act"]); it->charges = 5; it->active = true; } void iuse::grenade_act(game *g, player *p, item *it, bool t) { point pos = g->find_item(it); if (pos.x == -999 || pos.y == -999) return; if (t) // Simple timer effects g->sound(pos.x, pos.y, 0, _("Tick.")); // Vol 0 = only heard if you hold it else // When that timer runs down... g->explosion(pos.x, pos.y, 12, 28, false); } void iuse::flashbang(game *g, player *p, item *it, bool t) { g->add_msg_if_player(p,_("You pull the pin on the flashbang.")); it->make(g->itypes["flashbang_act"]); it->charges = 5; it->active = true; } void iuse::flashbang_act(game *g, player *p, item *it, bool t) { point pos = g->find_item(it); if (pos.x == -999 || pos.y == -999) return; if (t) // Simple timer effects g->sound(pos.x, pos.y, 0, _("Tick.")); // Vol 0 = only heard if you hold it else // When that timer runs down... g->flashbang(pos.x, pos.y); } void iuse::c4(game *g, player *p, item *it, bool t) { int time = query_int(_("Set the timer to (0 to cancel)?")); if (time == 0) { g->add_msg_if_player(p,"Never mind."); return; } g->add_msg_if_player(p,_("You set the timer to %d."), time); it->make(g->itypes["c4armed"]); it->charges = time; it->active = true; } void iuse::c4armed(game *g, player *p, item *it, bool t) { point pos = g->find_item(it); if (pos.x == -999 || pos.y == -999) return; if (t) // Simple timer effects g->sound(pos.x, pos.y, 0, _("Tick.")); // Vol 0 = only heard if you hold it else // When that timer runs down... g->explosion(pos.x, pos.y, 40, 3, false); } void iuse::EMPbomb(game *g, player *p, item *it, bool t) { g->add_msg_if_player(p,_("You pull the pin on the EMP grenade.")); it->make(g->itypes["EMPbomb_act"]); it->charges = 3; it->active = true; } void iuse::EMPbomb_act(game *g, player *p, item *it, bool t) { point pos = g->find_item(it); if (pos.x == -999 || pos.y == -999) return; if (t) // Simple timer effects g->sound(pos.x, pos.y, 0, _("Tick.")); // Vol 0 = only heard if you hold it else { // When that timer runs down... for (int x = pos.x - 4; x <= pos.x + 4; x++) { for (int y = pos.y - 4; y <= pos.y + 4; y++) g->emp_blast(x, y); } } } void iuse::scrambler(game *g, player *p, item *it, bool t) { g->add_msg_if_player(p,_("You pull the pin on the scrambler grenade.")); it->make(g->itypes["scrambler_act"]); it->charges = 3; it->active = true; } void iuse::scrambler_act(game *g, player *p, item *it, bool t) { point pos = g->find_item(it); if (pos.x == -999 || pos.y == -999) return; if (t) // Simple timer effects g->sound(pos.x, pos.y, 0, _("Tick.")); // Vol 0 = only heard if you hold it else { // When that timer runs down... for (int x = pos.x - 4; x <= pos.x + 4; x++) { for (int y = pos.y - 4; y <= pos.y + 4; y++) g->scrambler_blast(x, y); } } } void iuse::gasbomb(game *g, player *p, item *it, bool t) { g->add_msg_if_player(p,_("You pull the pin on the teargas canister.")); it->make(g->itypes["gasbomb_act"]); it->charges = 20; it->active = true; } void iuse::gasbomb_act(game *g, player *p, item *it, bool t) { point pos = g->find_item(it); if (pos.x == -999 || pos.y == -999) return; if (t) { if (it->charges > 15) g->sound(pos.x, pos.y, 0, _("Tick.")); // Vol 0 = only heard if you hold it else { int junk; for (int i = -2; i <= 2; i++) { for (int j = -2; j <= 2; j++) { if (g->m.sees(pos.x, pos.y, pos.x + i, pos.y + j, 3, junk) && g->m.move_cost(pos.x + i, pos.y + j) > 0) g->m.add_field(g, pos.x + i, pos.y + j, fd_tear_gas, 3); } } } } else it->make(g->itypes["canister_empty"]); } void iuse::smokebomb(game *g, player *p, item *it, bool t) { g->add_msg_if_player(p,_("You pull the pin on the smoke bomb.")); it->make(g->itypes["smokebomb_act"]); it->charges = 20; it->active = true; } void iuse::smokebomb_act(game *g, player *p, item *it, bool t) { point pos = g->find_item(it); if (pos.x == -999 || pos.y == -999) return; if (t) { if (it->charges > 17) g->sound(pos.x, pos.y, 0, _("Tick.")); // Vol 0 = only heard if you hold it else { int junk; for (int i = -2; i <= 2; i++) { for (int j = -2; j <= 2; j++) { if (g->m.sees(pos.x, pos.y, pos.x + i, pos.y + j, 3, junk) && g->m.move_cost(pos.x + i, pos.y + j) > 0) g->m.add_field(g, pos.x + i, pos.y + j, fd_smoke, rng(1, 2) + rng(0, 1)); } } } } else it->make(g->itypes["canister_empty"]); } void iuse::acidbomb(game *g, player *p, item *it, bool t) { g->add_msg_if_player(p,_("You remove the divider, and the chemicals mix.")); p->moves -= 150; it->make(g->itypes["acidbomb_act"]); it->charges = 1; it->bday = int(g->turn); it->active = true; } void iuse::acidbomb_act(game *g, player *p, item *it, bool t) { if (!p->has_item(it)) { point pos = g->find_item(it); if (pos.x == -999) pos = point(p->posx, p->posy); it->charges = 0; for (int x = pos.x - 1; x <= pos.x + 1; x++) { for (int y = pos.y - 1; y <= pos.y + 1; y++) g->m.add_field(g, x, y, fd_acid, 3); } } } void iuse::arrow_flamable(game *g, player *p, item *it, bool t) { if (!p->use_charges_if_avail("fire", 1)) { g->add_msg_if_player(p,_("You need a lighter!")); return; } g->add_msg_if_player(p,_("You light the arrow!.")); p->moves -= 150; it->make(g->itypes["arrow_flamming"]); } void iuse::molotov(game *g, player *p, item *it, bool t) { if (!p->use_charges_if_avail("fire", 1)) { g->add_msg_if_player(p,_("You need a lighter!")); return; } g->add_msg_if_player(p,_("You light the molotov cocktail.")); p->moves -= 150; it->make(g->itypes["molotov_lit"]); it->charges = 1; it->bday = int(g->turn); it->active = true; } void iuse::molotov_lit(game *g, player *p, item *it, bool t) { int age = int(g->turn) - it->bday; if (!p->has_item(it)) { point pos = g->find_item(it); it->charges = -1; g->explosion(pos.x, pos.y, 8, 0, true); } else if (age >= 5) { // More than 5 turns old = chance of going out if (rng(1, 50) < age) { g->add_msg_if_player(p,_("Your lit molotov goes out.")); it->make(g->itypes["molotov"]); it->charges = 0; it->active = false; } } } void iuse::dynamite(game *g, player *p, item *it, bool t) { if (!p->use_charges_if_avail("fire", 1)) { it->charges++; g->add_msg_if_player(p,_("You need a lighter!")); return; } g->add_msg_if_player(p,_("You light the dynamite.")); it->make(g->itypes["dynamite_act"]); it->charges = 20; it->active = true; } void iuse::dynamite_act(game *g, player *p, item *it, bool t) { point pos = g->find_item(it); if (pos.x == -999 || pos.y == -999) return; if (t) // Simple timer effects g->sound(pos.x, pos.y, 0, _("ssss...")); else // When that timer runs down... g->explosion(pos.x, pos.y, 60, 0, false); } void iuse::firecracker_pack(game *g, player *p, item *it, bool t) { if (!p->use_charges_if_avail("fire", 1)) { g->add_msg_if_player(p,_("You need a lighter!")); return; } WINDOW* w = newwin(5, 41, (TERMY-5)/2, (TERMX-41)/2); wborder(w, LINE_XOXO, LINE_XOXO, LINE_OXOX, LINE_OXOX, LINE_OXXO, LINE_OOXX, LINE_XXOO, LINE_XOOX ); int mid_x = getmaxx(w) / 2; int tmpx = 5; mvwprintz(w, 1, 2, c_white, _("How many do you want to light? (1-%d)"), it->charges); mvwprintz(w, 2, mid_x, c_white, "1"); tmpx += shortcut_print(w, 3, tmpx, c_white, c_ltred, _("ncrease"))+1; tmpx += shortcut_print(w, 3, tmpx, c_white, c_ltred, _("ecrease"))+1; tmpx += shortcut_print(w, 3, tmpx, c_white, c_ltred, _("ccept"))+1; tmpx += shortcut_print(w, 3, tmpx, c_white, c_ltred, _("ancel"))+1; wrefresh(w); bool close = false; int charges = 1; char ch = getch(); while(!close) { if(ch == 'I') { charges++; if(charges > it->charges) { charges = it->charges; } mvwprintz(w, 2, mid_x, c_white, "%d", charges); wrefresh(w); } else if(ch == 'D') { charges--; if(charges < 1) { charges = 1; } mvwprintz(w, 2, mid_x, c_white, "%d ", charges); //Trailing space clears the second digit when decreasing from 10 to 9 wrefresh(w); } else if(ch == 'A') { if(charges == it->charges) { g->add_msg_if_player(p,_("You light the pack of firecrackers.")); it->make(g->itypes["firecracker_pack_act"]); it->charges = charges; it->bday = g->turn; it->active = true; } else { if(charges == 1) { g->add_msg_if_player(p,_("You light one firecracker.")); item new_it = item(g->itypes["firecracker_act"], int(g->turn)); new_it.charges = 2; new_it.active = true; p->i_add(new_it, g); it->charges -= 1; } else { g->add_msg_if_player(p,_("You light a string of %d firecrackers."), charges); item new_it = item(g->itypes["firecracker_pack_act"], int(g->turn)); new_it.charges = charges; new_it.bday = g->turn; new_it.active = true; p->i_add(new_it, g); it->charges -= charges; } if(it->charges == 1) { it->make(g->itypes["firecracker"]); } } close = true; } else if(ch == 'C') { close = true; } if(!close) { ch = getch(); } } } void iuse::firecracker_pack_act(game *g, player *p, item *it, bool t) { point pos = g->find_item(it); int current_turn = g->turn; int timer = current_turn - it->bday; if(timer < 2) { g->sound(pos.x, pos.y, 0, _("ssss...")); it->damage += 1; } else if(it->charges > 0) { int ex = rng(3,5); int i = 0; if(ex > it->charges) { ex = it->charges; } for(i = 0; i < ex; i++) { g->sound(pos.x, pos.y, 20, _("Bang!")); } it->charges -= ex; } } void iuse::firecracker(game *g, player *p, item *it, bool t) { if (!p->use_charges_if_avail("fire", 1)) { g->add_msg_if_player(p,_("You need a lighter!")); return; } g->add_msg_if_player(p,_("You light the firecracker.")); it->make(g->itypes["firecracker_act"]); it->charges = 2; it->active = true; } void iuse::firecracker_act(game *g, player *p, item *it, bool t) { point pos = g->find_item(it); if (pos.x == -999 || pos.y == -999) return; if (t) {// Simple timer effects g->sound(pos.x, pos.y, 0, _("ssss...")); } else { // When that timer runs down... g->sound(pos.x, pos.y, 20, _("Bang!")); } } void iuse::mininuke(game *g, player *p, item *it, bool t) { g->add_msg_if_player(p,_("You activate the mininuke.")); it->make(g->itypes["mininuke_act"]); it->charges = 10; it->active = true; } void iuse::mininuke_act(game *g, player *p, item *it, bool t) { point pos = g->find_item(it); if (pos.x == -999 || pos.y == -999) return; if (t) // Simple timer effects g->sound(pos.x, pos.y, 2, _("Tick.")); else { // When that timer runs down... g->explosion(pos.x, pos.y, 200, 0, false); int junk; for (int i = -4; i <= 4; i++) { for (int j = -4; j <= 4; j++) { if (g->m.sees(pos.x, pos.y, pos.x + i, pos.y + j, 3, junk) && g->m.move_cost(pos.x + i, pos.y + j) > 0) g->m.add_field(g, pos.x + i, pos.y + j, fd_nuke_gas, 3); } } } } void iuse::pheromone(game *g, player *p, item *it, bool t) { point pos(p->posx, p->posy); if (pos.x == -999 || pos.y == -999) return; g->add_msg_player_or_npc( p, _("You squeeze the pheremone ball.."), _(" squeezes the pheremone ball...") ); p->moves -= 15; int converts = 0; for (int x = pos.x - 4; x <= pos.x + 4; x++) { for (int y = pos.y - 4; y <= pos.y + 4; y++) { int mondex = g->mon_at(x, y); if (mondex != -1 && g->z[mondex].symbol() == 'Z' && g->z[mondex].friendly == 0 && rng(0, 500) > g->z[mondex].hp) { converts++; g->z[mondex].make_friendly(); } } } if (g->u_see(p)) { if (converts == 0) g->add_msg(_("...but nothing happens.")); else if (converts == 1) g->add_msg(_("...and a nearby zombie turns friendly!")); else g->add_msg(_("...and several nearby zombies turn friendly!")); } } void iuse::portal(game *g, player *p, item *it, bool t) { g->m.add_trap(p->posx + rng(-2, 2), p->posy + rng(-2, 2), tr_portal); } void iuse::manhack(game *g, player *p, item *it, bool t) { std::vector valid; // Valid spawn locations for (int x = p->posx - 1; x <= p->posx + 1; x++) { for (int y = p->posy - 1; y <= p->posy + 1; y++) { if (g->is_empty(x, y)) valid.push_back(point(x, y)); } } if (valid.size() == 0) { // No valid points! g->add_msg_if_player(p,_("There is no adjacent square to release the manhack in!")); return; } int index = rng(0, valid.size() - 1); p->moves -= 60; it->invlet = 0; // Remove the manhack from the player's inv monster m_manhack(g->mtypes[mon_manhack], valid[index].x, valid[index].y); if (rng(0, p->int_cur / 2) + p->skillLevel("electronics") / 2 + p->skillLevel("computer") < rng(0, 4)) g->add_msg_if_player(p,_("You misprogram the manhack; it's hostile!")); else m_manhack.friendly = -1; g->z.push_back(m_manhack); } void iuse::turret(game *g, player *p, item *it, bool t) { int dirx, diry; if(!g->choose_adjacent(_("Place the turret"), dirx, diry)) return; if (!g->is_empty(dirx, diry)) { g->add_msg_if_player(p,_("You cannot place a turret there.")); return; } p->moves -= 100; it->invlet = 0; // Remove the turret from the player's inv monster mturret(g->mtypes[mon_turret], dirx, diry); if (rng(0, p->int_cur / 2) + p->skillLevel("electronics") / 2 + p->skillLevel("computer") < rng(0, 6)) g->add_msg_if_player(p,_("You misprogram the turret; it's hostile!")); else mturret.friendly = -1; g->z.push_back(mturret); } void iuse::UPS_off(game *g, player *p, item *it, bool t) { if (it->charges == 0) g->add_msg_if_player(p,_("The power supply's batteries are dead.")); else { g->add_msg_if_player(p,_("You turn the power supply on.")); if (p->is_wearing("goggles_nv")) g->add_msg_if_player(p,_("Your light amp goggles power on.")); if (p->worn.size() && p->worn[0].type->is_power_armor()) g->add_msg_if_player(p, _("Your power armor engages.")); it->make(g->itypes["UPS_on"]); it->active = true; } } void iuse::UPS_on(game *g, player *p, item *it, bool t) { if (t) { // Normal use if (p->worn.size() && p->worn[0].type->is_power_armor()) { it->charges -= 4; if (it->charges < 0) { it->charges = 0; } } } else { // Turning it off g->add_msg_if_player(p,_("The UPS powers off with a soft hum.")); if (p->worn.size() && p->worn[0].type->is_power_armor()) g->add_msg_if_player(p, _("Your power armor disengages.")); it->make(g->itypes["UPS_off"]); it->active = false; } } void iuse::adv_UPS_off(game *g, player *p, item *it, bool t) { if (it->charges == 0) g->add_msg_if_player(p,_("The power supply has depleted the plutonium.")); else { g->add_msg_if_player(p,_("You turn the power supply on.")); if (p->is_wearing("goggles_nv")) g->add_msg_if_player(p,_("Your light amp goggles power on.")); if (p->worn.size() && p->worn[0].type->is_power_armor()) g->add_msg_if_player(p, _("Your power armor engages.")); it->make(g->itypes["adv_UPS_on"]); it->active = true; } } void iuse::adv_UPS_on(game *g, player *p, item *it, bool t) { if (t) { // Normal use if (p->worn.size() && p->worn[0].type->is_power_armor()) { it->charges -= 2; if (it->charges < 0) { it->charges = 0; } } } else { // Turning it off g->add_msg_if_player(p,_("The advanced UPS powers off with a soft hum.")); if (p->worn.size() && p->worn[0].type->is_power_armor()) g->add_msg_if_player(p, _("Your power armor disengages.")); it->make(g->itypes["adv_UPS_off"]); it->active = false; } } void iuse::tazer(game *g, player *p, item *it, bool t) { int dirx, diry; if(!g->choose_adjacent(_("Shock"),dirx,diry)){ it->charges += (dynamic_cast(it->type))->charges_per_use; return; } if (dirx == p->posx && diry == p->posy) { g->add_msg_if_player(p,_("Umm. No.")); it->charges += (dynamic_cast(it->type))->charges_per_use; return; } int mondex = g->mon_at(dirx, diry); int npcdex = g->npc_at(dirx, diry); if (mondex == -1 && npcdex == -1) { g->add_msg_if_player(p,_("Your tazer crackles in the air.")); return; } int numdice = 3 + (p->dex_cur / 2.5) + p->skillLevel("melee") * 2; p->moves -= 100; if (mondex != -1) { monster *z = &(g->z[mondex]); switch (z->type->size) { case MS_TINY: numdice -= 2; break; case MS_SMALL: numdice -= 1; break; case MS_LARGE: numdice += 2; break; case MS_HUGE: numdice += 4; break; } int mondice = z->dodge(); if (dice(numdice, 10) < dice(mondice, 10)) { // A miss! g->add_msg_if_player(p,_("You attempt to shock the %s, but miss."), z->name().c_str()); return; } g->add_msg_if_player(p,_("You shock the %s!"), z->name().c_str()); int shock = rng(5, 25); z->moves -= shock * 100; if (z->hurt(shock)) g->kill_mon(mondex, (p == &(g->u))); return; } if (npcdex != -1) { npc *foe = g->active_npc[npcdex]; if (foe->attitude != NPCATT_FLEE) foe->attitude = NPCATT_KILL; if (foe->str_max >= 17) numdice++; // Minor bonus against huge people else if (foe->str_max <= 5) numdice--; // Minor penalty against tiny people if (dice(numdice, 10) <= dice(foe->dodge(g), 6)) { g->add_msg_if_player(p,_("You attempt to shock %s, but miss."), foe->name.c_str()); return; } g->add_msg_if_player(p,_("You shock %s!"), foe->name.c_str()); int shock = rng(5, 20); foe->moves -= shock * 100; foe->hurtall(shock); if (foe->hp_cur[hp_head] <= 0 || foe->hp_cur[hp_torso] <= 0) { foe->die(g, true); g->active_npc.erase(g->active_npc.begin() + npcdex); } } } void iuse::mp3(game *g, player *p, item *it, bool t) { if (it->charges == 0) g->add_msg_if_player(p,_("The mp3 player's batteries are dead.")); else if (p->has_active_item("mp3_on")) g->add_msg_if_player(p,_("You are already listening to an mp3 player!")); else { g->add_msg_if_player(p,_("You put in the earbuds and start listening to music.")); it->make(g->itypes["mp3_on"]); it->active = true; } } void iuse::mp3_on(game *g, player *p, item *it, bool t) { if (t) { // Normal use if (!p->has_item(it) || p->has_disease("deaf") ) return; // We're not carrying it, or we're deaf. p->add_morale(MORALE_MUSIC, 1, 50); if (int(g->turn) % 10 == 0) { // Every 10 turns, describe the music std::string sound = ""; if (one_in(50)) sound = _("some bass-heavy post-glam speed polka"); switch (rng(1, 10)) { case 1: sound = _("a sweet guitar solo!"); p->stim++; break; case 2: sound = _("a funky bassline."); break; case 3: sound = _("some amazing vocals."); break; case 4: sound = _("some pumping bass."); break; case 5: sound = _("dramatic classical music."); if (p->int_cur >= 10) p->add_morale(MORALE_MUSIC, 1, 100); break; } if (sound.length() > 0) g->add_msg_if_player(p,_("You listen to %s"), sound.c_str()); } } else { // Turning it off g->add_msg_if_player(p,_("The mp3 player turns off.")); it->make(g->itypes["mp3"]); it->active = false; } } void iuse::vortex(game *g, player *p, item *it, bool t) { std::vector spawn; for (int i = -3; i <= 3; i++) { if (g->is_empty(p->posx - 3, p->posy + i)) spawn.push_back( point(p->posx - 3, p->posy + i) ); if (g->is_empty(p->posx + 3, p->posy + i)) spawn.push_back( point(p->posx + 3, p->posy + i) ); if (g->is_empty(p->posx + i, p->posy - 3)) spawn.push_back( point(p->posx + i, p->posy - 3) ); if (g->is_empty(p->posx + i, p->posy + 3)) spawn.push_back( point(p->posx + i, p->posy + 3) ); } if (spawn.empty()) { g->add_msg_if_player(p,_("Air swirls around you for a moment.")); it->make(g->itypes["spiral_stone"]); return; } g->add_msg_if_player(p,_("Air swirls all over...")); int index = rng(0, spawn.size() - 1); p->moves -= 100; it->make(g->itypes["spiral_stone"]); monster mvortex(g->mtypes[mon_vortex], spawn[index].x, spawn[index].y); mvortex.friendly = -1; g->z.push_back(mvortex); } void iuse::dog_whistle(game *g, player *p, item *it, bool t) { g->add_msg_if_player(p,_("You blow your dog whistle.")); for (int i = 0; i < g->z.size(); i++) { if (g->z[i].friendly != 0 && g->z[i].type->id == mon_dog) { bool u_see = g->u_see(&(g->z[i])); if (g->z[i].has_effect(ME_DOCILE)) { if (u_see) g->add_msg_if_player(p,_("Your %s looks ready to attack."), g->z[i].name().c_str()); g->z[i].rem_effect(ME_DOCILE); } else { if (u_see) g->add_msg_if_player(p,_("Your %s goes docile."), g->z[i].name().c_str()); g->z[i].add_effect(ME_DOCILE, -1); } } } } void iuse::vacutainer(game *g, player *p, item *it, bool t) { if (p->is_npc()) return; // No NPCs for now! if (!it->contents.empty()) { g->add_msg_if_player(p,_("That %s is full!"), it->tname().c_str()); return; } item blood(g->itypes["blood"], g->turn); bool drew_blood = false; for (int i = 0; i < g->m.i_at(p->posx, p->posy).size() && !drew_blood; i++) { item *map_it = &(g->m.i_at(p->posx, p->posy)[i]); if (map_it->type->id == "corpse" && query_yn(_("Draw blood from %s?"), map_it->tname().c_str())) { blood.corpse = map_it->corpse; drew_blood = true; } } if (!drew_blood && query_yn(_("Draw your own blood?"))) drew_blood = true; if (!drew_blood) return; it->put_in(blood); } void iuse::knife(game *g, player *p, item *it, bool t) { int choice = menu(true, _("Using knife:"), _("Cut up fabric"), _("Cut up plastic/kevlar"), _("Carve wood"), _("Cauterize"), _("Carve writing on item"), _("Cancel"), NULL); switch (choice) { if (choice == 5) break; case 1: { iuse::scissors(g, p, it, t); } break; case 2: { char ch = g->inv(_("Chop up what?")); item* cut = &(p->i_at(ch)); int amount = 0; if (cut->type->id == "null") { g->add_msg(_("You do not have that item!")); return; } if(cut->made_of("plastic")) { //if we're going to cut up a bottle, make sure it isn't full of liquid amount = cut->volume(); if(cut->is_container()) { if(cut->is_food_container()) { g->add_msg(_("That container has liquid in it!")); break; } } if(amount == 0) { g->add_msg(_("This object is too small to salvage a meaningful quantity of plastic from!")); break; } g->add_msg(ngettext("You cut the %1$s into one %2$i chunk.","You cut the %1$s into %2$i plastic chunks.", amount), cut->tname().c_str(), amount); int count = amount; item result(g->itypes["plastic_chunk"], int(g->turn), g->nextinv); p->i_rem(ch); bool drop = false; for (int i = 0; i < count; i++) { int iter = 0; while (p->has_item(result.invlet) && iter < inv_chars.size()) { result.invlet = g->nextinv; g->advance_nextinv(); iter++; } if (!drop && (iter == inv_chars.size() || p->volume_carried() >= p->volume_capacity())) drop = true; if (drop) g->m.add_item_or_charges(p->posx, p->posy, result); else p->i_add(result); } } else if(cut->made_of("kevlar")) { amount = cut->volume(); if(amount == 0) { g->add_msg(_("This object is too small to salvage a meaningful quantity of kevlar from!")); break; } g->add_msg(ngettext("You cut the %1$s into one %2$i chunk.","You cut the %1$s into %2$i plastic chunks.", amount), cut->tname().c_str(), amount); int count = amount; item result(g->itypes["kevlar_plate"], int(g->turn), g->nextinv); p->i_rem(ch); bool drop = false; for (int i = 0; i < count; i++) { int iter = 0; while (p->has_item(result.invlet) && iter < inv_chars.size()) { result.invlet = g->nextinv; g->advance_nextinv(); iter++; } if (!drop && (iter == inv_chars.size() || p->volume_carried() >= p->volume_capacity())) drop = true; if (drop) g->m.add_item_or_charges(p->posx, p->posy, result); else p->i_add(result); } } else { g->add_msg(_("You can't carve that up!")); } } break; case 3: { char ch = g->inv(_("Chop up what?")); item* cut = &(p->i_at(ch)); if (cut->type->id == "null") { g->add_msg(_("You do not have that item!")); return; } if (cut->type->id == "stick" || cut->type->id == "2x4") { g->add_msg(_("You carve several skewers from the %s."), cut->tname().c_str()); int count = 12; item skewer(g->itypes["skewer"], int(g->turn), g->nextinv); p->i_rem(ch); bool drop = false; for (int i = 0; i < count; i++) { int iter = 0; while (p->has_item(skewer.invlet) && iter < inv_chars.size()) { skewer.invlet = g->nextinv; g->advance_nextinv(); iter++; } if (!drop && (iter == inv_chars.size() || p->volume_carried() >= p->volume_capacity())) drop = true; if (drop) g->m.add_item_or_charges(p->posx, p->posy, skewer); else p->i_add(skewer); } } else { g->add_msg(_("You can't carve that up!")); } } break; case 4: { if (!p->has_disease("bite") && !p->has_disease("bleed")) g->add_msg_if_player(p,_("You are not bleeding or bitten, there is no need to cauterize yourself.")); else if (!p->use_charges_if_avail("fire", 4)) g->add_msg_if_player(p,_("You need a lighter with 4 charges before you can cauterize yourself.")); else p->cauterize(g); break; } case 5: { inscribe_item( g, p, _("Carve"), _("Carved"), true ); break; } } } void iuse::cut_log_into_planks(game *g, player *p, item *it) { p->moves -= 300; g->add_msg(_("You cut the log into planks.")); item plank(g->itypes["2x4"], int(g->turn), g->nextinv); item scrap(g->itypes["splinter"], int(g->turn), g->nextinv); bool drop = false; int planks = (rng(1, 3) + (p->skillLevel("carpentry") * 2)); int scraps = 12 - planks; if (planks >= 12) { planks = 12; } if (scraps >= planks) { g->add_msg(_("You waste a lot of the wood.")); } for (int i = 0; i < planks; i++) { int iter = 0; while (p->has_item(plank.invlet)) { plank.invlet = g->nextinv; g->advance_nextinv(); iter++; } if (!drop && (iter == inv_chars.size() || p->volume_carried() >= p->volume_capacity())) { drop = true; } if (drop) { g->m.add_item_or_charges(p->posx, p->posy, plank); } else { p->i_add(plank); } } for (int i = 0; i < scraps; i++) { int iter = 0; while (p->has_item(scrap.invlet)) { scrap.invlet = g->nextinv; g->advance_nextinv(); iter++; } if (!drop && (iter == inv_chars.size() || p->volume_carried() >= p->volume_capacity())) drop = true; if (drop) g->m.add_item_or_charges(p->posx, p->posy, scrap); else p->i_add(scrap); } } void iuse::lumber(game *g, player *p, item *it, bool t) { char ch = g->inv(_("Cut up what?")); item* cut = &(p->i_at(ch)); if (cut->type->id == "null") { g->add_msg(_("You do not have that item!")); return; } if (cut->type->id == "log") { p->i_rem(ch); cut_log_into_planks(g, p, it); return; } else { g->add_msg(_("You can't cut that up!")); } return; } void iuse::hacksaw(game *g, player *p, item *it, bool t) { int dirx, diry; if(!g->choose_adjacent(_("Cut up metal"), dirx, diry)) return; if (dirx == p->posx && diry == p->posy) { g->add_msg(_("Why would you do that?")); g->add_msg(_("You're not even chained to a boiler.")); return; } if (g->m.ter(dirx, diry) == t_chainfence_v || g->m.ter(dirx, diry) == t_chainfence_h || g->m.ter(dirx, diry) == t_chaingate_c) { p->moves -= 500; g->m.ter_set(dirx, diry, t_dirt); g->sound(dirx, diry, 15,_("grnd grnd grnd")); g->m.spawn_item(dirx, diry, "pipe", 0, 6); g->m.spawn_item(dirx, diry, "wire", 0, 20); if (g->m.ter(dirx, diry) == t_chainfence_posts) { p->moves -= 500; g->m.ter_set(dirx, diry, t_dirt); g->sound(dirx, diry, 15,_("grnd grnd grnd")); g->m.spawn_item(dirx, diry, "pipe", 0, 6); } else if (g->m.furn(dirx, diry) == f_rack) { p->moves -= 500; g->m.furn_set(dirx, diry, f_null); g->sound(dirx, diry, 15,_("grnd grnd grnd")); g->m.spawn_item(p->posx, p->posy, "pipe", 0, rng(1, 3)); g->m.spawn_item(p->posx, p->posy, "steel_chunk", 0); } else if (g->m.ter(dirx, diry) == t_bars && (g->m.ter(dirx + 1, diry) == t_sewage || g->m.ter(dirx, diry + 1) == t_sewage || g->m.ter(dirx - 1, diry) == t_sewage || g->m.ter(dirx, diry - 1) == t_sewage)) { g->m.ter_set(dirx, diry, t_sewage); p->moves -= 1000; g->sound(dirx, diry, 15,_("grnd grnd grnd")); g->m.spawn_item(p->posx, p->posy, "pipe", 0, 3); } else if (g->m.ter(dirx, diry) == t_bars && g->m.ter(p->posx, p->posy)) { g->m.ter_set(dirx, diry, t_floor); p->moves -= 500; g->sound(dirx, diry, 15,_("grnd grnd grnd")); g->m.spawn_item(p->posx, p->posy, "pipe", 0, 3); } else { g->add_msg(_("You can't cut that.")); } } } void iuse::tent(game *g, player *p, item *it, bool t) { int dirx, diry; if(!g->choose_adjacent(_("Pitch the tent"), dirx, diry)) return; //must place the center of the tent two spaces away from player //dirx and diry will be integratined with the player's position int posx = dirx - p->posx; int posy = diry - p->posy; if(posx == 0 && posy == 0){ g->add_msg_if_player(p,_("Invalid Direction")); return; } posx = posx*2 + p->posx; posy = posy*2 + p->posy; for (int i = -1; i <= 1; i++) for (int j = -1; j <= 1; j++) if (!g->m.has_flag(flat, posx + i, posy + j) || g->m.has_furn(posx + i, posy + j)) { g->add_msg(_("You need a 3x3 flat space to place a tent")); return; } for (int i = -1; i <= 1; i++) for (int j = -1; j <= 1; j++) g->m.furn_set(posx + i, posy + j, f_canvas_wall); g->m.furn_set(posx, posy, f_groundsheet); g->m.furn_set(posx - (dirx - p->posx), posy - (diry - p->posy), f_canvas_door); it->invlet = 0; } void iuse::shelter(game *g, player *p, item *it, bool t) { int dirx, diry; if(!g->choose_adjacent(_("Put up the shelter"), dirx, diry)) return; //must place the center of the tent two spaces away from player //dirx and diry will be integratined with the player's position int posx = dirx - p->posx; int posy = diry - p->posy; if(posx == 0 && posy == 0){ g->add_msg_if_player(p,_("Invalid Direction")); return; } posx = posx*2 + p->posx; posy = posy*2 + p->posy; for (int i = -1; i <= 1; i++) for (int j = -1; j <= 1; j++) if (!g->m.has_flag(flat, posx + i, posy + j) || g->m.has_furn(posx + i, posy + j)) { g->add_msg(_("You need a 3x3 flat space to place a shelter")); return; } for (int i = -1; i <= 1; i++) for (int j = -1; j <= 1; j++) g->m.furn_set(posx + i, posy + j, f_skin_wall); g->m.furn_set(posx, posy, f_skin_groundsheet); g->m.furn_set(posx - (dirx - p->posx), posy - (diry - p->posy), f_skin_door); it->invlet = 0; } void iuse::torch(game *g, player *p, item *it, bool t) { if (!p->use_charges_if_avail("fire", 1)) { g->add_msg_if_player(p,_("You need a lighter or fire to light this.")); } else { g->add_msg_if_player(p,_("You light the torch.")); it->make(g->itypes["torch_lit"]); it->active = true; } } void iuse::torch_lit(game *g, player *p, item *it, bool t) { if (t) { // Normal use // Do nothing... player::active_light and the lightmap::generate deal with this } else { // Turning it off g->add_msg_if_player(p,_("The torch is extinguished")); it->charges -= 1; it->make(g->itypes["torch"]); it->active = false; } } void iuse::candle(game *g, player *p, item *it, bool t) { if (!p->use_charges_if_avail("fire", 1)) { g->add_msg_if_player(p, _("You need a lighter to light this.")); } else { g->add_msg_if_player(p, _("You light the candle.")); it->make(g->itypes["candle_lit"]); it->active = true; } } void iuse::candle_lit(game *g, player *p, item *it, bool t) { if (t) { // Normal use // Do nothing... player::active_light and the lightmap::generate deal with this } else { // Turning it off g->add_msg_if_player(p,_("The candle winks out")); it->make(g->itypes["candle"]); it->active = false; } } void iuse::bullet_puller(game *g, player *p, item *it, bool t) { char ch = g->inv(_("Disassemble what?")); item* pull = &(p->i_at(ch)); if (pull->type->id == "null") { g->add_msg(_("You do not have that item!")); return; } if (p->skillLevel("gun") < 2) { g->add_msg(_("You need to be at least level 2 in the firearms skill before you\ can disassemble ammunition.")); return;} int multiply = pull->charges; if (multiply > 20) multiply = 20; item casing; item primer; item gunpowder; item lead; if (pull->type->id == "556_incendiary" || pull->type->id == "3006_incendiary" || pull->type->id == "762_51_incendiary") lead.make(g->itypes["incendiary"]); else lead.make(g->itypes["lead"]); if (pull->type->id == "shot_bird") { casing.make(g->itypes["shot_hull"]); primer.make(g->itypes["shotgun_primer"]); gunpowder.make(g->itypes["gunpowder"]); gunpowder.charges = 12*multiply; lead.charges = 16*multiply; } else if (pull->type->id == "shot_00" || pull->type->id == "shot_slug") { casing.make(g->itypes["shot_hull"]); primer.make(g->itypes["shotgun_primer"]); gunpowder.make(g->itypes["gunpowder"]); gunpowder.charges = 20*multiply; lead.charges = 16*multiply; } else if (pull->type->id == "22_lr" || pull->type->id == "22_ratshot") { casing.make(g->itypes["22_casing"]); primer.make(g->itypes["smrifle_primer"]); gunpowder.make(g->itypes["gunpowder"]); gunpowder.charges = 2*multiply; lead.charges = 2*multiply; } else if (pull->type->id == "22_cb") { casing.make(g->itypes["22_casing"]); primer.make(g->itypes["smrifle_primer"]); gunpowder.make(g->itypes["gunpowder"]); gunpowder.charges = 1*multiply; lead.charges = 2*multiply; } else if (pull->type->id == "9mm") { casing.make(g->itypes["9mm_casing"]); primer.make(g->itypes["smpistol_primer"]); gunpowder.make(g->itypes["gunpowder"]); gunpowder.charges = 4*multiply; lead.charges = 4*multiply; } else if (pull->type->id == "9mmP") { casing.make(g->itypes["9mm_casing"]); primer.make(g->itypes["smpistol_primer"]); gunpowder.make(g->itypes["gunpowder"]); gunpowder.charges = 5*multiply; lead.charges = 4*multiply; } else if (pull->type->id == "9mmP2") { casing.make(g->itypes["9mm_casing"]); primer.make(g->itypes["smpistol_primer"]); gunpowder.make(g->itypes["gunpowder"]); gunpowder.charges = 6*multiply; lead.charges = 4*multiply; } else if (pull->type->id == "38_special") { casing.make(g->itypes["38_casing"]); primer.make(g->itypes["smpistol_primer"]); gunpowder.make(g->itypes["gunpowder"]); gunpowder.charges = 5*multiply; lead.charges = 5*multiply; } else if (pull->type->id == "38_super") { casing.make(g->itypes["38_casing"]); primer.make(g->itypes["smpistol_primer"]); gunpowder.make(g->itypes["gunpowder"]); gunpowder.charges = 7*multiply; lead.charges = 5*multiply; } else if (pull->type->id == "10mm") { casing.make(g->itypes["40_casing"]); primer.make(g->itypes["lgpistol_primer"]); gunpowder.make(g->itypes["gunpowder"]); gunpowder.charges = 8*multiply; lead.charges = 8*multiply; } else if (pull->type->id == "40sw") { casing.make(g->itypes["40_casing"]); primer.make(g->itypes["smpistol_primer"]); gunpowder.make(g->itypes["gunpowder"]); gunpowder.charges = 6*multiply; lead.charges = 6*multiply; } else if (pull->type->id == "44magnum") { casing.make(g->itypes["44_casing"]); primer.make(g->itypes["lgpistol_primer"]); gunpowder.make(g->itypes["gunpowder"]); gunpowder.charges = 10*multiply; lead.charges = 10*multiply; } else if (pull->type->id == "45_acp" || pull->type->id == "45_jhp") { casing.make(g->itypes["45_casing"]); primer.make(g->itypes["lgpistol_primer"]); gunpowder.make(g->itypes["gunpowder"]); gunpowder.charges = 10*multiply; lead.charges = 8*multiply; } else if (pull->type->id == "45_super") { casing.make(g->itypes["45_casing"]); primer.make(g->itypes["lgpistol_primer"]); gunpowder.make(g->itypes["gunpowder"]); gunpowder.charges = 12*multiply; lead.charges = 10*multiply; } else if (pull->type->id == "454_Casull") { casing.make(g->itypes["454_casing"]); primer.make(g->itypes["smrifle_primer"]); gunpowder.make(g->itypes["gunpowder"]); gunpowder.charges = 20*multiply; lead.charges = 20*multiply; } else if (pull->type->id == "500_Magnum") { casing.make(g->itypes["500_casing"]); primer.make(g->itypes["lgpistol_primer"]); gunpowder.make(g->itypes["gunpowder"]); gunpowder.charges = 24*multiply; lead.charges = 24*multiply; } else if (pull->type->id == "57mm") { casing.make(g->itypes["57mm_casing"]); primer.make(g->itypes["smrifle_primer"]); gunpowder.make(g->itypes["gunpowder"]); gunpowder.charges = 4*multiply; lead.charges = 2*multiply; } else if (pull->type->id == "46mm") { casing.make(g->itypes["46mm_casing"]); primer.make(g->itypes["smpistol_primer"]); gunpowder.make(g->itypes["gunpowder"]); gunpowder.charges = 4*multiply; lead.charges = 2*multiply; } else if (pull->type->id == "762_m43") { casing.make(g->itypes["762_casing"]); primer.make(g->itypes["lgrifle_primer"]); gunpowder.make(g->itypes["gunpowder"]); gunpowder.charges = 7*multiply; lead.charges = 5*multiply; } else if (pull->type->id == "762_m87") { casing.make(g->itypes["762_casing"]); primer.make(g->itypes["lgrifle_primer"]); gunpowder.make(g->itypes["gunpowder"]); gunpowder.charges = 8*multiply; lead.charges = 5*multiply; } else if (pull->type->id == "223") { casing.make(g->itypes["223_casing"]); primer.make(g->itypes["smrifle_primer"]); gunpowder.make(g->itypes["gunpowder"]); gunpowder.charges = 4*multiply; lead.charges = 2*multiply; } else if (pull->type->id == "556" || pull->type->id == "556_incendiary") { casing.make(g->itypes["223_casing"]); primer.make(g->itypes["smrifle_primer"]); gunpowder.make(g->itypes["gunpowder"]); gunpowder.charges = 6*multiply; lead.charges = 2*multiply; } else if (pull->type->id == "270") { casing.make(g->itypes["3006_casing"]); primer.make(g->itypes["lgrifle_primer"]); gunpowder.make(g->itypes["gunpowder"]); gunpowder.charges = 10*multiply; lead.charges = 5*multiply; } else if (pull->type->id == "3006" || pull->type->id == "3006_incendiary") { casing.make(g->itypes["3006_casing"]); primer.make(g->itypes["lgrifle_primer"]); gunpowder.make(g->itypes["gunpowder"]); gunpowder.charges = 8*multiply; lead.charges = 6*multiply; } else if (pull->type->id == "308") { casing.make(g->itypes["308_casing"]); primer.make(g->itypes["lgrifle_primer"]); gunpowder.make(g->itypes["gunpowder"]); gunpowder.charges = 10*multiply; lead.charges = 6*multiply; } else if (pull->type->id == "762_51" || pull->type->id == "762_51_incendiary") { casing.make(g->itypes["308_casing"]); primer.make(g->itypes["lgrifle_primer"]); gunpowder.make(g->itypes["gunpowder"]); gunpowder.charges = 10*multiply; lead.charges = 6*multiply; } else { g->add_msg(_("You cannot disassemble that.")); return; } pull->charges = pull->charges - multiply; if (pull->charges == 0) p->i_rem(ch); g->add_msg(_("You take apart the ammunition.")); p->moves -= 500; if (casing.type->id != "null"){ casing.charges = multiply; int iter = 0; while ((casing.invlet == 0 || p->has_item(casing.invlet)) && iter < inv_chars.size()) { casing.invlet = g->nextinv; g->advance_nextinv(); iter++;} if (p->weight_carried() + casing.weight() < p->weight_capacity() && p->volume_carried() + casing.volume() < p->volume_capacity() && iter < inv_chars.size()) { p->i_add(casing);} else g->m.add_item_or_charges(p->posx, p->posy, casing);} if (primer.type->id != "null"){ primer.charges = multiply; int iter = 0; while ((primer.invlet == 0 || p->has_item(primer.invlet)) && iter < inv_chars.size()) { primer.invlet = g->nextinv; g->advance_nextinv(); iter++;} if (p->weight_carried() + primer.weight() < p->weight_capacity() && p->volume_carried() + primer.volume() < p->volume_capacity() && iter < inv_chars.size()) { p->i_add(primer);} else g->m.add_item_or_charges(p->posx, p->posy, primer);} int iter = 0; while ((gunpowder.invlet == 0 || p->has_item(gunpowder.invlet)) && iter < inv_chars.size()) { gunpowder.invlet = g->nextinv; g->advance_nextinv(); iter++;} if (p->weight_carried() + gunpowder.weight() < p->weight_capacity() && p->volume_carried() + gunpowder.volume() < p->volume_capacity() && iter < inv_chars.size()) { p->i_add(gunpowder);} else g->m.add_item_or_charges(p->posx, p->posy, gunpowder); iter = 0; while ((lead.invlet == 0 || p->has_item(lead.invlet)) && iter < inv_chars.size()) { lead.invlet = g->nextinv; g->advance_nextinv(); iter++;} if (p->weight_carried() + lead.weight() < p->weight_capacity() && p->volume_carried() + lead.volume() < p->volume_capacity() && iter < inv_chars.size()) { p->i_add(lead);} else g->m.add_item_or_charges(p->posx, p->posy, lead); p->practice(g->turn, "gun", rng(1, multiply / 5 + 1)); } void iuse::boltcutters(game *g, player *p, item *it, bool t) { int dirx, diry; if(!g->choose_adjacent(_("Cut up metal"),dirx,diry)) return; if (dirx == p->posx && diry == p->posy) { g->add_msg_if_player(p, _("You neatly sever all of the veins\nand arteries in your body. Oh wait,\nNever mind.")); return; } if (g->m.ter(dirx, diry) == t_chaingate_l) { p->moves -= 100; g->m.ter_set(dirx, diry, t_chaingate_c); g->sound(dirx, diry, 5, _("Gachunk!")); g->m.spawn_item(p->posx, p->posy, "scrap", 0, 3); } else if (g->m.ter(dirx, diry) == t_chainfence_v || g->m.ter(dirx, diry) == t_chainfence_h) { p->moves -= 500; g->m.ter_set(dirx, diry, t_chainfence_posts); g->sound(dirx, diry, 5,_("Snick, snick, gachunk!")); g->m.spawn_item(dirx, diry, "wire", 0, 20); } else { g->add_msg(_("You can't cut that.")); } } void iuse::mop(game *g, player *p, item *it, bool t) { int dirx, diry; if(!g->choose_adjacent("Mop",dirx,diry)) return; if (dirx == p->posx && diry == p->posy) { g->add_msg_if_player(p,_("You mop yourself up.")); g->add_msg_if_player(p,_("The universe implodes and reforms around you.")); return; } if (g->m.moppable_items_at(dirx, diry)) { g->m.mop_spills(dirx, diry); g->add_msg(_("You mop up the spill")); p->moves -= 15; } else { g->add_msg_if_player(p,_("There's nothing to mop there.")); } } void iuse::rag(game *g, player *p, item *it, bool t) { if (p->has_disease("bleed")){ if (one_in(2)){ g->add_msg_if_player(p,_("You managed to stop the bleeding.")); p->rem_disease("bleed"); } else { g->add_msg_if_player(p,_("You couldn't stop the bleeding.")); } p->use_charges("rag", 1); it->make(g->itypes["rag_bloody"]); } else { g->add_msg_if_player(p,_("You're not bleeding enough to need your %s."), it->type->name.c_str()); } } void iuse::pda(game *g, player *p, item *it, bool t) { if (it->charges == 0) g->add_msg_if_player(p,_("The PDA's batteries are dead.")); else { g->add_msg_if_player(p,_("You activate the flashlight app.")); it->make(g->itypes["pda_flashlight"]); it->active = true; it->charges --; } } void iuse::pda_flashlight(game *g, player *p, item *it, bool t) { if (t) { // Normal use // Do nothing... player::active_light and the lightmap::generate deal with this } else { // Turning it off g->add_msg_if_player(p,_("The PDA screen goes blank.")); it->make(g->itypes["pda"]); it->active = false; } } void iuse::LAW(game *g, player *p, item *it, bool t) { g->add_msg_if_player(p,_("You pull the activating lever, readying the LAW to fire.")); it->make(g->itypes["LAW"]); it->charges++; // When converting a tool to a gun, you need to set the current ammo type, this is usually done when a gun is reloaded. it->curammo = dynamic_cast(g->itypes["66mm_HEAT"]); } /* MACGUFFIN FUNCTIONS * These functions should refer to it->associated_mission for the particulars */ void iuse::mcg_note(game *g, player *p, item *it, bool t) { std::stringstream message; message << "Dear " << it->name << ":\n"; /* faction* fac = NULL; direction dir = NORTH; // Pick an associated faction switch (it->associated_mission) { case MISSION_FIND_FAMILY_FACTION: fac = &(g->factions[rng(0, g->factions.size() - 1)]); break; case MISSION_FIND_FAMILY_KIDNAPPER: fac = g->random_evil_faction(); break; } // Calculate where that faction is if (fac != NULL) { int omx = g->cur_om->posx, omy = g->cur_om->posy; if (fac->omx != g->cur_om->posx || fac->omx != g->cur_om->posy) dir = direction_from(omx, omy, fac->omx, fac->omy); else dir = direction_from(g->levx, g->levy, fac->mapx, fac->mapy); } // Produce the note and generate the next mission switch (it->associated_mission) { case MISSION_FIND_FAMILY_FACTION: if (fac->name == "The army") message << "\ I've been rescued by an army patrol. They're taking me\n\ to their outpost to the " << direction_name(dir) << ".\n\ Please meet me there. I need to know you're alright."; else message << "\ This group came through, looking for survivors. They\n\ said they were members of this group calling itself\n" << fac->name << ".\n\ They've got a settlement to the " << direction_name(dir) << ", so\n\ I guess I'm heading there. Meet me there as soon as\n\ you can, I need to know you're alright."; break; popup(message.str().c_str()); */ } void iuse::artifact(game *g, player *p, item *it, bool t) { if (!it->is_artifact()) { debugmsg("iuse::artifact called on a non-artifact item! %s", it->tname().c_str()); return; } else if (!it->is_tool()) { debugmsg("iuse::artifact called on a non-tool artifact! %s", it->tname().c_str()); return; } it_artifact_tool *art = dynamic_cast(it->type); int num_used = rng(1, art->effects_activated.size()); if (num_used < art->effects_activated.size()) num_used += rng(1, art->effects_activated.size() - num_used); std::vector effects = art->effects_activated; for (int i = 0; i < num_used; i++) { int index = rng(0, effects.size() - 1); art_effect_active used = effects[index]; effects.erase(effects.begin() + index); switch (used) { case AEA_STORM: { g->sound(p->posx, p->posy, 10, _("Ka-BOOM!")); int num_bolts = rng(2, 4); for (int j = 0; j < num_bolts; j++) { int xdir = 0, ydir = 0; while (xdir == 0 && ydir == 0) { xdir = rng(-1, 1); ydir = rng(-1, 1); } int dist = rng(4, 12); int boltx = p->posx, bolty = p->posy; for (int n = 0; n < dist; n++) { boltx += xdir; bolty += ydir; g->m.add_field(g, boltx, bolty, fd_electricity, rng(2, 3)); if (one_in(4)) { if (xdir == 0) xdir = rng(0, 1) * 2 - 1; else xdir = 0; } if (one_in(4)) { if (ydir == 0) ydir = rng(0, 1) * 2 - 1; else ydir = 0; } } } } break; case AEA_FIREBALL: { point fireball = g->look_around(); if (fireball.x != -1 && fireball.y != -1) g->explosion(fireball.x, fireball.y, 8, 0, true); } break; case AEA_ADRENALINE: g->add_msg_if_player(p,_("You're filled with a roaring energy!")); p->add_disease("adrenaline", rng(200, 250)); break; case AEA_MAP: { bool new_map = false; for (int x = int(g->levx / 2) - 20; x <= int(g->levx / 2) + 20; x++) { for (int y = int(g->levy / 2) - 20; y <= int(g->levy / 2) + 20; y++) { if (!g->cur_om->seen(x, y, g->levz)) { new_map = true; g->cur_om->seen(x, y, g->levz) = true; } } } if (new_map) { g->add_msg_if_player(p,_("You have a vision of the surrounding area...")); p->moves -= 100; } } break; case AEA_BLOOD: { bool blood = false; for (int x = p->posx - 4; x <= p->posx + 4; x++) { for (int y = p->posy - 4; y <= p->posy + 4; y++) { if (!one_in(4) && g->m.add_field(g, x, y, fd_blood, 3) && (blood || g->u_see(x, y))) blood = true; } } if (blood) g->add_msg_if_player(p,_("Blood soaks out of the ground and walls.")); } break; case AEA_FATIGUE: { g->add_msg_if_player(p,_("The fabric of space seems to decay.")); int x = rng(p->posx - 3, p->posx + 3), y = rng(p->posy - 3, p->posy + 3); g->m.add_field(g, x, y, fd_fatigue, rng(1, 2)); } break; case AEA_ACIDBALL: { point acidball = g->look_around(); if (acidball.x != -1 && acidball.y != -1) { for (int x = acidball.x - 1; x <= acidball.x + 1; x++) { for (int y = acidball.y - 1; y <= acidball.y + 1; y++) { g->m.add_field(g, x, y, fd_acid, rng(2, 3)); } } } } break; case AEA_PULSE: g->sound(p->posx, p->posy, 30, _("The earth shakes!")); for (int x = p->posx - 2; x <= p->posx + 2; x++) { for (int y = p->posy - 2; y <= p->posy + 2; y++) { std::string junk; g->m.bash(x, y, 40, junk); g->m.bash(x, y, 40, junk); // Multibash effect, so that doors &c will fall g->m.bash(x, y, 40, junk); if (g->m.is_destructable(x, y) && rng(1, 10) >= 3) g->m.ter_set(x, y, t_rubble); } } break; case AEA_HEAL: g->add_msg_if_player(p,_("You feel healed.")); p->healall(2); break; case AEA_CONFUSED: for (int x = p->posx - 8; x <= p->posx + 8; x++) { for (int y = p->posy - 8; y <= p->posy + 8; y++) { int mondex = g->mon_at(x, y); if (mondex != -1) g->z[mondex].add_effect(ME_STUNNED, rng(5, 15)); } } case AEA_ENTRANCE: for (int x = p->posx - 8; x <= p->posx + 8; x++) { for (int y = p->posy - 8; y <= p->posy + 8; y++) { int mondex = g->mon_at(x, y); if (mondex != -1 && g->z[mondex].friendly == 0 && rng(0, 600) > g->z[mondex].hp) g->z[mondex].make_friendly(); } } break; case AEA_BUGS: { int roll = rng(1, 10); mon_id bug = mon_null; int num = 0; std::vector empty; for (int x = p->posx - 1; x <= p->posx + 1; x++) { for (int y = p->posy - 1; y <= p->posy + 1; y++) { if (g->is_empty(x, y)) empty.push_back( point(x, y) ); } } if (empty.empty() || roll <= 4) g->add_msg_if_player(p,_("Flies buzz around you.")); else if (roll <= 7) { g->add_msg_if_player(p,_("Giant flies appear!")); bug = mon_fly; num = rng(2, 4); } else if (roll <= 9) { g->add_msg_if_player(p,_("Giant bees appear!")); bug = mon_bee; num = rng(1, 3); } else { g->add_msg_if_player(p,_("Giant wasps appear!")); bug = mon_wasp; num = rng(1, 2); } if (bug != mon_null) { monster spawned(g->mtypes[bug]); spawned.friendly = -1; for (int j = 0; j < num && !empty.empty(); j++) { int index_inner = rng(0, empty.size() - 1); point spawnp = empty[index_inner]; empty.erase(empty.begin() + index_inner); spawned.spawn(spawnp.x, spawnp.y); g->z.push_back(spawned); } } } break; case AEA_TELEPORT: g->teleport(p); break; case AEA_LIGHT: g->add_msg_if_player(p,_("The %s glows brightly!"), it->tname().c_str()); g->add_event(EVENT_ARTIFACT_LIGHT, int(g->turn) + 30); break; case AEA_GROWTH: { monster tmptriffid(g->mtypes[0], p->posx, p->posy); mattack tmpattack; tmpattack.growplants(g, &tmptriffid); } break; case AEA_HURTALL: for (int j = 0; j < g->z.size(); j++) g->z[j].hurt(rng(0, 5)); break; case AEA_RADIATION: g->add_msg(_("Horrible gasses are emitted!")); for (int x = p->posx - 1; x <= p->posx + 1; x++) { for (int y = p->posy - 1; y <= p->posy + 1; y++) g->m.add_field(g, x, y, fd_nuke_gas, rng(2, 3)); } break; case AEA_PAIN: g->add_msg_if_player(p,_("You're wracked with pain!")); p->pain += rng(5, 15); break; case AEA_MUTATE: if (!one_in(3)) p->mutate(g); break; case AEA_PARALYZE: g->add_msg_if_player(p,_("You're paralyzed!")); p->moves -= rng(50, 200); break; case AEA_FIRESTORM: g->add_msg_if_player(p,_("Fire rains down around you!")); for (int x = p->posx - 3; x <= p->posx + 3; x++) { for (int y = p->posy - 3; y <= p->posy + 3; y++) { if (!one_in(3)) { if (g->m.add_field(g, x, y, fd_fire, 1 + rng(0, 1) * rng(0, 1))) g->m.field_at(x, y).findField(fd_fire)->setFieldAge(g->m.field_at(x, y).findField(fd_fire)->getFieldAge() + 30); } } } break; case AEA_ATTENTION: g->add_msg_if_player(p,_("You feel like your action has attracted attention.")); p->add_disease("attention", 600 * rng(1, 3)); break; case AEA_TELEGLOW: g->add_msg_if_player(p,_("You feel unhinged.")); p->add_disease("teleglow", 100 * rng(3, 12)); break; case AEA_NOISE: g->add_msg_if_player(p,_("Your %s emits a deafening boom!"), it->tname().c_str()); g->sound(p->posx, p->posy, 100, ""); break; case AEA_SCREAM: g->add_msg_if_player(p,_("Your %s screams disturbingly."), it->tname().c_str()); g->sound(p->posx, p->posy, 40, ""); p->add_morale(MORALE_SCREAM, -10, 0, 300, 5); break; case AEA_DIM: g->add_msg_if_player(p,_("The sky starts to dim.")); g->add_event(EVENT_DIM, int(g->turn) + 50); break; case AEA_FLASH: g->add_msg_if_player(p,_("The %s flashes brightly!"), it->tname().c_str()); g->flashbang(p->posx, p->posy); break; case AEA_VOMIT: g->add_msg_if_player(p,_("A wave of nausea passes through you!")); p->vomit(g); break; case AEA_SHADOWS: { int num_shadows = rng(4, 8); monster spawned(g->mtypes[mon_shadow]); int num_spawned = 0; for (int j = 0; j < num_shadows; j++) { int tries = 0, monx, mony, junk; do { if (one_in(2)) { monx = rng(p->posx - 5, p->posx + 5); mony = (one_in(2) ? p->posy - 5 : p->posy + 5); } else { monx = (one_in(2) ? p->posx - 5 : p->posx + 5); mony = rng(p->posy - 5, p->posy + 5); } } while (tries < 5 && !g->is_empty(monx, mony) && !g->m.sees(monx, mony, p->posx, p->posy, 10, junk)); if (tries < 5) { num_spawned++; spawned.sp_timeout = rng(8, 20); spawned.spawn(monx, mony); g->z.push_back(spawned); } } if (num_spawned > 1) g->add_msg_if_player(p,_("Shadows form around you.")); else if (num_spawned == 1) g->add_msg_if_player(p,_("A shadow forms nearby.")); } break; } } } void iuse::spray_can(game *g, player *p, item *it, bool t) { // We have to access the actual it_tool class to figure out how many charges this thing uses. // Because the charges have already been removed in player::use, we will have to refund the charges if the user cancels. // This is a stupid hack, but it's the only way short of rewriting all of the iuse:: functions to draw their own charges as needed. it_tool *tool = dynamic_cast(it->type); int charges_per_use = tool->charges_per_use; if ( it->type->id == _("permanent_marker") ) { int ret=menu(true, _("Write on what?"), _("The ground"), _("An item"), _("Cancel"), NULL ); if (ret == 2 ) { // inscribe_item returns false if the action fails or is canceled somehow. bool canceled_inscription = !inscribe_item( g, p, _("Write"), _("Written"), false ); if( canceled_inscription ) { //Refund the charges, because the inscription was never made. it->charges += charges_per_use; } return; } else if ( ret != 1) // User chose cancel or some other undefined key. { //Refund the charges, because the player canceled the action. it->charges += charges_per_use; return; } } bool ismarker = (it->type->id=="permanent_marker"); std::string message = string_input_popup(ismarker?_("Write what?"):_("Spray what?")); if(message.empty()) { //Refund the charges, because the player canceled the action. it->charges += charges_per_use; } else { if(g->m.add_graffiti(g, p->posx, p->posy, message)) { g->add_msg( ismarker? _("You write a message on the ground.") : _("You spray a message on the ground.") ); } else { g->add_msg( ismarker? _("You fail to write a message here.") : _("You fail to spray a message here.") ); // Refuned the charges, because the grafitti failed. it->charges += charges_per_use; } } } void iuse::heatpack(game *g, player *p, item *it, bool t) { char ch = g->inv(_("Heat up what?")); item* heat = &(p->i_at(ch)); if (heat->type->id == "null") { g->add_msg(_("You do not have that item!")); return; } if (heat->type->is_food()) { p->moves -= 300; g->add_msg(_("You heat up the food.")); heat->item_tags.insert("HOT"); heat->active = true; heat->item_counter = 600; // sets the hot food flag for 60 minutes it->make(g->itypes["heatpack_used"]); return; } else if (heat->is_food_container()) { p->moves -= 300; g->add_msg(_("You heat up the food.")); heat->contents[0].item_tags.insert("HOT"); heat->contents[0].active = true; heat->contents[0].item_counter = 600; // sets the hot food flag for 60 minutes it->make(g->itypes["heatpack_used"]); return; } { g->add_msg(_("You can't heat that up!")); } return; } void iuse::dejar(game *g, player *p, item *it, bool t) { if( (it->type->id).substr(0,4) == "jar_" ) { g->add_msg_if_player(p,_("You open the jar, exposing it to the atmosphere.")); } else if( (it->type->id).substr(0,4) == "bag_" ) { g->add_msg_if_player(p,_("You open the vacuum pack, exposing it to the atmosphere.")); } else { // No matching substring, bail out. return; } // Strips off "jar_" or "bag_" from the id to get the content type. itype_id ujfood = (it->type->id).substr(4); // temp create item to discover container item ujitem( g->itypes[ujfood], 0 ); //discovering container itype_id ujcont = (dynamic_cast(ujitem.type))->container; //turning "sealed jar of xxx" into container for "xxx" it->make( g->itypes[ujcont] ); //shoving the "xxx" into the container it->contents.push_back( item( g->itypes[ujfood], 0 ) ); it->contents[0].bday = g->turn + 3600 - (g->turn % 3600); } void iuse::rad_badge(game *g, player *p, item *it, bool t) { g->add_msg_if_player(p,_("You remove the badge from its wrapper, exposing it to ambient radiation.")); it->make(g->itypes["rad_badge"]); } void iuse::boots(game *g, player *p, item *it, bool t) { int choice = -1; if (it->contents.size() == 0) choice = menu(true, _("Using boots:"), _("Put a knife in the boot"), _("Cancel"), NULL); else if (it->contents.size() == 1) choice = menu(true, _("Take what:"), it->contents[0].tname().c_str(), _("Put a knife in the boot"), _("Cancel"), NULL); else choice = menu(true, _("Take what:"), it->contents[0].tname().c_str(), it->contents[1].tname().c_str(), _("Cancel"), NULL); if ((it->contents.size() > 0 && choice == 1) || // Pull 1st (it->contents.size() > 1 && choice == 2)) { // Pull 2nd p->moves -= 15; item knife = it->contents[choice - 1]; if (!p->is_armed() || p->wield(g, -3)) { p->i_add(knife); p->wield(g, knife.invlet); it->contents.erase(it->contents.begin() + choice - 1); } } else if ((it->contents.size() == 0 && choice == 1) || // Put 1st (it->contents.size() == 1 && choice == 2)) { // Put 2st char ch = g->inv_type(_("Put what?"), IC_TOOL); item* put = &(p->i_at(ch)); if (put == NULL || put->is_null()) { g->add_msg_if_player(p, _("You do not have that item!")); return; } if (put->type->use != &iuse::knife) { g->add_msg_if_player(p, _("That isn't knife!")); return; } if (put->type->volume > 5) { g->add_msg_if_player(p, _("That item does not fit in your boot!")); return; } p->moves -= 30; g->add_msg_if_player(p, _("You put the %s in your boot."), put->tname().c_str()); it->put_in(p->i_rem(ch)); } } void iuse::towel(game *g, player *p, item *it, bool t) { // check if player is wet if( abs(p->has_morale(MORALE_WET)) ) { p->rem_morale(MORALE_WET); g->add_msg_if_player(p,_("You use the %s to dry off!"), it->name.c_str()); } else { g->add_msg_if_player(p,_("You are already dry, %s has no effect"), it->name.c_str()); } } void iuse::unfold_bicycle(game *g, player *p, item *it, bool t) { vehicle *bicycle = g->m.add_vehicle( g, veh_bicycle, p->posx, p->posy, 0, 0, 0); if( bicycle ) { // Mark the vehicle as foldable. bicycle->tags.insert("convertible"); // Restore HP of parts if we stashed them previously. if( it->item_vars.count("folding_bicycle_parts") ) { std::istringstream part_hps; part_hps.str(it->item_vars["folding_bicycle_parts"]); for (int p = 0; p < bicycle->parts.size(); p++) { part_hps >> bicycle->parts[p].hp; } } g->add_msg_if_player(p, _("You painstakingly unfold the bicycle and make it ready to ride.")); p->moves -= 500; it->invlet = 0; } else { g->add_msg_if_player(p, _("There's no room to unfold the bicycle.")); } }