are not for 0.3. Obviously.
Summary: New item type MI_THROWING_NET. The enchantment of a net describes its state, i.e. whether it's brand-new or almost falling apart (happens at -8).
New attribute ATTR_CAUGHT (for monsters ENCH_CAUGHT) that means the victim cannot move and instead struggles against the net until it manages to wriggle out of it (takes a while depending on size) or it is destroyed. Monsters can still use items and spells when trapped.
New trap type TRAP_NET that currently is the only source of throwing nets, though Gladiators (and some types of hunters maybe?) should start with a few, and David suggested also allowing the creation of nets for shops.
git-svn-id: https://crawl-ref.svn.sourceforge.net/svnroot/crawl-ref/trunk@2020 c06c8d41-db1a-0410-9941-cceddc491573
4UXFU3FZOCBSLDQ4S7MJKAE2H7VUHCNRDQMIY6NJ3PHYXWNGISDQC 5ZYOO2RVGH53ONV4U5NO6MTINQXET6GV6TETPVCFAVOX44LDNR4QC RRFPZKCRHPOJH4LDHYMJIQLN2ASWVJBZQW6DDUTBNQRDD7KMEAYAC 557IY36VX2M4ERVCP5HNI3YTHHVTHPETZ5RWDX5BKDKXXIYCFUJAC 5XSXMOBGXFLTIQE6WDXWWFVDOTUPZSIQ2FWT3YI5QMVU6D76IUYQC 7Y5HSDFKA5TPLS2TWTRFMQVX6UXUDHXU5MUMXQSDFAIY4THQ3BIQC ZJIGDAAKOHJWPD7TMNTNKP7ZT4K4GHD7UGSAWERTIJA3BGL5BETQC SDLKLUNFGVKDS55DDJZCBAVIB7NL3RRYPTACAY65SCUQKV6APFSAC I2B33Z7NZGC33AMDSSK446AZZYWKPHWLAGULVHKKZU4MVB4BNJOAC RPOZZWKG5GLPHVZZ7ZKMKS64ZMV2LDCQSARBJFJ6FZOTOKCQO7FAC K2CS6TCX2NDVL2ASEHGP4J4K4IJ6FP3ANNKTSIWVG43HPYSBX6ZQC QDTVLBRGHDTRUVT7I3O72K6TMOYAUSAJBZUHGOEFU2RKJNUPWZSQC QDWDUURSNLMT6AXNNJ3DEQCWAKCAIHV6MP5F7QGIBGXOG2BI2NPQC MX2KOWAIE37VLSQJWXVEDVQVB3DL325Q7YFUSSHYMAIH53Y74IJQC AOAJ6D3OKSELEYKAT55XCVU5LYJ7SMCZKC6DIEGLLB3TF2LEENWQC NNG27Y5ZQAZX6UD7F7M4F6KEZBEDFXPEEC3LFUSX4ESKT7K6UJQAC X5WLJCJVW55SXZVP7IKP7ADCJIGNKN4PKAXFECVR6TNK7XSMZR7QC GS2I6EO4OQZ5FHQJQ6YRUDPSJ5XWGLHN544MVQPSF2PATUSJFSSAC 3QLM46S44Z7GDLWPH3VHBMW2RSWZAOLGJMG2BDKNGUOZIM4IX6WAC DDU4A3JGN5IUIPP5IASOODKPR2WBHSDSV4FITZ6HNXNSXXQACWAQC QS3ZRS3E6KL3YJHPKYEWCWJYRBJSXD5OOYF6Y25HZVECGPJRDB5QC 6GT5JAWOIIL4SQ5MWIID6ZVO3KKQFWDQDZNVFHZ6DNK5QCBXJ4UAC 5KJCHLIUFKRPMIVWUAYT6EOF7SW4PTQF6Y5OPEFWXGLE7DUGYLZAC 5V47S4NNTHWTSAHV3YLO2VGH7JTUIYJ3GBPDN5ZM4UQALT2ZEXDQC DTO3EUKWHZ5RJNGNCFYXSOVTIPVXPP637F2W7WFGYKJ7JK7VNKNQC HJV7BZBM752K5I47ILBQJJXSPODBBLGKDX5DWJTRDXPJ3V7AEVWAC OP6CTAKWCAU64JXQ3USQYR5E5IFHQHNCACII5UMVRXUTZXJQOAZAC ILOED4VB4I6VPAUTR75ZWX6MXDYXB5DO2EDK2UH67O3HNKWV23RQC L6O4LGZRKBURVWEY7XRVCSQLJ5RULNBEWMQJ6I2UYVWWB66FM3MQC GQL5SIGBHLU3FMCE54XVGLRY5AZHRM6DUEB722REA2DPLGJSN6EQC VVEULZ7FMS53F6WZUJLNJ23URJMCCWHBUEDVGKI6R72JO2DLL5HQC case TRAP_NET:{if (one_chance_in(3)){if (trapKnown){simple_monster_message(monster," fails to trigger a net trap.");}return;}if (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);}}trap_item( OBJ_MISSILES, MI_THROWING_NET,env.trap[which_trap].x, env.trap[which_trap].y );grd[env.trap[which_trap].x][env.trap[which_trap].y] = DNGN_FLOOR;env.trap[which_trap].type = TRAP_UNASSIGNED;break;}
if (mitm[net].base_type == OBJ_MISSILES&& mitm[net].sub_type == MI_THROWING_NET){break;}}dec_mitm_item_quantity( net, 1 );if (see_grid(monster->x, monster->y)){if (player_monster_visible(monster)){mprf("The net rips apart, and %s comes free!",monster->name(DESC_NOCAP_THE).c_str());}else{mpr("All of a sudden the net rips apart!");}}}elsemonster->add_ench(ENCH_CAUGHT);}
// monsters caught in a net try to get away// this is only urgent if you are aroundif (!finalAnswer && monsterNearby && mons_is_caught(monster)&& one_chance_in(3)){if (ms_quick_get_away( monster, hspell_pass[6])){spell_cast = hspell_pass[6];finalAnswer = true;}else if (ms_quick_get_away( monster, hspell_pass[5])){spell_cast = hspell_pass[5];finalAnswer = true;}}
if (mons_is_confused( monster )|| (monster->type == MONS_AIR_ELEMENTAL&& monster->has_ench(ENCH_SUBMERGED))){std::vector<coord_def> moves;
if (mons_is_confused( monster )|| (monster->type == MONS_AIR_ELEMENTAL&& monster->has_ench(ENCH_SUBMERGED))){std::vector<coord_def> moves;
int pfound = 0;for (int yi = -1; yi <= 1; ++yi){for (int xi = -1; xi <= 1; ++xi){coord_def c = monster->pos() + coord_def(xi, yi);if (in_bounds(c) && !grid_is_solid(grd(c))&& one_chance_in(++pfound)){mmov_x = xi;mmov_y = yi;}}}
int pfound = 0;for (int yi = -1; yi <= 1; ++yi){for (int xi = -1; xi <= 1; ++xi){coord_def c = monster->pos() + coord_def(xi, yi);if (in_bounds(c) && !grid_is_solid(grd(c))&& one_chance_in(++pfound)){mmov_x = xi;mmov_y = yi;}}}
// bounds check: don't let confused monsters try to run// off the mapif (monster->x + mmov_x < 0|| monster->x + mmov_x >= GXM){mmov_x = 0;}
// bounds check: don't let confused monsters try to run// off the mapif (monster->x + mmov_x < 0|| monster->x + mmov_x >= GXM){mmov_x = 0;}
if (mgrd[monster->x + mmov_x][monster->y + mmov_y] != NON_MONSTER&& (mmov_x != 0 || mmov_y != 0)){monsters_fight(i,mgrd[monster->x + mmov_x][monster->y + mmov_y]);
if (mgrd[monster->x + mmov_x][monster->y + mmov_y] != NON_MONSTER&& (mmov_x != 0 || mmov_y != 0)){monsters_fight(i,mgrd[monster->x + mmov_x][monster->y + mmov_y]);
brkk = true;mmov_x = 0;mmov_y = 0;}}if (brkk)continue;
brkk = true;mmov_x = 0;mmov_y = 0;}}
// figure out if they fightif (monsters_fight(i, targmon))
// see if we move into (and fight) an unfriendly monsterint targmon = mgrd[monster->x + mmov_x][monster->y + mmov_y];if (targmon != NON_MONSTER&& targmon != i&& !mons_aligned(i, targmon))
monster->behaviour = BEH_WANDER;monster->target_x = 10 + random2(GXM - 10);monster->target_y = 10 + random2(GYM - 10);// monster->speed_increment -= monster->speed;
if (testbits(monster->flags, MF_BATTY)){monster->behaviour = BEH_WANDER;monster->target_x = 10 + random2(GXM - 10);monster->target_y = 10 + random2(GYM - 10);// monster->speed_increment -= monster->speed;}mmov_x = 0;mmov_y = 0;brkk = true;
if (monster->x + mmov_x == you.x_pos&& monster->y + mmov_y == you.y_pos){bool isFriendly = mons_friendly(monster);bool attacked = false;if (!isFriendly)
if (monster->x + mmov_x == you.x_pos&& monster->y + mmov_y == you.y_pos)
monster->behaviour = BEH_WANDER;monster->target_x = 10 + random2(GXM - 10);monster->target_y = 10 + random2(GYM - 10);
monster_attack(i);attacked = true;if (testbits(monster->flags, MF_BATTY)){monster->behaviour = BEH_WANDER;monster->target_x = 10 + random2(GXM - 10);monster->target_y = 10 + random2(GYM - 10);}
// detach monster from the grid first, so it// doesn't get hit by its own explosion (GDL)mgrd[monster->x][monster->y] = NON_MONSTER;
// detach monster from the grid first, so it// doesn't get hit by its own explosion (GDL)mgrd[monster->x][monster->y] = NON_MONSTER;
else if (monster->has_ench(ENCH_CAUGHT)){if (mons_friendly(monster)){switch(random2(8)){case 0:strcat(info, " says, \"Help me, ");strcat(info, you.your_name);strcat(info, ", please!\"");break;case 1:strcat(info, " cries, \"MUMMY!\"");break;case 2:strcat(info, " shouts, \"");strcat(info, you.your_name);strcat(info, "! Can't you see I need your help?\"");break;case 3:strcat(info, " shouts, \"I could do with a little help here, you know.\"");break;case 4:strcat(info, " mumbles something.");break;case 5:strcat(info, " says, \"Umm, ");strcat(info, you.your_name);strcat(info, "? Help?\"");break;case 6:strcat(info, " cries.");break;case 7:strcat(info, " cries, \"Why me?");break;}}else // unfriendly monsters{switch(random2(12)){case 0:strcat(info, " screams, \"HEY! This isn't fair!\"");break;case 1:strcat(info, " screams, \"Help! Get me out of here!\"");break;case 2:strcat(info, " begs, \"Could you help me? I swear I won't hurt you.\"");break;case 3:strcat(info, " yells, \"LEMME GO!\"");break;case 4:strcat(info, " cries, \"Please! I'll never do it again!\"");break;case 5:strcat(info, " mutters, \"Just what did I do to deserve this?\"");break;case 6:strcat(info, " asks, \"Hey, want to switch places?\"");break;case 7:strcat(info, " cries, \"I hate you!\"");break;case 8:strcat(info, " snarls, \"This is all your fault!\"");break;case 9:strcat(info, " says, \"I meant to do this, just so you know.\"");break;case 10:strcat(info, " shouts, \"This is all a huge misunderstanding!");break;case 11:strcat(info, " cries, \"Why me?\"");break;}}}
case ENCH_CAUGHT:{if (mons_is_paralysed(this) || this->behaviour == BEH_SLEEP)break;int net, next;for (net = igrd[x][y]; net != NON_ITEM; net = next){next = mitm[net].link;if (mitm[net].base_type == OBJ_MISSILES&& mitm[net].sub_type == MI_THROWING_NET){break;}}if (net == NON_ITEM) // really shouldn't happen!{del_ench(ENCH_CAUGHT);break;}
// handled in handle_pickupif (mons_itemuse(type) == MONUSE_EATS_ITEMS)break;// the enchantment doubles as the durability of a net// the more corroded it gets, the more easily it will breakint hold = mitm[net].plus; // this will usually be negativeint mon_size = body_size(PSIZE_BODY);// smaller monsters can escape more quicklyif (mon_size < random2(SIZE_BIG) // BIG = 5&& !has_ench(ENCH_BERSERK)){if (mons_near(this) && !player_monster_visible(this))mpr("Something wriggles in the net.");elsesimple_monster_message(this, " struggles to escape the net.");// confused monsters have trouble finding the exitif (has_ench(ENCH_CONFUSION) && !one_chance_in(5))break;decay_enchantment(me, 2*(NUM_SIZE_LEVELS - mon_size) - hold);// frayed nets are easier to escapeif (mon_size <= -(hold-1)/2)decay_enchantment(me, (NUM_SIZE_LEVELS - mon_size));}else // large (and above) monsters always thrash the net and destroy it{ // e.g. ogre, large zombie (large); centaur, nage, hydra (big)if (mons_near(this) && !player_monster_visible(this))mpr("Something wriggles in the net.");elsesimple_monster_message(this, " struggles against the net.");// confused monsters more likely to struggle without resultif (has_ench(ENCH_CONFUSION) && one_chance_in(3))break;// nets get destroyed more quickly for larger monsters// and if already strongly frayedint damage = 0;// tiny: 1/6, little: 2/5, small: 3/4, medium and above: alwaysif (random2(SIZE_GIANT - mon_size) <= mon_size)damage++;// extra damage for large (50%) and big (always)if (mon_size == SIZE_BIG || mon_size == SIZE_LARGE && coinflip())damage++;// overall damage per struggle:// tiny -> 1/6// little -> 2/5// small -> 3/4// medium -> 1// large -> 1,5// big -> 2// extra damage if already damagedif (random2(body_size(PSIZE_BODY) - hold + 1) >= 4)damage++;// berserking doubles damage dealtif (has_ench(ENCH_BERSERK))damage *= 2;mitm[net].plus -= damage;if (mitm[net].plus < -7){if (mons_near(this)){if (player_monster_visible(this)){mprf("The net rips apart, and %s comes free!",name(DESC_NOCAP_THE).c_str());}else{mpr("All of a sudden the net rips apart!");}}dec_mitm_item_quantity( net, 1 );del_ench(ENCH_CAUGHT, true);}}break;}
if (mon->type == MONS_FIRE_VORTEX || mon->type == MONS_SPATIAL_VORTEX)return;if (!mons_is_caught(mon) && mon->add_ench(ENCH_CAUGHT)){if (mons_near(mon) && !player_monster_visible(mon))mpr("Something gets caught in the net!");elsesimple_monster_message(mon, " is caught in the net!");}}void player_caught_in_net(){if (you.body_size(PSIZE_BODY) >= SIZE_GIANT)return;if (!you.attribute[ATTR_CAUGHT]){you.attribute[ATTR_CAUGHT] = 10;mpr("You become entangled in the net!");}}
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){mpr("A net drops to the ground!");}else{mpr("A large net falls onto you!");player_caught_in_net();}
// attempts to take a net off a given monster// Do not expect gratitude for this!// ----------------------------------void remove_net_from(monsters *mon){you.turn_is_over = true;int net, next;for (net = igrd[mon->x][mon->y]; net != NON_ITEM; net = next){next = mitm[net].link;if (mitm[net].base_type == OBJ_MISSILES&& mitm[net].sub_type == MI_THROWING_NET){break;}}if (net == NON_ITEM){mon->del_ench(ENCH_CAUGHT, true);return;}// factor in whether monster is paralysed or invisibleint paralys = 0;if (mons_is_paralysed(mon)) // makes this easierparalys = random2(5);int invis = 0;if (!player_monster_visible(mon)) // makes this harderinvis = 3 + random2(5);
bool net_destroyed = false;if ( random2(you.skills[SK_TRAPS_DOORS] + 2) + paralys<= random2( 2*mon->body_size(PSIZE_BODY) + 3 ) + invis){if (one_chance_in(you.skills[SK_TRAPS_DOORS] + you.dex/2)){mitm[net].plus--;mpr("You tear at the net.");if (mitm[net].plus < -7){mpr("Whoops! The net comes apart in your hands!");net_destroyed = true;dec_mitm_item_quantity( net, 1 );mon->del_ench(ENCH_CAUGHT, true);}}if (!net_destroyed){if (player_monster_visible(mon)){mprf("You fail to remove the net from %s.",mon->name(DESC_NOCAP_THE).c_str());}elsempr("You fail to remove the net.");}if (random2(you.dex) > 5 + random2( 2*mon->body_size(PSIZE_BODY) ))exercise(SK_TRAPS_DOORS, 1 + random2(mon->body_size(PSIZE_BODY)/2));return;}mon->del_ench(ENCH_CAUGHT, true);if (player_monster_visible(mon))mprf("You free %s.", mon->name(DESC_NOCAP_THE).c_str());elsempr("You loosen the net.");}void free_self_from_net(bool damage_net){int net, next;for (net = igrd[you.x_pos][you.y_pos]; net != NON_ITEM; net = next){next = mitm[net].link;if (mitm[net].base_type == OBJ_MISSILES&& mitm[net].sub_type == MI_THROWING_NET){break;}}if (net == NON_ITEM) // really shouldn't happen!{you.attribute[ATTR_CAUGHT] = 0;return;}int hold = mitm[net].plus;if (damage_net){mpr("You struggle against the net.");int damage = 1;// extra damage for cutting weaponsif (you.equip[EQ_WEAPON] != -1&& can_cut_meat(you.inv[you.equip[EQ_WEAPON]])){damage++;}if (you.body_size(PSIZE_BODY) > SIZE_MEDIUM)damage++;if (hold < 0 && !one_chance_in(-hold/2))damage++;if (you.duration[DUR_BERSERKER])damage *= 2;mitm[net].plus -= damage;if (mitm[net].plus < -7){mpr("You rip the net and break free!");dec_mitm_item_quantity( net, 1 );you.attribute[ATTR_CAUGHT] = 0;return;}}else // you try to escape{mpr("You struggle to escape from the net.");you.attribute[ATTR_CAUGHT]--;if (you.body_size(PSIZE_BODY) < SIZE_MEDIUM)you.attribute[ATTR_CAUGHT]--;if (hold < 0 && !one_chance_in(-hold/2))you.attribute[ATTR_CAUGHT]--;if (you.attribute[ATTR_CAUGHT] <= 0){mpr("You break free from the net!");you.attribute[ATTR_CAUGHT] = 0;return;}}}
case MI_THROWING_NET:// Nets use throwing and T&D skills// They don't do any damage!baseDam = 0;exDamBonus = 0;// but accuracy is important for this onebaseHit = 1;exHitBonus += (skill_bump(SK_RANGED_COMBAT) * 7 / 2);// Adjust for strength and dex.exHitBonus = dex_adjust_thrown_tohit(exHitBonus);// Nets train throwingexercise(SK_RANGED_COMBAT, 1);break;
case MI_THROWING_NET:description += "A throwing net as used by gladiators. ";if (!is_throwable(item, you.body_size()))description += "Unfortunately, it is too large for you to throw. ";if (item.plus < 0){std::string how;if (item.plus > -3)how = "a little";else if (item.plus > -5)how = "somewhat";else if (item.plus > -7)how = "very";elsehow = "extremely";description += "It looks ";description += how;description += " worn.";}else if (item.plus > 1)description += "The net looks brand-new!";break;