git-svn-id: https://crawl-ref.svn.sourceforge.net/svnroot/crawl-ref/trunk@5621 c06c8d41-db1a-0410-9941-cceddc491573
SCXTTP2FDNB2A7F4XXGXSSOEKZQ7ODDGN5YBCTZXGZ22CLCEH3WQC LHVZICXASE4UFBQQ3UEQF4DLPFGD2NNZV7FFTRUK6PVB6XLZNQQAC ERIX6ZUTNIN7ZPU7MSY43P4DGAOZVOSCJBKP2Y2W5GRH7M5BTNQAC WZWOQZCXUB7QX7PGQMIUCH5JM5YME25GE2GMMT2NIJP5OIZUZLBQC K2CS6TCX2NDVL2ASEHGP4J4K4IJ6FP3ANNKTSIWVG43HPYSBX6ZQC ZGZVOMRXLVC42FV67RBTLBOZWFYRL4UHL54A365BR76OUIYRWQXAC NQMXQ6OQVUSC7Y7F7IL252QW4A5JED224EECNHWAM4ZZYVNY745AC EY6KXNVGJ5OWJQWBE3W5E4T625XZXUNJMXIEQLCZUAJASUK4KHMQC DH3YTI6VVI727SQXO4CXSDCSBG2UN3UAWLFULBGRLBVH22ACRXIAC 5BJPWUPLJFS34FUTFJVKA4A52YMIGV6EWDXLNSDCWBJWBGVSQFGQC 7MDPXLMPCFLZS6CLZBN4FN4RDNBW4Z6Q2NNPWD2N3LOW5LQISM3AC SDLKLUNFGVKDS55DDJZCBAVIB7NL3RRYPTACAY65SCUQKV6APFSAC ABNTYDXOCBICW3TEDGRCEHA7XJBVINEXKUXQ5ORY2XI7SKMVTGJAC M6MBPHNAERUXYJ7KHK5FE2B44CLBY4M5MR5KY74HVDFNHVLOEQIAC T7CUIVICB74342RA32BR37T36FOX4RBSQIB5PNOHTGTGUYGDKSTQC AUXVWXWIFSTWFA6VZXN2FMG7FQEKRZVV6MD32VQQ7J2RKCXHAVGAC RPOZZWKG5GLPHVZZ7ZKMKS64ZMV2LDCQSARBJFJ6FZOTOKCQO7FAC NVSFIV2ZKP44XHCSCXG6OZVGL67OIFINC34J2EMKTA4KULCERUEAC RX6575DZOHRUXQUZH34YZGPZJF4STUPLBQDIVTINA2L6LVCKRIGQC S6PQTZAN4UKH5SQLQZDMVTIZFHERA6WHZ7IW25VZWZXKU6ITOCPAC GPEJOT73KMACP33IPAKFR5ROGHCOIP22VXZMQNYTGLEA2OSZUM2AC HHGJTYLLLXXUIFOWZDV7XEXBJT6I7OUCOCW5BALLX37LCN5FEKYAC RUJXBJYRHCLDLXQD3ZRTI7AVECGURT7E5E6PMI2GL7Q4RHYXF4IAC FU663V7RFZNSMG5P2E7TZJZWSGXWLCCFXSVGH4Z222FIJTH4R3KAC 6QOJM3P5IONWA3LWLN7YT7KZKNSFNIGNRLL5ZIKFRQ42BDURNAEAC DDU4A3JGN5IUIPP5IASOODKPR2WBHSDSV4FITZ6HNXNSXXQACWAQC KBNY5FWKTEAKABFCLPC3QFKFSVZKAGXINPCIFV6WDSWFO4VCKNTAC // last updated 24may2000 {dlb}/* ************************************************************************ called from: ability - spell* *********************************************************************** */bool animate_a_corpse(int x, int y, corpse_type class_allowed,beh_type beha, unsigned short hitting,bool god_gift = false, bool actual = true,bool silent = false);// last updated 24may2000 {dlb}/* ************************************************************************ called from: ability - it_use3 - monstuff - mstuff2 - spell* *********************************************************************** */int animate_dead(actor *caster, int pow, beh_type beha, unsigned short hitting,bool god_gift = false, bool actual = true);// updated 24may2000 {dlb}/* ************************************************************************ called from: spell* *********************************************************************** */
// Try to equip the zombie/skeleton with the objects it died with.// This excludes items which were dropped by the player onto the corpse,// and corpses which were picked up and moved by the player, so the player// can't equip their undead slaves with items of their choice.//// The item selection logic has one problem: if a first monster without// any items dies and leaves a corpse, and then a second monster with// items dies on the same spot but doesn't leave a corpse, then the// undead can be equipped with the second monster's items if the second// monster is either of the same type as the first, or if the second// monster wasn't killed by the player or a player's pet.static void _equip_undead(int x, int y, int corps, int monster, int monnum){// Delay this until after 0.4#if 0monsters* mon = &menv[monster];monster_type type = static_cast<monster_type>(monnum);if (mons_itemuse(monnum) < MONUSE_STARTING_EQUIPMENT)return;// If the player picked up and dropped the corpse then all its// original equipment fell off.if (mitm[corps].flags & ISFLAG_DROPPED)return;// A monster's corpse is last in the linked list after its items,// so (for example) the first item after the second-to-last corpse// is the first item belonging to the last corpse.int objl = igrd[x][y];int first_obj = NON_ITEM;while (objl != NON_ITEM && objl != corps){item_def item(mitm[objl]);if (item.base_type == OBJ_CORPSES){first_obj = NON_ITEM;continue;}if (first_obj == NON_ITEM)first_obj = objl;objl = item.link;}ASSERT(objl == corps);if (first_obj == NON_ITEM)return;// Iterate backwards over the list, since the items earlier in the// linked list were dropped most recently and hence more likely to// be items the monster didn't die with.std::vector<int> item_list;objl = first_obj;while (objl != NON_ITEM && objl != corps){item_list.push_back(objl);objl = mitm[objl].link;}for (int i = item_list.size() - 1; i >= 0; i--){objl = item_list[i];item_def &item(mitm[objl]);// Stop equipping monster if the item probably didn't originally// belong to the monster.if ( (origin_known(item) && (item.orig_monnum - 1) != monnum)|| (item.flags & (ISFLAG_DROPPED | ISFLAG_THROWN))|| item.base_type == OBJ_CORPSES){return;}mon_inv_type mslot;switch(item.base_type){case OBJ_WEAPONS:if (mon->inv[MSLOT_WEAPON] != NON_ITEM){if (mons_wields_two_weapons(type))mslot = MSLOT_ALT_WEAPON;else{if (is_range_weapon(mitm[mon->inv[MSLOT_WEAPON]])== is_range_weapon(item)){// Two different items going into the same// slot indicate that this and further items// weren't equipment the monster died with.return;}else// The undead are too stupid to switch between weapons.continue;}}elsemslot = MSLOT_WEAPON;break;case OBJ_ARMOUR:mslot = equip_slot_to_mslot(get_armour_slot(item));// A piece of armour which can't be worn indicates that this// and further items weren't the equipment the monster died// with.if (mslot == NUM_MONSTER_SLOTS)return;break;case OBJ_MISSILES:mslot = MSLOT_MISSILE;break;case OBJ_GOLD:mslot = MSLOT_GOLD;break;// The undead are too stupid to use these.case OBJ_WANDS:case OBJ_SCROLLS:case OBJ_POTIONS:case OBJ_MISCELLANY:continue;default:continue;} // switch// Two different items going into the same slot indicate that// this and further items weren't equipment the monster died// with.if (mon->inv[mslot] != NON_ITEM)return;unlink_item(objl);mon->inv[mslot] = objl;if (mslot != MSLOT_ALT_WEAPON || mons_wields_two_weapons(mon))mon->equip(item, mslot, 0);} // while#endif}static bool _raise_corpse(int x, int y, int corps, beh_type beha,unsigned short hitting, bool god_gift, bool actual){const item_def& item = mitm[corps];if (!_is_animatable_corpse(item))return (false);if (!actual)return (true);const monster_type zombie_type =static_cast<monster_type>(item.plus);const int number = (item.props.exists(MONSTER_NUMBER)) ?item.props[MONSTER_NUMBER].get_short() : 0;// Headless hydras cannot be raised, sorry.if (zombie_type == MONS_HYDRA && number == 0)return (false);monster_type mon = MONS_PROGRAM_BUG;if (item.sub_type == CORPSE_BODY){mon = (mons_zombie_size(item.plus) == Z_SMALL) ?MONS_ZOMBIE_SMALL : MONS_ZOMBIE_LARGE;}else{mon = (mons_zombie_size(item.plus) == Z_SMALL) ?MONS_SKELETON_SMALL : MONS_SKELETON_LARGE;}int monster = create_monster(mgen_data(mon, beha, 0,coord_def(x, y), hitting,god_gift ? MF_GOD_GIFT : 0,zombie_type, number));if (monster != -1){const int monnum = item.orig_monnum - 1;if (mons_is_unique(monnum)){menv[monster].mname = origin_monster_name(item);// Special case for Blork the orc: shorten his name to "Blork"// to avoid mentions of "Blork the orc the orc skeleton".if (monnum == MONS_BLORK_THE_ORC)menv[monster].mname = "Blork";}_equip_undead(x, y, corps, monster, monnum);}destroy_item(corps);return (true);}bool animate_a_corpse(int x, int y, corpse_type class_allowed,beh_type beha, unsigned short hitting,bool god_gift, bool actual,bool silent){bool success = false;int corps = igrd[x][y];// This searches all the items on the ground for a corpse.while (corps != NON_ITEM){const item_def& item = mitm[corps];if (_is_animatable_corpse(item)&& (class_allowed == CORPSE_BODY|| item.sub_type == CORPSE_SKELETON)){bool was_butchering = is_being_butchered(item);success = _raise_corpse(x, y, corps, beha, hitting, god_gift,actual);if (actual && success){if (!silent){if (was_butchering)mpr("The corpse you are butchering rises to attack!");if (is_terrain_seen(x, y))mpr("The dead are walking!");}if (was_butchering)xom_is_stimulated(255);}break;}corps = item.link;}return (success);}int animate_dead(actor *caster, int pow, beh_type beha, unsigned short hitting,bool god_gift, bool actual){UNUSED(pow);static env_show_grid losgrid;const coord_def c(caster->pos());int minx = c.x - 6;int maxx = c.x + 7;int miny = c.y - 6;int maxy = c.y + 7;int xinc = 1;int yinc = 1;int number_raised = 0;int number_seen = 0;if (coinflip()){minx = c.x + 6;maxx = c.x - 7;xinc = -1;}if (coinflip()){miny = c.y + 6;maxy = c.y - 7;yinc = -1;}if (caster != &you)losight(losgrid, grd, c.x, c.y, true);env_show_grid &los(caster == &you? env.no_trans_show : losgrid);coord_def a;for (a.x = minx; a.x != maxx; a.x += xinc){for (a.y = miny; a.y != maxy; a.y += yinc){if (!in_bounds(a) || !see_grid(los, c, a))continue;int corps = igrd(a);if (corps != NON_ITEM){// This searches all the items on the ground for a// corpse. Only one of a stack will be raised.while (corps != NON_ITEM){if (animate_a_corpse(a.x, a.y, CORPSE_BODY, beha,hitting, god_gift, actual, true)){number_raised++;if (see_grid(env.show, you.pos(), a))number_seen++;break;}corps = mitm[corps].link;}}}}return (number_raised);}
// last updated 24may2000 {dlb}/* ************************************************************************ called from: ability - spell* *********************************************************************** */int animate_a_corpse(int axps, int ayps, beh_type corps_beh,int corps_hit, int class_allowed);// last updated 24may2000 {dlb}/* ************************************************************************ called from: ability - it_use3 - monstuff - mstuff2 - spell* *********************************************************************** */int animate_dead(actor *caster, int power, beh_type corps_beh,int corps_hit, int actual);
int animate_dead( actor *caster, int power, beh_type corps_beh,int corps_hit, int actual ){UNUSED( power );static env_show_grid losgrid;const coord_def c(caster->pos());int minx = c.x - 6;int maxx = c.x + 7;int miny = c.y - 6;int maxy = c.y + 7;int xinc = 1;int yinc = 1;int number_raised = 0;int number_seen = 0;if (coinflip()){minx = c.x + 6;maxx = c.x - 7;xinc = -1;}
if (coinflip()){miny = c.y + 6;maxy = c.y - 7;yinc = -1;}if (caster != &you)losight(losgrid, grd, c.x, c.y, true);env_show_grid &los(caster == &you? env.no_trans_show : losgrid);coord_def a;bool was_butchered = false;for (a.x = minx; a.x != maxx; a.x += xinc)for (a.y = miny; a.y != maxy; a.y += yinc){if (!in_bounds(a) || !see_grid(los, c, a))continue;if (igrd(a) != NON_ITEM){int objl = igrd(a);int hrg = 0;// This searches all the items on the ground for a corpse.// Only one of a stack will be raised.while (objl != NON_ITEM){if (is_animatable_corpse(mitm[objl])&& !is_being_butchered(mitm[objl])){if (is_being_butchered(mitm[objl], false))was_butchered = true;int num = raise_corpse(objl, a.x, a.y, corps_beh,corps_hit, actual);number_raised += num;if (see_grid(env.show, you.pos(), a))number_seen += num;break;}hrg = mitm[objl].link;objl = hrg;}objl = 1;}}if (actual == 0)return (number_raised);if (was_butchered)mpr("The corpse you are butchering rises to attack!");if (number_seen > 0)mpr("The dead are walking!");return (number_raised);}int animate_a_corpse( int axps, int ayps, beh_type corps_beh, int corps_hit,int class_allowed ){int rc = 0;int objl = igrd[axps][ayps];// This searches all the items on the ground for a corpsewhile (objl != NON_ITEM){const item_def& item = mitm[objl];if (is_animatable_corpse(item)&& (class_allowed == CORPSE_BODY|| item.sub_type == CORPSE_SKELETON)){bool was_butchering = is_being_butchered(item);rc = raise_corpse(objl, axps, ayps, corps_beh, corps_hit, 1);if (rc){if (was_butchering)mpr("The corpse you are butchering rises to attack!");if (is_terrain_seen(axps, ayps))mpr("The dead are walking!");if (was_butchering)xom_is_stimulated(255);}break;}objl = item.link;}return rc;}// Try to equip the zombie/skeleton with the objects it died with.// This excludes items which were dropped by the player onto the corpse,// and corpses which were picked up and moved by the player, so the player// can't equip their undead slaves with items of their choice.//// The item selection logic has one problem: if a first monster without// any items dies and leaves a corpse, and then a second monster with// items dies on the same spot but doesn't leave a corpse, then the// undead can be equipped with the second monster's items if the second// monster is either of the same type as the first, or if the second// monster wasn't killed by the player or a player's pet.static void _equip_undead( int x, int y, int corps, int monster, int monnum){// Delay this until after 0.4#if 0monsters* mon = &menv[monster];monster_type type = static_cast<monster_type>(monnum);if (mons_itemuse(monnum) < MONUSE_STARTING_EQUIPMENT)return;// If the player picked up and dropped the corpse then all its// original equipment fell off.if (mitm[corps].flags & ISFLAG_DROPPED)return;// A monster's corpse is last in the linked list after its items,// so (for example) the first item after the second-to-last corpse// is the first item belonging to the last corpse.int objl = igrd[x][y];int first_obj = NON_ITEM;while (objl != NON_ITEM && objl != corps){item_def item(mitm[objl]);if (item.base_type == OBJ_CORPSES){first_obj = NON_ITEM;continue;}if (first_obj == NON_ITEM)first_obj = objl;objl = item.link;}ASSERT(objl == corps);if (first_obj == NON_ITEM)return;// Iterate backwards over the list, since the items earlier in the// linked list were dropped most recently and hence more likely to// be items the monster didn't die with.std::vector<int> item_list;objl = first_obj;while (objl != NON_ITEM && objl != corps){item_list.push_back(objl);objl = mitm[objl].link;}for (int i = item_list.size() - 1; i >= 0; i--){objl = item_list[i];item_def &item(mitm[objl]);// Stop equipping monster if the item probably didn't originally// belong to the monster.if ( (origin_known(item) && (item.orig_monnum - 1) != monnum)|| (item.flags & (ISFLAG_DROPPED | ISFLAG_THROWN))|| item.base_type == OBJ_CORPSES){return;}mon_inv_type mslot;switch(item.base_type){case OBJ_WEAPONS:if (mon->inv[MSLOT_WEAPON] != NON_ITEM){if (mons_wields_two_weapons(type))mslot = MSLOT_ALT_WEAPON;else{if (is_range_weapon(mitm[mon->inv[MSLOT_WEAPON]])== is_range_weapon(item)){// Two different items going into the same// slot indicate that this and further items// weren't equipment the monster died with.return;}else// The undead are too stupid to switch between weapons.continue;}}elsemslot = MSLOT_WEAPON;break;case OBJ_ARMOUR:mslot = equip_slot_to_mslot(get_armour_slot(item));// A piece of armour which can't be worn indicates that this// and further items weren't the equipment the monster died// with.if (mslot == NUM_MONSTER_SLOTS)return;break;case OBJ_MISSILES:mslot = MSLOT_MISSILE;break;case OBJ_GOLD:mslot = MSLOT_GOLD;break;// The undead are too stupid to use these.case OBJ_WANDS:case OBJ_SCROLLS:case OBJ_POTIONS:case OBJ_MISCELLANY:continue;default:continue;} // switch// Two different items going into the same slot indicate that// this and further items weren't equipment the monster died// with.if (mon->inv[mslot] != NON_ITEM)return;unlink_item(objl);mon->inv[mslot] = objl;if (mslot != MSLOT_ALT_WEAPON || mons_wields_two_weapons(mon))mon->equip(item, mslot, 0);} // while#endif}static int raise_corpse( int corps, int corx, int cory,beh_type corps_beh, int corps_hit, int actual ){int returnVal = 1;if (!mons_zombie_size(mitm[corps].plus))returnVal = 0;else if (actual != 0){monster_type type = MONS_PROGRAM_BUG;if (mitm[corps].sub_type == CORPSE_BODY){if (mons_zombie_size(mitm[corps].plus) == Z_SMALL)type = MONS_ZOMBIE_SMALL;elsetype = MONS_ZOMBIE_LARGE;}else{if (mons_zombie_size(mitm[corps].plus) == Z_SMALL)type = MONS_SKELETON_SMALL;elsetype = MONS_SKELETON_LARGE;}const int number =mitm[corps].props.exists(MONSTER_NUMBER)? mitm[corps].props[MONSTER_NUMBER].get_short(): 0;const monster_type zombie_type =static_cast<monster_type>(mitm[corps].plus);// Headless hydras cannot be raised, sorry.if (!number && zombie_type == MONS_HYDRA)return (0);int monster = create_monster(mgen_data(type, corps_beh, 0,coord_def(corx, cory), corps_hit,0, zombie_type, number));if (monster != -1){const int monnum = mitm[corps].orig_monnum - 1;if (mons_is_unique(monnum)){menv[monster].mname = origin_monster_name(mitm[corps]);// Special case for Blork the orc: shorten his name to "Blork"// to avoid mentions of "Blork the orc the orc skeleton".if (monnum == MONS_BLORK_THE_ORC)menv[monster].mname = "Blork";}_equip_undead(corx, cory, corps, monster, monnum);}destroy_item(corps);}return returnVal;} // end raise_corpse()
// see special handling in monstuff::handle_spell {dlb}animate_dead( monster, 5 + random2(5), SAME_ATTITUDE(monster),monster->foe, 1 );
// see special handling in monstuff::handle_spell() {dlb}animate_dead(monster, 5 + random2(5), SAME_ATTITUDE(monster),monster->foe);
animate_a_corpse( you.x_pos, you.y_pos, BEH_FRIENDLY,you.pet_target, CORPSE_BODY );
animate_a_corpse(you.x_pos, you.y_pos, CORPSE_BODY, BEH_FRIENDLY,you.pet_target, true);
animate_dead( &you, 1 + you.skills[SK_INVOCATIONS], BEH_FRIENDLY,you.pet_target, 1 );
animate_dead(&you, 1 + you.skills[SK_INVOCATIONS], BEH_FRIENDLY,you.pet_target, true);