void shHero::payDoctor (shMonster *doctor) { static const char *MedicalProcedureNames[] = { "Wound Treatment", "Restoration Treatment", "Intestinal Examination", "Systems Diagnostics", "Radiation Purge", "Caesarean Section", "Canister Amputation", "Teef Extraction", "Tail Amputation" }; static bool hadamputation = false; char buf[200]; shMenu *menu = I->newMenu ("Medical Services Menu", 0); int serv; const int TREATMENT_COST = 200; if (tryToTranslate (doctor)) { /* make all services known */ for (int i = 0; i < kMedMaxService; ++i) { MedicalProcedureData[i].mNameKnown = 1; } } char letter = 'a'; for (int i = 0; i < kMedMaxService; ++i) { serv = doctor->mDoctor.mPermute[i]; /* try not to offer unneeded services */ switch (serv) { case kMedHealing: if (Hero.mHP != Hero.mMaxHP or Hero.is (kViolated) or Hero.is (kConfused) or Hero.is (kStunned)) { break; } continue; case kMedRestoration: { int add = 0; FOR_ALL_ABILITIES (j) { int abil = Hero.mAbil.getByIndex (j); if (kPsi == j) { abil += Hero.mPsiDrain; } if (abil < Hero.mMaxAbil.getByIndex (j)) { add = 1; break; } } if (add) break; continue; } case kMedRectalExam: case kMedDiagnostics: case kMedRadPurification: /* these services are always available: */ break; case kMedCaesareanSection: if (Hero.getStoryFlag ("impregnation")) break; continue; case kMedCanisterAmputation: if (Hero.getStoryFlag ("superglued tongue")) break; continue; case kMedTeefExtraction: if (!Hero.getStoryFlag ("lost teef") and Hero.isOrc ()) break; continue; case kMedTailAmputation: if (Hero.mIlkId == kMonXelNaga and !Hero.getStoryFlag ("lost tail")) break; continue; default: continue; } snprintf (buf, sizeof(buf), "%s ($%d)", MedicalProcedureData[serv].mNameKnown ? MedicalProcedureNames[serv] : MedicalProcedureData[serv].mDesc, TREATMENT_COST); menu->addIntItem (letter++, buf, serv); } int res; if (!menu->getIntResult (&res)) return; /* nothing picked */ delete menu; MedicalProcedures choice = MedicalProcedures (res); int price = TREATMENT_COST; if (countMoney () < price) { I->p ("You don't have enough money for that."); return; } if (Hero.is (kFrightened) and choice == kMedTeefExtraction and MedicalProcedureData[choice].mNameKnown) { I->p ("No way! You are too afraid of the dentist at the moment!"); return; } loseMoney (price); doctor->gainMoney (price); const char *who = doctor->the (); shObjectIlk *ilk; switch (choice) { case kMedHealing: ilk = &AllIlks[kObjHealingRayGun]; I->p ("%s injects you with a %s serum!", who, !Hero.isBlind () ? ilk->getRayGunColor () : "kind of"); if (Hero.healing (NDX (10, 5), 0) and !Hero.isBlind ()) { ilk->mFlags |= kIdentified; MedicalProcedureData[choice].mNameKnown = 1; } break; case kMedRestoration: ilk = &AllIlks[kObjRestorationRayGun]; I->p ("%s injects you with a %s serum!", who, !Hero.isBlind () ? ilk->getRayGunColor () : "kind of"); if (Hero.restoration (NDX (3, 2))) { MedicalProcedureData[choice].mNameKnown = 1; if (!Hero.isBlind ()) ilk->mFlags |= kIdentified; } break; case kMedRectalExam: { int probed = 0; /* Was loser option pre PRIME 1.7 but why not make it useful in a border case? */ MedicalProcedureData[choice].mNameKnown = 1; I->p ("%s probes you!", who); /* Any resistance is treated like obstacle. */ if (!Hero.mResistances[kViolating]) { Hero.sufferDamage (kAttProbe); probed = 1; } else { /* If hero wears loser anorak he is immune. */ I->p ("You seem unaffected."); Hero.mCloak->setKnown (); if (Hero.tryToTranslate (doctor)) { I->p ("\"I cannot perform the service while you wear %s.\"", THE (Hero.mCloak)); Hero.mCloak->setKnown (); /* Get rid of buggy loser anorak for 200 BZ. */ if (I->yn ("\"May I remove it?\"")) { I->p ("%s removes %s.", who, YOUR (Hero.mCloak)); Hero.doff (Hero.mCloak); I->p ("%s probes you again!", who); Hero.sufferDamage (kAttProbe); probed = 1; } else { I->p ("Money-back guarantee requires me to refuse payment."); gainMoney (price); doctor->loseMoney (price); } } else { I->p ("%s chirps something and gives back your money.", who); gainMoney (price); doctor->loseMoney (price); } if (probed and Hero.getStoryFlag ("impregnation")) { I->p ("\"You have a parasite.\""); } /* Thank you, Captain Obvious! */ } break; } case kMedDiagnostics: MedicalProcedureData[choice].mNameKnown = 1; I->p ("%s probes you!", who); Hero.doDiagnostics (0); break; case kMedRadPurification: MedicalProcedureData[choice].mNameKnown = 1; I->p ("%s injects you with a %s serum!", who, !Hero.isBlind () ? "bubbly" : "kind of"); Hero.mRad = maxi (0, Hero.mRad - RNG (50, 200)); if (!Hero.mRad) I->p ("You feel purified."); else I->p ("You feel less contaminated."); break; case kMedCaesareanSection: { if (!Hero.getStoryFlag ("impregnation")) break; MedicalProcedureData[choice].mNameKnown = 1; Hero.setStoryFlag ("impregnation", 0); int x = Hero.mX; int y = Hero.mY; int queen = !RNG (0, 17); int colicky = !RNG (0, 5); shMonster *baby = new shMonster (queen ? kMonAlienPrincess : kMonChestburster); if (!colicky) { baby->mDisposition = shMonster::kIndifferent; } Level->findNearbyUnoccupiedSquare (&x, &y); if (!baby) { I->p ("Unfortunately, your baby was stillborn."); } else { I->p ("It's a %s!", queen ? "girl" : "boy"); if (Level->putCreature (baby, x, y)) { /* FIXME: something went wrong */ } else { I->drawScreen (); } } I->p ("You lose a lot of blood during the operation."); if (Hero.sufferDamage (kAttCaesareanSection)) { Hero.shCreature::die (kKilled, "complications in childbirth"); } break; } case kMedCanisterAmputation: { if (!Hero.getStoryFlag ("superglued tongue")) break; MedicalProcedureData[choice].mNameKnown = 1; I->p ("%s cuts away the glued canister.", who); Hero.resetStoryFlag ("superglued tongue"); amputationDiscount (doctor, this, &hadamputation, price); } case kMedTeefExtraction: { if (Hero.getStoryFlag ("lost teef")) break; int sum = NDX (11, 100); Hero.setStoryFlag ("lost teef", sum); MedicalProcedureData[choice].mNameKnown = 1; /* Kind of pointless. */ if (Hero.is (kFrightened)) { char *buf = GetBuf (); strcpy (buf, who); buf[0] = toupper (buf[0]); I->p ("Oh no!! %s gets at your teef!", buf); I->p ("You panic and try to flee but %s has immobilized you already.", who); } else I->p ("%s extracts your teef.", who); I->p ("Your magnificent teef are worth $%d buckazoids.", sum); gainMoney (sum); break; } case kMedTailAmputation: { if (Hero.getStoryFlag ("lost tail")) break; Hero.setStoryFlag ("lost tail", 1); MedicalProcedureData[choice].mNameKnown = 1; I->p ("%s amputates your tail!", who); Hero.amputateTail (); amputationDiscount (doctor, this, &hadamputation, price); } case kMedMaxService: break; } I->drawSideWin (); }
void kma_free(void* ptr, kma_size_t size) { // return size is larger than half page // simply free the page if(size > MAXSPACE / 2) { kpage_t* page = *((kpage_t**)((void*)ptr - sizeof(kpage_t*))); free_page(page); return; } // put the return buffer into the freelist int index = NDX(size + sizeof(bufHeader_t)); kma_size_t reqSpace = SPACE(index); bufHeader_t* bufPtr; bufPtr = (bufHeader_t*)(ptr - sizeof(bufHeader_t)); bufPtr->ptr = kflPtr->p2fl[index]; kflPtr->p2fl[index] = bufPtr; kflPtr->spaceUsed -= reqSpace; // if all buffers are returned, free all pages cleanupKFL(); }
//constructor: shMonster::shMonster (shMonId id, int extralevels /* = 0 */ ) :shCreature () { int do_or = 0; int do_and = 0; int gotweapon = 0; shMonsterIlk *ilk = &MonIlks[id]; mIlkId = id; mType = ilk->mType; strncpy (mName, ilk->mName, 30); mCLevel = ilk->mBaseLevel; mNaturalArmorBonus = ilk->mNaturalArmorBonus; mReflexSaveBonus = 0; mDir = kNoDirection; mTame = 0; mStrategy = ilk->mDefaultStrategy; mDisposition = ilk->mDefaultDisposition; mTactic = kReady; mDestX = -1; mEnemyX = -1; mPlannedMoveIndex = -1; mSpellTimer = 0; memcpy (mInnateResistances, ilk->mInnateResistances, sizeof (mInnateResistances)); mInnateIntrinsics = ilk->mInnateIntrinsics; for (int i = 0; i < ilk->mNumPowers; ++i) if (ilk->mPowers[i] == kTelepathyPower) mInnateIntrinsics |= kTelepathy; /* Assume always on. */ mFeats = ilk->mFeats; #define IMMUNE 122 switch (mType) { case kMutant: mInnateResistances[kRadiological] = IMMUNE; mInnateResistances[kMagnetic] = IMMUNE; break; case kHumanoid: mInnateResistances[kMagnetic] = IMMUNE; break; case kAnimal: mInnateResistances[kMagnetic] = IMMUNE; mInnateIntrinsics |= kScent; break; case kInsect: mInnateResistances[kMagnetic] = IMMUNE; mInnateResistances[kRadiological] = IMMUNE; mInnateIntrinsics |= kScent; break; case kOutsider: mInnateResistances[kMagnetic] = IMMUNE; break; case kBot: mInnateResistances[kToxic] = IMMUNE; mInnateResistances[kPsychic] = IMMUNE; mInnateResistances[kRadiological] = IMMUNE; mInnateResistances[kViolating] = IMMUNE; mInnateResistances[kMesmerizing] = IMMUNE; mInnateResistances[kBlinding] = IMMUNE; mInnateIntrinsics |= kBreathless; break; case kDroid: mInnateResistances[kToxic] = IMMUNE; mInnateResistances[kPsychic] = IMMUNE; mInnateResistances[kRadiological] = IMMUNE; mInnateResistances[kViolating] = IMMUNE; mInnateResistances[kMesmerizing] = IMMUNE; mInnateResistances[kBlinding] = IMMUNE; mInnateIntrinsics |= kBreathless; break; case kProgram: mInnateResistances[kToxic] = IMMUNE; mInnateResistances[kRadiological] = IMMUNE; mInnateResistances[kViolating] = IMMUNE; /* Processes can be put to sleep so no kMesmerizing immunity. */ mInnateIntrinsics |= kBreathless; break; case kConstruct: mInnateResistances[kToxic] = IMMUNE; mInnateResistances[kPsychic] = IMMUNE; mInnateResistances[kRadiological] = IMMUNE; mInnateResistances[kStunning] = IMMUNE; mInnateResistances[kConfusing] = IMMUNE; mInnateResistances[kViolating] = IMMUNE; mInnateResistances[kParalyzing] = IMMUNE; mInnateResistances[kMesmerizing] = IMMUNE; mInnateResistances[kBlinding] = IMMUNE; mInnateIntrinsics |= kBreathless; break; case kOoze: mInnateResistances[kToxic] = 3; mInnateResistances[kMagnetic] = IMMUNE; mInnateResistances[kRadiological] = IMMUNE; mInnateResistances[kViolating] = IMMUNE; mInnateResistances[kWebbing] = IMMUNE; mInnateIntrinsics |= kBreathless; break; case kAberration: mInnateResistances[kMagnetic] = IMMUNE; mInnateResistances[kRadiological] = IMMUNE; mInnateResistances[kViolating] = IMMUNE; break; case kCyborg: mInnateResistances[kToxic] = 2; mInnateResistances[kRadiological] = 10; mInnateIntrinsics |= kBreathless; break; case kEgg: mInnateResistances[kViolating] = IMMUNE; mInnateIntrinsics |= kBreathless; /* fall through */ case kBeast: mInnateResistances[kMagnetic] = IMMUNE; mInnateIntrinsics |= kScent; break; case kVermin: mInnateResistances[kMagnetic] = IMMUNE; mInnateIntrinsics |= kScent; mInnateIntrinsics |= kCanSwim; break; case kAlien: mAlienEgg.mHatchChance = 0; mInnateResistances[kMagnetic] = IMMUNE; mInnateResistances[kRadiological] = 10; mInnateResistances[kCorrosive] = IMMUNE; mInnateIntrinsics |= kScent; if (!isA (kMonAlienQueen)) /* Too heavy and bloated. */ mInnateIntrinsics |= kJumpy; gainRank (kUnarmedCombat, mCLevel/2); break; default: debug.log ("Alert! Unknown monster type"); mInnateResistances[kMagnetic] = IMMUNE; } #undef IMMUNE if (3 == ilk->mGender) { mGender = RNG (1, 2); } else { mGender = ilk->mGender; } /* roll ability scores */ rollAbilityScores (ilk->mStr, ilk->mCon, ilk->mAgi, ilk->mDex, ilk->mInt, ilk->mPsi); /* roll hit points */ rollHitPoints (ilk->mHitDice, 8); /* setup speed */ mSpeed = ilk->mSpeed; computeAC (); mGlyph = ilk->mGlyph; if (isA (kMonMutantNinjaTurtle)) mGlyph.mTileX += RNG (4); /* Got four of those. */ mState = kActing; if (equipment[id].mPtr) /* Does monster get standard equipment? */ for (int i = 0; i < equipment[id].mCnt; ++i) { const char *str = equipment[id].mPtr[i]; if ('|' == str[0]) { /* the or symbol indicates don't try to create the object unless the previous obj failed */ if (0 == do_or) { do_or = 1; do_and = 0; continue; } else { ++str; } } else if (',' == str[0]) { /* the comma symbol indicates create the object only if the prev obj was made */ if (1 == do_and) { ++str; } else { continue; } } shObject *obj = createObject (str, 0); if (NULL == obj) { do_or = 1; do_and = 0; debug.log ("unable to equip %s", str); continue; } do_or = 0; do_and = 1; addObjectToInventory (obj); if (!mWeapon and obj->isA (kWeapon)) { if (obj->myIlk ()->mMeleeSkill != kNoSkillCode) { gainRank (obj->myIlk ()->mMeleeSkill, 1 + mCLevel * 2/3); } if (obj->myIlk ()->mGunSkill != kNoSkillCode) { gainRank (obj->myIlk ()->mGunSkill, 1 + mCLevel * 2/3); } ++gotweapon; /* don't wield until hero is in sight so he can see message */ //wield (obj, 1); } else if (obj->isA (kArmor) or obj->isA (kImplant)) { don (obj, 1); } } if (!gotweapon) { gainRank (kUnarmedCombat, 1 + mCLevel); } /* Maybe monster gets some more treasure. */ if (noTreasure () or kAnimal == mType or kBeast == mType or kAberration == mType or kInsect == mType or kVermin == mType or kOutsider == mType or kEgg == mType or kOoze == mType or kAlien == mType or kBot == mType or kConstruct == mType) { /* No treasure requested or a monster does not want treasure. */ } else { if (RNG (50) <= 5 + mCLevel) { shObject *cash = new shObject (kObjMoney); cash->mCount = NDX (mCLevel + 1, 10); addObjectToInventory (cash); } if (RNG (80) <= 5 + mCLevel) { shObject *obj = generateObject (-1); while (obj->getMass () > 5000) { delete obj; obj = generateObject (-1); } addObjectToInventory (obj); } } computeIntrinsics (); if (RNG (100) < ilk->mPeacefulChance) { mDisposition = kIndifferent; } debug.log ("spawned %s with %d HP speed %d", mName, mHP, mSpeed); }
void* kma_malloc(kma_size_t size) { // Check if the request is valid if(size > MAXSPACE) { printf("ERROR: too large request!\n"); return NULL; } // If no page is present in kernel // get a new page and initialize the header if(kflPtr == NULL) { if(initKFL(size)) return NULL; } // If the request size is larger than half page // simply return a whole page if(size > MAXSPACE / 2) { kpage_t* page; page = get_page(); *((kpage_t**)(page->ptr)) = page; return page->ptr + sizeof(kpage_t*); } // Roundup the size and calculate the index and size int index = NDX(size + sizeof(bufHeader_t)); kma_size_t reqSpace = SPACE(index); bufHeader_t* bufPtr; bool reqNewPage; // printf("size: %d\tindex: %d\t request space: %d\n", size, index, reqSpace); do { reqNewPage = FALSE; if(kflPtr->p2fl[index] == NULL) // No avalible buffer in freelist { if((reqSpace <= kflPtr->freespaceSize)) // cut a buffer from the current page { bufPtr = (bufHeader_t*) kflPtr->freespacePtr; kflPtr->freespaceSize -= reqSpace; kflPtr->freespacePtr += reqSpace; kflPtr->spaceUsed += reqSpace; return (void*)bufPtr + sizeof(bufHeader_t); } else // get a new page and initialize the header { allocSpaceLeft(index-1); initKFL(size); reqNewPage = TRUE; } } else // remove the buffer from the freelist and return it { bufPtr = kflPtr->p2fl[index]; kflPtr->p2fl[index] = (bufHeader_t*)bufPtr->ptr; kflPtr->spaceUsed += (int)reqSpace; return (void*)bufPtr + sizeof(bufHeader_t); } }while(reqNewPage); return NULL; }
int shMapLevel::buildSewer () { int x, y, i, n; int lighting = RNG (2) ? -1 : 1; SewerRoom nodes[NODECOLS][NODEROWS]; mMapType = kSewer; x = RNG (NODECOLS); y = RNG (NODEROWS); //first pass buildSewerHelper (nodes, x, y, 0); //second pass, make more tightly connected for (n = 10; n; n--) { if (RNG(3)) { x = RNG (NODECOLS-1); y = RNG (NODEROWS); nodes[x][y].mWalls[1] = 0; nodes[x+1][y].mWalls[2] = 0; } else { x = RNG (NODECOLS); y = RNG (NODEROWS-1); nodes[x][y].mWalls[3] = 0; nodes[x][y+1].mWalls[0] = 0; } } for (x = 0; x < NODECOLS; x++) { for (y = 0; y < NODEROWS; y++) { if (nodes[x][y].mDeadEnd or !RNG(7)) { nodes[x][y].mBulbous = 1; } } } // force 2 bulbous rooms x = RNG (NODECOLS/3); y = RNG (NODEROWS); nodes[x][y].mBulbous = 1; x = NODECOLS - 1 - RNG (NODECOLS/3); y = RNG (NODEROWS); nodes[x][y].mBulbous = 1; // don't have adjacent bulbous rooms (looks bad) for (x = 0; x < NODECOLS-1; x++) { for (y = 0; y < NODEROWS; y++) { if (nodes[x][y].mBulbous and nodes[x+1][y].mBulbous and nodes[x][y].mWalls[1]) { if (RNG(2)) nodes[x][y].mBulbous = 0; else nodes[x+1][y].mBulbous = 0; } } } for (x = 0; x < NODECOLS; x++) { for (y = 0; y < NODEROWS-1; y++) { if (nodes[x][y].mBulbous and nodes[x][y+1].mBulbous and nodes[x][y].mWalls[3]) { if (RNG(2)) nodes[x][y].mBulbous = 0; else nodes[x][y+1].mBulbous = 0; } } } for (x = 0; x < NODECOLS; x++) { for (y = 0; y < NODEROWS; y++) { buildSewerRoom (nodes, x, y); } } for (n = NDX(2,4); n; n--) { floodMuck (RNG(NODECOLS)*6+5, RNG(NODEROWS)*4+2, kSewage, NDX(8,20)); } for (i = NDX (2, 3); i; --i) { findUnoccupiedSquare (&x, &y); switch (RNG (4)) { case 0: addTrap (x, y, shFeature::kPit); break; case 1: addTrap (x, y, shFeature::kHole); break; case 2: addTrap (x, y, shFeature::kTrapDoor); break; case 3: addTrap (x, y, shFeature::kRadTrap); break; } } for (i = 0; i < 8; i++) { findUnoccupiedSquare (&x, &y); putObject (generateObject (mDLevel), x, y); } for (x = 0; x < mColumns; x++) for (y = 0; y < mRows; y++) setLit (x, y, lighting, lighting, lighting, lighting); return 1; }
void shHero::quaffFromVat (shFeature *vat) { assert (vat->mX == Hero.mX and vat->mY == Hero.mY); int dryup = 3; int result; if (isInShop ()) { quaffFromOwnedVat (vat); } if (vat->mVat.mHealthy <= -3) { /* You need to pour some nasty stuff in to achieve this. */ result = -2; } else if (vat->mVat.mRadioactive and !RNG (10 + vat->mVat.mHealthy)) { result = -1; } else if (RNG (2) < vat->mVat.mHealthy) { /* Healthy vats are quite likely to give a good effect, and they're the only way to get the gain ability effect. */ result = RNG (0, 6); } else if (vat->mVat.mHealthy < 0) { /* Extraordinarily unhealthy vats may poison. */ result = RNG (1, 10); } else { result = RNG (1, 9); } switch (result) { case -2: I->p ("Arrgghh!! You vomit."); if (sufferDamage (kAttVatPlague)) { shCreature::die (kKilled, "a filthy sludge vat"); } vat->mVat.mAnalyzed = 1; break; case -1: mRad += RNG (1, 100); I->p ("Ick! That had a toxic taste!"); break; case 0: Hero.gainAbility (false, 1); vat->mVat.mAnalyzed = 1; break; case 1: if (vat->mVat.mRadioactive) { getMutantPower (); dryup = 2; break; } /* else fall through... */ case 2: mRad -= RNG (1, 200); mRad = maxi (0, mRad); if (!mRad) I->p ("You feel purified!"); else I->p ("You feel less contaminated."); break; case 3: mHP += NDX (4, 6); mHP = mini (mHP, mMaxHP); I->p ("You feel better!"); break; case 4: { int amt = RNG (1, 6); Hero.mPsiDrain -= amt; Hero.mAbil.mPsi += amt; I->p ("You feel invigorated!"); break; } case 5: I->p ("Mmmm... bouncy bubbly beverage!"); if (Hero.getStoryFlag ("impregnation")) { abortion (1); /* Here message given is slightly different. */ I->p ("You feel the alien embryo inside you die."); } break; case 6: I->p ("Mmmm... hot fun!"); if (Hero.needsRestoration ()) Hero.restoration (RNG (2) + mini (3, vat->mVat.mHealthy)); break; case 7: I->p ("Oops! You fall in! You are covered in slime!"); damageEquipment (kAttVatCorrosion, kCorrosive); I->p ("You climb out of the vat."); break; case 8: { int x = mX; int y = mY; shMonster *monster = new shMonster (kMonVatSlime); if (0 != Level->findNearbyUnoccupiedSquare (&x, &y) or 0 != Level->putCreature (monster, x, y)) { I->p ("The sludge gurgles!"); } else { I->p ("It's alive!"); } break; } case 9: I->p ("You are jolted by an electric shock!"); if (sufferDamage (kAttVatShock)) { shCreature::die (kKilled, "an improperly grounded sludge vat"); } dryup = 2; break; case 10: I->p ("This stuff is poisonous!"); Hero.abortion (); if (sufferDamage (kAttVatPoison)) { shCreature::die (kKilled, "drinking some unhealthy sludge"); } dryup = 2; vat->mVat.mAnalyzed = 1; break; } if (!RNG (dryup)) { I->p ("The vat dries up!"); Level->forgetFeature (vat->mX, vat->mY); Level->removeFeature (vat); } }