====== Money ====== This example replicates the former British currency system of 12 [[https://en.wikipedia.org/wiki/Old_pence|pennies]] to one [[https://en.wikipedia.org/wiki/Shilling_(British_coin)|shilling]] and 20 shillings to one [[https://en.wikipedia.org/wiki/Bank_of_England_£1_note|pound]]. It's easily adaptable to any other combination of up to three denominations, and could fairly readily be extended to more, if anyone thinks that's a reasonable monetary system in an adventure game. Note that the **examine** verb has been extended so that if it gets applied to anything which has a **price** property, and which the player doesn't currently own, it will (a) tell you how much the item costs, and also (b) let you know whether you have enough money about your person to buy it. It's left as an "exercise for the reader" to make the **howmuchsub** routine output "tuppence", "thruppence" and "sixpence" etc. where appropriate. Anyone who's really keen could decide to include farthings, groats, florins, crowns, half-crowns, sovereigns and even guineas if they wanted to. The //howmuchsub// and //workoutchange// functions contain the "magic numbers" 240, 20 and 12, because although the class definitions of //pound// and //shilling// declare their values (which are successfully used by the //wealth// function), you can only refer to these values for __created instances__ of the classes; you can't actually reference the properties of the class itself. Note also that the **buy** routine will get rid of as much small change as it can, in favour of spending larger denominations. class money with name "money"; class banknote class money, with name "note" "notes//p"; class coin class money, with name "coin" "coins//p"; class pound(20) class banknote, with name "pound" "pounds//p", short_name "Pound note", value 240, description "A fairly standard banknote with a picture of some presumably historically significant person in the middle, and a serial number in the top left and bottom right corners."; class shilling(50) class coin, with name "shilling" "shillings//p", short_name "Shilling", value 12, description "It's a silvery shilling. What more can I say?"; class penny(50) class coin, with name "penny" "p" "pennies//p" "pence//p", short_name "Penny", plural "Pennies", value 1, description "It's quite a large copper-coloured coin."; ! How many of a certain type of object does an object contain (including its sub-objects)? [ possessions p t c n; ! p=parent object to be scanned ! t=type of owned object to look for ! c=child objects as they are found (of any sort) ! n=running total of how many t's there are n=0; for (c=child(p) : C : c=sibling(c)) { if(c ofclass t) n++; else n=n+possessions(c,t); } return n; ]; ! What total value of money does an object contain (including sub-objects)? [ wealth p c m; ! p=parent object to be scanned ! c=child objects as they are found ! m=running total of monetary value m=0; for (c=child(p) : c : c=sibling(c)) { if(c ofclass money) m=m+c.value; else m=m+wealth(c); } return m; ]; ! Remove n items of type t from object p or its descendants ! We favour taking them from the top level first where possible. ! We also assume we know in advance that the parent object has enough of them to start with. [ takething p n t c s; ! p=parent object to be scanned ! n=how many to remove ! t=type of thing to look for ! c=child objects as they are found ! s=next sibling if (n==0) return 0; ! Look at all direct children first for (c=child(p) : c : c=s) { s=sibling(c); if(c ofclass t && n>0) { t.destroy(c); if(--n == 0) return 0; } } ! Then do grandchildren for (c=child(p) : c : c=sibling(c)) { if(children(c)>0 && n>0) { if ((n=takething(c,n,t)) == 0) return 0; } } return n; ]; ! Create n object instances of type t and give them to p ! If n is more than are available, just make that many instead [ givething n t p; n=min(n,t.remaining()); while(n--) { move t.create() to p; } ]; [ forsale; if (noun ofclass object && noun in location && noun provides price) rtrue; rfalse; ]; extend "take" first * noun=forsale -> payfirst; extend "get" first * noun=forsale -> buy; extend "pay" * "for" noun=forsale -> buy; extend "examine" first * noun=forsale -> howmuch; [ payfirstsub; "It is generally-accepted practice in an establishment such as this to pay for something rather than just taking it."; ]; [ howmuchsub l s d; ; print "The price of ", (the) noun, " is "; l=noun.price/240; s=(noun.price-240*o)/12; d=noun.price-240*o-12*h; if (l) { print l, " Pound"; if (l>1) print "s"; if (s+d) { if (s && d) print ", "; else print " and "; } } else print " exactly"; if (s) { print s, " Shilling"; if (s>1) print "s"; if (d) print " and "; } if (d) print d, " Pen"; if (d==1) print "ny"; else print "ce"; print ". "; if (wealth(player)==0) "It's a pity you don't have any money right now."; if (noun.price>wealth(player)) "It's a pity you don't have enough money right now."; if (noun.price*10>wealth(player)*8) "You can just about afford that."; "Easily affordable!"; ]; [ workoutchange cost p a b c x y z n r; ! cost=cost of item ! p=player reference ! abc=cost breakdown ! xyz=possessions ! n=temporary variable ! return value to indicate whether any change was given ! need to find out how many of each denomination p owns, remove the necessary, and give back change ! We spend as many small coins as we can and as few notes as possible... ! What's the price of what we want to buy? a=cost/240; b=(cost-a*240)/12; c=cost-a*240-b*12; ! How much money have we got, in the various denominations? x=possessions(p,pound); y=possessions(p,shilling); z=possessions(p,penny); ! Let's assume for now that we don't need change r=false; !Have we got enough small coins to pay the penny part? if (z>=c) { z=z-c; takething(p,c,penny); c=0; } ! No - spend something bigger and get change else { ! Can we give a shilling? if (y>0) { y--; z=z+12-c; takething(p,1,shilling); givething(12-c,penny,p); r=true; c=0; } ! No - it'll have to be a pound else { x--; y=y+(240-c)/20; z=(240-c)%20; takething(p,1,pound); givething((240-c)/20,shilling,p); givething((240-c)%20,penny,p); r=true; c=0; } } ! So, we've paid the necessary pennies - can we get rid of any more and avoid giving away shillings / pounds? ! Give 12 pennies if we can, save one shilling n=min(z/12,b); z=z-n*12; b=b-n; takething(p,n*12,penny); ! Give 240 pennies if possible(!), save one pound n=min(z/240,a); z=z-n*240; a=a-n; takething(p,n*240,penny); ! Finished fiddling with pennies ! Do we have enough shillings to just hand over the number needed? if (y>=b) { y=y-b; takething(p,b,shilling); b=0; } ! No - spend a pound and get change else { x--; y=y+20-b; takething(p,1,pound); givething(20-b,shilling,p); r=true; b=0; } ! Can we get rid of any more shillings to avoid losing pounds? n=min(y/20,a); y=y-n*20; a=a-n; takething(p,n*20,shilling); ! Finally spend any pounds we still need to x=x-a; taketing(p,a,pound); a=0; ! Return false if we had the right money to pay with, or true if we get change in return return r; ]; [ buysub; if (location hasnt shop) { print "You can't buy anything here"; if (wealth(player) == 0) print ", and besides, you have no money anyway"; "."; } if (noun notin location) { print "You can buy things here, but ", (a) noun, " is not one of them (or, possibly, they're just out of stock)"; if (wealth(player) == 0) print ", and besides, you have no money anyway"; "."; } if (noun.price == false) { print "They have ", (a) noun, " here, but not for sale"; if (wealth(player) == 0) print ", and besides, you have no money anyway"; "."; } if (noun.price > wealth(player)) "You can see ",(a) noun," on sale here, but you don't have enough money."; move noun to player; print "The sales assistant takes your money and puts it safely into the till"; if(workoutchange(noun.price,player)) print ". You put the change into your pocket"; " and you take your new purchase."; ]; ! Why doesn't Inform already have max() and min() functions!? ! Hmm, probably for the same reason that it has a++ and a-- but is lacking a+= and a-= [ min a b; if(a ---- [[.:|Go up]]\\ Return to [[:|main index]].