8 int _GetMinBalance(int Account);
9 int _CanTransfer(int Source, int Destination, int Ammount);
10 int _Transfer(int Source, int Destination, int Ammount, const char *Reason);
11 int _GetSalesAcct(tItem *Item);
15 * \brief Dispense an item for a user
17 * The core of the dispense system, I kinda like it :)
19 int DispenseItem(int ActualUser, int User, tItem *Item)
23 char *username, *actualUsername;
25 handler = Item->Handler;
27 salesAcct = _GetSalesAcct(Item);
29 // Check if the user can afford it
30 if( Item->Price && !_CanTransfer(User, salesAcct, Item->Price) )
32 return 2; // 2: No balance
35 // HACK: Naming a slot "dead" disables it
36 if( strcmp(Item->Name, "dead") == 0 )
39 // Check if the dispense is possible
40 if( handler->CanDispense ) {
41 ret = handler->CanDispense( User, Item->ID );
42 if(ret) return 1; // 1: Unable to dispense
45 // Get username for debugging
46 username = Bank_GetAcctName(User);
48 // Ordering: Pay, Drop. Worst case requires a refund, other ordering leads to drops when payment fails.
54 reason = mkstr("Dispense - %s:%i %s", handler->Name, Item->ID, Item->Name);
55 if( _Transfer( User, salesAcct, Item->Price, reason ) != 0 ) {
56 Log_Error("Dispense failed (%s dispensing %s:%i '%s') - Cokebank error!",
57 username, Item->Handler->Name, Item->ID, Item->Name);
60 return -1; // -1: Unknown error
65 // Actually do the dispense
66 if( handler->DoDispense ) {
67 ret = handler->DoDispense( User, Item->ID );
69 Log_Error("Dispense failed (%s dispensing %s:%i '%s')",
70 username, Item->Handler->Name, Item->ID, Item->Name);
72 return -1; // -1: Unknown Error
76 actualUsername = Bank_GetAcctName(ActualUser);
78 // And log that it happened
81 // Special format for zero cost dispenses
82 Log_Info("test dispense '%s' (%s:%i) for %s by %s [no change]",
83 Item->Name, handler->Name, Item->ID,
84 username, actualUsername
89 Log_Info("dispense '%s' (%s:%i) for %s by %s [cost %i, balance %i]",
90 Item->Name, handler->Name, Item->ID,
91 username, actualUsername, Item->Price, Bank_GetBalance(User)
96 free( actualUsername );
101 * \brief Refund a dispense
103 int DispenseRefund(int ActualUser, int DestUser, tItem *Item, int OverridePrice)
107 char *username, *actualUsername;
109 src_acct = _GetSalesAcct(Item);
111 if( OverridePrice > 0 )
112 price = OverridePrice;
116 ret = _Transfer( src_acct, DestUser, price, "Refund");
119 username = Bank_GetAcctName(DestUser);
120 actualUsername = Bank_GetAcctName(ActualUser);
122 Log_Info("refund '%s' (%s:%i) to %s by %s [cost %i, balance %i]",
123 Item->Name, Item->Handler->Name, Item->ID,
124 username, actualUsername, price, Bank_GetBalance(DestUser)
128 free(actualUsername);
134 * \brief Give money from one user to another
136 int DispenseGive(int ActualUser, int SrcUser, int DestUser, int Ammount, const char *ReasonGiven)
139 char *actualUsername;
140 char *srcName, *dstName;
142 // HACK: Naming a slot "dead" disables it (catch for snack)
143 if( strcmp(ReasonGiven, "dead") == 0 )
146 if( Ammount < 0 ) return 1; // Um... negative give? Not on my watch!
148 ret = _Transfer( SrcUser, DestUser, Ammount, ReasonGiven );
149 if(ret) return 2; // No Balance
152 actualUsername = Bank_GetAcctName(ActualUser);
153 srcName = Bank_GetAcctName(SrcUser);
154 dstName = Bank_GetAcctName(DestUser);
156 Log_Info("give %i from %s to %s by %s [balances %i, %i] - %s",
157 Ammount, srcName, dstName, actualUsername,
158 Bank_GetBalance(SrcUser), Bank_GetBalance(DestUser),
164 free(actualUsername);
171 * \brief Move money from one user to another (Admin Only)
173 int DispenseTransfer(int ActualUser, int SrcUser, int DestUser, int Ammount, const char *ReasonGiven)
176 char *actualUsername;
177 char *srcName, *dstName;
179 // Make sure the user is an admin
180 if( !(Bank_GetFlags(ActualUser) & USER_FLAG_ADMIN) )
183 ret = _Transfer( SrcUser, DestUser, Ammount, ReasonGiven );
184 if(ret) return 2; // No Balance
187 actualUsername = Bank_GetAcctName(ActualUser);
188 srcName = Bank_GetAcctName(SrcUser);
189 dstName = Bank_GetAcctName(DestUser);
191 Log_Info("move %i from %s to %s by %s [balances %i, %i] - %s",
192 Ammount, srcName, dstName, actualUsername,
193 Bank_GetBalance(SrcUser), Bank_GetBalance(DestUser),
199 free(actualUsername);
206 * \brief Add money to an account
208 int DispenseAdd(int ActualUser, int User, int Ammount, const char *ReasonGiven)
211 char *dstName, *byName;
213 #if DISPENSE_ADD_BELOW_MIN
214 ret = _Transfer( Bank_GetAcctByName(COKEBANK_ADDSRC_ACCT,1), User, Ammount, ReasonGiven );
216 ret = Bank_Transfer( Bank_GetAcctByName(COKEBANK_ADDSRC_ACCT,1), User, Ammount, ReasonGiven );
220 byName = Bank_GetAcctName(ActualUser);
221 dstName = Bank_GetAcctName(User);
223 Log_Info("add %i to %s by %s [balance %i] - %s",
224 Ammount, dstName, byName, Bank_GetBalance(User), ReasonGiven
233 int DispenseSet(int ActualUser, int User, int Balance, const char *ReasonGiven, int *OrigBalance)
235 int curBal = Bank_GetBalance(User);
236 char *byName, *dstName;
238 if( Bank_Transfer( Bank_GetAcctByName(COKEBANK_DEBT_ACCT,1), User, Balance-curBal, ReasonGiven ) )
241 byName = Bank_GetAcctName(ActualUser);
242 dstName = Bank_GetAcctName(User);
244 Log_Info("set balance of %s to %i by %s [was %i, balance %i] - %s",
245 dstName, Balance, byName, curBal, Bank_GetBalance(User), ReasonGiven
248 *OrigBalance = curBal;
256 * \brief Donate money to the club
258 int DispenseDonate(int ActualUser, int User, int Ammount, const char *ReasonGiven)
261 char *srcName, *byName;
263 if( Ammount < 0 ) return 2;
265 ret = _Transfer( User, Bank_GetAcctByName(COKEBANK_DONATE_ACCT,1), Ammount, ReasonGiven );
268 byName = Bank_GetAcctName(ActualUser);
269 srcName = Bank_GetAcctName(User);
271 Log_Info("donate %i from %s by %s [balance %i] - %s",
272 Ammount, srcName, byName, Bank_GetBalance(User), ReasonGiven
281 int DispenseUpdateItem(int User, tItem *Item, const char *NewName, int NewPrice)
286 if( NewPrice < 0 ) return 2;
287 if( !Item ) return 2;
288 if( strlen(NewName) < 1 ) return 2;
292 Item->Name = strdup(NewName);
293 Item->Price = NewPrice;
295 username = Bank_GetAcctName(User);
297 Log_Info("item %s:%i updated to '%s' %i by %s",
298 Item->Handler->Name, Item->ID,
299 NewName, NewPrice, username
310 // --- Internal Functions ---
311 int _GetMinBalance(int Account)
313 int flags = Bank_GetFlags(Account);
315 // Evil little piece of HACK:
316 // root's balance cannot be changed by any of the above functions
317 // - Stops dispenses as root by returning insufficent balance.
319 char *username = Bank_GetAcctName(Account);
320 if( strcmp(username, "root") == 0 )
328 // - Internal accounts have no lower bound
329 if( flags & USER_FLAG_INTERNAL ) return INT_MIN;
332 // if( flags & USER_FLAG_ADMIN ) return -5000;
335 // if( flags & USER_FLAG_COKE ) return -2000;
337 // Anyone else, non-negative
342 * \brief Check if a transfer is possible
343 * \return Boolean success
345 int _CanTransfer(int Source, int Destination, int Ammount)
347 // if( Bank_GetFlags(Source) & USER_FLAG_DISABLED )
351 if( Bank_GetBalance(Source) - Ammount < _GetMinBalance(Source) )
356 if( Bank_GetBalance(Destination) + Ammount < _GetMinBalance(Destination) )
362 int _Transfer(int Source, int Destination, int Ammount, const char *Reason)
364 if( !_CanTransfer(Source, Destination, Ammount) )
366 return Bank_Transfer(Source, Destination, Ammount, Reason);
369 int _GetSalesAcct(tItem *Item)
371 char string[sizeof(COKEBANK_SALES_PREFIX)+strlen(Item->Handler->Name)];
372 strcpy(string, COKEBANK_SALES_PREFIX);
373 strcat(string, Item->Handler->Name);
374 return Bank_GetAcctByName(string, 1);