a random type (including enchantments, which isn't so good since they don't have a visible beam). Might want to add BEAM_CHAOS and make it a beam of that.
Weapons of chaos either does a random brand effect (fire, poison, etc) or a random chaos effect (which includes cloning the attack victim).
The AF_CHAOS monster attack flavour either does a random monster flavour or chaos effect (same chaos effects as for weapons).
The relative frequency of all the different effects/brands/flavours no doubt needs adjustment.
All of this is currently only available via Xom. 10% of all common-type demons sent in by Xom will be chaos spawn (the only kind that use AF_CHAOS, and never randomly generated otherwise). All item gifts from Xom which are generated with a brand will have their brand switched to chaos (this should probably be made to happen less than 100% of the time). And finally one of Xom's bad acts is to upgrade a non-branded weapon of a nearby hostile monster to a chaos brand (this might need to be made less (or more) common).
Oh, and if a randart has a brand which would be identified if it were merely an ego weapon, it now identifies the RAP_BRAND property of the randart.
git-svn-id: https://crawl-ref.svn.sourceforge.net/svnroot/crawl-ref/trunk@7704 c06c8d41-db1a-0410-9941-cceddc491573
JYEEOUYQ7ZPKOGWUV7VCORBVSOLF2UCBFBH3TR75RGOSS6PNKYUAC RCFS63VUDBLUMOF2T4OS6OFHBA2LEGCKX7KHMUWTFJNMVASDGWAAC 64HB7VYSYHQEN5UP7OYJ5GSVA2XMDSLLH647UPWE5NSFF3AVZSSQC HIFVBWCWJAGT4DKS6DXL5YB4E64EJMMJNJ2VEJZP7G2Q357MDE5QC DIY6I5TK7SSDULLLPKGT4LUS7IAL25NOJW7BM7WS542NYQPJ2K2AC KAGCUOULIUHCPZSOSC6EJGOTH4PMEWCTMA4KGT7F5GQOQY5QX32QC YJ4Q65CCPG2R3O2CFICU6WS27ISYEHQGWIHNOOYPN2TIPKNXVX7QC LRNJ7O6FCNZ6TWEEQLXB6ZTKSDJNZ6HXV6T6RFVW5VU6E73MX4AQC QZM4EDMUKU7QWQKWXHTRINNWH3GQQ6RSAX7WIX6PQAEM5V2Y2BQQC HHW3CT6TLHVUGKIBE2KNYJTWGZMSFA6OVIUFOTZTIH6SGRA7DLDQC Q652MJM34TH2ZV6CPA2RERMJMDMK2TQEAALRMXK2G6Y25UWKRJ3QC JZTWTPXIUEVACX5B6FYQRVRJD3KQN653C4G4GXT2VSMX4EP7WS3AC SROWUFFIKQV3PLGRJBPFUBMY4THTWIR2632PTVDAYEB5R3BDSDJAC BMKL2AB2HBBBVAHWDYXPYZHSCO345QWOQHFSICFRN5BCYZ3UEK3AC KFULGQQOHWUTXOM3BXCCYPGGVGGY4Z6265XUFRCBPNLTZAEHJZSQC 3WNSWDDTTPWQ24SUOFU7EL6GODIMVTK4TL3P3AFLNB6AXUIIHFSAC B3HWU2BEQQ4E6WKVTW3JQQJFMWTVW3XWKY6BHFNBRHSZPRCF2OTQC FIYBXLWALQINNQTHG2KNDUUTAQAZRDDLXW2XOVSKDKBADJ3XCJ4AC IQGGFC563RBS7GDOACKCLXK752EE5RC3T6G5L6H446SXTMSA7T2AC L4Z2MHAQ2AAQSTVWBUCTBPXXJDLGR4JH2MMPQA3WBVCPCVNFMUXQC LS2AILMM7THCB7OHESW7BGJMNZZXFHYOYVZBZH6OCFNETNLDEP5QC RGGANRTOXB5K2HRQGK2F4XFZJVZSWOLVWFXZVVFEQQPO64Z4SQ7QC 5CPP63H7WJ3GLSHJM4Z2YSU2NISLVESEJ3OYMO4MFZEXVOCV4NIAC PHBACPMH3F34GODHVDKNCMXWU373RJQGVTDLBFCCDLLWDXVYOLTAC K2CS6TCX2NDVL2ASEHGP4J4K4IJ6FP3ANNKTSIWVG43HPYSBX6ZQC PBKRKGKARGZSLVFVDTK5NWDXQD26NHNN67LDSSB75CLEWBR6TLEQC 3ZT5EQNS5KXWEXAKV7C3TTFZ6QHOCR57LTFTETPKIVZGTXHZKRQAC DGFWFFHCEBQK2TSMHN7RYPRNRVGEAYXM7GYJ4L37Z2ZNSIIUWQ4QC DF5LOTJFSXOT7UBDHLBDLGA22OY4L7ZF6CVFP6H3KL4N5CHB5C5QC SA36K3OJ75PNVR2F4QAPNU2LUGFTVHNIAZVSXCBXBT2NLW2RTUPAC CGYTZT5QWIEGYKUOLOK7MFXSLJKLYRZONER5ZCDZO5XYWSLG475QC RPOZZWKG5GLPHVZZ7ZKMKS64ZMV2LDCQSARBJFJ6FZOTOKCQO7FAC NMZFKLRNGUMWPRLQCGHJPKTEFPPBIGMM2MEND5CR3QIEF5Z6BQDAC NDKS43E4XVAU3FDY276OF5JW7E5SF6F5EJD2XLV5JLKZ5W6N554QC EZ3ZUOFAHXI73BSCXNYS36TTK4OGCQBSFEIRVNXUAE64ZVKDW5PAC VCQYSNAWZZHOZMARWQ4AJBDNFSS7T7CZBQISSPZ2YIIK5PVAWPRQC KK5IGMPS7OBB2LA7SMGWVR534Q4LYKUD2MESO5IAMOKLNBBDWOMQC 74ETEQCJPMFG26EEH6SNDQNOWYZ2JBRFXGBQ3MMCGQPSVGSTIJVQC 5SKXI22WN2Y4SWUG634WDB7QXLBNV54RPN5OHAXRI55OFM5YBF5QC CUM44NOPIB7LGTRY2O2R5MYXAB27R3TFM6LUBEQHZFXLZWJ55QZAC 47NSOFQMBZCDIBHEAZSENFUGDSQCX3GJHFBUZ65ARDKCYIZ435LAC XJBNF2N35THJC2KYGCMPLC3CDCJP25CEDKHUI3P55V6H5YWXBUKAC SVY2PTCLXR3KNPQAWXVXTTGCC5DR334HOAKHYO3VDDRWM2BWMALAC PWY4VZVHDLYL7UVNCCOW7BM7LYK2BOGTL23P75HXUJ33MHJPEJPQC ENQRCBNN7MKP6FFQAZ62FYXEVWCRJB5747LTYMZGRGINXQL6HT5AC R2DQBWKIW7YUJB5SOQ7J274JIYRVX4H3ISFRPAL5RG2RVVP4G2KAC 4HLF6Q3OBOOHCCJ76L2BXVIYI6EMJ2G7O4XXZPFTLFP6BQGSUZNAC JESCEQPAFC23D6BUZMBOB4M54XT3GQZJYT7NCJ556LEUCHRER3SQC QDTVLBRGHDTRUVT7I3O72K6TMOYAUSAJBZUHGOEFU2RKJNUPWZSQC L254F6ZIU2HWGLFFGPIORTN4C3TDQ3E5JZ7Z7GQA5AEDIKL6PKDAC NVSFIV2ZKP44XHCSCXG6OZVGL67OIFINC34J2EMKTA4KULCERUEAC 3DQXSE4YGFBBDUWK4YEOFWW4UPWILWELFSLP37SL6BERGAZJC5YAC J6APXOT4QOGQFONWB7G546VTVF6QG42HVOROMHF7YBDJPR4K26OAC W74555HMPXUQ72AGKBXC5P3STMMX5DZAW6ZESUDLNVJBCAG43PLAC 6GDKXNFXPKQ6AVNOSMJECN7CLELM2KCMVRM2A7BARLK2NNILN6SAC VNHFP63ZLLZU3A3PLXP4BITX57DUIYDHFOHQYK3BOBHV3S64G26QC SDLKLUNFGVKDS55DDJZCBAVIB7NL3RRYPTACAY65SCUQKV6APFSAC AIVXE6QBRVCZAASKQRZO6LBDGTYEYSSD2DZCWRX4VLSKE3GCNIDAC ASCTVJSN3NXYQHRVXAORA43CV6H5V2572IMK4UGRHKBAGJOWHC4AC S34LKQDIQJLIWVIPASOJBBZ6ZCXDHP5KPS7TRBZJSCDRVNCLK6UAC 3EUPIYJNWOMOQBP2Z5SGSMWK453BXJD6KL2WFTR3NM565MEBYASAC ZJIGDAAKOHJWPD7TMNTNKP7ZT4K4GHD7UGSAWERTIJA3BGL5BETQC FLAGBNUNSIQNFDN53CDWABJRTTFWDL4PG34AI474ZKPXDEPYHOAQC R22TTMI6WXWULC7ODKFF3QCB7MOTETQQ6IR4BUCUPOCQKQNCTT5AC L4PKJZERR7WADKWHY3MR6J6OZFREVPL3CB43I6MLJ2BVKWCUTE7AC ILADK4YNPQVYLZYDMGGBYN2EBBCIPCDNUCWZH27DQTKOMVUDLVMAC K7J2IGELTIQL5KAMBV62MFVIVMEZEWCOLZ7GHFXHYPANYIF7BRZAC 5FHWTG7M6FW4B3I33YI7QSM3OZIB6ZGC6TI6JISSLY5Y43HI56VAC PR42BCP5BPRFD2MP5H6CIJP7E57Q6TKL6SOXZWFKMFVR2OZWHT7AC SPFKVC5KJVGMD4ITZWLWTB6N42IV6AWXGPEEXCYPI7BGFZKY5FHAC U3SFBWHMMMO2PY6PAX7FMSBSND4RCWGJR42HB47LNQXLOX7ZOB6QC C5VA63WAQRWPENIMXRPUPZLZJMC77PL2B3A77HYFWDCZU5QDG7VQC RBAGQ2PB7V5YAM5KSHSZR2E3MLKDSRVM5XYGI2TIXP5QMVBOQHDQC KBNY5FWKTEAKABFCLPC3QFKFSVZKAGXINPCIFV6WDSWFO4VCKNTAC OSGS3PH2L5CBTDVZCZS6OCFQNA4A7RMEXBYJQB7DDZBYYJW7QSSAC ODQ7LIJ2UROGGENIORRXZFWII3ZM2N45YD53FKWDQB7LLRXR4PHAC ENOQQ6DEA6ECRNTBGYYNK7G3DFEILMKQBNKP4SUQIZW2L6HWVR7QC ODCWOILHAMEQQVMGVUU6PWRSMHAINWP3MYFMPVMQBQZ5RYKGO45AC 7BBEAPSUBQMBK4XC2Q6YJ2JPSVSPCSBJUYXM6EWXHNTQG4AEJX3QC IL3QYB75HIQQULVII3MPZKFXJAM7EE73MBHYK6I3EJQLFXRHO6LQC 2OQFLBVWCTXCWUPSDM76KNXTNC3YPAKRI5KLDAEU4KQLN4DEOLYQC Y56C5OMUQ5XF2G6DKDV4R5MED44UOIUPTBBQVWQBUHYIXYA5MOZAC I7QLYOTE6DLQZM7YWUWYLKHRJRB2A3STQ42ALSRGQICEWKD2QTEQC AIIVH43Z5X3GTPFY4FXQRZPG6Y7QPH2KJ47VM2Q43PCGGD5MTMOAC BMHUBADDGIOZRVN4P3O5QKIDUYD4RFWBS7MP5X6LZWAYHUBRVD2QC NMZFCCM6O3KO2GJWKOSULN27B3QIZKWPBOB62PAILXMRQD4JMIMAC if (is_unrandom_artefact(item) || is_fixed_artefact(item))return;if (item.base_type != OBJ_WEAPONS && item.base_type != OBJ_MISSILES)return;int brand;if (item.base_type == OBJ_WEAPONS){// Only switch already branded items.if (get_weapon_brand(item) == SPWPN_NORMAL)return;brand = (int) SPWPN_CHAOS;}else{// Only switch already branded items.if (get_ammo_brand(item) == SPWPN_NORMAL)return;brand = (int) SPMSL_CHAOS;}if (is_random_artefact(item))randart_set_property(item, RAP_BRAND, brand);elseitem.special = brand;}
}static void _xom_acquirement(object_class_type force_class){god_acting gdact(GOD_XOM);int item_index = NON_ITEM;if (!acquirement(force_class, GOD_XOM, false, &item_index)|| item_index == NON_ITEM){god_speaks(GOD_XOM, "\"No, never mind.\"");return;}_try_brand_switch(item_index);stop_running();
}static bool _is_chaos_upgradeable(const item_def &item,const monsters* mon){// Since Xom is a god he is capable of changing randarts, but not// other artifacts.if (is_artefact(item) && !is_random_artefact(item))return (false);// Only upgrade permanent items, since the player should get a// chance to use the item if s/he can defeat the monster.if (item.flags & ISFLAG_SUMMONED)return (false);// Don't know how to downgrade blessed blades to normal blades.// Can be justified as good gods protecting blessed blades.if (is_blessed_blade(item))return (false);// God gifts from good gods are protected. Also, Beogh hates all// the other gods so he'll protect his gifts as well.if (item.orig_monnum < 0){god_type iorig = static_cast<god_type>(-item.orig_monnum - 2);if ((iorig > GOD_NO_GOD && iorig < NUM_GODS)&& (is_good_god(iorig) || iorig == GOD_BEOGH)){return (false);}}// Leave branded items alone, since this is supposed to be an// upgrade.if (item.base_type == OBJ_MISSILES){// Don't make boulders or throwing nets of chaos.if (item.sub_type == MI_LARGE_ROCK|| item.sub_type == MI_THROWING_NET){return (false);}if (get_ammo_brand(item) == SPMSL_NORMAL)return (true);}else{// If the weapon is a launcher and the monster is either out// of ammo or is carrying javelins then don't bother upgrading// launcher.if (is_range_weapon(item)&& (mon->inv[MSLOT_MISSILE] == NON_ITEM|| !has_launcher(mitm[mon->inv[MSLOT_MISSILE]]))){return (false);}if (get_weapon_brand(item) == SPWPN_NORMAL)return (true);}return (false);}static bool _choose_chaos_upgrade(const monsters* mon){// Only choose monsters that will attack.if (!mon->alive() || mons_attitude(mon) != ATT_HOSTILE|| mons_is_fleeing(mon) || mons_is_panicking(mon)){return (false);}if (mons_itemuse(mon) < MONUSE_STARTING_EQUIPMENT)return (false);// Holy beings are presumably protected by another god, unless they're// gifts from Xom.if (mons_is_holy(mon) && mon->god != GOD_XOM)return (false);// God gifts from good gods will be protected by their god from being// given chaos weapons, while other gods won't mind the help in their// servants killing the player.if (mon->god != GOD_NO_GOD && is_good_god(mon->god))return (false);// Beogh presumably doesn't want Xom messing with his orcs, even if// it would give them a better weapon.if (mons_genus(mon->type) == MONS_ORC)return (false);mon_inv_type slots[] = {MSLOT_WEAPON, MSLOT_ALT_WEAPON, MSLOT_MISSILE};// NOTE: Code assumes that the monster will only be carrying one// missile launcher at a time.bool special_launcher = false;for (int i = 0; i < 3; i++){const mon_inv_type slot = slots[i];const int midx = mon->inv[slot];if (midx == NON_ITEM)continue;const item_def &item(mitm[midx]);// Monster already has a chaos weapon, give upgrade to a different// monster.if (is_chaotic_item(item))return (false);if (_is_chaos_upgradeable(item, mon)){if (item.base_type != OBJ_MISSILES)return (true);// If for some weird reason a monster is carrying a bow// and javelins then branding the javelins is okay since// they won't be fired by the bow.if (!special_launcher || !has_launcher(item))return (true);}if (is_range_weapon(item)){// If the launcher alters its ammo then branding the monster's// ammo won't be an upgrade.int brand = get_weapon_brand(item);if (brand == SPWPN_FLAME || brand == SPWPN_FROST|| brand == SPWPN_VENOM){special_launcher = true;}}}return (false);}static void _do_chaos_upgrade(item_def &item, const monsters* mon){ASSERT(item.base_type == OBJ_MISSILES|| item.base_type == OBJ_WEAPONS);ASSERT(!is_unrandom_artefact(item) && !is_fixed_artefact(item));bool seen = false;if (mon && you.can_see(mon) && item.base_type == OBJ_WEAPONS){seen = true;description_level_type desc = mons_friendly(mon) ? DESC_CAP_YOUR :DESC_CAP_THE;std::string msg = mon->name(desc);msg += "'s ";msg = replace_all(msg, "s's", "s'"); // Proper posessive.msg += item.name(DESC_PLAIN, false, false, false);msg += " is briefly surrounded by a scintillating arua of ""random colours.";mpr(msg.c_str());}const int brand = (item.base_type == OBJ_WEAPONS) ? (int) SPWPN_CHAOS :(int) SPMSL_CHAOS;if (is_random_artefact(item)){randart_set_property(item, RAP_BRAND, brand);if (seen)randart_wpn_learn_prop(item, RAP_BRAND);}else{item.special = brand;if (seen)set_ident_flags(item, ISFLAG_KNOW_TYPE);}
monsters *mon =choose_random_nearby_monster(0, _choose_chaos_upgrade);if (!mon)continue;god_speaks(GOD_XOM, _get_xom_speech("chaos upgrade").c_str());mon_inv_type slots[] = {MSLOT_WEAPON, MSLOT_ALT_WEAPON,MSLOT_MISSILE};for (int i = 0; i < 3; i++){int idx = mon->inv[slots[i]];if (idx == NON_ITEM)continue;item_def &item(mitm[idx]);if (!_is_chaos_upgradeable(item, mon))continue;_do_chaos_upgrade(item, mon);done = true;break;}ASSERT(done);// Wake the monster up.behaviour_event( mon, ME_ALERT, MHITYOU );}else if (x_chance_in_y(8, sever)){
break;default:break;}return (retval);}bool is_chaotic_item(const item_def& item){bool retval = false;switch (item.base_type){case OBJ_WEAPONS:{const int item_brand = get_weapon_brand(item);retval = (item_brand == SPWPN_CHAOS);}break;case OBJ_MISSILES:{const int item_brand = get_ammo_brand(item);retval = (item_brand == SPMSL_CHAOS);}
if (((item.base_type == OBJ_POTIONS && item.sub_type == POT_MUTATION)|| (item.base_type == OBJ_WANDS&& item.sub_type == WAND_POLYMORPH_OTHER))&& item_type_known(item)){
if (item_type_known(item) && is_chaotic_item(item))
switch (random2(6)){case 0: attk.flavour = AF_POISON_NASTY; break;case 1: attk.flavour = AF_ROT; break;case 2: attk.flavour = AF_DRAIN_XP; break;case 3: attk.flavour = AF_FIRE; break;case 4: attk.flavour = AF_COLD; break;case 5: attk.flavour = AF_BLINK; break;}
mon_attack_flavour flavours[] ={AF_POISON_NASTY, AF_ROT, AF_DRAIN_XP, AF_FIRE, AF_COLD, AF_BLINK};attk.flavour = RANDOM_ELEMENT(flavours);
0, 10, MONS_CHAOS_SPAWN, MONS_CHAOS_SPAWN, MH_NATURAL, -3,{ AT_NO_ATK, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },{ 0, 0, 0, 0 },0, 0, MST_NO_SPELLS, CE_MUTAGEN_RANDOM, Z_NOZOMBIE, S_RANDOM, I_NORMAL,HT_LAND, 0, DEFAULT_ENERGY, MONUSE_NOTHING, SIZE_BIG
0, 12, MONS_CHAOS_SPAWN, MONS_CHAOS_SPAWN, MH_DEMONIC, -7,{ {AT_RANDOM, AF_CHAOS, 21}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },{ 6, 3, 5, 0 },7, 12, MST_NO_SPELLS, CE_MUTAGEN_RANDOM, Z_NOZOMBIE, S_RANDOM, I_ANIMAL,HT_LAND, 11, DEFAULT_ENERGY, MONUSE_NOTHING, SIZE_BIG
}}std::string setup_chaos_ammo(bolt &pbolt, item_def ammo){ASSERT(!is_artefact(ammo));const bool poisoned = (get_ammo_brand(ammo) == SPMSL_POISONED);// Don't choose BEAM_POISON or BEAM_HEALING if we have poisoned ammo.const int pois_weight = poisoned ? 0 : 10;const int heal_weight = poisoned ? 0 : 10;const beam_type flavour = static_cast<beam_type>(random_choose_weighted( pois_weight, BEAM_POISON,heal_weight, BEAM_HEALING,10, BEAM_FIRE,10, BEAM_COLD,10, BEAM_ELECTRICITY,10, BEAM_NEG,10, BEAM_ACID,10, BEAM_HELLFIRE,10, BEAM_NAPALM,10, BEAM_HELLFROST,10, BEAM_SLOW,10, BEAM_HASTE,10, BEAM_PARALYSIS,10, BEAM_CONFUSION,10, BEAM_INVISIBILITY,10, BEAM_POLYMORPH,10, BEAM_BANISH,10, BEAM_DISINTEGRATION,0 ));std::string name;int colour;if (poisoned)name = "poison ";switch(flavour){case BEAM_POISON:name += "poison";colour = EC_POISON;break;case BEAM_HEALING:name += "healing";colour = EC_HEAL;break;case BEAM_FIRE:name += "flame";colour = EC_FIRE;break;case BEAM_COLD:name += "frost";colour = EC_ICE;break;case BEAM_ELECTRICITY:name += "lightning";colour = EC_ELECTRICITY;break;case BEAM_NEG:name += "negative energy";colour = EC_NECRO;break;case BEAM_ACID:name += "acid";colour = YELLOW;break;case BEAM_HELLFIRE:name += "hellfire";colour = EC_FIRE;break;case BEAM_NAPALM:name += "sticky fire";colour = EC_FIRE;break;case BEAM_HELLFROST:name += "hellfrost";colour = EC_ICE;break;case BEAM_SLOW:name += "slowing";colour = EC_ENCHANT;break;case BEAM_HASTE:name += "hasting";colour = EC_ENCHANT;break;case BEAM_PARALYSIS:name += "paralysis";colour = EC_ENCHANT;break;case BEAM_CONFUSION:name += "confusion";colour = EC_ENCHANT;break;case BEAM_INVISIBILITY:name += "invisibility";colour = EC_ENCHANT;break;case BEAM_POLYMORPH:name += "polymorphing";colour = EC_MUTAGENIC;break;case BEAM_BANISH:name += "banishment";colour = EC_WARP;break;case BEAM_DISINTEGRATION:name += "disintegration";colour = EC_DEATH;break;default:ASSERT(!"Invalid chaos ammo flavour.");break;
pbolt.name = "bolt of ";pbolt.name += name;pbolt.flavour = flavour;pbolt.colour = colour;pbolt.type = dchar_glyph(DCHAR_FIRED_BOLT);// Get name for a plain arrow/bolt/dart/needle.ammo.special = 0;std::string ammo_name = ammo.name(DESC_NOCAP_A);ammo_name += " of ";ammo_name += name;return ammo_name;
if ((bow_brand == SPWPN_FLAME || ammo_brand == SPMSL_FLAME)&& ammo_brand != SPMSL_ICE && bow_brand != SPWPN_FROST)
// Chaos overides flame and frost/ice.if (bow_brand == SPWPN_CHAOS || ammo_brand == SPMSL_CHAOS){ammo_name = setup_chaos_ammo(pbolt, item);// [dshaligram] Branded arrows are much stronger.dice_mult = (dice_mult * 150) / 100;pbolt.effect_known = false;}else if ((bow_brand == SPWPN_FLAME || ammo_brand == SPMSL_FLAME)&& ammo_brand != SPMSL_ICE && bow_brand != SPWPN_FROST)
if ((bow_brand == SPWPN_FROST || ammo_brand == SPMSL_ICE)&& ammo_brand != SPMSL_FLAME && bow_brand != SPWPN_FLAME)
else if ((bow_brand == SPWPN_FROST || ammo_brand == SPMSL_ICE)&& ammo_brand != SPMSL_FLAME && bow_brand != SPWPN_FLAME)
}void melee_attack::_monster_die(monsters* monster, killer_type killer,int killer_index){const bool chaos = damage_brand == SPWPN_CHAOS;// Copy defender before it gets reset by monster_die()monsters* def_copy = NULL;if (chaos)def_copy = new monsters(*monster);monster_die(monster, killer, killer_index);if (chaos){chaos_killed_defender(def_copy);delete def_copy;}
const monsters* mon = dynamic_cast<const monsters*>(defender);// No uniques, pandemonium lords or player ghosts. Also, figuring// out the name for the clone of a named monster isn't worth it.if (mons_is_unique(mon->type) || mon->is_named() || mon->ghost.get())return (false);// Holy beings can't be duplicated by chaotic means.if (mons_is_holy(mon))return (false);// Is there space for the clone?int squares = 0;for (int i = 0; i < 8; i++){const coord_def p = mon->pos() + Compass[i];if (in_bounds(p) && p != you.pos() && mgrd(p) == NON_MONSTER&& monster_habitable_grid(mon, grd(p))){if (one_chance_in(++squares))*pos = p;}}if (squares == 0)return (false);// Is there an open slot in menv?for (int i = 0; i < MAX_MONSTERS; i++)if (menv[i].type == -1){*midx = i;break;}if (*midx == NON_MONSTER)return (false);// Is the monster carrying an artefact?for (int i = 0; i < NUM_MONSTER_SLOTS; i++){const int index = mon->inv[i];if (index == NON_ITEM)continue;if (is_artefact(mitm[index]))return (false);}return (true);}static bool _do_clone(monsters* orig, coord_def pos, int midx){bool obvious = false;monsters &mon(menv[midx]);mon = *orig;mon.position = pos;mgrd(pos) = midx;// Duplicate objects, or unequip them if they can't be duplicated.for (int i = 0; i < NUM_MONSTER_SLOTS; i++){const int old_index = orig->inv[i];if (old_index == NON_ITEM)continue;const int new_index = get_item_slot(0);if (new_index == NON_ITEM){mon.unequip(mitm[old_index], i, 0, true);mon.inv[i] = NON_ITEM;continue;}mon.inv[i] = new_index;mitm[new_index] = mitm[old_index];}// The player shouldn't get new permanent followers from cloning.if (mon.attitude == ATT_FRIENDLY && !mons_is_summoned(&mon))mon.mark_summoned(6, true);if (you.can_see(orig) && you.can_see(&mon)){simple_monster_message(orig, " is duplicated!");obvious = true;}mark_interesting_monst(&mon, mon.behaviour);if (you.can_see(&mon)){seen_monster(&mon);viewwindow(true, false);}return (obvious);}enum chaos_type{CHAOS_CLONE,CHAOS_POLY,CHAOS_POLY_UP,CHAOS_MAKE_SHIFTER,CHAOS_HEAL,CHAOS_HASTE,CHAOS_INVIS,CHAOS_SLOW,CHAOS_PARA,CHAOS_PETRIFY,NUM_CHAOS_TYPES};// XXX: We might want to vary the probabilites for the various effects// based on whether the source is weapon of chaos or a monster with// AF_CHAOSvoid melee_attack::chaos_affects_defender(){coord_def clone_pos;int clone_midx;const bool mon = defender->atype() == ACT_MONSTER;const bool immune = mon && mons_immune_magic(def);const bool is_shifter = mon && mons_is_shapeshifter(def);const bool is_chaotic = mon && mons_is_chaotic(def);const bool can_clone = _can_clone(defender, &clone_pos, &clone_midx);const bool can_poly = is_shifter || (defender->can_safely_mutate()&& !immune);int clone_chance = can_clone ? 1 : 0;int poly_chance = can_poly ? 1 : 0;int poly_up_chance = can_poly ? 1 : 0;int shifter_chance = can_poly ? 1 : 0;if (is_chaotic){// Polymorphing might reduce amount of chaos in the world.poly_chance = 0;poly_up_chance = 0;// Chaos wants more chaos.clone_chance *= 2;// Chaos loves shifters.if (is_shifter){clone_chance *= 2;poly_up_chance = 4;// Already a shiftershifter_chance = 0;}}// NOTE: Must appear in exact same order as in chaos_type enumeration.int probs[NUM_CHAOS_TYPES] ={clone_chance, // CHAOS_CLONEpoly_chance, // CHAOS_POLYpoly_up_chance, // CHAOS_POLY_UPshifter_chance, // CHAOS_MAKE_SHIFTER5, // CHAOS_HEAL5, // CHAOS_HASTE5, // CHAOS_INVIS15, // CHAOS_SLOW15, // CHAOS_PARA15, // CHAOS_PETRIFY};bolt beam;beam.flavour = BEAM_NONE;int choice = choose_random_weighted(probs, probs + NUM_CHAOS_TYPES);switch(static_cast<chaos_type>(choice)){case CHAOS_CLONE:ASSERT(can_clone);ASSERT(defender->atype() == ACT_MONSTER);obvious_effect = _do_clone(def, clone_pos, clone_midx);break;case CHAOS_POLY:ASSERT(can_poly);beam.flavour = BEAM_POLYMORPH;break;case CHAOS_POLY_UP:ASSERT(can_poly);ASSERT(defender->atype() == ACT_MONSTER);obvious_effect = you.can_see(defender);monster_polymorph(def, RANDOM_MONSTER, PPT_MORE, true);break;case CHAOS_MAKE_SHIFTER:ASSERT(can_poly);ASSERT(!is_shifter);ASSERT(defender->atype() == ACT_MONSTER);obvious_effect = you.can_see(defender);def->add_ench(one_chance_in(3) ?ENCH_GLOWING_SHAPESHIFTER : ENCH_SHAPESHIFTER);// Immediately polymorph monster, just to make the effect obvious.monster_polymorph(def, RANDOM_MONSTER, PPT_SAME, true);break;case CHAOS_HEAL:beam.flavour = BEAM_HEALING;break;case CHAOS_HASTE:beam.flavour = BEAM_HASTE;break;case CHAOS_INVIS:beam.flavour = BEAM_INVISIBILITY;break;case CHAOS_SLOW:beam.flavour = BEAM_SLOW;break;case CHAOS_PARA:beam.flavour = BEAM_PARALYSIS;break;case CHAOS_PETRIFY:beam.flavour = BEAM_PETRIFY;break;default:ASSERT(!"Invalid chaos effect type");break;}if (beam.flavour != BEAM_NONE){beam.name = atk_name(DESC_CAP_THE);beam.range = 1;beam.colour = BLACK;beam.is_beam = false;beam.is_explosion = false;beam.is_big_cloud = false;beam.effect_known = false;beam.thrower = (attacker->atype() == ACT_PLAYER) ? KILL_YOU: def->confused_by_you() ? KILL_YOU_CONF: KILL_MON;beam.beam_source =(attacker->atype() == ACT_PLAYER) ? MHITYOU : monster_index(atk);beam.source = attacker->pos();beam.target = defender->pos();beam.pos = defender->pos();beam.damage = dice_def(damage_done + special_damage + aux_damage, 1);beam.ench_power = beam.damage.num;fire_beam(beam);if (you.can_see(defender))obvious_effect = beam.obvious_effect;}if (!you.can_see(attacker))obvious_effect = false;}void melee_attack::chaos_affects_attacker(){}// NOTE: Isn't called if monster dies from poisoning caused by chaos.void melee_attack::chaos_killed_defender(monsters* def_copy){}// NOTE: random_chaos_brand() and random_chaos_attack_flavour() should// return a set of effects that are roughly the same, to make it easy// for chaos_affects_defender() not to do duplicate effects caused// by the non-chaos brands/flavours they return.int melee_attack::random_chaos_brand(){int brands[] = {SPWPN_FLAMING, SPWPN_FREEZING, SPWPN_ELECTROCUTION,SPWPN_VENOM, SPWPN_DRAINING, SPWPN_VAMPIRICISM,SPWPN_PAIN, SPWPN_DISTORTION, SPWPN_CONFUSE,SPWPN_CHAOS};return (RANDOM_ELEMENT(brands));}mon_attack_flavour melee_attack::random_chaos_attack_flavour(){mon_attack_flavour flavours[] ={AF_FIRE, AF_COLD, AF_ELEC, AF_POISON_NASTY, AF_VAMPIRIC, AF_DISTORT,AF_CONFUSE, AF_CHAOS};return (RANDOM_ELEMENT(flavours));}
%%%%# Chaos spawns shouldn't have coherent speech, since that would be too# orderly for beings of pure chaos.chaos spawnVISUAL:@The_monster@ grows dozens of eye stalks in order to get a better look at you.VISUAL:@The_monster@ splits into many small globs of multi-coloured light, then recombines.VISUAL:@The_monster@ breifly grows a face disturbingly similar to your own.@The_monster@ ululates chillingly with its many mouths.@The_monster@ gibbers incoherently in a cacophony of voices.