void shHero::payMelnorme (shMonster *trader) { if (trader->isHostile ()) { int result; shMenu *amends = I->newMenu ("Make amends:", 0); amends->addIntItem ('a', "Apologize", 1, 1); amends->addIntItem ('p', "Pay reparations", 2, 1); amends->getIntResult (&result); delete amends; switch (result) { case -1: return; case 1: if (trader->mHP == trader->mMaxHP) { if (tryToTranslate (trader)) { I->p ("\"We believe you.\""); } else { I->p ("%s mumbles soothingly.", THE (trader)); } pacifyMelnorme (trader); } else { if (tryToTranslate (trader)) { I->p ("\"It is not enough.\""); } else { I->p ("%s mumbles stalwartly.", THE (trader)); } } return; case 2: { int demand = (trader->mMaxHP - trader->mHP) * 10; demand = maxi (50, demand); if (demand <= countMoney ()) { if (I->yn ("Pay %s %d buckazoids?", THE (trader), demand)) { I->p ("%s accepts the money.", THE (trader)); pacifyMelnorme (trader); loseMoney (demand); trader->gainMoney (demand); } } else { I->p ("%s demands %d buckazoids but you don't" " have that much.", THE (trader), demand); } } } return; } static int (shObject::*tests[])(void) = { &shObject::isBugginessKnown, &shObject::isChargeKnown, &shObject::isEnhancementKnown, &shObject::isAppearanceKnown }; static void (shObject::*actions[])(void) = { &shObject::setBugginessKnown, &shObject::setChargeKnown, &shObject::setEnhancementKnown, &shObject::setAppearanceKnown }; int (shObject::*test) (void); void (shObject::*action) (void); reorganizeInventory (); shMenu *menu = I->newMenu ("Melnorme Services Menu", 0); char buf[200]; shObjectVector v; int price = 1000, services = 0; int price1 = 40 - Hero.mAbil.mPsi; /* Bugginess. */ int price2 = 225 - 5 * Hero.mAbil.mPsi; /* Knowledge. */ int price3 = price1 / 2; /* Remaining. */ if (!trader->is (kGenerous)) { /* Ward against drinking a lot of nano cola. */ price1 = maxi (10, price1); price2 = maxi (100, price2); price3 = maxi (10, price3); } else { price1 = 10; price2 = 100; price3 = 10; } if (tryToTranslate (trader)) { /* Make all services known. */ for (int i = 0; i < kMelnMaxService; ++i) { MelnormeServiceData[i].mNameKnown = 1; } } char letter = 'a'; for (int i = 0; i < kMelnMaxService; ++i) { int serv = trader->mMelnorme.mPermute[i]; /* Offer only eligible services. */ if (serv == kMelnRandomIdentify) { if (trader->mMelnorme.mKnowledgeExhausted or !hasTranslation ()) continue; price = price2; ++services; } else if (serv >= kMelnRevealBugginess and serv <= kMelnRevealAppearance) { test = tests[serv - kMelnRevealBugginess]; v.reset (); unselectObjectsByFunction (&v, Hero.mInventory, test); if (!v.count ()) continue; if (serv == kMelnRevealBugginess) { price = price1; } else { price = price3; } ++services; } snprintf (buf, sizeof (buf), "%s ($%d)", MelnormeServiceData[serv].mNameKnown ? MelnormeServiceNames[serv] : MelnormeServiceData[serv].mDesc, price); menu->addIntItem (letter++, buf, serv); } if (!services) { if (tryToTranslate (trader)) { I->p ("Unfortunately I cannot help you at the moment."); } else { I->p ("%s mumbles something in sad voice.", THE (trader)); } return; } int choice; if (!menu->getIntResult (&choice)) return; delete menu; price = choice == kMelnRandomIdentify ? price2 : choice == kMelnRevealBugginess ? price1 : price3; if (countMoney () < price) { I->p ("You don't have enough money for that."); return; } loseMoney (price); trader->gainMoney (price); shObject *obj = NULL; if (choice == kMelnRandomIdentify) { int n = kObjNumIlks; int tries = 10; int success = 0; while (tries--) { int i = RNG (n); shObjectIlk *ilk = &AllIlks[i]; if (!(ilk->mFlags & kIdentified) and ilk->mProbability != ABSTRACT) { char *buf = GetBuf (); strncpy (buf, ilk->mReal.mName, SHBUFLEN); makePlural (buf, SHBUFLEN); ilk->mFlags |= kIdentified; I->p ("%s tells you how to recognize %s.", THE (trader), buf); success = 1; break; } } if (!success) { I->p ("%s offers you several facts but you know all of them.", THE (trader)); I->p ("\"It seems you know all I do.\""); trader->mMelnorme.mKnowledgeExhausted = 1; I->p ("%s returns your money."); trader->loseMoney (price); gainMoney (price); } MelnormeServiceData[choice].mNameKnown = 1; } else if (choice >= kMelnRevealBugginess and choice <= kMelnRevealAppearance) { v.reset (); test = tests[choice - kMelnRevealBugginess]; unselectObjectsByFunction (&v, Hero.mInventory, test); obj = quickPickItem (&v, "perform service on", 0); if (obj) { if (hasTranslation () or RNG (4)) { /* 75% - lets be generous. */ action = actions[choice - kMelnRevealBugginess]; (obj->*action) (); if (!hasTranslation ()) { I->p ("You manage to understand %s.", THE (trader)); } MelnormeServiceData[choice].mNameKnown = 1; I->p ("%c - %s", obj->mLetter, obj->inv ()); } else { I->p ("This time you fail to understand %s.", THE (trader)); } } } I->drawSideWin (); }
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 (); }
} int main(int argc, char** argv){ struct gameState *G; int numplayers, money, handpos, rseed, rcard, choice1, choice2, choice3, coinflip, i, numtests,r; int *k; int players[4]; numtests=1; for(i=0; i<numtests; i++){ G=newGame(); rseed=atoi(argv[1]); k = malloc(sizeof(int)*10); numplayers=rand()%3+2; chooseKingdomCards(k); initializeGame(numplayers, k, rseed, G); printf("FOR SEED %d\n", rseed); if(isGameOver(G)){ printf("game creation error\n"); printf("test %d failed\n",i); } else{ while(!isGameOver(G)){ printf("player %d turn start\n", whoseTurn(G)); handpos=-1; coinflip=rand()%10; rcard=chooseHandCard(G, k, &handpos); choice1=rand()%2; choice2=0; if(choice1==0){ choice2=1; } choice3=rand()%2; if(rcard!=-1 || rcard==curse){ r=playCard(handpos, choice1,choice2,choice3,G); printf("player %d played ", whoseTurn(G)); printCard(rcard, r); } money=countMoney(G); printf("money: %d\n", money); rcard=randomBuyCard(G, money, k); if(coinflip!=9){ //small chance to not buy anything r=buyCard(rcard, G); printf("player %d bought ", whoseTurn(G)); printCard(rcard, r); } printf("player %d hand\n", whoseTurn(G)); printhand(G); printf("player %d score: %d\n", whoseTurn(G), scoreFor(whoseTurn(G),G)); printf("player %d turn ending\n", whoseTurn(G)); endTurn(G); if(isGameOver(G)){ printf("game over player %d won\n", getWinners(players, G)); } } free(k); free(G); printf("test %d passed\n", i); } }
int main (int argc, char** argv) { int finalKingdomCards[10][2]; int kingdomCards[10][2]; struct gameState G; struct gameState *p = &G; int money; int i, j, h, randomIndex, randomCategory, randomNumberSeed, curCard; int player; int numPlayers; int k[10]; int kingdomCard; int cardFound; FILE *fp; fp = fopen("testCase.c", "w"); randomNumberSeed = 16; fprintf(fp, "#include \"testFunctions.h\" \n\ int main (int argc, char** argv) { \n\ struct gameState G; \n\ struct gameState *p = &G; \n\ int money; \n\ int player; \n\ int numPlayers;\n" ); srand(randomNumberSeed); /* Play NUM_GAMES games of dominion. */ for (h = 0; h < NUM_GAMES; h++) { /* Make an array of the 10 kingdom cards (#7-26) that will be used in this game */ printf("Kingdom Cards:\n"); i = 0; while (i < 10) { kingdomCard = (rand() % 20) + 7; cardFound = 0; for (j = 0; j < i; j++) { if (kingdomCard == k[j]) { cardFound = 1; break; } } if (!cardFound && (kingdomCard != salvager) && (kingdomCard != tribute)) { finalKingdomCards[i][0] = kingdomCard; finalKingdomCards[i][1] = 0; kingdomCards[i][0] = kingdomCard; kingdomCards[i][1] = 0; k[i] = kingdomCard; printCard(k[i]); i++; } } fprintf(fp, "\n\tint k[10] = {"); for (i = 0; i < 9; i++) fprintf(fp, "%d, ", k[i]); fprintf(fp, "%d};", k[9]); /* random number of players (from 2-4) */ numPlayers = (rand() % 3) + 2; fprintf(fp, "\n\tnumPlayers = %d;",numPlayers); /* Allocate memory for game. */ initializeGame(numPlayers, k, randomNumberSeed, p); fprintf(fp, "\n\tinitializeGame(numPlayers, k, 16, p);"); while (!isGameOver(p)) { money = countMoney(p); player = whoseTurn(p); fprintf(fp, "\n\tmoney = countMoney(p);"); fprintf(fp, "\n\tplayer = whoseTurn(p);"); /* Loop through current player's hand and play the first kingdom card encountered. */ for (i = 0; i < numHandCards(p); i++) { curCard = handCard(i, p); if (!p->numActions) break; if ((curCard <= 26) && (curCard >= 7) && (curCard != gardens)) { /* This part pushes something onto the stack which corrupts some data and causes invalid cards to enter the game */ // printf("%d: About to play ", player); // printCard(curCard); // printf("...\n"); switch(curCard) { case ambassador: for (j = 0; j < numHandCards(p); j++) { if (handCard(j, p) == curse) { if (playCard(i, j, -1, -1, p) != -1) { fprintf(fp, "\n\tplayCard(%d, %d, -1, -1, p);", i, j); } else printf("%d: There was a problem with playing ambassador\n\n\n", player); money = countMoney(p); break; } } break; case baron: if (playCard(i, 0, 1, 1, p) != -1) { fprintf(fp, "\n\tplayCard(%d, 0, 1, 1, p);", i); } else { printf("%d: ", player); printf("There was a problem with playing "); printCard(curCard); printf("\n\n\n"); } money = countMoney(p); break; case feast: for (j = 0; j < numHandCards(p); j++) { if (supplyCount(handCard(j, p), p) > 1 && getCardCost(handCard(j, p)) <= 5) { if (playCard(i, handCard(j, p), 1, 1, p) == 0) { fprintf(fp, "\n\tplayCard(%d, %d, 1, 1, p);", i, handCard(j, p)); } else printf("%d: There was a problem with playing feast\n\n\n", player); money = countMoney(p); break; } } break; /* Find treasure card to trash (pass as choice1 as position) treasure card to gain: pass as choice2 by name. */ case mine: for (j = 0; j < numHandCards(p); j++) { if (handCard(j, p) == copper) { if (playCard(i, j, silver, -1, p) == 0) { fprintf(fp, "\n\tplayCard(%d, %d, silver, -1, p);", i, j); } else printf("%d: There was a problem with playing mine\n\n\n", player); money = countMoney(p); break; } else if (handCard(j, p) == silver) { if (playCard(i, j, gold, -1, p) == 0) { fprintf(fp, "\n\tplayCard(%d, %d, gold, -1, p);", i, j); } else printf("%d: There was a problem with playing mine\n\n\n", player); money = countMoney(p); break; } } break; case remodel: for (j = 0; j < numHandCards(p); j++) { if (getCardCost(handCard(j, p)) >= 3) { if (playCard(i, j, duchy, -1, p) == 0) { fprintf(fp, "\n\tplayCard(%d, %d, duchy, -1, p);", i, j); } else printf("%d: There was a problem with playing remodel!\n\n\n", player); money = countMoney(p); break; } } break; default: if (playCard(i, 1, 1, 1, p) != -1) { fprintf(fp, "\n\tplayCard(%d, 1, 1, 1, p);", i); } else { printf("%d: ", player); printf("Failed to play "); printCard(curCard); printf("\n\n"); } money = countMoney(p); break; } } } randomCategory = (rand() % 100) + 1; /* Always buy a province if you can afford it */ if (money >= 8) { if (buyCard(province, p) == 0) { fprintf(fp, "\n\tbuyCard(province, p);"); } else printf("%d: failed to buy province\n", player); } /* Buy money 55% of the time */ else if (randomCategory > 45) { if (money >= 6) { if (buyCard(gold, p) == 0) fprintf(fp, "\n\tbuyCard(gold, p);"); else printf("%d: failed to buy gold\n", player); } else if (money >= 3) { if (buyCard(silver, p) == 0) fprintf(fp, "\n\tbuyCard(silver, p);"); else printf("%d: failed to buy silver\n", player); } } /* Buy a Kingdom card 40% of the time */ else if (randomCategory > 5) { for (i = 0; i < 20; i++) { randomIndex = rand() % 10; if (getCardCost(k[randomIndex]) <= money) { if (buyCard(k[randomIndex], p) == 0) { fprintf(fp, "\n\tbuyCard(%d, p);", k[randomIndex]); incrementCard(k[randomIndex], finalKingdomCards); break; } else { printf("%d: failed to buy ", player); printCard(k[randomIndex]); printf("\n"); break; } } } } /* Buy a duchy 5% of the time */ else { if (money >= 5) { if (buyCard(duchy, p) == 0) fprintf(fp, "\n\tbuyCard(duchy, p);"); else printf("%d: failed to buy duchy\n", player); } } endTurn(p); fprintf(fp, "\n\tendTurn(p);\n"); for (i = 0; i < numPlayers; i++) { printf ("Player %d Score: %d\n", i, scoreFor(i, p)); } printf("\n"); /* Look through every card in play */ for (j = 0; j < numPlayers; j++) { /* Check hand */ for (i = 0; i < p->handCount[j]; i++) { curCard = p->hand[j][i]; if (contains(k, curCard)) incrementCard(curCard, kingdomCards); if (!(curCard <= treasure_map && curCard >= curse)) { printf("\n\n"); printCard(curCard); printf("\n\n"); } assert(curCard <= treasure_map && curCard >= curse); } /* Check discard pile */ for (i = 0; i < p->discardCount[j]; i++) { curCard = p->discard[j][i]; if (contains(k, curCard)) incrementCard(curCard, kingdomCards); if (!(curCard <= treasure_map && curCard >= curse)) { printf("\n\n"); printCard(curCard); printf("\n\n"); } assert(curCard <= treasure_map && curCard >= curse); } /* Check deck */ for (i = 0; i < p->deckCount[j]; i++) { curCard = p->deck[j][i]; if (contains(k, curCard)) incrementCard(curCard, kingdomCards); if (!(curCard <= treasure_map && curCard >= curse)) { printf("\n\n"); printCard(curCard); printf("\n\n"); } assert(curCard <= treasure_map && curCard >= curse); } } /* Now it's the other player's turn */ } printf("All tests passed!\n\n\n\n"); } fprintf(fp, "\n\treturn 0;\n}"); fclose(fp); return 0; }