(new Xom effects), tweaked to fit into current trunk.
FM4LIPXOMA65AXD33QNNRVMURTVCLGB7NCQYYS6I3DPOZFIKN4XQC VFS5GS5BT64LETFFNKKZRHRT4EX6L3DYQD4QQKSBOKO4NHW4K6BQC HP72STXEK6KJ5SAPZKKLLAXC5HB7J4E6X6NK2BNFP6GARF52K5RQC LZN527GR3AULRHWIBA537RR4WSCNNYY4XSEZ6VFF7TKGYSUSBOCAC UWYK2M6I6P6EFAVHLWQGDK77STFO3SPO5SVOF5WZTOKUH2O6BBHQC 5BJPWUPLJFS34FUTFJVKA4A52YMIGV6EWDXLNSDCWBJWBGVSQFGQC IFYZSFWJRTV6JM46H6U4CMTQX46VT562EAM64Y6UYU3F6RDWRRYQC TYAUNNAVB4GEKXYSR447JXRDKRJJZHAVV7XLWGU7RXEP5JMJCQKAC QK7YLIH7SWBSL3OEBQJYVFNTW4XT5FF6U3GPKW7PEGHBLPV3TVQAC TPJYUAKSEZMCCCJANJ5EQ7F67QVTPFEOWBD7WYK33NLRN657Y5VQC KFULGQQOHWUTXOM3BXCCYPGGVGGY4Z6265XUFRCBPNLTZAEHJZSQC GYOKKBVTZ6HRW2NYC3EMGSB6ULBX24L5DLDZNEP2F6UTA4KPU3CAC HCVH2CWL32UD66O6Z7ZYDUASWN3RF5TW6FSWURGMD7MELKB772FAC SJJMO4TFG3QO46SLHUFSUYXXVZJDULVYTU4RTCM7TQPIGHZTWBDAC 542WW2UJM6XF22442ZD5NFMTS6HTDM74JKJ7GQHBLQ3D6C6T4C3AC GP7RUHLNB4KISSZAENEYVNY3MB5YRCFRWRWYAROBZIQ5MR4DXB7QC V25XPIUUPVMKRK663D33PWE3GFQR47XZAV642T2NYGRFWZR5LT6AC ZF6STV5NEMEP5O5S6QO52R2CS5JEAGUQA5OKSBI2BIWF3OLZP4CQC XYQFJLTMLSU7LC7VODUJVN5F2P47STH2KVSP7Q3BSCUUDRHROW7QC NYURIMPCM2RADLMIQSN76OPKXQSK4XBLFNXD2OO53KGZI3MA6AQAC LUD5XPFLSYPJOYZG6DDV4C5WIQUGZPE7YV6AR75ENCAIISD3LZWQC WPWQO7BWPJHMAWU7FUJE5VZDZV66365DLBLLK64T557E7NDEMKXQC IQGGFC563RBS7GDOACKCLXK752EE5RC3T6G5L6H446SXTMSA7T2AC 5UERXKWLQVLPKE6LN74XZ6V6NGZ3RL3RE22O4MH3ID7IQQ27YWPAC BERPOHVI3K3SUE6M4MJVDSJVJ7Q4LWGRZ3SM2AZENUZJLRC2AP3AC TPO6FNMPNUSWH4NCKO3VLYNAADEPSAXLUITCCACLZZSY53PKA62QC 43XCHFXZ34FDVT2QG23RZ65V6NRBY6PE3ENQEEDXFYKRR7IRFHCAC FWNNTOEERPUKXPE4OC52UABFZLKIU3O5GRNNLDK4QI4HR2IOU36QC JYEEOUYQ7ZPKOGWUV7VCORBVSOLF2UCBFBH3TR75RGOSS6PNKYUAC 45CWQUPQHKUFUJ4MVL5K3KCVCCKLY2Z7RZWZ53UT723RV5STPSRAC H2OHWQKMHL66CPVJGJL35RY7EIZB74SZTGOLDJDSCG5WVEVPIIUAC 7GCM5WFIKX5N2PQ5UCVNMFJEKTZTBCUVZH5RZ7CPDL3Z6GB26KAQC 64HB7VYSYHQEN5UP7OYJ5GSVA2XMDSLLH647UPWE5NSFF3AVZSSQC 22YVHM74WBJNJE4PA5CBEUTDWM6FAGGGILI26A4LXAURX55TNRKAC VO5CYD7Z4FYFDT6DGVBX6RT3PHLRSUJA6TWV3GPYVE7QCSJ3JEAAC HGBHRHXFVTEWYYV2D5HKTKL4Z6OSNR2ZOIHFQX55CVRCXQUQ7MQAC 2HG3XZSSPWPPEAPBGO7PBXSJOGJWXIU6UIGEWZZAG54OMM5HQXUQC LEZWYG752CKY6URMLSQTOADDRAJ5NTT7KH7BC5ENGQ55GXKHQMWQC CDEJUVHMOT2SRPKWBB5IUPAXPGX6TUTGRBFLSPTR4XNZABDLSNUQC PUY2VWZJ3G7HNCLIHZP5VGT2DAGHI436ETDJQTPEBFPRSEHOM2NQC ZYXDNELXBXZ6F5EVS5R6CTR4SIZ6G2RX6DKGHAZYTKPO6XJCZYRAC 7TC5S2NB46NFPXQKVXUYA26DZ2OE42WWE7RUSBJHXQPUGAWHIFMAC T6O6AMWRWJE6EQWGKWJRHQG7X2V7XRWS5WZOQIMWUD6TPLHUGPBAC PHBACPMH3F34GODHVDKNCMXWU373RJQGVTDLBFCCDLLWDXVYOLTAC BAQJ26USF7KRR6ALYPXUPUFOYLNGBQVQOS53JXJJWZKDVREHFL2QC KO7PZNWIRLSAPOXUHK7U446ZXT562QCPIT3AYFYKPG7OWRLNBU4QC 5CPP63H7WJ3GLSHJM4Z2YSU2NISLVESEJ3OYMO4MFZEXVOCV4NIAC FAVME2A2U4OUKN2BTISAG5PCI5Y4BN6YVFKCSQQHHZLEVVVF4LKAC BMXIXQKM2247TENYZSOULFAT6VSZJNGGFBQ3SN7IOM4ROQRVTHZAC TRBDS4IKHBASW2CTAQ2YHMBMBMRB6QEBQ4ZE7GRSR3U2VJXA7TJQC FYSQ7HXDIKXZXDGYVKZMODW7HYQQLRZO52Q2HVM3PYBD37UT5B4AC 5MGUZD2UACJCSG74TEZHI3Z4YL5KL6ZVUCQ3XVZKDOLKM7EMGWJAC IWYUUMWDNSGRNR7CJDMJQJHQ6T4UTTGX6X5DQMQ4LH7CZUODDQPQC IBV5MNXWCCOWCI7DPVTPFEEMLX7QWP75EP6YQ3RA2WJOKWSGMPSQC AVEOSLDREJHWFZE6ULAWGQPDT24YX4OAOGL7YAUCFVRGHCS22UCAC A54S2WRWNIV4Y4XB5JHR7NALLB55ZCX3Z5DSGBMAVGVY6I7KY2GAC RDOOG5LBE5TCTFYCKJIB7TGGTRFX4HBLMJZYXS5TCFWNCU3QII5QC ERS7DYNAVCC7QUVG5FXJJRONYESLZU22CQGKCA5HLLLG6DMXYRLQC 2NVJIPJ5NMHUI2J4WOR6KE4XZOCJIVWHQK4M2M6KG7PL24PGBDGAC 2U7MKFVTHEPKDLBYR4X6GINIEIBG5B3YR3INX36ITGP7MEPTR3VQC BQ5QKUWLCYSBO4A7EWZN4FXPNSIAR6JPBAZE4PSV6XCUNTV53ERQC QNSFZBLVAN7BPYYRXUELHBZCLIQTYDATDIXF3YVH7LBBST66VUCQC W5VEC2PBIM5DMU5233HOWAZUEPTGWJRZZIA3H35YYQQW6BTP6XUAC QLIDDODO7Q7S2UTKVR2SMRMEAXHRPA5C7SU267EQGV6VJ7UXW5JQC SDLKLUNFGVKDS55DDJZCBAVIB7NL3RRYPTACAY65SCUQKV6APFSAC TGJZXTUIAKCFZQJ54ZQEBGFBVZSJCAX6AWDRSH3TP7UJRLGUM5SAC UPA65AL4JXYLIHH4D42IWJHRTOAF2BPOVZOAKOXBLZBYIMDZDFFQC K2CS6TCX2NDVL2ASEHGP4J4K4IJ6FP3ANNKTSIWVG43HPYSBX6ZQC EFWEYIB2R3DPD3JWIPU6LS6SFLPMYN7J7X4GBZR7DJWKHJ3UELSAC JVWWN7BKTLALZ3VIKCFC45EUJ7CC5MLMH2ZOGOTNRF7FLWJGSMQAC ESWIM76FGJL4QFLSHU6AC4D74PT7OPLQ7ZCJYWLZS5UCBAJDXYHAC O6ZMFKDI3XO2SWPNEYHIPYFDWJR4TVDP5BAATK6LVCVETQID6E7AC RPOZZWKG5GLPHVZZ7ZKMKS64ZMV2LDCQSARBJFJ6FZOTOKCQO7FAC SIDH2P7NBIG5KEOE27XHD3ZT2NQ2OJZFN6VZXWNWYFFY5YVXSSVQC RX6575DZOHRUXQUZH34YZGPZJF4STUPLBQDIVTINA2L6LVCKRIGQC NMZFCCM6O3KO2GJWKOSULN27B3QIZKWPBOB62PAILXMRQD4JMIMAC BINKDWGFGUPTOA7IE5KK4ZIELGU5WC3X47MYXOWU4X43EGAC5DUAC U2CE3EGQNU6WJMRSUMVRLWPY5Q32VAE2ESTQARJQHJAG4EIHOJCQC DWWOM6V2Z4RQVT6AKW6OYLSFOUE4W5PTP2SH4AAZE2E4EIH4RLUAC };enum xom_event_type{XOM_DID_NOTHING = 0,// good actsXOM_GOOD_POTION,XOM_GOOD_SPELL_TENSION,XOM_GOOD_SPELL_CALM,XOM_GOOD_MAPPING,XOM_GOOD_CONFUSION, // 5XOM_GOOD_SINGLE_ALLY,XOM_GOOD_ANIMATE_MON_WPN,XOM_GOOD_ANNOYANCE_GIFT,XOM_GOOD_RANDOM_ITEM,XOM_GOOD_ACQUIREMENT, // 10XOM_GOOD_ALLIES,XOM_GOOD_POLYMORPH,XOM_GOOD_SWAP_MONSTERS,XOM_GOOD_TELEPORT,XOM_GOOD_VITRIFY, // 15XOM_GOOD_MUTATION,XOM_GOOD_MAJOR_ALLY,XOM_GOOD_LIGHTNING,XOM_GOOD_SCENERY,XOM_LAST_GOOD_ACT = XOM_GOOD_SCENERY, // 19// bad actsXOM_BAD_MISCAST_PSEUDO, // 20XOM_BAD_MISCAST_MINOR,XOM_BAD_MISCAST_MAJOR,XOM_BAD_MISCAST_NASTY,XOM_BAD_STATLOSS,XOM_BAD_TELEPORT, // 25XOM_BAD_SWAP_WEAPONS,XOM_BAD_CHAOS_UPGRADE,XOM_BAD_MUTATION,XOM_BAD_POLYMORPH,XOM_BAD_STAIRS, // 30XOM_BAD_CONFUSION,XOM_BAD_DRAINING,XOM_BAD_TORMENT,XOM_BAD_ANIMATE_WPN,XOM_BAD_SUMMON_DEMONS, // 35XOM_BAD_BANISHMENT,XOM_LAST_BAD_ACT = XOM_BAD_BANISHMENT, // 36XOM_PLAYER_DEAD = 100, // player already dead (shouldn't happen)NUM_XOM_EVENTS
#endif
static const char *describe_xom_mood(){return (you.piety > 180) ? "Xom's teddy bear." :(you.piety > 150) ? "a beloved toy of Xom." :(you.piety > 120) ? "a favourite toy of Xom." :(you.piety > 80) ? "a toy of Xom." :(you.piety > 50) ? "a plaything of Xom." :(you.piety > 20) ? "a special plaything of Xom.": "a very special plaything of Xom.";}
{favour = (you.piety > 180) ? "Xom's teddy bear." :(you.piety > 150) ? "a beloved toy of Xom." :(you.piety > 120) ? "a favourite toy of Xom." :(you.piety > 80) ? "a toy of Xom." :(you.piety > 50) ? "a plaything of Xom." :(you.piety > 20) ? "a special plaything of Xom.": "a very special plaything of Xom.";}
favour = describe_xom_mood();
return (false);}static bool _xom_give_item(int power){if (_xom_annoyance_gift(power))return (true);
god_speaks(GOD_XOM, _get_xom_speech("general gift").c_str());
return (false);}static int _xom_give_item(int power, bool debug = false){if (_xom_annoyance_gift(power, debug))return (XOM_GOOD_ANNOYANCE_GIFT);if (!debug)god_speaks(GOD_XOM, _get_xom_speech("general gift").c_str());
static bool _art_is_safe(item_def item){int prop_str = artefact_wpn_property(item, ARTP_STRENGTH);int prop_int = artefact_wpn_property(item, ARTP_INTELLIGENCE);int prop_dex = artefact_wpn_property(item, ARTP_DEXTERITY);return (prop_str >= 0 && prop_int >= 0 && prop_dex >= 0);}static int _xom_swap_weapons(bool debug = false){if (player_stair_delay())return (XOM_DID_NOTHING);item_def *wpn = you.weapon();if (!wpn)return (XOM_DID_NOTHING);if (you.duration[DUR_BERSERKER]|| wpn->base_type != OBJ_WEAPONS|| get_weapon_brand(*wpn) == SPWPN_DISTORTION|| !safe_to_remove_or_wear(*wpn, true, true)){return (XOM_DID_NOTHING);}std::vector<monsters *> mons_wpn;for (unsigned i = 0; i < MAX_MONSTERS; ++i){monsters* m = &menv[i];if (!m->alive())continue;if (!see_grid(m->pos()))continue;if (!wpn || mons_wont_attack(m) || mons_is_summoned(m)|| mons_itemuse(m) < MONUSE_STARTING_EQUIPMENT|| (m->flags & MF_HARD_RESET)){continue;}const int mweap = m->inv[MSLOT_WEAPON];if (mweap == NON_ITEM)continue;const item_def weapon = mitm[mweap];// Let's be nice about this.if (weapon.base_type == OBJ_WEAPONS&& !(weapon.flags & ISFLAG_SUMMONED)&& you.can_wield(weapon, true) && m->can_wield(*wpn, true)&& !get_weapon_brand(weapon) != SPWPN_DISTORTION&& (!is_artefact(weapon) || _art_is_safe(weapon))){mons_wpn.push_back(m);}}if (mons_wpn.empty())return (XOM_DID_NOTHING);if (debug)return (XOM_BAD_SWAP_WEAPONS);god_speaks(GOD_XOM, _get_xom_speech("swap weapons").c_str());const int num_mons = mons_wpn.size();// Pick a random monster...monsters *mon = mons_wpn[random2(num_mons)];// ...and get its weapon.int monwpn = mon->inv[MSLOT_WEAPON];int mywpn = you.equip[EQ_WEAPON];ASSERT (monwpn != NON_ITEM);ASSERT (mywpn != -1);unwield_item();item_def &myweapon = you.inv[mywpn];int index = get_item_slot(10);if (index == NON_ITEM)return (XOM_DID_NOTHING);// Move monster's old item to player's inventory as last step.mon->unequip(*(mon->mslot_item(MSLOT_WEAPON)), MSLOT_WEAPON, 0, true);mon->inv[MSLOT_WEAPON] = NON_ITEM;mitm[index] = myweapon;unwind_var<int> save_speedinc(mon->speed_increment);if (!mon->pickup_item(mitm[index], false, true)){mpr("Monster wouldn't take item.", MSGCH_ERROR);mon->inv[MSLOT_WEAPON] = monwpn;mon->equip(mitm[monwpn], MSLOT_WEAPON, 0);unlink_item(index);destroy_item(myweapon);return (XOM_DID_NOTHING);}// Mark the weapon as thrown, so that we'll autograb it once the// monster is dead.mitm[index].flags |= ISFLAG_THROWN;mprf("%s wields %s!",mon->name(DESC_CAP_THE).c_str(),myweapon.name(DESC_NOCAP_YOUR).c_str());mon->equip(myweapon, MSLOT_WEAPON, 0);// Item is gone from player's inventory.dec_inv_item_quantity(mywpn, myweapon.quantity);mitm[monwpn].pos.reset();mitm[monwpn].link = NON_ITEM;int freeslot = find_free_slot(mitm[monwpn]);if (freeslot < 0 || freeslot >= ENDOFPACK|| is_valid_item(you.inv[freeslot])){// Something is terribly wrong.return (XOM_DID_NOTHING);}item_def &myitem = you.inv[freeslot];// Copy item.myitem = mitm[monwpn];myitem.link = freeslot;myitem.pos.set(-1, -1);// Remove "dropped by ally" flag.myitem.flags &= ~(ISFLAG_DROPPED_BY_ALLY);if (!myitem.slot)myitem.slot = index_to_letter(myitem.link);origin_set_monster(myitem, mon);note_inscribe_item(myitem);dec_mitm_item_quantity(monwpn, myitem.quantity);you.m_quiver->on_inv_quantity_changed(freeslot, myitem.quantity);burden_change();mprf("You wield %s %s!",mon->name(DESC_NOCAP_ITS).c_str(),you.inv[freeslot].name(DESC_PLAIN).c_str());you.equip[EQ_WEAPON] = freeslot;wield_effects(freeslot, true);you.wield_change = true;you.m_quiver->on_weapon_changed();return (XOM_BAD_SWAP_WEAPONS);}
return (true);
if (mons_wont_attack(m) || mons_is_summoned(m)|| mons_itemuse(m) < MONUSE_STARTING_EQUIPMENT|| (m->flags & MF_HARD_RESET)){continue;}const int mweap = m->inv[MSLOT_WEAPON];if (mweap == NON_ITEM)continue;const item_def weapon = mitm[mweap];if (weapon.base_type == OBJ_WEAPONS&& !(weapon.flags & ISFLAG_SUMMONED)&& weapon.quantity == 1&& !is_range_weapon(weapon)&& !is_special_unrandom_artefact(weapon)&& !get_weapon_brand(weapon) != SPWPN_DISTORTION){mons_wpn.push_back(m);}}if (mons_wpn.empty())return (XOM_DID_NOTHING);if (debug)return (XOM_GOOD_ANIMATE_MON_WPN);god_speaks(GOD_XOM, _get_xom_speech("animate monster weapon").c_str());const int num_mons = mons_wpn.size();// Pick a random monster...monsters *mon = mons_wpn[random2(num_mons)];// ...and get its weapon.const int wpn = mon->inv[MSLOT_WEAPON];ASSERT(wpn != NON_ITEM);const int dur = std::min(2 + (random2(sever) / 5), 6);const int monster = create_monster(mgen_data(MONS_DANCING_WEAPON, BEH_FRIENDLY,dur, SPELL_TUKIMAS_DANCE,mon->pos(), mon->mindex(), 0, GOD_XOM));if (monster == -1)return (XOM_DID_NOTHING);// Make the monster unwield its weapon.mon->unequip(*(mon->mslot_item(MSLOT_WEAPON)), MSLOT_WEAPON, 0, true);mon->inv[MSLOT_WEAPON] = NON_ITEM;mprf("%s %s dances into the air!",apostrophise(mon->name(DESC_CAP_THE)).c_str(),mitm[wpn].name(DESC_PLAIN).c_str());destroy_item(menv[monster].inv[MSLOT_WEAPON]);menv[monster].inv[MSLOT_WEAPON] = wpn;mitm[wpn].set_holding_monster(monster);menv[monster].colour = mitm[wpn].colour;return (XOM_GOOD_ANIMATE_MON_WPN);
return (true);
return (XOM_GOOD_LIGHTNING);}static int _xom_change_scenery(bool debug = false){std::vector<coord_def> candidates;for (radius_iterator ri(you.pos(), LOS_RADIUS, false, true); ri; ++ri){if (!in_bounds(*ri) || !see_grid(*ri))continue;dungeon_feature_type feat = grd(*ri);if (feat >= DNGN_FOUNTAIN_BLUE && feat <= DNGN_DRY_FOUNTAIN_BLOOD)candidates.push_back(*ri);else if (feat >= DNGN_CLOSED_DOOR && feat <= DNGN_SECRET_DOOR|| feat == DNGN_OPEN_DOOR && you.pos() != *ri){candidates.push_back(*ri);}}const std::string speech = _get_xom_speech("scenery");if (candidates.empty()){if (!one_chance_in(8))return (XOM_DID_NOTHING);// Place one or more altars to Xom.coord_def place;bool success = false;const int max_altars = std::max(1, random2(random2(14)));for (int tries = max_altars; tries > 0; --tries){if ((random_near_space(you.pos(), place)|| random_near_space(you.pos(), place, true))&& grd(place) == DNGN_FLOOR && see_grid(place)){if (debug)return (XOM_GOOD_SCENERY);grd(place) = DNGN_ALTAR_XOM;success = true;}}if (success){god_speaks(GOD_XOM, speech.c_str());return (XOM_GOOD_SCENERY);}return (XOM_DID_NOTHING);}if (debug)return (XOM_GOOD_SCENERY);const int fountain_diff = (DNGN_DRY_FOUNTAIN_BLUE - DNGN_FOUNTAIN_BLUE);std::random_shuffle(candidates.begin(), candidates.end());int doors_open = 0;int doors_close = 0;int fountains_flow = 0;int fountains_blood = 0;for (unsigned int i = 0; i < candidates.size(); ++i){coord_def pos = candidates[i];switch (grd(pos)){case DNGN_CLOSED_DOOR:case DNGN_DETECTED_SECRET_DOOR:case DNGN_SECRET_DOOR:grd(pos) = DNGN_OPEN_DOOR;doors_open++;break;case DNGN_OPEN_DOOR:grd(pos) = DNGN_CLOSED_DOOR;doors_close++;break;case DNGN_DRY_FOUNTAIN_BLUE:case DNGN_DRY_FOUNTAIN_SPARKLING:case DNGN_DRY_FOUNTAIN_BLOOD:{if (x_chance_in_y(fountains_flow, 5))continue;grd(pos) = (dungeon_feature_type) (grd(pos) - fountain_diff);fountains_flow++;break;}case DNGN_FOUNTAIN_BLUE:if (x_chance_in_y(fountains_blood, 3))continue;grd(pos) = DNGN_FOUNTAIN_BLOOD;fountains_blood++;break;default:break;}}if (!doors_open && !doors_close && !fountains_flow && !fountains_blood)return (XOM_DID_NOTHING);god_speaks(GOD_XOM, speech.c_str());std::vector<std::string> effects;if (doors_open > 0){snprintf(info, INFO_SIZE, "%s door%s burst%s open",doors_open == 1 ? "A" :doors_open == 2 ? "Two": "Several",doors_open == 1 ? "" : "s",doors_open == 1 ? "s" : "");effects.push_back(info);}if (doors_close > 0){snprintf(info, INFO_SIZE, "%s%s door%s slam%s shut",doors_close == 1 ? "a" :doors_close == 2 ? "two": "several",doors_open > 0 ? (doors_close == 1 ? "nother" : " other"): "",doors_close == 1 ? "" : "s",doors_close == 1 ? "s" : "");std::string closed = info;if (effects.empty())closed = uppercase_first(closed);effects.push_back(closed);}if (!effects.empty()){mprf("%s!",comma_separated_line(effects.begin(), effects.end(),", and ").c_str());effects.clear();}if (fountains_flow > 0){snprintf(info, INFO_SIZE,"%s fountain%s start%s reflowing",fountains_flow == 1 ? "A" : "Some",fountains_flow == 1 ? "" : "s",fountains_flow == 1 ? "s" : "");effects.push_back(info);}if (fountains_blood > 0){snprintf(info, INFO_SIZE,"%s%s fountain%s start%s gushing blood",fountains_blood == 1 ? "a" : "some",fountains_flow > 0 ? (fountains_blood == 1 ? "nother": " other"): "",fountains_blood == 1 ? "" : "s",fountains_blood == 1 ? "s" : "");std::string fountains = info;if (effects.empty())fountains = uppercase_first(fountains);effects.push_back(fountains);}if (!effects.empty()){mprf("%s!",comma_separated_line(effects.begin(), effects.end(),", and ").c_str());}return (XOM_GOOD_SCENERY);
done = _xom_send_one_ally(sever);else if (x_chance_in_y(6, sever)){_xom_give_item(sever);done = true;}
done = _xom_send_one_ally(sever, debug);else if (tension < random2(5) && x_chance_in_y(6, sever))done = _xom_change_scenery(debug);else if (x_chance_in_y(7, sever))done = _xom_give_item(sever, debug);
else if (tension > random2(10) && x_chance_in_y(7, sever))done = _xom_send_allies(sever);else if (x_chance_in_y(8, sever))done = _xom_polymorph_nearby_monster(true);else if (tension > 0 && x_chance_in_y(9, sever))done = _xom_rearrange_pieces(sever);else if (random2(tension) < 15 && x_chance_in_y(10, sever)){_xom_give_item(sever);done = true;}else if (x_chance_in_y(11, sever) && you.level_type != LEVEL_ABYSS)
else if (tension > random2(10) && x_chance_in_y(8, sever))done = _xom_send_allies(sever, debug);else if (tension > random2(8) && x_chance_in_y(9, sever))done = _xom_animate_monster_weapon(sever, debug);else if (x_chance_in_y(10, sever))done = _xom_polymorph_nearby_monster(true, debug);else if (tension > 0 && x_chance_in_y(11, sever))done = _xom_rearrange_pieces(sever, debug);else if (random2(tension) < 15 && x_chance_in_y(12, sever))done = _xom_give_item(sever, debug);else if (x_chance_in_y(13, sever) && you.level_type != LEVEL_ABYSS)
else if (tension > random2(15) && x_chance_in_y(14, sever))done = _xom_send_major_ally(sever);else if (tension > 0 && x_chance_in_y(15, sever))done = _xom_throw_divine_lightning();
else if (tension > random2(15) && x_chance_in_y(16, sever))done = _xom_send_major_ally(sever, debug);else if (tension > 0 && x_chance_in_y(17, sever))done = _xom_throw_divine_lightning(debug);
const int level = random2(max_level + 1);
const int level = (nasty ? 1 + random2(max_level): random2(max_level + 1));if (debug){switch (level){case 0: return (XOM_BAD_MISCAST_PSEUDO);case 1: return (XOM_BAD_MISCAST_MINOR);case 2: return (XOM_BAD_MISCAST_MAJOR);case 3: return (XOM_BAD_MISCAST_NASTY);}}
{_xom_miscast(0, nasty);done = true;}
done = _xom_miscast(0, nasty, debug);
done = true;}else if (x_chance_in_y(8, sever)){done = _xom_chaos_upgrade_nearby_monster();badness = 2 + coinflip();}else if (random2(tension) < 10 && x_chance_in_y(9, sever)){done = _xom_give_mutations(false);badness = 3;
done = XOM_BAD_TELEPORT;
// It's pointless to confuse player if there's no danger nearby.else if (tension > 0 && x_chance_in_y(12, sever))
else if (random2(tension) < 11 && x_chance_in_y(13, sever))
god_speaks(GOD_XOM, _get_xom_speech("banishment").c_str());// handles note takingbanished(DNGN_ENTER_ABYSS, "Xom");badness = 5;done = true;
if (!debug){god_speaks(GOD_XOM, _get_xom_speech("banishment").c_str());// handles note takingbanished(DNGN_ENTER_ABYSS, "Xom");badness = 5;}done = XOM_BAD_BANISHMENT;
}#ifdef WIZARDstruct xom_effect_count{std::string effect;int count;xom_effect_count(std::string e, int c) : effect(e), count(c) {};};static bool _sort_xom_effects(const xom_effect_count &a,const xom_effect_count &b){if (a.count == b.count)return (a.effect < b.effect);return (a.count > b.count);}static const char* _xom_effect_to_name(int effect){ASSERT(effect < XOM_PLAYER_DEAD);// See xom.hstatic const char* _xom_effect_names[] ={"nothing",// good acts"potion", "spell (tension)", "spell (no tension)", "mapping","confuse monsters", "single ally", "animate monster weapon","annoyance gift", "random item gift", "acquirement", "summon allies","polymorph", "swap monsters", "teleportation", "vitrification","mutation", "permanent ally", "lightning", "change scenery",// bad acts"miscast (pseudo)", "miscast (minor)", "miscast (major)","miscast (nasty)", "stat loss", "teleportation", "swap weapons","chaos upgrade", "mutation", "polymorph", "repel stairs", "confusion","draining", "torment", "animate weapon", "summon demons", "banishment"};std::string result = "";if (effect > XOM_DID_NOTHING && effect < XOM_PLAYER_DEAD){if (effect <= XOM_LAST_GOOD_ACT)result = "GOOD: ";elseresult = "BAD: ";}result += _xom_effect_names[effect];return (result.c_str());}// Loops over the entire piety spectrum and calls xom_acts() multiple// times for each value, then prints the results into a file.// TODO: Allow specification of niceness, tension, boredness, and repeats.void debug_xom_effects(){// Repeat N times.const int N = 10;FILE *ostat = fopen("xom_debug.stat", "a");if (!ostat){mprf(MSGCH_ERROR, "Can't write 'xom_debug.stat'. Aborting.");return;}const int real_piety = you.piety;const god_type real_god = you.religion;you.religion = GOD_XOM;const int tension = get_tension(GOD_XOM);fprintf(ostat, "---- STARTING XOM DEBUG TESTING ----\n");fprintf(ostat, "%s\n", dump_overview_screen(false).c_str());fprintf(ostat, screenshot().c_str());fprintf(ostat, "\n%s\n", mpr_monster_list().c_str());fprintf(ostat, " --> Tension: %d\n", tension);if (you.penance[GOD_XOM])fprintf(ostat, "You are under Xom's penance!\n");else if (_xom_is_bored())fprintf(ostat, "Xom is BORED.\n");std::vector<int> mood_effects;std::vector<std::vector<int> > all_effects;std::vector<std::string> moods;std::vector<int> mood_good_acts;std::string old_mood = "";std::string mood = "";// Add an empty list to later add all effects to.all_effects.push_back(mood_effects);moods.push_back("total");mood_good_acts.push_back(0); // count total good actsint mood_good = 0;for (int p = 0; p <= MAX_PIETY; ++p){you.piety = p;int sever = abs(p - HALF_MAX_PIETY);mood = describe_xom_mood();if (old_mood != mood){if (old_mood != ""){all_effects.push_back(mood_effects);mood_effects.clear();mood_good_acts.push_back(mood_good);mood_good_acts[0] += mood_good;mood_good = 0;}moods.push_back(mood);old_mood = mood;}// Repeat N times.for (int i = 0; i < N; ++i){bool niceness = xom_is_nice(tension);int result = xom_acts(niceness, sever, tension, true);mood_effects.push_back(result);all_effects[0].push_back(result);if (result <= XOM_LAST_GOOD_ACT)mood_good++;}}all_effects.push_back(mood_effects);mood_effects.clear();mood_good_acts.push_back(mood_good);mood_good_acts[0] += mood_good;const int num_moods = moods.size();std::vector<xom_effect_count> xom_ec_pairs;for (int i = 0; i < num_moods; ++i){mood_effects = all_effects[i];const int total = mood_effects.size();if (i == 0)fprintf(ostat, "\nTotal effects (all piety ranges)\n");elsefprintf(ostat, "\nMood: You are %s\n", moods[i].c_str());fprintf(ostat, "GOOD%7.2f%%\n",(100.0 * (float) mood_good_acts[i] / (float) total));fprintf(ostat, "BAD %7.2f%%\n",(100.0 * (float) (total - mood_good_acts[i]) / (float) total));std::sort(mood_effects.begin(), mood_effects.end());xom_ec_pairs.clear();int old_effect = XOM_DID_NOTHING;int count = 0;for (int k = 0; k < total; ++k){if (mood_effects[k] != old_effect){if (count > 0){std::string name = _xom_effect_to_name(old_effect);xom_effect_count xec = xom_effect_count(name, count);xom_ec_pairs.push_back(xec);}old_effect = mood_effects[k];count = 1;}elsecount++;}if (count > 0){std::string name = _xom_effect_to_name(old_effect);xom_effect_count xec = xom_effect_count(name, count);xom_ec_pairs.push_back(xec);}std::sort(xom_ec_pairs.begin(), xom_ec_pairs.end(), _sort_xom_effects);for (unsigned int k = 0; k < xom_ec_pairs.size(); ++k){xom_effect_count xec = xom_ec_pairs[k];fprintf(ostat, "%7.2f%% %s\n",(100.0 * (float) xec.count / (float) total),xec.effect.c_str());}}fprintf(ostat, "---- FINISHED XOM DEBUG TESTING ----\n");fclose(ostat);mpr("Results written into 'xom_debug.stat'.");you.piety = real_piety;you.religion = real_god;
#endif