#include #include #include #include #include #include #include "attack.h" #include "defs.h" #include "flag.h" #include "god.h" #include "io.h" #include "lf.h" #include "map.h" #include "move.h" #include "nexus.h" #include "objects.h" #include "shops.h" #include "spell.h" #include "text.h" #define DEF_REMCURSECOST 60 #define DEF_BLESSCOST 50 #define DEF_IDCOST 20 #define DEF_SURCHARGE 15 #define DEF_RESIZECOST 80 #define DEF_REPAIRCOSTPERHP 2 extern enum GAMEMODE gamemode; extern prompt_t prompt; extern lifeform_t *player; extern WINDOW *mainwin; // "buf" is the name of an object // // this function will adjust the object name to avoid objects which shouldn't appear in shops. // returns TRUE if the name was modified. int apply_shopob_restrictions(char *buf) { if (strstr(buf, "gold dollar")) { strcpy(buf, "potion of water"); return B_TRUE; } if (strstr(buf, "credit card")) { strcpy(buf, "paper clip"); return B_TRUE; } return B_FALSE; } // dir == 1 means "better skills increase the price" // dir == -1 means "better skills decrease the price" float applyshoppricemod(float origprice, lifeform_t *lf, object_t *shop, enum SHOPACTION action) { float newprice; float pricepct = 100; int dir; if (action == SA_BUY) { dir = -1; } else { dir = 1; } if (lf) { enum SKILLLEVEL slev; // price goes up/down for charisma (+/- 25%) // high bonus = lower price. pricepct += ((getstatmod(lf, A_CHA)/2) * dir); // reduce based on speech (up to -30%); slev = getskill(lf, SK_SPEECH); if (slev) { int modamt; modamt = ((int)(slev*5))*dir; pricepct += modamt; } } if (shop) { flag_t *f; f = hasflag(shop->flags, F_SHOPDONATED); if (f) { pricepct += ((((float)f->val[0]) / 100.0) * dir); } } // -30 - +30 percent discount/penalty in aligned // temples based on your god's happiness if (lf && shop) { if (shop->type->id == OT_TEMPLE) { flag_t *f; f = hasflag(shop->flags, F_LINKGOD); if (f && godprayedto(f->val[0])) { enum PIETYLEV plev; plev = getpietylev(f->val[0], NULL, NULL); pricepct += ((plev*10) * dir); } } } newprice = pctof(pricepct, origprice); if (origprice > 0) { limitf(&newprice, 1, NA); } return newprice; } int canafford(lifeform_t *lf, int amt) { int goldamt = 0,gemamt = 0; goldamt = countmoney(lf->pack); if (getskill(lf, SK_SPEECH) >= PR_BEGINNER) { gemamt = applyshoppricemod(counthighestobflagvalue(lf->pack, F_GEM), lf, NULL, SA_BUY); // adjust using charisma etc } if ((goldamt >= amt ) || (gemamt >= amt) || hasob(lf->pack, OT_CREDITCARD)) { return B_TRUE; } return B_FALSE; } int getshopblessprice(object_t *o, object_t *shop) { int cost = 0; int remcursecost, blesscost,surcharge; remcursecost = applyshoppricemod(DEF_REMCURSECOST, player, shop, SA_BUY); blesscost = applyshoppricemod(DEF_BLESSCOST, player, shop, SA_BUY); surcharge = applyshoppricemod(DEF_SURCHARGE, player, shop, SA_BUY); if (iscursed(o)) { cost = remcursecost; if (isequipped(o)) cost += surcharge; } else { cost = blesscost; } cost *= o->amt; return cost; } int isalignedtemple(object_t *shop) { flag_t *f; f = hasflag(shop->flags, F_LINKGOD); if (f && godprayedto(f->val[0])) { return B_TRUE; } return B_FALSE; } int obmatchessellflag(object_t *o, flag_t *f, enum SHOPACTION action) { if ((f->val[0] == F_NONE) || hasflag(o->flags, f->val[0])) { if ((f->val[2] == NA) || (o->type->obclass->id == f->val[2])) { if ((action == SA_SELL) && (f->val[1] == NA)) { } else { return B_TRUE; } } } return B_FALSE; } void shop(lifeform_t *lf, object_t *vm) { int y,i,done; int curmenu = 0; char ch,buf[BUFLEN]; char toptext[BUFLEN],shopname[BUFLEN]; int ntaken = 0; int ngiven = 0; flag_t *f; object_t *o; strcpy(toptext, ""); taketime(lf, getactspeed(lf)); if (!isplayer(lf)) { if (cansee(player, lf)) { char lfname[BUFLEN]; getlfname(lf, lfname); getobname(vm, shopname, 1); msg("%s browses through %s.", lfname, shopname); } return; } // closed? f = shopisclosed(vm); if (f) { sayphrase(NULL, f->val[2], SV_TALK, hoursto12(f->val[0]), NULL, player); return; } if (lfhasflag(lf, F_STENCH)) { msg("\"Pheeew! You're not coming in smelling like that.\""); return; } if (hasflagval(vm->flags, F_BANNEDLF, lf->id, NA, NA, NULL)) { if (!lfhasflag(lf, F_ANONYMOUS)) { msg("\"You are not welcome here, thief!\""); return; } } // temple to dead god? if (vm->type->id == OT_TEMPLE) { flag_t *f; lifeform_t *god = NULL; f = hasflag(vm->flags, F_LINKGOD); if (f) { god = findgod(f->val[0]); } if (!god) { msg("This temple seems to have been abandoned."); return; } } getobname(vm, shopname, 1); makeuppercase(shopname); // assign letters to objects ch = 'a'; for (o = vm->contents->first ; o ; o = o->next) { o->letter = ch; if (++ch > 'z') ch = 'A'; } // list objects for sale and ask for input done = B_FALSE; while (!done) { enum SHOPRETURN (*shopfunc)(lifeform_t *, object_t *, int, char *, int *) = NULL; int *shoparg = NULL; cls(); mvwprintw(mainwin, 0, 0, toptext); y = 2; centre(mainwin,C_WHITE, y, noprefix(shopname)); y += 2; // check for special sm_xxx menu ids first if (curmenu == SM_ABSOLVE) { shopfunc = shopabsolve; shoparg = NULL; } else if (curmenu == SM_BLESS) { shopfunc = shopbless; shoparg = NULL; } else if (curmenu == SM_MIRACLE) { shopfunc = shopmiracle; shoparg = NULL; } else if (curmenu == SM_PURCHASEITEMS) { shopfunc = shoppurchase; shoparg = &ntaken; } else if (curmenu == SM_DETECTCURSE) { shopfunc = shopdetectcurse; shoparg = NULL; } else if (curmenu == SM_DONATE) { shopfunc = shopdonate; shoparg = &ngiven; } else if (curmenu == SM_ID) { shopfunc = shopid; shoparg = &ngiven; } else if (curmenu == SM_REST) { shopfunc = shoprest; shoparg = &ngiven; } else if (curmenu == SM_RESIZE) { shopfunc = shopresize; shoparg = &ngiven; } else if (curmenu == SM_REPAIR) { shopfunc = shoprepair; shoparg = &ngiven; } else if (curmenu == SM_SELLITEMS) { shopfunc = shopsell; shoparg = &ngiven; } if (shopfunc) { switch (shopfunc(lf, vm, y, toptext, shoparg)) { case SR_BACK: curmenu = 0; break; case SR_CONTINUE: break; case SR_QUIT: done = B_TRUE; break; } } else { flag_t *retflag[MAXCANDIDATES]; int nretflags,curidx = 0,found = B_TRUE; // show menu items getflags(vm->flags, retflag, &nretflags, F_SHOPMENU, F_NONE); while (found) { found = B_FALSE; for (i = 0; i < nretflags; i++) { f = retflag[i]; // check menu id if ((f->val[0] / 100) != curmenu) continue; // check menuitem index if ((f->val[0] % 100) == curidx) { snprintf(buf, BUFLEN, "%c - %s", f->text[0], f->text + 2); mvwprintw(mainwin, y, 0, "%s", buf); y++; found = B_TRUE; curidx++; } } } // ask for selection y += 2; // ask what to do mvwprintw(mainwin, y, 0, "What will you do (ESC to exit)? "); ch = getch(); // handle selection if (ch == 27) { done = B_TRUE; } else { flag_t *selection = NULL; // find matching menu item for (i = 0; i < nretflags; i++) { f = retflag[i]; // check menu id if ((f->val[0] / 100) != curmenu) continue; // check menuitem index if (f->text[0] == ch) { // handle the action. selection = f; } } if (selection) { switch (selection->val[1]) { case MA_GOTOMENU: curmenu = selection->val[2]; break; case MA_QUIT: done = B_TRUE; break; } } } } // end if curmenu == -1 or something else } // end while not done restoregamewindows(); if (hasflagval(vm->flags, F_BANNEDLF, lf->id, NA, NA, NULL)) { msg("\"...and stay out!\""); } else if (hasflag(lf->flags, F_RESTINGINMOTEL)) { switch (rnd(1,2)) { case 1: snprintf(buf, BUFLEN, "Sleep well!"); break; case 2: snprintf(buf, BUFLEN, "Enjoy your stay!"); break; case 3: snprintf(buf, BUFLEN, "Sweet dreams!"); break; } msg("\"%s\"", buf); more(); } else if (vm->type->id == OT_TEMPLE) { strcpy(buf, ""); // message based on the god... f = hasflag(vm->flags, F_LINKGOD); if (f) { switch (f->val[0]) { case R_GODDEATH: switch (rnd(1,2)) { case 1: snprintf(buf, BUFLEN, "Go forth and kill!"); break; case 2: snprintf(buf, BUFLEN, "Hecta's favour be with you!"); break; } break; case R_GODMERCY: switch (rnd(1,3)) { case 1: snprintf(buf, BUFLEN, "Go in peace."); break; case 2: snprintf(buf, BUFLEN, "Peace be with you."); break; case 3: snprintf(buf, BUFLEN, "Remain merciful, traveller."); break; } break; case R_GODPURITY: switch (rnd(1,2)) { case 1: snprintf(buf, BUFLEN, "Stay pure, friend."); break; case 2: snprintf(buf, BUFLEN, "May the purity of Amberon ride with you."); break; } break; case R_GODTHIEVES: switch (rnd(1,3)) { case 1: snprintf(buf, BUFLEN, "May your lockpicks never break!"); break; case 2: snprintf(buf, BUFLEN, "Safe passage, friend."); break; case 3: snprintf(buf, BUFLEN, "Felix's favour be with you!"); break; } break; } } if (strlen(buf)) { msg("\"%s\"", buf); } } else if (ntaken > ngiven) { switch (rnd(1,2)) { case 1: snprintf(buf, BUFLEN, "Pleasure doing business with you!"); break; case 2: snprintf(buf, BUFLEN, "Thank you, come again!"); break; } msg("\"%s\"", buf); } else if (ngiven > ntaken) { switch (rnd(1,2)) { case 1: snprintf(buf, BUFLEN, "Thank you again for your generosity!"); break; case 2: snprintf(buf, BUFLEN, "I look forward to your next visit!"); break; } msg("\"%s\"", buf); } else { switch (rnd(1,2)) { case 1: snprintf(buf, BUFLEN, "See you next time."); break; case 2: snprintf(buf, BUFLEN, "Farewell!"); break; } msg("\"%s\"", buf); } } enum SHOPRETURN shopdetectcurse(lifeform_t *lf, object_t *vm, int starty, char *toptext, int *ndonated) { object_t *o; char ch; int y; int cost = 0,possible = B_TRUE; y = starty; // calculate cost for (o = lf->pack->first ; o; o = o->next) { if (!o->blessknown && !hasflag(o->flags, F_NOBLESS)) { cost += 10; } } if (!cost) { mvwprintw(mainwin, y, 0, "You do not seem to possess anything which merits our services."); y += 2; possible = B_FALSE; } else { // aligned templte? if (isalignedtemple(vm)) { cost = 0; } else { cost = applyshoppricemod(cost, lf, vm, SA_BUY); } // ask what to detect if (cost) { mvwprintw(mainwin, y, 0, "It will cost $%d to perform an divination on your items.", cost); } else { mvwprintw(mainwin, y, 0, "For a fellow worshipper, we will perform divinations on your items for free.", cost); } y += 2; if (countmoney(lf->pack) < cost) { mvwprintw(mainwin, y, 0, "Unfortunately, you cannot afford this.", cost); y += 2; possible = B_FALSE; } } if (possible){ if (cost) { mvwprintw(mainwin, y, 0, "Pay to detect auras on your items (you have $%d) [yn]? ", countmoney(lf->pack)); } else { mvwprintw(mainwin, y, 0, "Detect auras on your items [yn]? "); } } else { mvwprintw(mainwin, y, 0, "[Press a key to return]"); } ch = getch(); if (possible && (ch == 'y')) { givemoney(player, NULL, cost); dospelleffects(lf, OT_S_DETECTAURA, 10, lf, NULL, NULL, B_BLESSED, NULL, B_FALSE, NULL); more(); } return SR_BACK; } enum SHOPRETURN shopdonate(lifeform_t *lf, object_t *vm, int starty, char *toptext, int *ndonated) { int count = 0; object_t *o; // ask what to donate /* switch (vm->type->id) { case OT_SHOPARMOUR: wantflag = F_ARMOURRATING; wantoc = OC_ARMOUR; break; case OT_SHOPWEAPON: wantflag = F_DAM; wantoc = OC_WEAPON; break; case OT_TEMPLE: wantflag = F_NONE; wantoc = OC_MONEY; break; default: wantflag = F_NONE; wantoc = OC_NONE; break; } */ o = doaskobject(lf->pack, "What will you donate?", NULL, &count, B_TRUE, B_FALSE, B_FALSE, '\0', vm, SA_DONATE, NULL, B_FALSE); // validate it if (o) { long goldgiven = 0; long multi = 0; flag_t *f; // can we remove it? if (isequipped(o)) { if (takeoff(lf, o)) { more(); return SR_CONTINUE; } } // confirm count for gold if (o->type->obclass->id == OC_MONEY) { char answer[BUFLEN],buf[BUFLEN]; snprintf(buf, BUFLEN, "How much money will you donate (you have $%d)?", o->amt); askstring(buf, '?', answer, BUFLEN, NULL); count = atoi(answer); if (count <= 0) { return SR_CONTINUE; } if (count > o->amt) count = o->amt; } if (o->type->id == OT_GOLD) { givemoney(lf, NULL, count); (*ndonated)++; goldgiven += count; } else { object_t *newob; char let; int thisval,pct = 100; if (vm->contents->first) { let = vm->contents->last->letter + 1; } else { let = 'a'; } thisval = getobvalue(o); if (!isknown(o)) { pct -= 50; } if (!isidentified(o)) { pct -= 25; } thisval = pctof(pct, thisval); newob = moveob(o, vm->contents, count); newob->letter = let; (*ndonated)++; practice(player, SK_SPEECH, 1); goldgiven += thisval; } if ((vm->type->id == OT_TEMPLE) && goldgiven) { flag_t *f; f = hasflag(o->flags, F_LINKGOD); if (f) { lifeform_t *god = NULL; god = findgod(f->val[0]); msg("\"%s appreciates your kind donation.\"", god->race->name); modpiety(god->race->id, (goldgiven/2)); } else { msg("\"We appreciate your kind donation.\""); } } else { sayphrase(NULL, SP_THANKS, SV_TALK, NA, NULL, player); more(); } f = hasflag(vm->flags, F_SHOPDONATED); if (f) { f->val[0] += goldgiven; } else { addflag(vm->flags, F_SHOPDONATED, goldgiven, NA, NA, NULL); } // remember amount donated, for addition to final score f = lfhasflagval(lf, F_SCOREBONUS, NA, NA, NA, SCB_DONATIONS); if (f) { multi = f->val[1]; goldgiven += f->val[0]; } else { f = addflag(lf->flags, F_SCOREBONUS, 0, NA, NA, SCB_DONATIONS); multi = 0; } // cope with >= 65535 while (goldgiven > 65535) { goldgiven -= 65535; multi++; } f->val[0] = goldgiven; f->val[1] = multi; } else { return SR_BACK; } angergodmaybe(R_GODTHIEVES, 10, GA_MONEY); more(); return SR_CONTINUE; } enum SHOPRETURN shopabsolve(lifeform_t *lf, object_t *vm, int starty, char *toptext, int *ndonated) { char ch; int y; int piety,cost = 0,possible = B_TRUE; flag_t *f; lifeform_t *god = NULL; y = starty; // get linked god f = hasflag(vm->flags, F_LINKGOD); god = findgod(f->val[0]); piety = getpiety(god->race->id); if (piety < 100) { cost = (100 - piety) * 3; cost = applyshoppricemod(cost, lf, vm, SA_BUY); mvwprintw(mainwin, y, 0, "It will cost $%d to absolve your sins against %s.", cost, god->race->name); y += 2; } else { mvwprintw(mainwin, y, 0, "You do not appear to have sinned against %s.", god->race->name); y += 2; possible = B_FALSE; } if (possible) { if (countmoney(lf->pack) >= cost) { mvwprintw(mainwin, y, 0, "Pay for absolution (you have $%d) [yn]? ", countmoney(lf->pack)); } else { mvwprintw(mainwin, y, 0, "You cannot afford to pay $%d for absolution.", cost); y+= 2; possible = B_FALSE; } } if (!possible) { mvwprintw(mainwin, y, 0, "[Press any key]"); } ch = getch(); if (!possible || (ch != 'y')) { return SR_BACK; } givemoney(lf, NULL, cost); setpiety(god->race->id, 100); msg("\"You sins are forgiven!\""); more(); return SR_BACK; } enum SHOPRETURN shopbless(lifeform_t *lf, object_t *vm, int starty, char *toptext, int *ndonated) { object_t *o; char ch,buf[BUFLEN]; int y; int remcursecost, blesscost,surcharge; y = starty; remcursecost = applyshoppricemod(DEF_REMCURSECOST, lf, vm, SA_BUY); blesscost = applyshoppricemod(DEF_BLESSCOST, lf, vm, SA_BUY); surcharge = applyshoppricemod(DEF_SURCHARGE, lf, vm, SA_BUY); if (isalignedtemple(vm)) { blesscost /= 2; limit(&blesscost, 1, NA); remcursecost = 0; surcharge = 0; } mvwprintw(mainwin, y, 0, "So long as their aura is known, we can bestow a blessing on most items."); y += 2; if (remcursecost == 0) { mvwprintw(mainwin, y, 0, "Curse removal - FREE",remcursecost); y++; } else { mvwprintw(mainwin, y, 0, "Curse removal - $%d each",remcursecost); y++; } mvwprintw(mainwin, y, 0, "Blessings - $%d each",blesscost); y += 2; if (surcharge != 0) { mvwprintw(mainwin, y, 0, "(there is a $%d surcharge for uncursing an equipped item)",surcharge); y += 2; } mvwprintw(mainwin, y, 0, "Pay for a blessing (you have $%d) [yn]? ", countmoney(lf->pack)); ch = getch(); if (ch != 'y') { return SR_BACK; } // ask which object snprintf(buf, BUFLEN, "Bless which object (you have $%d)?", countmoney(lf->pack)); initprompt(&prompt, buf); for (o = player->pack->first ; o ; o = o->next) { int ok = B_FALSE; if (o->blessknown && (o->blessed != B_BLESSED) && !hasflag(o->flags, F_NOBLESS)) { ok = B_TRUE; } else if (!o->blessknown && !hasflag(o->flags, F_NOBLESS)) { ok = B_TRUE; } if (ok) { char costbuf[BUFLEN]; getobname(o, buf, o->amt); snprintf(costbuf, BUFLEN, "%-60s($%d)", buf, getshopblessprice(o, vm)); addchoice(&prompt, o->letter, costbuf, costbuf, o, NULL); } } addchoice(&prompt, '-', "(nothing)", NULL, NULL, NULL); ch = getchoice(&prompt); o = (object_t *)prompt.result; if (o) { int cost; cost = getshopblessprice(o, vm); if (countmoney(player->pack) < cost) { msg("You cannot afford the $%d blessing price.", cost); more(); } else { msg("You hand over $%d to the priest.", cost); more(); givemoney(player, NULL, cost); // already blessed? msg("The priest raise his hands in supplication."); more(); if (isblessed(o)) { msg("\"Hey, this item is already blessed!\""); more(); o->blessknown = B_TRUE; // chance to get your money back. if (skillcheck(player, SC_SPEECH, 100, 0)) { char goldbuf[BUFLEN]; msg("\"...so I will return your payment.\""); more(); snprintf(goldbuf, BUFLEN, "%d gold dollars", cost); addob(player->pack, goldbuf); } else { msg("\"Unfortunately, we do not offer refunds.\""); more(); } } else { blessob(o); } more(); } } return SR_CONTINUE; } enum SHOPRETURN shopid(lifeform_t *lf, object_t *vm, int starty, char *toptext, int *nid) { flag_t *sellflag[MAXCANDIDATES]; char buf[BUFLEN],obname[BUFLEN]; int nsellflags; object_t *o; int y,ch,i; int cost = DEF_IDCOST; y = starty; cost = applyshoppricemod(DEF_IDCOST,lf, vm, SA_ID); *nid = 0; mvwprintw(mainwin, y, 0, "We can help inspect your items for a small fee."); y += 2; mvwprintw(mainwin, y, 0, "For just $%d per item we can reveal their general purpose,", cost); y++; mvwprintw(mainwin, y, 0, "however please note that we are unable to detect magical"); y++; mvwprintw(mainwin, y, 0, "enchantments or blessings.", cost); y += 2; mvwprintw(mainwin, y, 0, "Identify items [y/n]? ", countmoney(lf->pack)); ch = getch(); if (ch != 'y') { return SR_BACK; } getflags(vm->flags, sellflag, &nsellflags, F_SHOPACCEPTSFLAG, F_NONE); // ask what to sell snprintf(buf, BUFLEN, "What would you like to inspect (you have $%d)?", countmoney(lf->pack)); initprompt(&prompt, buf); prompt.maycancel = B_TRUE; for (o = player->pack->first ; o ; o = o->next) { int ok = B_FALSE; for (i = 0; i < nsellflags; i++) { if (obmatchessellflag(o, sellflag[i], SA_ID)) { if (!isknown(o)) { ok = B_TRUE; break; } } } if (ok) { char costbuf[BUFLEN]; getobname(o, buf, o->amt); snprintf(costbuf, BUFLEN, "%-60s($%d)", buf, cost); addchoice(&prompt, o->letter, costbuf, costbuf, o, NULL); } } addchoice(&prompt, '-', "(nothing)", NULL, NULL, NULL); ch = getchoice(&prompt); o = (object_t *)prompt.result; if (!o) { return SR_BACK; } // confirm getobname(o, obname, o->amt); if (countmoney(player->pack) < cost) { msg("You cannot afford the $%d inspection fee.", cost); more(); } else { // pay. msg("You hand over $%d.", cost); more(); givemoney(player, NULL, cost); // id it. makeknown(o->type->id); // get name again getobname(o, obname, o->amt); // tell the player msg("\"%s %s.\"",(o->amt == 1) ? "That is" : "Those are", obname); more(); } return SR_CONTINUE; } // returns F_OPENHOURS flag if the shop is closed. flag_t *shopisclosed(object_t *shop) { flag_t *f; f = hasflag(shop->flags, F_OPENHOURS); if (f) { int h = -1,m = -1,s = -1; splittime(&h, &m, &s); if (!timeisbetween(h, f->val[0], f->val[1])) { return f; } } return NULL; } enum SHOPRETURN shopmiracle(lifeform_t *lf, object_t *vm, int starty, char *toptext, int *ndonated) { char ch; int y; int piety,cost = 0,possible = B_TRUE; flag_t *f; lifeform_t *god = NULL; y = starty; // get linked god f = hasflag(vm->flags, F_LINKGOD); god = findgod(f->val[0]); piety = getpiety(god->race->id); cost = 1000 - piety; cost = applyshoppricemod(cost,lf, vm, SA_BUY); if (godisangry(god->race->id)) { mvwprintw(mainwin, y, 0, "%s does not currently find you worthy of miracles.", god->race->name); y += 2; possible = B_FALSE; } else { mvwprintw(mainwin, y, 0, "For $%d, we will ask %s to intervene on your behalf.", cost, god->race->name); y += 2; } if (possible) { if (countmoney(lf->pack) >= cost) { mvwprintw(mainwin, y, 0, "Pay for a miracle (you have $%d) [yn]? ", countmoney(lf->pack)); } else { mvwprintw(mainwin, y, 0, "You cannot afford to pay $%d.", cost); y+= 2; possible = B_FALSE; } } if (!possible) { mvwprintw(mainwin, y, 0, "[Press any key]"); } ch = getch(); if (!possible || (ch != 'y')) { return SR_BACK; } givemoney(lf, NULL, cost); godgiftmaybe(god->race->id, B_TRUE, B_TRUE); more(); return SR_BACK; } // returns B_TRUE if shop transaction should end enum SHOPRETURN shoppurchase(lifeform_t *lf, object_t *vm, int starty, char *toptext, int *npurchased) { object_t *o; int y; char buf[BUFLEN], buf2[BUFLEN], choices[BUFLENSMALL]; char ch; static enum { BUY, EXAMINE } shopmode = BUY; y = starty; // list objects for sale for (o = vm->contents->first ; o ; o = o->next) { char obname[BUFLEN]; int thisprice; enum COLOUR col; getshopobname(o, obname, o->amt); thisprice = (int)getshopprice(o, player, vm); snprintf(buf, BUFLEN, "%c - %s", o->letter, obname); if (shopmode == BUY) { if (canafford(player, thisprice)) { col = C_GREY; } else { col = C_RED; } } else { col = C_GREY; } snprintf(buf2, BUFLEN, "^%d%-60s$%d", col, buf, thisprice); wmove(mainwin, y, 0); textwithcol(mainwin, buf2); y++; } strcpy(choices, ""); y++; wmove(mainwin, y, 0); textwithcol(mainwin, "^n"); mvwprintw(mainwin, y, 0, "You have $%d.", countmoney(player->pack)); y++; y++; // ask what to do mvwprintw(mainwin, y, 0, "What will you %s (ESC=done, ?=toggle action)? ", (shopmode == BUY) ? "buy" : "examine"); ch = getch(); if (ch == 27) { strcpy(toptext, ""); return SR_BACK; } else if (ch == '?') { if (shopmode == BUY) { shopmode = EXAMINE; } else { shopmode = BUY; } } else { // try to find that object... o = hasobletter(vm->contents, ch); if (o) { if (shopmode == EXAMINE) { describeob(o); } else { enum SKILLLEVEL slev; char obname[BUFLEN],validchars[BUFLENSMALL]; char answer; int value; value = (int)getshopprice(o, player, vm); slev = getskill(player, SK_THIEVERY); // confirm getshopobname(o, obname, o->amt); snprintf(buf, BUFLEN, "Buy%s %s for $%d?", slev ? "/steal" : "", obname, value); strcpy(validchars, "yn"); if (slev) { strcat(validchars, "s"); } answer = askchar(buf, validchars,"n", B_TRUE, B_FALSE); if (answer == 'y') { char ques[BUFLEN]; object_t *oo; // do you have enough money (or a credit card)? if (canafford(player, value)) { object_t *money = NULL; enum SKILLLEVEL slev; slev = getskill(lf, SK_SPEECH); // determine payment method snprintf(ques, BUFLEN, "How will you pay for %s ($%d)?", obname, value); initprompt(&prompt, ques); for (oo = player->pack->first ; oo ; oo = oo->next) { if ((oo->type->id == OT_GOLD) || (oo->type->id == OT_CREDITCARD) || hasflag(oo->flags, F_GEM)) { char moneyname[BUFLEN]; char fullname[BUFLEN]; int valid = B_FALSE; getobname(oo, moneyname, oo->amt); if (oo->type->id == OT_GOLD) { // only list gold if you have enough if (getobvalue(oo) >= value) valid = B_TRUE; strcpy(fullname, moneyname); } else if (hasflag(oo->flags, F_GEM)) { // gems are only valid if our psychology skill is high // enough to convince the shopkeeper to accept them. if (slev >= PR_BEGINNER) { int thisval; thisval = applyshoppricemod(getobvalue(oo), player, vm, SA_SELL); if (thisval >= value) { valid = B_TRUE; snprintf(fullname, BUFLEN, "%s (worth $%d)", moneyname, thisval); } } } else { // always list anything else (credit cards) valid = B_TRUE; strcpy(fullname, moneyname); } if (valid) { addchoice(&prompt, oo->letter, fullname, fullname, oo, NULL); } } } money = NULL; if (prompt.nchoices == 1) { // only one possibility. // is it gold? money = (object_t *)prompt.choice[0].data; if (money->type->id != OT_GOLD) { // if not gold, still confirm it. money = NULL; } } if (!money) { addchoice(&prompt, '-', "(cancel)", "(cancel)", NULL, NULL); prompt.maycancel = B_TRUE; getchoice(&prompt); money = (object_t *)prompt.result; } if (money) { int buyit = B_FALSE; char buytext[BUFLEN]; enum { PM_GOLD, PM_GEM, PM_CARD, } purchasemethod; if (money->type->id == OT_CREDITCARD) { purchasemethod = PM_CARD; if (getcharges(money) >= value) { // you got it! buyit = B_TRUE; usecharges(money, value); strcpy(buytext, "Charged to card"); if (npurchased) (*npurchased)++; } else { // maxed! usecharges(money, getcharges(o)); // use up all remaining charges // get kicked out msg("^B\"Trying to use a maxed out card, eh? Get out of here, thief!\""); more(); // shop closes addflag(vm->flags, F_BANNEDLF, player->id, NA, NA, NULL); return SR_QUIT; } } else { // ie gold or gem; if (getobvalue(money) >= value) { buyit = B_TRUE; // lose money (do this first to avoid potential weight issues) if (hasflag(money->flags, F_GEM)) { int gemsneeded; char gemname[BUFLEN]; int valpergem,amtpaid = 0, change = 0; valpergem = applyshoppricemod(real_getobvalue(money, 1), player, vm, SA_SELL); gemsneeded = value / valpergem; limit(&gemsneeded, 1, NA); // (in case gem is worth more than object) getobname(money, gemname, gemsneeded); // calculate how much change to give... amtpaid = gemsneeded * valpergem; change = amtpaid - value; // remove enough gems to pay... removeob(money, gemsneeded); purchasemethod = PM_GEM; // announce that we're using a gem // also determine whether the player get change if (slev >= PR_ADEPT) { msg("You hand over %s%s.", gemname, (change > 0) ? " and ask for change." : ""); more(); if (change > 0) { char changebuf[BUFLEN]; snprintf(changebuf, BUFLEN, "%d gold dollars", change); addob(player->pack, changebuf); msg("You receive $%d change.", change); more(); } } else { msg("You hand over %s.", gemname); more(); } } else { givemoney(player, NULL, value); purchasemethod = PM_GOLD; } strcpy(buytext, "Purchased"); if (npurchased) (*npurchased)++; } else { msg("\"I'm afraid that won't cover it...\""); more(); o = NULL; } } if (buyit) { int shopamt; // clear o->letter o->letter = '\0'; // give object shopamt = o->amt; // avoid "purchased: 2 apples" when you only bought 1 but were holding 1 o = moveob(o, player->pack, ALL); identify(o); getobname(o, obname, shopamt); snprintf(toptext, BUFLEN, "%s: %c - %s", buytext, o->letter, obname); if (npurchased) (*npurchased)++; if (purchasemethod == PM_CARD) { // god of thieves likes credit cards... pleasegodmaybe(R_GODTHIEVES, (value/75)); more(); // in case there was an effect } else { practice(player, SK_SPEECH, 1); } } } else { msg("Cancelled."); more(); o = NULL; } // end if money } else { msg("You can't afford that!"); more(); o = NULL; } } else if (answer == 's') { // steal // skillcheck - difficulty based on total value of objects here if (skillcheck(player, SC_STEAL, 75+(value/10), 0)) { int shopamt; // success o->letter = '\0'; shopamt = o->amt; // avoid "stolen: 2 apples" when you only bought 1 but were holding 1 o = moveob(o, player->pack, ALL); identify(o); getobname(o, obname, shopamt); snprintf(toptext, BUFLEN, "Stolen: %c - %s", o->letter, obname); practice(player, SK_THIEVERY, 1); pleasegodmaybe(R_GODTHIEVES, (value/50)); more(); // in case there was an effect o = NULL; } else { msg("^B\"HEY! Get out of my shop, thief!\""); more(); // shop closes addflag(vm->flags, F_BANNEDLF, player->id, NA, NA, NULL); return SR_QUIT; } } else { // cancelled strcpy(toptext, ""); } } // end if shopmode == ... } else { snprintf(toptext, BUFLEN, "No such item."); } // end if o } // end if ch return SR_CONTINUE; } enum SHOPRETURN shoprepair(lifeform_t *lf, object_t *vm, int starty, char *toptext, int *ndonated) { object_t *o; char ch,buf[BUFLEN]; int y,hpcost; char obname[BUFLEN]; flag_t *f; y = starty; hpcost = DEF_REPAIRCOSTPERHP; // get list of objects to repair snprintf(buf, BUFLEN, "Repair which object (you have $%d)?", countmoney(lf->pack)); initprompt(&prompt, buf); for (o = player->pack->first ; o ; o = o->next) { if (isarmour(o) && isdamaged(o)) { char desc[BUFLEN]; int thiscost; // determine cost... f = hasflag(o->flags, F_OBHP); thiscost = applyshoppricemod((f->val[1] - f->val[0]) * hpcost, lf, vm, SA_BUY); // add to prompt getobname(o, obname, o->amt); snprintf(desc, BUFLEN, "%s ($%d)", obname,thiscost); addchoice(&prompt, o->letter, desc, desc, o, NULL); } } addchoice(&prompt, '-', "(nothing)", NULL, NULL, NULL); mvwprintw(mainwin, y, 0, "We offer repair services for most kinds armour."); y+=2; if (prompt.nchoices == 1) { mvwprintw(mainwin, y, 0, "You have no armour in need of repair."); y += 2; mvwprintw(mainwin, y, 0, "[Press any key]"); } else { mvwprintw(mainwin, y, 0, "Pay to repair your armour (you have $%d) [yn]? ", countmoney(lf->pack)); } ch = getch(); if ((prompt.nchoices == 1) || (ch != 'y')) { return SR_BACK; } // ask which object ch = getchoice(&prompt); o = (object_t *)prompt.result; if (o) { int thiscost; // determine cost... f = hasflag(o->flags, F_OBHP); thiscost = applyshoppricemod((f->val[1] - f->val[0]) * hpcost, lf, vm, SA_BUY); if (thiscost > countmoney(player->pack)) { msg("You can't afford to repair that item!"); more(); return SR_CONTINUE; } msg("You hand over $%d.", thiscost); more(); givemoney(player, NULL, thiscost); f->val[0] = f->val[1]; getobname(o, obname, o->amt); msg("Your %s %s completely repaired.", obname, (o->amt == 1) ? "is" : "are"); more(); } return SR_CONTINUE; } enum SHOPRETURN shopresize(lifeform_t *lf, object_t *vm, int starty, char *toptext, int *ndonated) { object_t *o; char ch,buf[BUFLEN]; int y; int resizecost; y = starty; resizecost = applyshoppricemod(pctof(75, DEF_RESIZECOST), lf, vm, SA_BUY); mvwprintw(mainwin, y, 0, "For just $%d per item, we can resize weapons or armour to fit you.", resizecost); y ++; mvwprintw(mainwin, y, 0, "(item quality will not be affected)"); y += 2; if (countmoney(player->pack) < resizecost) { mvwprintw(mainwin, y, 0, "Sadly, you cannot afford the resizing fee."); y += 2; mvwprintw(mainwin, y, 0, "[Press a key to return]"); getch(); return SR_BACK; } else { mvwprintw(mainwin, y, 0, "Pay to resize an item (you have $%d) [yn]? ", countmoney(lf->pack)); } ch = getch(); if (ch != 'y') { return SR_BACK; } // ask which object snprintf(buf, BUFLEN, "Resize which object (you have $%d)?", countmoney(lf->pack)); initprompt(&prompt, buf); for (o = player->pack->first ; o ; o = o->next) { if (hasflag(o->flags, F_MULTISIZE) && !armourfits(player, o, NULL)) { char costbuf[BUFLEN]; getobname(o, buf, o->amt); snprintf(costbuf, BUFLEN, "%-60s($%d)", buf, resizecost); addchoice(&prompt, o->letter, costbuf, costbuf, o, NULL); } } addchoice(&prompt, '-', "(nothing)", NULL, NULL, NULL); ch = getchoice(&prompt); o = (object_t *)prompt.result; if (o) { msg("You hand over $%d.", resizecost); more(); givemoney(player, NULL, resizecost); resizeobject(o, getlfsize(player)); // always go to player's size getobname(o, buf, 1); msgnocap("%c - %s", o->letter, buf); more(); } return SR_CONTINUE; } enum SHOPRETURN shoprest(lifeform_t *lf, object_t *vm, int starty, char *toptext, int *ndonated) { char ch,obid[BUFLENSMALL],buf[BUFLEN]; int y,i; int cost = 0,possible = B_TRUE, amt; y = starty; cost = applyshoppricemod(10, lf, vm, SA_BUY); mvwprintw(mainwin, y, 0, "We offer good quality rooms for only $%d per hour.", cost); y += 2; if (countmoney(lf->pack) >= cost) { mvwprintw(mainwin, y, 0, "Rent a room (you have $%d) [yn]? ", countmoney(lf->pack)); } else { mvwprintw(mainwin, y, 0, "You cannot afford to pay $%d.", cost); y+= 2; possible = B_FALSE; } if (!possible) { mvwprintw(mainwin, y, 0, "[Press any key]"); } ch = getch(); if (!possible || (ch != 'y')) { return SR_BACK; } // how many hours? snprintf(buf, BUFLEN, "How many hours will you pay for (you have $%d)?", countmoney(lf->pack)); initprompt(&prompt, buf); for (i = 1; i <= 9; i++) { int thiscost; thiscost = cost * i; snprintf(buf, BUFLEN, "%d hour%s ($%d)", i, (i == 1) ? "" : "s", thiscost); addchoice(&prompt, '0' + i, buf, buf, NULL, NULL); } addchoice(&prompt, '-', "Cancel", NULL, NULL, NULL); ch = getchoice(&prompt); if (ch == '-') { return SR_BACK; } amt = ch - '0'; // ie. 1 - 12 cost *= amt; givemoney(lf, NULL, cost); // mark that we are resting in a hotel snprintf(obid, BUFLEN, "%ld", vm->id); addflag(lf->flags, F_RESTINGINMOTEL, amt*60, 0, NA, obid); addflag(lf->flags, F_RESTUNTILBETTER, B_TRUE, NA, NA, NULL); breakaitargets(lf, B_FALSE); startresting(lf, B_FALSE); more(); return SR_QUIT; } enum SHOPRETURN shopsell(lifeform_t *lf, object_t *vm, int starty, char *toptext, int *nsold) { int count = 0; flag_t *sellflag[MAXCANDIDATES],*curflag = NULL ; char buf[BUFLEN]; int nsellflags; object_t *o; int y,ch,i; y = starty; *nsold = 0; mvwprintw(mainwin, y, 0, "We offer good prices for quality items."); y += 2; mvwprintw(mainwin, y, 0, "Sell items [y/n]? ", countmoney(lf->pack)); ch = getch(); if (ch != 'y') { return SR_BACK; } getflags(vm->flags, sellflag, &nsellflags, F_SHOPACCEPTSFLAG, F_NONE); // ask what to sell snprintf(buf, BUFLEN, "What will you sell (you have $%d)?", countmoney(lf->pack)); o = doaskobject(player->pack, buf, NULL, &count, B_TRUE, B_FALSE, B_FALSE, '\0', vm, SA_SELL, NULL, B_FALSE); if (!o) { return SR_BACK; } // validate it if (o) { object_t *newob; char let, paymentbuf[BUFLEN],obname[BUFLEN],buf[BUFLEN]; int sellprice; // get matching sell flag curflag = NULL; for (i = 0; i < nsellflags; i++) { if (obmatchessellflag(o, sellflag[i], SA_SELL)) { curflag = sellflag[i]; break; } } if (!curflag) { // you picked something impoassible msg("We don't accept that kind of object."); more(); return SR_CONTINUE; } // can we remove it? if (isequipped(o)) { if (takeoff(lf, o)) { more(); return SR_CONTINUE; } } // calculate sale price sellprice = applyshoppricemod ( pctof(curflag->val[1], real_getobvalue(o, 1)), lf, vm, SA_SELL ); sellprice *= count; // confirm getobname(o, obname, count); snprintf(buf, BUFLEN, "Sell %s for $%d?", obname, sellprice); ch = askchar(buf, "yn","n", B_TRUE, B_FALSE); if (ch == 'y') { // move object to the shop if (vm->contents->first) { let = vm->contents->last->letter + 1; } else { let = 'a'; } newob = moveob(o, vm->contents, count); newob->letter = let; (*nsold)++; // give money to player snprintf(paymentbuf, BUFLEN, "%d gold dollars", sellprice); addob(player->pack, paymentbuf); practice(player, SK_SPEECH, 1); msg("Pleasure doing business with you!!"); more(); } } else { return SR_BACK; } return SR_CONTINUE; }