Here is how I handle money in Tads3. I use the typical RPG money system of gold, silver and copper.
To use this you need to include the bignum.h file (in gameMain usually):
#ifndef _BIGNUM_H_
#include <bignum.h>
#endif
Then in gameMain I put these:
myBank = new BigNumber('0') // BigNumber('99123456') // the "master" bank variable for the player
myCarriedMoney = new BigNumber('50') // 12345678') // '50') // temp variable mostly - recalculated "on the fly" based on carried gold, silver and copper
myCarriedGold = new BigNumber('2550') // actual
myCarriedSilver = new BigNumber('320') // actual
myCarriedCopper = new BigNumber('50') // actual
getPlayerBank(){
// local gold = new BigNumber(myBank.getAbs() / 10000).getFloor();// floor is biggest int less than this number. i.e. 12.3456 = 12
local gold = new BigNumber(gameMain.myBank.getAbs() / 10000).getFloor();
local silver = new BigNumber(gameMain.myBank.getAbs() / 100).getFloor();
silver = silver.divideBy(100)[2];// second list item is remainder
local copper = new BigNumber(gameMain.myBank.getAbs()).getFloor();
copper = copper.divideBy(100)[2];// second list item is remainder
local s0 = 'In the bank you have: ' +
gold + 'g ' +
silver + 's ' +
copper + 'c ' + '';
// '\bTotal (converting all to copper): ' + gameMain.myBank + 'c ';
return s0;
}
getPlayerCarriedMoney(){
// --... // local gold = new BigNumber(myBank.getAbs() / 10000).getFloor();// floor is biggest int less than this number. i.e. 12.3456 = 12
// local gold = new BigNumber(gameMain.myCarriedMoney.getAbs() / 10000).getFloor();
// local silver = new BigNumber(gameMain.myCarriedMoney.getAbs() / 100).getFloor();
// silver = silver.divideBy(100)[2];// second list item is remainder
// local copper = new BigNumber(gameMain.myCarriedMoney.getAbs()).getFloor();
// copper = copper.divideBy(100)[2];// second list item is remainder
local gold = 0;
if(gameMain.myCarriedGold > 0) gold = new BigNumber(gameMain.myCarriedGold.getAbs()).getFloor();
local silver = 0;
if(gameMain.myCarriedSilver > 0) silver = new BigNumber(gameMain.myCarriedSilver.getAbs()).getFloor();
local copper = 0;
if(gameMain.myCarriedCopper > 0) copper = new BigNumber(gameMain.myCarriedCopper.getAbs()).getFloor();
local s0 = 'Your carried money is: ' +
gold + 'g ' +
silver + 's ' +
copper + 'c';
return s0;
}
…and to actually interact with your bank money I’d have an NPC banker and some input screens with lists of things you can do:
- exit
- deposit
- withdraw
If you select “2” for withdraw, then ask how much gold, silver and copper. Then using some math, convert it and move it all over, subtracting from bank variable “myBank” and adding to variable “myCarriedMoney.”
Here is my banker NPC code (disregard the CromexxHuman and Male classes and go with Actor or Person here):
banker: CromexxHuman, Male
name = 'banker'
vocabWords = '(the) (bank) banker Roy Dribbik male/man/dude/guy/fellow/teller/tellar'
properName = 'Roy Dribbik'
isProperName = true
isawake = true
isQualifiedName = (isProperName)
location = erifAveBankInterior
firstPlayerMeetingNPCObject = nil // player object
firstPlayerMeetingNPCGender = nil // sex 'male' or 'female'
desc {
"Roy Dribbik, the banker, is dressed in a forest green suit with black pinstripes.
He\'s wearing a matching tie and thin little reading glasses and even has a banker\'s
visor on his head. He\'s got grey eyes and white tufts of hair around the ears but is
otherwise bald. He looks like he\'s in his fifties or sixties. ";
}
showBank(){
local sa = gameMain.getPlayerBank();
local sb = gameMain.getPlayerCarriedMoney();
"<table border=1 width=350 bgcolor=#000000>
<tr><td><font color=#000000>\b<<sa>></font></td></tr>
<tr><td><font color=#000000>\b<<sb>></font></td></tr>
<tr><td><font color=#000000>\b(1) Deposit\b(2) Withraw\b(3) Goodbye</font></td></tr>
</table>";
local iDone = 0;
local s0 = '';
do{
"<br> >";
s0 = inputManager.getInputLine(nil, nil);
s0 = s0.toLower();
if((s0 == 'deposit') ||
(s0 == 'withdraw') ||
(s0 == 'goodbye') ||
(s0 == 'bye') ||
(s0 == '1') ||
(s0 == '2') ||
(s0 == '3')){
iDone++;
}else{
"Please select <b>1</b> - <b>3</b><br>";
}
"\n";
}while(iDone==0);
if((s0=='3') || (s0=='goodbye') || (s0 =='bye')){
if(banker.agendaList != nil){
foreach(local obj in banker.agendaList){
banker.removeFromAgenda(obj);// clear the agenda list
}
}
// banker.setCurState(bankerBye);
// gTranscript.showReports(true);// Per Mike Roberts "...'true' turns off the transcript for the remainder of the turn, so if you're doing a series of timeDelay() pauses, you only need to do this once, before the first pause."
// nestedActorAction(gPlayerChar,Goodbye);// exit;
// if(banker.curState != nil){
// "....bye!";
banker.curState.endConversation(gPlayerChar,endConvBye);// endConvBye);// see: endConvxxx in adv3.h - see: actor.t
// gPlayerChar.curState.endConversation(banker,endConvBye);
// gPlayerChar.endConversation();
// banker.setCurState(bankerWorking);
// }
// gPlayerChar.sayGoodbye(banker);// actor);
// libGlobal.totalTurns--;
// local tokList = Tokenizer.tokenize('goodbye');
// executeCommand(gPlayerChar,gPlayerChar,tokList,nil);// gActor, gActor
}else if((s0=='2') || (s0=='withdraw')){
banker.withdraw();
}else{
banker.deposit();
}
}
deposit(){
local gold = new BigNumber(gameMain.myCarriedGold.getAbs()).getFloor();
local silver = new BigNumber(gameMain.myCarriedSilver.getAbs()).getFloor();
local copper = new BigNumber(gameMain.myCarriedCopper.getAbs()).getFloor();
if(gold + silver + copper == 0){
"You have no money in your posession to deposit!\b";
inputManager.pauseForMore(true);
banker.showBank();
}else{
if(copper != 0){
banker.depositAmount(copper,'copper');
}
if(silver != 0){
banker.depositAmount(silver,'silver');
}
if(gold != 0){
banker.depositAmount(gold,'gold');
}
inputManager.pauseForMore(true);
banker.showBank();
}
}
/*
* where oMoneyObject = gameMain.myCarriedGold, ...silver, ... copper
* sName = 'gold', 'silver' or 'copper'
*/
depositAmount(oMoneyObject,sName){
oMoneyObject = new BigNumber(oMoneyObject.getAbs()).getFloor();
local iDone = 0;
local s0 = '';
local oBigNumborf;
local iFailDigitTest = 0;
local digitPat = new RexPattern('<digit>');// matches a single digit in a string
do{
"<br>Please enter amount of <<sName>> to deposit >";
s0 = inputManager.getInputLine(nil, nil);
if(s0 == nil) s0 = '0';
if(s0 == '') s0 = '0';
s0 = s0.toLower();
// rex search for <digit> ... this stops cheaters from trying to trick the parser with math tokens, etc.
iFailDigitTest = 0;// reset flag
for(local i = 0; i <= s0.length;i++){
if(! rexMatch(digitPat,s0,i)) iFailDigitTest++;
}
oBigNumborf = new BigNumber(s0);
// getFraction() returns everything to the right of the decimal point, if this is > 0 it is a fraction
if(oBigNumborf.getFraction() > 0){
"Please enter whole numbers.<br>";
}else if(iFailDigitTest > 0){
"Please enter a whole number without any alphabetical or special characters (including the avoidance of decimal points). ";
}else if(toInteger(s0) > oMoneyObject){
"That\'s more <<sName>> than you have available.<br>";
}else if(toInteger(s0) < 0){
"You can\'t deposit negative amounts of <<sName>>.<br>";
}else if(toInteger(s0) >= 0){
"The banker says,\"Depositing <<s0>> <<sName>> to your account.\"<br>";
if(sName == 'copper'){
gameMain.myBank += toInteger(s0);// copper gets directly added
gameMain.myCarriedCopper -= toInteger(s0);
}else if(sName == 'silver'){
gameMain.myBank += (toInteger(s0) * 100); // silver converted to copper is * 100
gameMain.myCarriedSilver -= toInteger(s0);
}else if(sName == 'gold'){
gameMain.myBank += (toInteger(s0) * 10000);// gold converted to copper is * 10000
gameMain.myCarriedGold -= toInteger(s0);
}
iDone++;
}else{
"You must enter a numeric amount from 0 to <<toInteger(s0)>>.<br>";
}
"\n";
}while(iDone==0);
}
withdraw(){
local gold = new BigNumber(gameMain.myBank.getAbs() / 10000).getFloor();
local silver = new BigNumber(gameMain.myBank.getAbs() / 100).getFloor();
silver = silver.divideBy(100)[2];// second list item is remainder
local copper = new BigNumber(gameMain.myBank.getAbs()).getFloor();
copper = copper.divideBy(100)[2];// second list item is remainder
if(gold + silver + copper == 0){
"You have no money in the bank to withdraw!\b";
inputManager.pauseForMore(true);
banker.showBank();
}else{
if(copper != 0){
banker.withdrawAmount(copper,'copper');
}
if(silver != 0){
banker.withdrawAmount(silver,'silver');
}
if(gold != 0){
banker.withdrawAmount(gold,'gold');
}
inputManager.pauseForMore(true);
banker.showBank();
}
}
/*
* where oMoneyObject = gameMain.myCarriedGold, ...silver, ... copper
* sName = 'gold', 'silver' or 'copper'
*/
withdrawAmount(oMoneyObject,sName){
local iDone = 0;
local s0 = '';
local oBigNum;
local iFailDigitTest = 0;
local digitPat = new RexPattern('<digit>');// matches a single digit in a string
do{
"<br>Please enter amount of <<sName>> to withdraw >";
s0 = inputManager.getInputLine(nil, nil);
if(s0 == nil) s0 = '0';
if(s0 == '') s0 = '0';
s0 = s0.toLower();
// rex search for <digit> ... this stops cheaters from trying to trick the parser with math tokens, etc.
iFailDigitTest = 0;// reset flag
for(local i = 0; i <= s0.length;i++){
if(! rexMatch(digitPat,s0,i)) iFailDigitTest++;
}
oBigNum = new BigNumber(s0);
// getFraction() returns everything to the right of the decimal point, if this is > 0 it is a fraction
if(oBigNum.getFraction() > 0){
"Please enter whole numbers.<br>";
}else if(iFailDigitTest > 0){
"Please enter a whole number without any alphabetical or special characters (including the avoidance of decimal points). ";
}else if(toInteger(s0) > oMoneyObject){
"That\'s more <<sName>> than you have in the bank.<br>";
}else if(toInteger(s0) < 0){
"You can\'t withdraw negative amounts of <<sName>>.<br>";
}else if(toInteger(s0) >= 0){
"The banker says,\"Withdrawing <<s0>> <<sName>> from your account.\"<br>";
if(sName == 'copper'){
gameMain.myBank -= toInteger(s0);
gameMain.myCarriedCopper += toInteger(s0);
}else if(sName == 'silver'){
gameMain.myBank -= (toInteger(s0) * 100); // silver converted to copper is * 100
gameMain.myCarriedSilver += toInteger(s0);
}else if(sName == 'gold'){
gameMain.myBank -= (toInteger(s0) * 10000);// gold converted to copper is * 10000
gameMain.myCarriedGold += toInteger(s0);
}
iDone++;
}else{
"You must enter a numeric amount from 0 to <<toInteger(s0)>>.<br>";
}
"\n";
}while(iDone==0);
}
;
+ bankerTalking: InConversationState
stateDesc = nil
attentionSpan = 4 // after 4 turns he goes back to wandering
nextState = bankerWorking
specialDesc = "The banker, Mr. Dribbik, stands behind his teller window talking to you. "
;
++ bankerWorking: ConversationReadyState
specialDesc = "A banker is here. "
// stateDesc = "A banker is here. "
isInitState = true
;
+++ bankerHello: HelloTopic
topicResponse {
"\"Hello there,\" you say to the banker.\b\"Welcome to my bank,\" he says.
(<a href='ask about money'>ask about your money</a>)";
}
// <a plain href='<<libMessages.commandFullScore>>'>";
;
+++ bankerBye: ByeTopic
topicResponse {
"\"Bye,\" you say to the banker.\b\"Thank you for coming to my bank. See you again,\" he says. ";
// gTranscript.showReports(true);// Per Mike Roberts "...'true' turns off the transcript for the remainder of the turn, so if you're doing a series of timeDelay() pauses, you only need to do this once, before the first pause."
// banker.setCurState(bankerWorking);
}
isActive = bankerHello.isActive
;
+++ bankerImpBye: ImpByeTopic
topicResponse {
"The banker shrugs and waits for the next customer. ";
}
;
++ bankerDAT: DefaultAskTellTopic
topicResponse {
"<q>What do you think about <<gTopic.getTopicText>>?</q> you ask.<.p>";
"<q>This is a place of business, not a public inquiry office,\" the banker states rather coldly. He\'s expecting you to maybe <a href='ask about money'>ask about your money</a>.<.p> ";
}
;
++ AskTopic @playerMoney
name = 'your money'
topicResponse {
banker.showBank();// open up the banker transaction "screen"
}
;
I have a working system using this method, plus an experience point system, RPG character screen (with inventory slots), items with statistic modifiers, etc. in my latest ongoing project “Villain” over on this site (as programmer Cleo Kraft):
http://www.tfgamessite.com/
See this post once you log into the board (you may need game creator status to see this thread though - not sure): http://www.tfgamessite.com/phpbb3/viewtopic.php?f=6&t=2221