Atrinik Server  4.0
bank.c
Go to the documentation of this file.
1 /*************************************************************************
2  * Atrinik, a Multiplayer Online Role Playing Game *
3  * *
4  * Copyright (C) 2009-2014 Alex Tokar and Atrinik Development Team *
5  * *
6  * Fork from Crossfire (Multiplayer game for X-windows). *
7  * *
8  * This program is free software; you can redistribute it and/or modify *
9  * it under the terms of the GNU General Public License as published by *
10  * the Free Software Foundation; either version 2 of the License, or *
11  * (at your option) any later version. *
12  * *
13  * This program is distributed in the hope that it will be useful, *
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of *
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
16  * GNU General Public License for more details. *
17  * *
18  * You should have received a copy of the GNU General Public License *
19  * along with this program; if not, write to the Free Software *
20  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *
21  * *
22  * The author can be reached at admin@atrinik.org *
23  ************************************************************************/
24 
32 #include <global.h>
33 #include <toolkit/string.h>
34 #include <arch.h>
35 #include <player.h>
36 #include <object.h>
37 
43 #define BANK_STRING_NONE 0
44 
45 #define BANK_STRING_AMOUNT 1
46 
47 #define BANK_STRING_ALL -1
48 
54 typedef struct bank_info {
56  int mode;
57 
59  uint32_t amber;
60 
62  uint32_t mithril;
63 
65  uint32_t jade;
66 
68  uint32_t gold;
69 
71  uint32_t silver;
72 
74  uint32_t copper;
75 } bank_info_t;
76 
84 static void bank_parse_string(const char *str, bank_info_t *info)
85 {
86  memset(info, 0, sizeof(*info));
87 
88  while (isspace(*str)) {
89  str++;
90  }
91 
92  /* Easy, special case: all money */
93  if (strncasecmp(str, "all", 3) == 0) {
94  info->mode = BANK_STRING_ALL;
95  return;
96  }
97 
98  info->mode = BANK_STRING_NONE;
99 
100  char word[MAX_BUF];
101  size_t pos = 0;
102  while (string_get_word(str, &pos, ' ', VS(word), 0)) {
103  if (!string_isdigit(word)) {
104  continue;
105  }
106 
107  unsigned long value = strtoul(word, NULL, 10);
108 
109  if (!string_get_word(str, &pos, ' ', VS(word), 0)) {
110  continue;
111  }
112 
113  size_t len = strlen(word);
114  if (strncasecmp("amber", word, len) == 0) {
115  info->mode = BANK_STRING_AMOUNT;
116  info->amber += value;
117  } else if (strncasecmp("mithril", word, len) == 0) {
118  info->mode = BANK_STRING_AMOUNT;
119  info->mithril += value;
120  } else if (strncasecmp("jade", word, len) == 0) {
121  info->mode = BANK_STRING_AMOUNT;
122  info->jade += value;
123  } else if (strncasecmp("gold", word, len) == 0) {
124  info->mode = BANK_STRING_AMOUNT;
125  info->gold += value;
126  } else if (strncasecmp("silver", word, len) == 0) {
127  info->mode = BANK_STRING_AMOUNT;
128  info->silver += value;
129  } else if (strncasecmp("copper", word, len) == 0) {
130  info->mode = BANK_STRING_AMOUNT;
131  info->copper += value;
132  }
133  }
134 }
135 
145 static uint32_t bank_get_coins_num(object *op, archetype_t *at)
146 {
147  uint32_t num = 0;
148  FOR_INV_PREPARE(op, tmp) {
149  if (tmp->type == MONEY && tmp->arch == at) {
150  num += tmp->nrof;
151  } else if (tmp->type == CONTAINER && (tmp->race == NULL ||
152  strstr(tmp->race, "gold") != NULL)) {
153  num += bank_get_coins_num(tmp, at);
154  }
155  } FOR_INV_FINISH();
156 
157  return num;
158 }
159 
171 static int64_t bank_remove_coins(object *op, archetype_t *at, uint32_t nrof)
172 {
173  int64_t amount = 0;
174 
175  FOR_INV_PREPARE(op, tmp) {
176  if (nrof == 0 && at != NULL) {
177  return amount;
178  }
179 
180  if (tmp->type == MONEY && (at == NULL || tmp->arch == at)) {
181  if (at == NULL || tmp->nrof <= nrof) {
182  if (at != NULL) {
183  nrof -= tmp->nrof;
184  }
185 
186  amount += tmp->nrof * tmp->value;
187  object_remove(tmp, 0);
188  object_destroy(tmp);
189  } else {
190  tmp->nrof -= nrof;
191  amount += nrof * tmp->value;
192  nrof = 0;
193  }
194  } else if (tmp->type == CONTAINER && (tmp->race == NULL ||
195  strstr(tmp->race, "gold") != NULL)) {
196  amount += bank_remove_coins(tmp, at, nrof);
197  }
198  } FOR_INV_FINISH();
199 
200  return amount;
201 }
202 
212 static void bank_insert_coins(object *op, archetype_t *at, uint32_t nrof)
213 {
214  object *tmp = object_get();
215  object_copy(tmp, &at->clone, false);
216  tmp->nrof = nrof;
217  object_insert_into(tmp, op, 0);
218 }
219 
227 object *bank_find_info(object *op)
228 {
229  FOR_INV_PREPARE(op, tmp) {
230  if (tmp->arch->name == shstr_cons.player_info &&
231  tmp->name == shstr_cons.BANK_GENERAL) {
232  return tmp;
233  }
234  } FOR_INV_FINISH();
235 
236  return NULL;
237 }
238 
246 static object *bank_create_info(object *op)
247 {
248  object *bank = arch_get(shstr_cons.player_info);
249 
250  FREE_AND_COPY_HASH(bank->name, shstr_cons.BANK_GENERAL);
251  return object_insert_into(bank, op, 0);
252 }
253 
262 static object *bank_get_info(object *op)
263 {
264  object *bank = bank_find_info(op);
265  if (bank == NULL) {
266  bank = bank_create_info(op);
267  }
268  return bank;
269 }
270 
278 int64_t bank_get_balance(object *op)
279 {
280  HARD_ASSERT(op != NULL);
281 
282  object *bank = bank_find_info(op);
283  if (bank == NULL) {
284  return 0;
285  }
286 
287  return bank->value;
288 }
289 
300 int bank_deposit(object *op, const char *text, int64_t *value)
301 {
302  HARD_ASSERT(op != NULL);
303  HARD_ASSERT(text != NULL);
304  HARD_ASSERT(value != NULL);
305 
306  bank_info_t info;
307  bank_parse_string(text, &info);
308  *value = 0;
309 
310  if (info.mode == BANK_STRING_NONE) {
311  return BANK_SYNTAX_ERROR;
312  } else if (info.mode == BANK_STRING_ALL) {
313  *value = bank_remove_coins(op, NULL, 0);
314  object *bank = bank_get_info(op);
315  bank->value += *value;
316  } else {
317  if (info.amber != 0) {
318  if (bank_get_coins_num(op, coins_arch[0]) < info.amber) {
319  return BANK_DEPOSIT_AMBER;
320  }
321  }
322 
323  if (info.mithril != 0) {
324  if (bank_get_coins_num(op, coins_arch[1]) < info.mithril) {
325  return BANK_DEPOSIT_MITHRIL;
326  }
327  }
328 
329  if (info.jade != 0) {
330  if (bank_get_coins_num(op, coins_arch[2]) < info.jade) {
331  return BANK_DEPOSIT_JADE;
332  }
333  }
334 
335  if (info.gold != 0) {
336  if (bank_get_coins_num(op, coins_arch[3]) < info.gold) {
337  return BANK_DEPOSIT_GOLD;
338  }
339  }
340 
341  if (info.silver != 0) {
342  if (bank_get_coins_num(op, coins_arch[4]) < info.silver) {
343  return BANK_DEPOSIT_SILVER;
344  }
345  }
346 
347  if (info.copper != 0) {
348  if (bank_get_coins_num(op, coins_arch[5]) < info.copper) {
349  return BANK_DEPOSIT_COPPER;
350  }
351  }
352 
353  if (info.amber != 0) {
354  bank_remove_coins(op, coins_arch[0], info.amber);
355  }
356 
357  if (info.mithril != 0) {
358  bank_remove_coins(op, coins_arch[1], info.mithril);
359  }
360 
361  if (info.jade != 0) {
362  bank_remove_coins(op, coins_arch[2], info.jade);
363  }
364 
365  if (info.gold != 0) {
366  bank_remove_coins(op, coins_arch[3], info.gold);
367  }
368 
369  if (info.silver != 0) {
370  bank_remove_coins(op, coins_arch[4], info.silver);
371  }
372 
373  if (info.copper != 0) {
374  bank_remove_coins(op, coins_arch[5], info.copper);
375  }
376 
377  *value = info.amber * coins_arch[0]->clone.value +
378  info.mithril * coins_arch[1]->clone.value +
379  info.jade * coins_arch[2]->clone.value +
380  info.gold * coins_arch[3]->clone.value +
381  info.silver * coins_arch[4]->clone.value +
382  info.copper * coins_arch[5]->clone.value;
383  object *bank = bank_get_info(op);
384  bank->value += *value;
385  }
386 
387  return BANK_SUCCESS;
388 }
389 
402 int bank_withdraw(object *op, const char *text, int64_t *value)
403 {
404  HARD_ASSERT(op != NULL);
405  HARD_ASSERT(text != NULL);
406  HARD_ASSERT(value != NULL);
407 
408  bank_info_t info;
409  bank_parse_string(text, &info);
410 
411  object *bank = bank_find_info(op);
412  *value = 0;
413 
414  if (bank == NULL || bank->value == 0) {
415  return BANK_WITHDRAW_MISSING;
416  }
417 
418  if (info.mode == BANK_STRING_NONE) {
419  return BANK_SYNTAX_ERROR;
420  } else if (info.mode == BANK_STRING_ALL) {
421  *value = bank->value;
422  bank->value = 0;
423  shop_insert_coins(op, *value);
424  } else {
425  if (info.amber > 100000 || info.mithril > 100000 ||
426  info.jade > 100000 || info.gold > 100000 ||
427  info.silver > 1000000 || info.copper > 1000000) {
428  return BANK_WITHDRAW_HIGH;
429  }
430 
431  int64_t big_value = info.amber * coins_arch[0]->clone.value +
432  info.mithril * coins_arch[1]->clone.value +
433  info.jade * coins_arch[2]->clone.value +
434  info.gold * coins_arch[3]->clone.value +
435  info.silver * coins_arch[4]->clone.value +
436  info.copper * coins_arch[5]->clone.value;
437 
438  if (big_value > bank->value) {
439  return BANK_WITHDRAW_MISSING;
440  }
441 
442  if (!player_can_carry(op, info.amber * coins_arch[0]->clone.weight +
443  info.mithril * coins_arch[1]->clone.weight +
444  info.jade * coins_arch[2]->clone.weight +
445  info.gold * coins_arch[3]->clone.weight +
446  info.silver * coins_arch[4]->clone.weight +
447  info.copper * coins_arch[5]->clone.weight)) {
449  }
450 
451  if (info.amber != 0) {
452  bank_insert_coins(op, coins_arch[0], info.amber);
453  }
454 
455  if (info.mithril != 0) {
456  bank_insert_coins(op, coins_arch[1], info.mithril);
457  }
458 
459  if (info.jade != 0) {
460  bank_insert_coins(op, coins_arch[2], info.jade);
461  }
462 
463  if (info.gold != 0) {
464  bank_insert_coins(op, coins_arch[3], info.gold);
465  }
466 
467  if (info.silver != 0) {
468  bank_insert_coins(op, coins_arch[4], info.silver);
469  }
470 
471  if (info.copper != 0) {
472  bank_insert_coins(op, coins_arch[5], info.copper);
473  }
474 
475  *value = big_value;
476  bank->value -= big_value;
477  }
478 
479  return BANK_SUCCESS;
480 }
#define FREE_AND_COPY_HASH(_sv_, _nv_)
Definition: global.h:100
void object_destroy(object *ob)
Definition: object.c:1441
#define BANK_STRING_AMOUNT
Definition: bank.c:45
int player_can_carry(object *pl, uint32_t weight)
Definition: player.c:1036
object * object_get(void)
Definition: object.c:993
#define FOR_INV_PREPARE(op_, it_)
Definition: define.h:1691
#define FOR_INV_FINISH()
Definition: define.h:1698
struct archetype * coins_arch[NUM_COINS]
Definition: treasure.c:258
void object_copy(object *op, const object *src, bool no_speed)
Definition: object.c:886
Definition: bank.c:54
object * bank_find_info(object *op)
Definition: bank.c:227
static void bank_insert_coins(object *op, archetype_t *at, uint32_t nrof)
Definition: bank.c:212
uint32_t copper
Definition: bank.c:74
object * arch_get(const char *name)
Definition: arch.c:430
int bank_deposit(object *op, const char *text, int64_t *value)
Definition: bank.c:300
#define MONEY
Definition: define.h:226
static object * bank_create_info(object *op)
Definition: bank.c:246
static object * bank_get_info(object *op)
Definition: bank.c:262
#define BANK_WITHDRAW_OVERWEIGHT
Definition: global.h:59
void object_remove(object *op, int flags)
Definition: object.c:1623
#define BANK_DEPOSIT_SILVER
Definition: global.h:64
#define BANK_STRING_NONE
Definition: bank.c:43
int mode
Definition: bank.c:56
#define BANK_DEPOSIT_MITHRIL
Definition: global.h:70
static void bank_parse_string(const char *str, bank_info_t *info)
Definition: bank.c:84
#define BANK_DEPOSIT_COPPER
Definition: global.h:62
Definition: arch.h:40
uint32_t silver
Definition: bank.c:71
uint32_t weight
Definition: object.h:246
#define BANK_DEPOSIT_GOLD
Definition: global.h:66
object * object_insert_into(object *op, object *where, int flag)
Definition: object.c:2158
uint32_t amber
Definition: bank.c:59
static uint32_t bank_get_coins_num(object *op, archetype_t *at)
Definition: bank.c:145
#define BANK_WITHDRAW_HIGH
Definition: global.h:55
uint32_t jade
Definition: bank.c:65
const char * name
Definition: object.h:168
#define BANK_SYNTAX_ERROR
Definition: global.h:50
uint32_t gold
Definition: bank.c:68
#define CONTAINER
Definition: define.h:493
uint32_t nrof
Definition: object.h:264
#define BANK_WITHDRAW_MISSING
Definition: global.h:57
uint64_t num
Number of successful updates.
Definition: metaserver.c:43
#define BANK_DEPOSIT_JADE
Definition: global.h:68
struct bank_info bank_info_t
int bank_withdraw(object *op, const char *text, int64_t *value)
Definition: bank.c:402
#define BANK_SUCCESS
Definition: global.h:52
void shop_insert_coins(object *op, int64_t value)
Definition: shop.c:587
uint32_t mithril
Definition: bank.c:62
#define BANK_STRING_ALL
Definition: bank.c:47
shstr_constants shstr_cons
Definition: init.c:58
static int64_t bank_remove_coins(object *op, archetype_t *at, uint32_t nrof)
Definition: bank.c:171
int64_t value
Definition: object.h:240
object clone
An object from which to do object_copy().
Definition: arch.h:47
#define BANK_DEPOSIT_AMBER
Definition: global.h:72
int64_t bank_get_balance(object *op)
Definition: bank.c:278