// Adds 'parent' as a sire or dam of 'child' // after checking for re-parentage and cycles. void add_parent(CatID child, CatID parent) { // Update Child Pointers int childPointer = getCat(child); if (childPointer == NIL) { childPointer = nextFreeCat(); cats[childPointer].tableEntry = child; // EDIT ME symTable[child] = childPointer; } // check for re-parentage if (is_male(parent) ? cats[childPointer].sire != NIL : cats[childPointer].dam != NIL) { printf("Input ignored: %d already has a %s.\n", child, is_male(parent) ? "sire" : "dam"); return; } // Update Parent Pointers int parentPointer = getCat(parent); // printf("%d\n", parentPointer); if (parentPointer == NIL) { parentPointer = nextFreeCat(); cats[parentPointer].tableEntry = parent; // EDIT ME symTable[parent] = parentPointer; } // check for cycles if (is_ancestor(parent, child)) { printf("Input ignored: it would cause cycle\n"); return; } // set parent pointer if (is_male(parent)) cats[childPointer].sire = parentPointer; else cats[childPointer].dam = parentPointer; // set child pointer if (cats[parentPointer].eldest_child == NIL) { // this is first child to be added assert(cats[parentPointer].youngest_child == NIL); cats[parentPointer].eldest_child = childPointer; cats[parentPointer].youngest_child = childPointer; } else { // this is not the first child to be added CatID youngest_child = cats[parentPointer].youngest_child; assert(youngest_child != NIL); if (is_male(parent)) { assert(cats[youngest_child].next_younger_by_sire == NIL); cats[youngest_child].next_younger_by_sire = childPointer; } else { assert(cats[youngest_child].next_younger_by_dam == NIL); cats[youngest_child].next_younger_by_dam = childPointer; } cats[parentPointer].youngest_child = childPointer; } }
void change_sex(void) { /* setting u.umonster for caveman/cavewoman or priest/priestess swap unintentionally makes `Upolyd' appear to be true */ boolean already_polyd = (boolean) Upolyd; /* Some monsters are always of one sex and their sex can't be changed */ /* succubi/incubi can change, but are handled below */ /* !already_polyd check necessary because is_male() and is_female() are true if the player is a priest/priestess */ if (!already_polyd || (!is_male(youmonst.data) && !is_female(youmonst.data) && !is_neuter(youmonst.data))) flags.female = !flags.female; if (already_polyd) /* poly'd: also change saved sex */ u.mfemale = !u.mfemale; max_rank_sz(); /* [this appears to be superfluous] */ if ((already_polyd ? u.mfemale : flags.female) && urole.name.f) strcpy(pl_character, urole.name.f); else strcpy(pl_character, urole.name.m); u.umonster = ((already_polyd ? u.mfemale : flags.female) && urole.femalenum != NON_PM) ? urole.femalenum : urole.malenum; if (!already_polyd) { u.umonnum = u.umonster; } else if (u.umonnum == PM_SUCCUBUS || u.umonnum == PM_INCUBUS) { flags.female = !flags.female; /* change monster type to match new sex */ u.umonnum = (u.umonnum == PM_SUCCUBUS) ? PM_INCUBUS : PM_SUCCUBUS; set_uasmon(); } }
// -------------------------------------------------------------------------------- // Set Soft Links void setSoftLinks(int damCat) { for(int i = catMemory; i < memoryEnd; i++) { if(is_male(i)) { //i is male CatID curr = cats[i].eldest_child; while(curr != NIL) { cats[curr].sire = i; //printf("%d sire is %d \n", curr, cats[curr].sire); cats[i].youngest_child = curr; curr = cats[curr].next_younger_by_sire; } } else { //i is a female CatID curr = cats[i].eldest_child; while(curr != NIL) { cats[curr].dam = i; //printf("%d dam is %d\n", curr, cats[curr].dam); cats[i].youngest_child = curr; curr = cats[i].next_younger_by_dam; } } } }
// Sets the 'counter' on all the descendants of 'cat' to 'COUNTER_SENTINEL'. void clear_descendants(CatID cat, int max_depth, int curr_depth) { if (cat == NIL) return; else if (curr_depth > max_depth) return; else { // clear self cats[cat].counter = COUNTER_SENTINEL; // recur on children by looping though the eldest's siblings for (CatID child = cats[cat].eldest_child; child != NIL; child = get_sibling(child, is_male(cat))) { clear_descendants(child, max_depth, curr_depth + 1); } } }
// Sets the 'counter' on the descendants of 'cat'. void mark_descendants(CatID cat, int max_depth, int curr_depth) { if (cat == NIL) return; else if (curr_depth > max_depth) return; else { // mark self cats[cat].counter = min_counter(curr_depth, cats[cat].counter); // recur on children by looping though the eldest's siblings for (CatID child = cats[cat].eldest_child; child != NIL; child = get_sibling(child, is_male(cat))) { mark_descendants(child, max_depth, curr_depth + 1); } } }
// Prints "<cat1> is the <relationship> of <cat2>.\n" void print_relationship(CatID cat1, int count1, CatID cat2, int count2) { assert(count1 != COUNTER_SENTINEL); assert(count2 != COUNTER_SENTINEL); printf("%d is the ", cats[cat1].tableEntry); //printf("%d is the ", cats[cat1].tableEntry); if (count1 == 0 && count2 == 0) { printf("same as"); } else if (count1 == 0) { print_great_grand(count2 - 1); printf(is_male(cats[cat1].tableEntry) ? "father of" : "mother of"); } else if (count2 == 0) { print_great_grand(count1 - 1); printf(is_male(cats[cat1].tableEntry) ? "son of" : "daughter of"); } else if (count1 == 1 && count2 == 1) { printf(is_male(cats[cat1].tableEntry) ? "brother of" : "sister of"); } else if (count1 == 1) { print_great_grand(count2 - 2); printf(is_male(cats[cat1].tableEntry) ? "uncle of" : "aunt of"); } else if (count2 == 1) { print_great_grand(count1 - 2); printf(is_male(cats[cat1].tableEntry) ? "nephew of" : "niece of"); } else { int i = min_counter(count1, count2) - 1; int j = abs(count1 - count2); print_ordinal(i); printf(" cousin"); if (j > 0) printf(", %d time%s removed", j, j == 1 ? "" : "s"); printf(" of"); } printf(" %d.\n", cats[cat2].tableEntry); //printf(" eldest_child: %d.\n", cats[cat1].eldest_child); }
// Function called for each part (ex. 3@1) of the save command void save_descendants(int cat, int lvl) { cat = getCat(cat); int damCat = getTopCat(cat, lvl); //printf("%d cat, %d damCat, %d lvl(s)\n", cats[cat].tableEntry, cats[damCat].tableEntry, lvl); // EXTRA //cats[cat].counter = COUNTER_SENTINEL; //cats[toSpacePointer] = cats[cat]; //symTable[ cats[cat].tableEntry ] = toSpacePointer; // EXTRA /* damCat = move_saved_dam(toSpacePointer, damCat); int eldestCat = move_saved_cats(damCat); cats[damCat].eldest_child = eldestCat; */ int eldestCat = -1; if (cats[damCat].eldest_child != NIL) { eldestCat = move_saved_cats(cats[damCat].eldest_child); } damCat = move_saved_dam(toSpacePointer, damCat); cats[damCat].eldest_child = eldestCat; if (is_male(damCat)) cats[eldestCat].sire = damCat; else cats[eldestCat].dam = damCat; if (catMemory == 0) { toSpacePointer = 0; catMemory = NUM_CATS; memoryEnd = NUM_CATS * 2; } else { toSpacePointer = NUM_CATS; catMemory = 0; memoryEnd = NUM_CATS; } //printf("getCat %d | getTopCat %d\n", cat, damCat); setSoftLinks(damCat); }
// Prints the descendants of 'curr'. void print_descendants(CatID root, CatID curr, int max_depth, int curr_depth) { if (curr == NIL) return; else if (curr_depth > max_depth) return; else { // print self if (curr_depth == cats[curr].counter) { printf("At generation %d, ", curr_depth); print_relationship(curr, curr_depth, root, 0); // ensure we don't print this cat again cats[curr].counter = COUNTER_SENTINEL; } // recur on children by looping though the eldest's siblings for (CatID child = cats[curr].eldest_child; child != NIL; child = get_sibling(child, is_male(curr))) { print_descendants(root, child, max_depth, curr_depth + 1); } } }
/* returns 1 if polymorph successful */ int polymon(int mntmp) { boolean sticky = sticks(youmonst.data) && u.ustuck && !u.uswallow, was_blind = !!Blind, dochange = FALSE; boolean could_pass_walls = Passes_walls; int mlvl; if (mvitals[mntmp].mvflags & G_GENOD) { /* allow G_EXTINCT */ pline("You feel rather %s-ish.",mons[mntmp].mname); exercise(A_WIS, TRUE); return 0; } /* KMH, conduct */ u.uconduct.polyselfs++; if (!Upolyd) { /* Human to monster; save human stats */ u.macurr = u.acurr; u.mamax = u.amax; u.mfemale = flags.female; } else { /* Monster to monster; restore human stats, to be * immediately changed to provide stats for the new monster */ u.acurr = u.macurr; u.amax = u.mamax; flags.female = u.mfemale; } if (youmonst.m_ap_type) { /* stop mimicking immediately */ if (multi < 0) unmul(""); } else if (mons[mntmp].mlet != S_MIMIC) { /* as in polyman() */ youmonst.m_ap_type = M_AP_NOTHING; } if (is_male(&mons[mntmp])) { if (flags.female) dochange = TRUE; } else if (is_female(&mons[mntmp])) { if (!flags.female) dochange = TRUE; } else if (!is_neuter(&mons[mntmp]) && mntmp != u.ulycn) { if (!rn2(10)) dochange = TRUE; } if (dochange) { flags.female = !flags.female; pline("You %s %s%s!", (u.umonnum != mntmp) ? "turn into a" : "feel like a new", (is_male(&mons[mntmp]) || is_female(&mons[mntmp])) ? "" : flags.female ? "female " : "male ", mons[mntmp].mname); } else { if (u.umonnum != mntmp) pline("You turn into %s!", an(mons[mntmp].mname)); else pline("You feel like a new %s!", mons[mntmp].mname); } if (Stoned && poly_when_stoned(&mons[mntmp])) { /* poly_when_stoned already checked stone golem genocide */ pline("You turn to stone!"); mntmp = PM_STONE_GOLEM; Stoned = 0; delayed_killer = 0; } u.mtimedone = rn1(500, 500); u.umonnum = mntmp; set_uasmon(); /* New stats for monster, to last only as long as polymorphed. * Currently only strength gets changed. */ if (strongmonst(&mons[mntmp])) ABASE(A_STR) = AMAX(A_STR) = STR18(100); if (Stone_resistance && Stoned) { /* [email protected] */ Stoned = 0; delayed_killer = 0; pline("You no longer seem to be petrifying."); } if (Sick_resistance && Sick) { make_sick(0L, NULL, FALSE, SICK_ALL); pline("You no longer feel sick."); } if (Slimed) { if (flaming(youmonst.data)) { pline("The slime burns away!"); Slimed = 0L; iflags.botl = 1; } else if (mntmp == PM_GREEN_SLIME) { /* do it silently */ Slimed = 0L; iflags.botl = 1; } } if (nohands(youmonst.data)) Glib = 0; /* mlvl = adj_lev(&mons[mntmp]); * We can't do the above, since there's no such thing as an * "experience level of you as a monster" for a polymorphed character. */ mlvl = (int)mons[mntmp].mlevel; if (youmonst.data->mlet == S_DRAGON && mntmp >= PM_GRAY_DRAGON) { u.mhmax = In_endgame(&u.uz) ? (8*mlvl) : (4*mlvl + dice(mlvl,4)); } else if (is_golem(youmonst.data)) { u.mhmax = golemhp(mntmp); } else { if (!mlvl) u.mhmax = rnd(4); else u.mhmax = dice(mlvl, 8); if (is_home_elemental(&u.uz, &mons[mntmp])) u.mhmax *= 3; } u.mh = u.mhmax; if (u.ulevel < mlvl) { /* Low level characters can't become high level monsters for long */ u.mtimedone = u.mtimedone * u.ulevel / mlvl; } if (uskin && mntmp != armor_to_dragon(uskin->otyp)) skinback(FALSE); break_armor(); drop_weapon(1); if (hides_under(youmonst.data)) u.uundetected = OBJ_AT(u.ux, u.uy); else if (youmonst.data->mlet == S_EEL) u.uundetected = is_pool(level, u.ux, u.uy); else u.uundetected = 0; if (u.utraptype == TT_PIT) { if (could_pass_walls && !Passes_walls) { u.utrap = rn1(6,2); } else if (!could_pass_walls && Passes_walls) { u.utrap = 0; } } if (was_blind && !Blind) { /* previous form was eyeless */ Blinded = 1L; make_blinded(0L, TRUE); /* remove blindness */ } newsym(u.ux,u.uy); /* Change symbol */ if (!sticky && !u.uswallow && u.ustuck && sticks(youmonst.data)) u.ustuck = 0; else if (sticky && !sticks(youmonst.data)) uunstick(); if (u.usteed) { if (touch_petrifies(u.usteed->data) && !Stone_resistance && rnl(3)) { char buf[BUFSZ]; pline("No longer petrifying-resistant, you touch %s.", mon_nam(u.usteed)); sprintf(buf, "riding %s", an(u.usteed->data->mname)); instapetrify(buf); } if (!can_ride(u.usteed)) dismount_steed(DISMOUNT_POLY); } if (flags.verbose) { static const char use_thec[] = "Use the command #%s to %s."; static const char monsterc[] = "monster"; if (can_breathe(youmonst.data)) pline(use_thec,monsterc,"use your breath weapon"); if (attacktype(youmonst.data, AT_SPIT)) pline(use_thec,monsterc,"spit venom"); if (youmonst.data->mlet == S_NYMPH) pline(use_thec,monsterc,"remove an iron ball"); if (attacktype(youmonst.data, AT_GAZE)) pline(use_thec,monsterc,"gaze at monsters"); if (is_hider(youmonst.data)) pline(use_thec,monsterc,"hide"); if (is_were(youmonst.data)) pline(use_thec,monsterc,"summon help"); if (webmaker(youmonst.data)) pline(use_thec,monsterc,"spin a web"); if (u.umonnum == PM_GREMLIN) pline(use_thec,monsterc,"multiply in a fountain"); if (is_unicorn(youmonst.data)) pline(use_thec,monsterc,"use your horn"); if (is_mind_flayer(youmonst.data)) pline(use_thec,monsterc,"emit a mental blast"); if (youmonst.data->msound == MS_SHRIEK) /* worthless, actually */ pline(use_thec,monsterc,"shriek"); if (lays_eggs(youmonst.data) && flags.female) pline(use_thec,"sit","lay an egg"); } /* you now know what an egg of your type looks like */ if (lays_eggs(youmonst.data)) { learn_egg_type(u.umonnum); /* make queen bees recognize killer bee eggs */ learn_egg_type(egg_type_from_parent(u.umonnum, TRUE)); } find_ac(); if ((!Levitation && !u.ustuck && !Flying && (is_pool(level, u.ux,u.uy) || is_lava(level, u.ux,u.uy))) || (Underwater && !Swimming)) spoteffects(TRUE); if (Passes_walls && u.utrap && u.utraptype == TT_INFLOOR) { u.utrap = 0; pline("The rock seems to no longer trap you."); } else if (likes_lava(youmonst.data) && u.utrap && u.utraptype == TT_LAVA) { u.utrap = 0; pline("The lava now feels soothing."); } if (amorphous(youmonst.data) || is_whirly(youmonst.data) || unsolid(youmonst.data)) { if (Punished) { pline("You slip out of the iron chain."); unpunish(); } } if (u.utrap && (u.utraptype == TT_WEB || u.utraptype == TT_BEARTRAP) && (amorphous(youmonst.data) || is_whirly(youmonst.data) || unsolid(youmonst.data) || (youmonst.data->msize <= MZ_SMALL && u.utraptype == TT_BEARTRAP))) { pline("You are no longer stuck in the %s.", u.utraptype == TT_WEB ? "web" : "bear trap"); /* probably should burn webs too if PM_FIRE_ELEMENTAL */ u.utrap = 0; } if (webmaker(youmonst.data) && u.utrap && u.utraptype == TT_WEB) { pline("You orient yourself on the web."); u.utrap = 0; } iflags.botl = 1; vision_full_recalc = 1; see_monsters(); exercise(A_CON, FALSE); exercise(A_WIS, TRUE); encumber_msg(); return 1; }