Traps now remember how much ammo they have. The ammo quantities (from David) are rather tentative.
Breaks savefiles.
git-svn-id: https://crawl-ref.svn.sourceforge.net/svnroot/crawl-ref/trunk@7076 c06c8d41-db1a-0410-9941-cceddc491573
CK7CT5TUFUL2AQY7FUHB5JI3FC2KSPWUWHXC6VEUJJ7G4OWUQFTAC GMHNPQVDPSYULW7PQC6HNDQDCSFBQH7CFAATVQBFJGCOIJI77C2QC 7QKUHGWIEHOXALP3ZE4UZO435KJX2REQE4WGO6EF5RKZEFIMZ6IQC FA4GXCEU3UQ7ODF3FOL2ZWCGIPKYDPI4DGOGY6EZK2GA2JOWQPZAC YXIS433HOV7EZPNYWGA4ZXOKLTQWU55G3HFEN22IBI5ZXTCRIKAAC NZBX4WLFXYQYYA5WEAXANO4QOUJQ6CUIACWZ7FPRNA2ABJ4UBWKQC XKQ2XYVSHYRTEKIYXFLXCPULEEO6IQUSKQHX32UZGNMAMQN2CTMQC INJZPX5A2B2A7P7TDYSAFJ2TPVHLMEY3H6CKJFHY4UMZHAQXI6ZQC 3TGQCOCG4VDWVRILHFOH45Z7KTSLPGP4R3OLPGFAFLWDHXRVJDHQC QD72QU3HMLD7JO2ZD6BAQQNEFKTDOH7BDVMVGL4TD65JGOZ5P7IAC 33TIRHHIR5EJQI67N2MQJHNY3RC43WZRZX6GAU2PX7T6RSAQXBNAC RWCCZ64BG3HSOTM54ANIGENC3F3AIR42LJFRYSAKMCPCIUSOZY5QC K7J2IGELTIQL5KAMBV62MFVIVMEZEWCOLZ7GHFXHYPANYIF7BRZAC SVY2PTCLXR3KNPQAWXVXTTGCC5DR334HOAKHYO3VDDRWM2BWMALAC TGJZXTUIAKCFZQJ54ZQEBGFBVZSJCAX6AWDRSH3TP7UJRLGUM5SAC VJDLV4PF2ZJ46NERO4LZUX5JE2CD5XBOBQCYYPTFWTHLUEYDUOYAC TFZ4TER7O2Z4FOGF2RCPEPYIHBTUA4LG3ECXLR7XGLCC6GO6OOTAC BBQWA33DPXWEDYOOPO45VAYD4JQDZQVMZSEJ4RUI5LLC733IMIIQC QEEJFAETO6B2J4IWDIDCJ5UNIFNNHHG22IWF2CUJRTJJBNE47CWQC UOUDDVHCP2526KI2KRMYS5NDRG5AL3FLPSAHKTVAQOXYVI5XHSVAC FZKMVCODMWQEVVBBQHTTXFBRO4LZEYLB646ZPVUMLHH6EER7FAOAC HAMUM5IA4BJMLRIME7KVVVYLRHVS55RIYMGLLQZL3F7QEP7FJ5KAC NVSFIV2ZKP44XHCSCXG6OZVGL67OIFINC34J2EMKTA4KULCERUEAC PHBACPMH3F34GODHVDKNCMXWU373RJQGVTDLBFCCDLLWDXVYOLTAC SIDH2P7NBIG5KEOE27XHD3ZT2NQ2OJZFN6VZXWNWYFFY5YVXSSVQC LGBOBJZ37D3LFSP62KD4IUA37O5ON4UDP724JHE7HZRTBSB27JZQC ZCRK2DJ5VKECRQXZTWT4NUDL2VT5ZHUK7NT6NQPLRJ56TDX5PJSAC 5XNQ3SSNBFXFNWA6DPM74W6FH65NX665P3DMH6YCWVFOPZTJSYCQC KEANRIMF5CGFVZ2XJYNFPOAKLXOSOJUOVA73IWBWOG576265ERHAC MJWFTUS66PTCNEYXEJA3CUJFXNWXIKDD6H3V24PW7HK64NSVOFSAC AVCMVFA3MKCXHO6H44UK5KJNIHTGQV7UA7GYXM26VI6TXXU5ZN6QC QUHEENPY2PYTEUS7C4R3CKE4FHSHGR2BIXB6EW676ESX3727PA3AC S2LIBA2CLTZ6ZU66AUZ2CCNLCDOBSGWQGTZ6HFAFP2XSWAALGLSQC 3DQXSE4YGFBBDUWK4YEOFWW4UPWILWELFSLP37SL6BERGAZJC5YAC JAYS2VMYWPH2YKIDWEXW2NOK4ATTIXTGZTXUVDDIQGCXLB5W4OUQC L57WEZMVIHTFRLWVIPWOIOWHCF2I53TVUVYJ2V6IZ64R56FVTZZAC DHXIQXK5VTL5JDDEERAVLZK4KBQLXFTBN5TQ6MH3PRBLG5ULOS4AC T7CUIVICB74342RA32BR37T36FOX4RBSQIB5PNOHTGTGUYGDKSTQC JA465VRRBEMSFQNUXRHTMUQ7OEBUE4GBPXYDQO5JXMAM3TDKQBLAC Q3ESS2G3M4LBHAIGM66QE2GXWVC67KSR2AXU3MNJEKSP4XKUGXWQC 45EMD3KLQPMERNMIKU5G76H6556XOMIW352TSBP7VLWJX2YYGS7AC SELQ6AD2GNYLGHJVONUUFDHSCMGYMMNQF5D72D7KTAYOV36T2BBAC AS2IQQJNNCEQNXXKTGYHLB7RO3ZKCF4F7GK6FJH66BOOKDDRGNIQC K2CS6TCX2NDVL2ASEHGP4J4K4IJ6FP3ANNKTSIWVG43HPYSBX6ZQC ILOED4VB4I6VPAUTR75ZWX6MXDYXB5DO2EDK2UH67O3HNKWV23RQC PSCYVKJ7DGXAL3V5U4O6AJTRV6Q3N3SHQWAZ73VIPRTE4W64F2XAC SDLKLUNFGVKDS55DDJZCBAVIB7NL3RRYPTACAY65SCUQKV6APFSAC LDBTCT5WIPLJPZWXS2RUQ26QKISCUUTLO77M464WOE6VSYSNPKYAC S5CIJLSFFXV445G6CH2AQ3YDU3P7RLSIHWV7GBJ4MZ4C26BWCY6AC 7YUGK5Q64KG5O7GJGTUBRRLHAHBCJ5YOE23YUPT6UBKUSB67CYAQC SRYIUTTRZYQDYPLLXYKEHMYWC4EGBYPOT65M2HZEIGFG6SDMV7SQC RPOZZWKG5GLPHVZZ7ZKMKS64ZMV2LDCQSARBJFJ6FZOTOKCQO7FAC X7X6JKZXOCG6NVLZLGNCQDFFXW4H3S77BVAJ5LS7ZHZ4GQVLMOMAC GJAFXCDBIGFUMCD6IJ523WAT754VOJSUXPNN7ZBECYRRP76CARPAC NWUWP5QCMJ7ZZMLCVB74PW7HDEFB6ICEQHNDHCGG7UWDQNNLGVMQC PL6I2CMSTHY5ZHWVMIQE5YTM5S5VPKBNZM6QJVHZSSKOJGIJ5W4AC XI7U6RL6MFTH6SZQMLO4XFWGXGIFJBCRT6ZFCJFR2B2MGRSKDDCAC RM2JXW3ATVYRYHF3NMG5ALGI64OJ7IP2F3MDUDPUT5TBKSSN4KVQC ILO5P5FRDUY4SEQEXMTUDKOPXAUBJRSORHHUVTLLCYOYSXBXOVRAC QDTVLBRGHDTRUVT7I3O72K6TMOYAUSAJBZUHGOEFU2RKJNUPWZSQC XIXBLWIVUPWM3P6XQIB7CS45JOOIYE6OBYYYERCFAYYO4VOWOYUQC VQZEJTCSRZ5RVLCCKUCIS3IVZPFYRC26I74X4WIJAPEY7NYID2UQC JFIJGK5PIN2ZQZWPXD4JDT3LAGZ567TOSTGESLA5UDUABEJODKUAC Y2NYY7HWFZ2LQDK3ACSLGS37F2J2IJ5LRGCIMZYXLEOSVPD3A4DAC DDU4A3JGN5IUIPP5IASOODKPR2WBHSDSV4FITZ6HNXNSXXQACWAQC OK6A6PMHOYIQIPXK32AKOH55QRFWQA43BJWHUOCZA2VIJ6NROHMQC SJDOBXECX7F3ZPPVR7FPURE53D47PP2TFIF4SB6XPS456PZV3DQAC ICPELTV6YVJTUITAKA4JXBHQPKG5OC3Z2V2KRCTNM7AEKHN6I2GAC FIYBXLWALQINNQTHG2KNDUUTAQAZRDDLXW2XOVSKDKBADJ3XCJ4AC XRZPPYWPWUOM4SFNI6BHKH2UKJQNLKOV6Y7XIEPEZXE5QYRT26PAC RSIUBEQUGNU4LO6KH4PKVROWQS33DAKSY4XFVGN7T3CEKSXABCSAC E5DMZFW6WCFAKTKKOQPYTQXZ2CGLWMVH64LRXDUI2UIG4VYUHIVQC S26C7QFN3OBMIHF5XRB5PKRCQVBY22OLUIJKTD4CEMHKWCWE457AC 4UXFU3FZOCBSLDQ4S7MJKAE2H7VUHCNRDQMIY6NJ3PHYXWNGISDQC X76YXE6RFL7QY5WL6MSSS44WHVA5FQMDQY3XTYP2UL6UZB4E6XMQC BRGAZR5AXWC2IALBVXO5SB354IRQEIRHSK55RZPGFI4AGIOD4LUQC OVDIHWR5FEPTBZCTEAXNPB4MYP5NUNPQMC6UM4F6SC4EBGWH3DSQC YCL3W2PFE6ILTGBFODCSXNPDIA46KVSZP2TI7HDMYAOEJT65RIEAC KN5WFFRSNGHIGI5IUYRBOA4R4K7XK3AEAAMN6ELDFTSYKPN7QX7AC FJQ2RENS2ATHQZUNEE5ZTSTHZ5VI6B36TQPAG3IUVBTULGVCCQ7AC X5WLJCJVW55SXZVP7IKP7ADCJIGNKN4PKAXFECVR6TNK7XSMZR7QC NV34PXZWSDIIPPJ3HHQIHB4M5UV66QIHOCUEHCSAACMBM765GX4QC G5G4JTXF6JP3GN7ESZTDLEDNJMTLCCE6BCDBORNAEBOUO5WYHAPQC LOEVXFCKSHE3TCQSUSHOIHHVDJT3RFLE6U3VDI6JXAQTQI5KCJ4AC T2AYVN57EFJQLFUFLAZDXKDAFDGTDLQIEQWQZNYFWJZBYSTYH4QQC 2SFHLF7KGHAKSXERQRCHYY3BFDOZCU5RB6KTSHMFMAF76R7DV4KQC NW6P7VRKBFBQ2FRDZBXN7APJZPYC4SYCIA3MOOE2KZGX43IXNK2AC KZIHM6RUX43HHKXG6HGJHVEEYUPVVNBFIWMT4SKPD2GAH5ZMA3KAC F4FAPEZ5P5CPHZIHUSRYULB3LY4LOJCUC7DZAYVL77LFFBUBCUNAC LTX72QGIPNUGWQN5ULPOMFCOPZTK7472DQY4AYX5WM3WHSUVXI5QC EHP6PYCIPYQ3KF4JFGBTZXEUQHN3FVAH4NUWEOWDDNKGPYVOTOJQC 3HGELZU7NELOQ635HZO6IJIYLBSNCJ5VPH46IE22KA3OSLEFK7AQC R2DQBWKIW7YUJB5SOQ7J274JIYRVX4H3ISFRPAL5RG2RVVP4G2KAC GPEJOT73KMACP33IPAKFR5ROGHCOIP22VXZMQNYTGLEA2OSZUM2AC WDEFQ6YABDQIGJXW5KT3OGR3EO6FZHXZELIRVIXQ4XDYTVOV5V6AC MDFQRJ6QZNFUBVSFWLXUJ6EBXOU47T3CVDI2XKBGNNRF4DXDKESQC 5DIBLX3RXK752JKG2BQQM76GYEOMQ5E2YKTLROH3QQGHCVLAGRJQC Y4NA3JSN63RLATF4NNBPSR5CWF5Z7UEMWCGVX4B6NOAR47CGM4GQC D7SLVLRNCYCBDYYRANHDG3JYEF25CFCSUY5FMF5KXVD5D4UZSDDAC 32PXX2XJVV7YSLLYNAVS7RYKYRAOQ565TZMTITSEPSSXOYPB5M2AC AV3TMWHWB3XBXQCT34UPMZBSIIKVXIGWQPNEFU4CZSBS3ZOF2CUQC 7Y5HSDFKA5TPLS2TWTRFMQVX6UXUDHXU5MUMXQSDFAIY4THQ3BIQC WT66JDIRTLLP37SHTV4GI3V64JFJ4D25LNRLGCHFG6CLEFKJ3QGQC 67WH6I2XIMRRL26UM4FJJJZEMJIDPW5Q77FFNZGKWGTWS7GTCJ6QC W7KGGF2VUXLD6YH55EPIRQ5SF5VKVKT33P6RNKCFCVQ4QXOLQE7AC ZBPS5ZTPF3DVTR5WET4XEFHYXU26CRHU2OHX3YO6PD4MTM2DUXAQC WRPGGZRVGWWYCBWL5W5HMAM7CWLYICKZ6A36ZGQ3UEDW5O25FMOQC H55P74Y6NHAPF3VPWXIAP7DODA3DV7NCT3SK6VVLWNNWZ7JIMBTAC D27U7RT2C77NEUBP6JCSQJ2DRCJVHOXUO2PFZ45VFYMEVMKI4TSAC UEI5JAVCMN7Y2SACTEZPZSNFJWOJTC55G24Q6LKQCT4XNDH5ZQIAC GQL5SIGBHLU3FMCE54XVGLRY5AZHRM6DUEB722REA2DPLGJSN6EQC 4FQAKUKUO6PCAZ3N4HUR5XL6E4VA5UQUZ3AEDGRBLVY7W2LMWI7QC 3KAINFIXO7WNWGUGZB43EUNFRS2ZPBLQZDTY456QACMRHYIJ7WDAC VXMRWJ2CPHIB2NAHMZKUV7DAFA7GLVA32WDS53WNT3BIDHK6GOZQC 7THPBJV4J3WDSXWL2XOYYN7RZQILOCPKFWQRYKBA74J7WWBFRLSQC X5OHFTHRXTI5KHFIYFJ6DB3W5MY3JUJKNTL4HF37MKABYNCOBOZAC 77H4BWWPPGLM3PLZH4QTAJRXIZTSDVNCOKZE223I437FN2UJ34RQC C3OUSRCHDUOJ6ELVDX6YWMQQVXDJLNEXTXWCDDAYWTKNPFPNSONAC 475LL4U4ND6PTNV4XKC7WQAOJC7RF2VCCVX3DRILP2PKIBFYWE6QC UZ6N6HOUPGVSPC5NQROEEDWMEGJA5XUWUY2AKH5QG65AZ25PVXDAC void itrap(struct bolt &pbolt, int trapped);void destroy_trap( const coord_def& pos );dungeon_feature_type trap_category(trap_type type);int trap_at_xy(const coord_def& xy);trap_type trap_type_at_xy(const coord_def& xy);
void destroy_trap(const coord_def& pos);trap_def* find_trap(const coord_def& where);trap_type get_trap_type(const coord_def& where);
static void dart_trap(bool trap_known, int trapped, bolt &pbolt, bool poison);
bool trap_def::active() const{return (this->type != TRAP_UNASSIGNED);}bool trap_def::type_has_ammo() const{bool rc = false;switch (this->type){case TRAP_DART: case TRAP_ARROW: case TRAP_BOLT:case TRAP_NEEDLE: case TRAP_SPEAR: case TRAP_AXE:rc = true;default:break;}return rc;}void trap_def::message_trap_entry(){if (this->type == TRAP_TELEPORT)mpr("You enter a teleport trap!");}void trap_def::disarm(){if (this->type_has_ammo() && this->ammo_qty > 0){item_def trap_item = this->generate_trap_item();trap_item.quantity = this->ammo_qty;copy_item_to_grid(trap_item, this->pos);}this->destroy();}void trap_def::destroy(){grd(this->pos) = DNGN_FLOOR;this->ammo_qty = 0;this->pos = coord_def(-1,-1);this->type = TRAP_UNASSIGNED;}void trap_def::hide(){grd(this->pos) = DNGN_UNDISCOVERED_TRAP;}void trap_def::prepare_ammo(){switch (this->type){case TRAP_DART:case TRAP_ARROW:case TRAP_BOLT:case TRAP_NEEDLE:this->ammo_qty = 3 + random2avg(9, 3);break;case TRAP_SPEAR:case TRAP_AXE:this->ammo_qty = 2 + random2avg(6, 3);break;default:this->ammo_qty = 0;break;}}void trap_def::reveal(){const dungeon_feature_type cat = this->category();grd(this->pos) = cat;set_envmap_obj(this->pos, cat);}std::string trap_def::name(description_level_type desc) const{if (this->type >= NUM_TRAPS)return ("buggy");const char* basename = trap_name(this->type);if (desc == DESC_CAP_A || desc == DESC_NOCAP_A){std::string prefix = (desc == DESC_CAP_A ? "A" : "a");if (is_vowel(basename[0]))prefix += 'n';prefix += ' ';return (prefix + basename);}else if (desc == DESC_CAP_THE)return (std::string("The ") + basename);else if (desc == DESC_NOCAP_THE)return (std::string("the ") + basename);else // everything elsereturn (basename);}bool trap_def::is_known(const actor* act) const{bool rc = false;const bool player_knows = (grd(pos) != DNGN_UNDISCOVERED_TRAP);if (act == NULL || act->atype() == ACT_PLAYER)rc = player_knows;else if (act->atype() == ACT_MONSTER){const monsters* monster = static_cast<const monsters*>(act);const bool mechanical = (this->category() == DNGN_TRAP_MECHANICAL);const int intel = mons_intel(monster->type);
// Smarter trap handling for intelligent monsters// * monsters native to a branch can be assumed to know the trap// locations and thus be able to avoid them// * friendlies and good neutrals can be assumed to have been warned// by the player about all traps s/he knows about// * very intelligent monsters can be assumed to have a high T&D// skill (or have memorised part of the dungeon layout ;) )rc = (intel >= I_NORMAL && mechanical&& (mons_is_native_in_branch(monster)|| (mons_wont_attack(monster) && player_knows)|| (intel >= I_HIGH && one_chance_in(3))));}return rc;}
if (random2( 20 + 5 * you.shield_blocks * you.shield_blocks )< player_shield_class())
// Only magical traps affect flying critters.if (triggerer.airborne() && this->category() != DNGN_TRAP_MAGICAL)
msg += "hits you!";mpr(msg.c_str());
// Alarm traps aren't set off by hostile monsters, because// that would be way too nasty for the player.const char* message_here = "An alarm trap emits a blaring wail!";const char* message_near = "You hear a blaring wail!";const char* message_far = "You hear a distant blaring wail!";noisy(12, this->pos, (you_trigger ? message_here :(in_sight ? message_near : message_far)));}break;
if (poison && x_chance_in_y(50 - (3 * player_AC()) / 2, 100)&& !player_res_poison())
case TRAP_BLADE:if (you_trigger){if (trig_knows && one_chance_in(3))mpr("You avoid triggering a blade trap.");else if (random2limit(player_evasion(), 40)+ (random2(you.dex) / 3) + (trig_knows ? 3 : 0) > 8)
damage_taken = roll_dice( pbolt.damage );damage_taken -= random2( player_AC() + 1 );if (damage_taken > 0)
else
ouch(damage_taken, NON_MONSTER, KILLED_BY_TRAP,pbolt.name.c_str());
mpr("A huge blade swings out and slices into you!");const int damage = (you.your_level * 2) + random2avg(29, 2)- random2(1 + player_AC());ouch(damage, NON_MONSTER, KILLED_BY_TRAP, " blade");bleed_onto_floor(you.pos(), -1, damage, true);
msg += "misses you.";mpr(msg.c_str());}if (player_light_armour(true) && coinflip())exercise( SK_DODGING, 1 );}pbolt.target = you.pos();if (coinflip())itrap( pbolt, trapped );} // end dart_trap()//// itrap takes location from target_x, target_y of bolt strcture.//
if (one_chance_in(5) || (trig_knows && coinflip())){// Trap doesn't trigger. Don't reveal it.if (you_know){simple_monster_message(m," fails to trigger a blade trap.");}elsethis->hide();}else if (random2(m->ev) > 8 || (trig_knows && random2(m->ev) > 8)){if (in_sight &&!simple_monster_message(m," avoids a huge, swinging blade.")){mpr("A huge blade swings out!");}}else{if (in_sight){std::string msg = "A huge blade swings out";if (player_monster_visible( m )){msg += " and slices into ";msg += m->name(DESC_NOCAP_THE);}msg += "!";mpr(msg.c_str());}
switch (env.trap[trapped].type){case TRAP_DART:base_type = OBJ_MISSILES;sub_type = MI_DART;break;case TRAP_ARROW:base_type = OBJ_MISSILES;sub_type = MI_ARROW;break;case TRAP_BOLT:base_type = OBJ_MISSILES;sub_type = MI_BOLT;break;case TRAP_SPEAR:base_type = OBJ_WEAPONS;sub_type = WPN_SPEAR;break;case TRAP_AXE:base_type = OBJ_WEAPONS;sub_type = WPN_HAND_AXE;break;case TRAP_NEEDLE:base_type = OBJ_MISSILES;sub_type = MI_NEEDLE;
if (damage_taken < 0)damage_taken = 0;if (!mons_is_summoned(m))bleed_onto_floor(m->pos(), m->type, damage_taken, true);hurt_monster(m, damage_taken);if (m->hit_points < 1)monster_die(m, KILL_MISC, NON_MONSTER);}}
base_type = OBJ_MISSILES;sub_type = MI_THROWING_NET;break;default:return;}
if (you_trigger){if (trig_knows && one_chance_in(3))mpr("A net swings high above you.");else{if (random2limit(player_evasion(), 40)+ (random2(you.dex) / 3) + (trig_knows ? 3 : 0) > 12){mpr("A net drops to the ground!");}else{mpr("A large net falls onto you!");player_caught_in_net();}
void handle_traps(trap_type trt, int i, bool trap_known){struct bolt beam;bool branchtype = false;// Mark traps as racial, if applicable. See the list of racial// restrictions in _determine_weapon_race() and// _determine_missile_race() in makeitem.cc.if (trap_category(trt) == DNGN_TRAP_MECHANICAL && trt != TRAP_BLADE&& trt != TRAP_NET){if (you.where_are_you == BRANCH_ORCISH_MINES){beam.name = "n orcish";branchtype = true;
this->destroy();}
beam.name = "n elven";branchtype = true;}elsebeam.name = "";}
bool triggered = true;if (one_chance_in(3) || (trig_knows && coinflip())){triggered = false;if (you_know)simple_monster_message(m, " fails to trigger a net trap.");}if (random2(m->ev) > 8|| (trig_knows && random2(m->ev) > 8)){if (in_sight){if (!simple_monster_message(m," nimbly jumps out of the way ""of a falling net.")){mpr("A large net falls down!");}}else{// FIXME: net traps don't trigger unless you can see// them? Preserving old behaviour here.if (in_sight){msg::stream << "A large net falls down";if (player_monster_visible(m))msg::stream << " onto " << m->name(DESC_NOCAP_THE);msg::stream << "!" << std::endl;}// FIXME: Fake a beam for monster_caught_in_net.bolt beam;beam.flavour = BEAM_MISSILE;beam.thrower = KILL_MISC;beam.beam_source = NON_MONSTER;monster_caught_in_net(m, beam);}}
switch (trt){case TRAP_DART:beam.name += " dart";beam.damage = dice_def( 1, 4 + (you.your_level / 2) );dart_trap(trap_known, i, beam, false);break;
if (triggered){item_def item = this->generate_trap_item();copy_item_to_grid(item, triggerer.pos());
case TRAP_NEEDLE:beam.name += " needle";beam.damage = dice_def( 1, 0 );dart_trap(trap_known, i, beam, true);break;case TRAP_ARROW:beam.name += (branchtype? "" : "n");beam.name += " arrow";beam.damage = dice_def( 1, 7 + you.your_level );dart_trap(trap_known, i, beam, false);break;case TRAP_BOLT:beam.name += " bolt";beam.damage = dice_def( 1, 13 + you.your_level );dart_trap(trap_known, i, beam, false);break;case TRAP_SPEAR:beam.name += " spear";beam.damage = dice_def( 1, 10 + you.your_level );dart_trap(trap_known, i, beam, false);break;case TRAP_AXE:beam.name += (branchtype? "" : "n");beam.name += " axe";beam.damage = dice_def( 1, 15 + you.your_level );dart_trap(trap_known, i, beam, false);break;case TRAP_TELEPORT:mpr("You enter a teleport trap!");if (scan_randarts(RAP_PREVENT_TELEPORTATION))mpr("You feel a weird sense of stasis.");elseyou_teleport_now( true );break;case TRAP_ALARM:if (silenced(you.pos())){if (trap_known)mpr("The alarm is silenced.");elsegrd(you.pos()) = DNGN_UNDISCOVERED_TRAP;return;
if (mons_is_caught(m))mark_net_trapping(m->pos());this->destroy();}
case TRAP_BLADE:if (trap_known && one_chance_in(3))mpr("You avoid triggering a blade trap.");else if (random2limit(player_evasion(), 40)+ (random2(you.dex) / 3) + (trap_known ? 3 : 0) > 8)
case TRAP_ZOT:if (you_trigger)
mpr("A huge blade swings out and slices into you!");int damage = (you.your_level * 2) + random2avg(29, 2)- random2(1 + player_AC());ouch(damage, NON_MONSTER, KILLED_BY_TRAP, " blade");bleed_onto_floor(you.pos(), -1, damage, true);}break;
// Zot traps are out to get *the player*! Hostile monsters// benefit and friendly monsters suffer. Such is life.
case TRAP_NET:if (trap_known && one_chance_in(3))mpr("A net swings high above you.");else{if (random2limit(player_evasion(), 40)+ (random2(you.dex) / 3) + (trap_known ? 3 : 0) > 12)
// Preserving original functionality: don't reveal location.if (!you_know)this->hide();if (mons_wont_attack(m)){MiscastEffect( m, ZOT_TRAP_MISCAST, SPTYP_RANDOM,3, "the power of Zot" );}else if (in_sight)
trap_item( OBJ_MISSILES, MI_THROWING_NET, env.trap[i].pos);if (you.attribute[ATTR_HELD])mark_net_trapping(you.pos());grd(env.trap[i].pos) = DNGN_FLOOR;env.trap[i].type = TRAP_UNASSIGNED;
if (trap_known && !you.airborne())mpr("You don't fall through the shaft.");if (!trap_known)grd(you.pos()) = DNGN_UNDISCOVERED_TRAP;return;
if (!you_know)this->hide();else if (!triggerer.airborne()){if (you_trigger){mpr("You don't fall through the shaft.");}else if (m){simple_monster_message(m," doesn't fall through the shaft.");}}
learned_something_new(TUT_SEEN_TRAP, you.pos());
if (you_trigger){learned_something_new(TUT_SEEN_TRAP, this->pos);// Exercise T&D if the trap revealed itself.if (!you_know && this->is_known())exercise(SK_TRAPS_DOORS, ((coinflip()) ? 2 : 1));}}
if (!trap_known) // Now you know...exercise(SK_TRAPS_DOORS, ((coinflip()) ? 2 : 1));
int trap_def::shot_damage(actor& act){if (act.atype() == ACT_PLAYER){switch (this->type){case TRAP_NEEDLE: return 0;case TRAP_DART: return random2( 4 + you.your_level/2) + 1;case TRAP_ARROW: return random2( 7 + you.your_level) + 1;case TRAP_SPEAR: return random2(10 + you.your_level) + 1;case TRAP_BOLT: return random2(13 + you.your_level) + 1;case TRAP_AXE: return random2(15 + you.your_level) + 1;default: return 0;}}else if (act.atype() == ACT_MONSTER){// Trap damage to monsters is not a function of level, because// they are fairly stupid and tend to have fewer hp than// players -- this choice prevents traps from easily killing// large monsters fairly deep within the dungeon.switch (this->type){case TRAP_NEEDLE: return 0;case TRAP_DART: return random2( 4) + 1;case TRAP_ARROW: return random2( 7) + 1;case TRAP_SPEAR: return random2(10) + 1;case TRAP_BOLT: return random2(13) + 1;case TRAP_AXE: return random2(15) + 1;default: return 0;}}return (0);
{grd(pos) = DNGN_FLOOR;env.trap[i].type = TRAP_UNASSIGNED;return;}}
return (&env.trap[i]);return (NULL);}trap_type get_trap_type(const coord_def& pos){if (trap_def* ptrap = find_trap(pos))return (ptrap->type);return (TRAP_UNASSIGNED);
for (i = 0; i < MAX_TRAPS; i++){if (env.trap[i].pos == you.pos() + disa.delta)break;if (i == MAX_TRAPS - 1){mpr("Error - couldn't find that trap.", MSGCH_ERROR);return;}}
trap_def& trap = *find_trap(where);
mpr("You have disarmed the trap.");bolt beam;beam.target = you.pos() + disa.delta;if (env.trap[i].type == TRAP_NET)trap_item( OBJ_MISSILES, MI_THROWING_NET, beam.target );else if (env.trap[i].type != TRAP_BLADE&& trap_category(env.trap[i].type) == DNGN_TRAP_MECHANICAL)
else
const int num_to_make = 10 + random2(you.skills[SK_TRAPS_DOORS]);for (j = 0; j < num_to_make; j++){// Places items (eg darts), which will automatically stack.itrap(beam, i);}
mpr("You have disarmed the trap.");trap.disarm();exercise(SK_TRAPS_DOORS, 1 + random2(5) + (you.your_level/5));
grd(you.pos() + disa.delta) = DNGN_FLOOR;env.trap[i].type = TRAP_UNASSIGNED;you.turn_is_over = true;// Reduced from 5 + random2(5).exercise(SK_TRAPS_DOORS, 1 + random2(5) + (you.your_level / 5));
item.base_type = base_type;item.sub_type = sub_type;item.plus = 0;item.plus2 = 0;item.flags = 0;item.special = 0;
object_class_type base;int sub;switch (this->type){case TRAP_DART: base = OBJ_MISSILES; sub = MI_DART; break;case TRAP_ARROW: base = OBJ_MISSILES; sub = MI_ARROW; break;case TRAP_BOLT: base = OBJ_MISSILES; sub = MI_BOLT; break;case TRAP_SPEAR: base = OBJ_WEAPONS; sub = WPN_SPEAR; break;case TRAP_AXE: base = OBJ_WEAPONS; sub = WPN_HAND_AXE; break;case TRAP_NEEDLE: base = OBJ_MISSILES; sub = MI_NEEDLE; break;case TRAP_NET: base = OBJ_MISSILES; sub = MI_THROWING_NET; break;default: return item;}item.base_type = base;item.sub_type = sub;
// give appropriate racial flag for Orcish Mines and Elven Halls// should we ever allow properties of dungeon features, we could use thatif (you.where_are_you == BRANCH_ORCISH_MINES)set_equip_race( item, ISFLAG_ORCISH );else if (you.where_are_you == BRANCH_ELVEN_HALLS)set_equip_race( item, ISFLAG_ELVEN );
if (items_stack( item, mitm[ igrd(where) ] ))
if (act.atype() == ACT_PLAYER)mpr("The trap is out of ammunition!");else if (player_can_hear(this->pos))mpr("You hear a soft click.");this->disarm();}else{item_def shot = this->generate_trap_item();bool poison = (this->type == TRAP_NEEDLE);int damage_taken =this->shot_damage(act) - random2(act.armour_class()+1);if (damage_taken < 0)damage_taken = 0;if (act.atype() == ACT_PLAYER)
inc_mitm_item_quantity( igrd(where), 1 );return (false);
if (one_chance_in(5) || (was_known && !one_chance_in(4))){mprf( "You avoid triggering %s trap.",this->name(DESC_NOCAP_A).c_str() );return; // no ammo generated either}// Start constructing the message.std::string msg = shot.name(DESC_CAP_A) + " shoots out and ";// Check for shield blocking.// Exercise only if the trap was unknown (to prevent scumming.)if (!was_known && you.shield() && one_chance_in(3))exercise(SK_SHIELDS, 1);if (random2(20 + 5 * you.shield_blocks * you.shield_blocks)< player_shield_class()){you.shield_blocks++;msg += "hits your shield.";mpr(msg.c_str());}else{// note that this uses full (not random2limit(foo,40))// player_evasion.int trap_hit = (20 + (you.your_level*2)) * random2(200) / 100;int your_dodge = player_evasion() + random2(you.dex) / 3- 2 + (you.duration[DUR_REPEL_MISSILES] * 10);// Check if it got past dodging. Deflect Missiles provides// immunity to such traps.if (trap_hit >= your_dodge&& you.duration[DUR_DEFLECT_MISSILES] == 0){// OK, we've been hit.msg += "hits you!";mpr(msg.c_str());// Needle traps can poison.if (poison && !player_res_poison()&& x_chance_in_y(50 - (3*player_AC()) / 2, 100)){poison_player(1 + random2(3));}ouch(damage_taken, NON_MONSTER, KILLED_BY_TRAP,shot.name(DESC_PLAIN).c_str());}else // trap dodged{msg += "misses you.";mpr(msg.c_str());}// Exercise only if the trap was unknown (to prevent scumming.)if (!was_known && player_light_armour(true) && coinflip())exercise(SK_DODGING, 1);}
// don't want to go overboard here. Will only generate up to three// separate trap items, or less if there are other items present.if (mitm[ igrd(where) ].link != NON_ITEM&& (item.base_type != OBJ_MISSILES|| item.sub_type != MI_THROWING_NET)){if (mitm[ mitm[ igrd(where) ].link ].link != NON_ITEM)return (false);
monsters* monster = static_cast<monsters *>(&act);// Determine whether projectile hits.bool hit = (((20+(you.your_level*2))*random2(200))/100>= monster->ev);// Check whether to poison.if (poison)poison = (hit && x_chance_in_y(50 - (3*monster->ac)/2, 100));if (see_grid(act.pos())){mprf("%s %s %s%s!",shot.name(DESC_CAP_A).c_str(),hit ? "hits" : "misses",monster->name(DESC_NOCAP_THE).c_str(),(damage_taken == 0&& !poison) ? ", but does no damage" : "");}if (poison)poison_monster(monster, KC_OTHER);// Apply damage.hurt_monster(monster, damage_taken);if (monster->hit_points < 1)monster_die(monster, KILL_MISC, NON_MONSTER);
// give appropriate racial flag for Orcish Mines and Elven Halls// should we ever allow properties of dungeon features, we could use thatif (you.where_are_you == BRANCH_ORCISH_MINES)set_equip_race( item, ISFLAG_ORCISH );else if (you.where_are_you == BRANCH_ELVEN_HALLS)set_equip_race( item, ISFLAG_ELVEN );
// Drop the item (sometimes.)if (coinflip())copy_item_to_grid(shot, act.pos());
trap = trap_at_xy(spd.target);if (trap != -1&& trap_category(env.trap[trap].type) != DNGN_TRAP_MECHANICAL)
{trap_def* ptrap = find_trap(spd.target);if (ptrap && ptrap->category() != DNGN_TRAP_MECHANICAL)
// mechanical traps are destroyed {dlb}:int which_trap = trap_at_xy(*ai);if ( which_trap != -1 ){trap_struct& trap(env.trap[which_trap]);if (trap_category(trap.type) == DNGN_TRAP_MECHANICAL){trap.type = TRAP_UNASSIGNED;trap.pos.set(1,1);}}
// All traps are destroyedif (trap_def* ptrap = find_trap(*ai))ptrap->destroy();
grd(p) = trap_category( env.trap[i].type );set_envmap_obj(p, grd(p));set_terrain_mapped(p);
trap.reveal();set_envmap_obj(trap.pos, grd(trap.pos));set_terrain_mapped(trap.pos);
if (new_grid >= DNGN_TRAP_MECHANICAL && new_grid <= DNGN_UNDISCOVERED_TRAP){int id = trap_at_xy( you.pos() );if (id != -1){bool trap_known = true;if (new_grid == DNGN_UNDISCOVERED_TRAP){trap_known = false;const dungeon_feature_type type =trap_category( env.trap[id].type );grd(you.pos()) = type;set_envmap_obj(you.pos(), type);}// It's not easy to blink onto a trap without setting it off.if (!stepped)trap_known = false;
if (trap_def* ptrap = find_trap(you.pos()))ptrap->trigger(you, !stepped); // blinking makes it hard to evade
// mechanical traps and shafts cannot be set off if the// player is flying or levitatingif (!player_is_airborne()|| trap_category( env.trap[id].type ) == DNGN_TRAP_MAGICAL){handle_traps(env.trap[id].type, id, trap_known);}}}
// NB: only works because grid location already verified// to be some sort of trap prior to function call: {dlb}void mons_trap(monsters *monster){if (!is_trap_square(grd(monster->pos())))return;// single calculation permissible {dlb}bool monsterNearby = mons_near(monster);const int which_trap = trap_at_xy(monster->pos());if (which_trap == -1)return;trap_struct& trap(env.trap[which_trap]);bool trapKnown = (grd(monster->pos()) != DNGN_UNDISCOVERED_TRAP);bool revealTrap = false; // more sophisticated trap uncovering {dlb}bool projectileFired = false; // <sigh> I had to do it, I swear {dlb}int damage_taken = -1; // must initialize at -1 for this f(x) {dlb}bolt beem;// flying monsters neatly avoid mechanical traps// and may actually exit this function early: {dlb}if (mons_flies(monster)){if (trap_category(trap.type) == DNGN_TRAP_MECHANICAL){if (trapKnown)simple_monster_message(monster, " flies safely over a trap.");return; // early return {dlb}}}// Trap damage to monsters is not a function of level, because they// are fairly stupid and tend to have fewer hp than players -- this// choice prevents traps from easily killing large monsters fairly// deep within the dungeon.switch (trap.type){case TRAP_DART:projectileFired = true;beem.name = " dart";beem.damage = dice_def( 1, 4 );beem.colour = OBJ_MISSILES;beem.type = MI_DART;break;case TRAP_NEEDLE:projectileFired = true;beem.name = " needle";beem.damage = dice_def( 1, 0 );beem.colour = OBJ_MISSILES;beem.type = MI_NEEDLE;break;case TRAP_ARROW:projectileFired = true;beem.name = "n arrow";beem.damage = dice_def( 1, 7 );beem.colour = OBJ_MISSILES;beem.type = MI_ARROW;break;case TRAP_SPEAR:projectileFired = true;beem.name = " spear";beem.damage = dice_def( 1, 10 );beem.colour = OBJ_WEAPONS;beem.type = WPN_SPEAR;break;case TRAP_BOLT:projectileFired = true;beem.name = " bolt";beem.damage = dice_def( 1, 13 );beem.colour = OBJ_MISSILES;beem.type = MI_BOLT;break;case TRAP_AXE:projectileFired = true;beem.name = "n axe";beem.damage = dice_def( 1, 15 );beem.colour = OBJ_WEAPONS;beem.type = WPN_HAND_AXE;break;// teleport traps are *never* revealed through// the triggering action of a monster, as any// number of factors could have been in play: {dlb}case TRAP_TELEPORT:monster_teleport(monster, true);break;// Alarm traps aren't set off by hostile monsters, because that would// be way too nasty for the player.case TRAP_ALARM:if (!mons_friendly(monster) || silenced(monster->pos())){if (trapKnown && you.can_see(monster) && !silenced(you.pos())){mpr("The alarm trap makes no noise.");}return;}noisy(12, monster->pos());if (!silenced(you.pos())){if (monsterNearby){mpr("You hear a blaring wail!", MSGCH_SOUND);if (you.can_see(monster))revealTrap = true;}elsempr("You hear a distant blaring wail!", MSGCH_SOUND);}break;// blade traps sometimes fail to trigger altogether,// resulting in an "early return" from this f(x) for// some - otherwise, blade *always* revealed: {dlb}case TRAP_BLADE:if (one_chance_in(5)|| trapKnown && intelligent_ally(monster) && coinflip()){if (trapKnown){simple_monster_message(monster," fails to trigger a blade trap.");}return; // early return {dlb}}if (random2(monster->ev) > 8|| trapKnown && intelligent_ally(monster)&& random2(monster->ev) > 8){if (monsterNearby && !simple_monster_message(monster," avoids a huge, swinging blade.")){mpr("A huge blade swings out!");}damage_taken = -1; // just to be certain {dlb}}else{if (monsterNearby){std::string msg = "A huge blade swings out";if (player_monster_visible( monster )){msg += " and slices into ";msg += monster->name(DESC_NOCAP_THE);}msg += "!";mpr(msg.c_str());}damage_taken = 10 + random2avg(29, 2);damage_taken -= random2(1 + monster->ac);if (damage_taken < 0)damage_taken = 0;if (!mons_is_summoned(monster)){bleed_onto_floor(monster->pos(), monster->type,damage_taken, true);}}revealTrap = true;break;case TRAP_NET:{if (one_chance_in(3)|| trapKnown && intelligent_ally(monster) && coinflip()){if (trapKnown){simple_monster_message(monster," fails to trigger a net trap.");}return;}if (random2(monster->ev) > 8|| trapKnown && intelligent_ally(monster)&& random2(monster->ev) > 8){if (monsterNearby && !simple_monster_message(monster," nimbly jumps out of the way of a falling net.")){mpr("A large net falls down!");}}else{if (monsterNearby){std::string msg = "A large net falls down";if (player_monster_visible( monster )){msg += " onto ";msg += monster->name(DESC_NOCAP_THE);}msg += "!";mpr(msg.c_str());monster_caught_in_net(monster, beem);}}trap_item( OBJ_MISSILES, MI_THROWING_NET, trap.pos );if (mons_is_caught(monster))mark_net_trapping(monster->pos());grd(trap.pos) = DNGN_FLOOR;trap.type = TRAP_UNASSIGNED;break;}// zot traps are out to get *the player*! Hostile monsters// benefit and friendly monsters suffer - such is life - on// rare occasion, the trap affects nearby players, triggering// an "early return" - zot traps are *never* revealed - instead,// enchantment messages serve as clues to the trap's presence: {dlb}case TRAP_ZOT:if (mons_friendly(monster) || mons_good_neutral(monster)){MiscastEffect( monster, ZOT_TRAP_MISCAST, SPTYP_RANDOM,3, "the power of Zot" );return; // early return}else if (monsterNearby){if (one_chance_in(5)){mpr("The power of Zot is invoked against you!");MiscastEffect( &you, ZOT_TRAP_MISCAST, SPTYP_RANDOM,3, "the power of Zot" );return; // early return {dlb}}}// output triggering message to player, where appropriate: {dlb}if (!silenced(monster->pos()) && !silenced(you.pos())){if (monsterNearby)mpr("You hear a loud \"Zot\"!", MSGCH_SOUND);elsempr("You hear a distant \"Zot\"!", MSGCH_SOUND);}
// XXX: It seem that back when a beam's colour determined its// flavour that Zot traps would heal, haste or make invisible// hostile monsters. The code has been fixed to work but// commented out.#if 0if (!mons_friendly(monster) && !mons_good_neutral(monster)){int temp_rand = random2(16);beem.thrower = KILL_MON; // probably unnecessarybeem.aux_source.clear();beem.flavour = ((temp_rand < 3) ? BEAM_HASTE : // 3 in 16 {dlb}(temp_rand < 7) ? BEAM_INVISIBILITY //4 in 16 {dlb}: BEAM_HEALING); // 9 in 16 {dlb}mons_ench_f2(monster, beem);}#endifdamage_taken = 0; // just to be certain {dlb}break;case TRAP_SHAFT:// Paranoiaif (!is_valid_shaft_level()){if (trapKnown && monsterNearby)mpr("The shaft disappears in a puff of logic!");grd(trap.pos) = DNGN_FLOOR;trap.type = TRAP_UNASSIGNED;return;}if (!monster->will_trigger_shaft()|| trapKnown && intelligent_ally(monster)){if (trapKnown && !monster->airborne())simple_monster_message(monster," doesn't fall through the shaft.");return;}if (monster->do_shaft())revealTrap = true;break;default:break;}// go back and handle projectile traps: {dlb}bool apply_poison = false;if (projectileFired){// projectile traps *always* revealed after "firing": {dlb}revealTrap = true;// determine whether projectile hits, calculate damage: {dlb}if (((20 + (you.your_level * 2)) * random2(200)) / 100>= monster->ev){damage_taken = roll_dice( beem.damage );damage_taken -= random2(1 + monster->ac);if (damage_taken < 0)damage_taken = 0;if (beem.colour == OBJ_MISSILES&& beem.type == MI_NEEDLE&& x_chance_in_y(50 - (3 * monster->ac)/ 2, 100)){apply_poison = true;}}else{damage_taken = -1; // negative damage marks a miss}if (monsterNearby){mprf("A%s %s %s%s!",beem.name.c_str(),(damage_taken >= 0) ? "hits" : "misses",monster->name(DESC_NOCAP_THE).c_str(),(damage_taken == 0) ? ", but does no damage" : "");}if (apply_poison)poison_monster( monster, KC_OTHER );// Generate "fallen" projectile, where appropriate. {dlb}if (x_chance_in_y(7, 10)){beem.target = monster->pos();itrap(beem, which_trap);}}// reveal undiscovered traps, where appropriate: {dlb}if (monsterNearby && !trapKnown && revealTrap)grd(trap.pos) = trap_category(trap.type);// apply damage and handle death, where appropriate: {dlb}if (damage_taken > 0){hurt_monster(monster, damage_taken);if (monster->hit_points < 1){monster_die(monster, KILL_MISC, NON_MONSTER);monster->speed_increment = 1;}}}
const bool player_knows_trap = (grd(where) != DNGN_UNDISCOVERED_TRAP);// Smarter trap handling for intelligent monsters// * monsters native to a branch can be assumed to know the trap// locations and thus be able to avoid them// * friendlies and good neutrals can be assumed to have been warned// by the player about all traps s/he knows about// * very intelligent monsters can be assumed to have a high T&D// skill (or have memorised part of the dungeon layout ;) )if (intel >= I_NORMAL && mechanical&& (mons_is_native_in_branch(monster)|| mons_wont_attack(monster)&& player_knows_trap|| intel >= I_HIGH && one_chance_in(3)))
if (trap.is_known(monster))
int trap = trap_at_xy(pos);if (trap >= 0){if (!_can_place_on_trap(mon_type, env.trap[trap].type))continue;}
const trap_def* ptrap = find_trap(pos);if (ptrap && !_can_place_on_trap(mon_type, ptrap->type))continue;
int trap = trap_at_xy(mg_pos);if (trap >= 0){if (!_can_place_on_trap(mg.cls, env.trap[trap].type))return (false);}
const trap_def* ptrap = find_trap(mg_pos);if (ptrap && !_can_place_on_trap(mg.cls, ptrap->type))return (false);
// A monster can be considered to know a trap if// a) they're hostile// b) they're friendly and *you* know about the trap (and told them)// c) they're friendly and know the terrainbool knows_trap = (!mons_friendly(mons)|| grd(npos) != DNGN_UNDISCOVERED_TRAP|| mons_intel(mons->type) >= I_NORMAL&& mons_is_native_in_branch(mons));trap_type tt = env.trap[trap].type;
const bool knows_trap = ptrap->is_known(mons);const trap_type tt = ptrap->type;
trap_type type;
trap_type type;int ammo_qty;dungeon_feature_type category() const;std::string name(description_level_type desc = DESC_PLAIN) const;bool is_known(const actor* act = 0) const;void trigger(actor& triggerer, bool flat_footed = false);void disarm();void destroy();void hide();void reveal();void prepare_ammo();bool type_has_ammo() const;bool active() const;private:void message_trap_entry();void shoot_ammo(actor& act, bool was_known);item_def generate_trap_item();int shot_damage(actor& act);
{if (grd(*ai) == DNGN_FLOOR&& trap_at_xy(*ai) == -1&& one_chance_in(++count)){
if (grd(*ai) == DNGN_FLOOR && find_trap(*ai) && one_chance_in(++count))
{const int i = trap_at_xy(f);if (i != -1) // should always happengrd(f) = trap_category(env.trap[i].type);}
find_trap(f)->reveal();