/* $Id: stock.c,v 1.666 2004/09/20 10:49:53 shrike Exp $ */ /************************************************************************************ * Copyright 2004 Astrum Metaphora consortium * * * * Licensed under the Apache License, Version 2.0 (the "License"); * * you may not use this file except in compliance with the License. * * You may obtain a copy of the License at * * * * http://www.apache.org/licenses/LICENSE-2.0 * * * * Unless required by applicable law or agreed to in writing, software * * distributed under the License is distributed on an "AS IS" BASIS, * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * * See the License for the specific language governing permissions and * * limitations under the License. * * * ************************************************************************************/ #include <sys/types.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include "merc.h" #include "db/db.h" #include "stock.h" #include "conquer.h" extern OBJ_DATA * fread_obj (CHAR_DATA * ch, FILE * fp); extern void fwrite_obj(CHAR_DATA * ch, OBJ_DATA * obj, FILE * fp, int iNest, bool is_quit, const char * header); static void clanstock_help ( CHAR_DATA *ch, const char *argument ); static void clanstock_list ( CHAR_DATA *ch, const char *argument ); static void clanstock_empty ( CHAR_DATA *ch, const char *argument ); static void clanstock_clear ( CHAR_DATA *ch, const char *argument ); static void clanstock_put ( CHAR_DATA *ch, const char *argument ); static void clanstock_get ( CHAR_DATA *ch, const char *argument ); static void clanstock_stat ( CHAR_DATA *ch, const char *argument ); static THING_DATA * new_thing_data ( void ); static void free_thing_data ( THING_DATA * thing ); static CMD_DATA clanstock_cmd_table[] = { // name do_fn min_pos min_level qp gold min_clanstatus extra { "help", clanstock_help, POS_DEAD, 1, 0, 0, CONQ_ALL, 0}, { "list", clanstock_list, POS_DEAD, 1, 0, 0, CONQ_ALL, 0}, { "put", clanstock_put, POS_DEAD, 1, 0, 0, CONQ_ALL, 0}, { "get", clanstock_get, POS_DEAD, 1, 0, 0, CONQ_ALL, 0}, { "empty", clanstock_empty, POS_DEAD, 1, 0, 0, CONQ_ELITE, 0}, { "clear", clanstock_clear, POS_DEAD, 1, 0, 0, CONQ_ELITE, 0}, { "stat", clanstock_stat, POS_DEAD, 93, 0, 0, CONQ_ALL, 0}, { NULL } }; // local functions needed cause there can be different stocks (clan, personal etc); static void show_stock_list (CHAR_DATA * ch, STOCK_DATA * stock); static void put_obj_stock (CHAR_DATA * ch, const char * argument, STOCK_DATA * stock); static void get_obj_stock (CHAR_DATA * ch, const char *argument, STOCK_DATA * stock); static void save_stock (STOCK_DATA * stock, const char * path, const char * filename); void load_stock (STOCK_DATA * stock, const char * path, const char * filename); static void fread_thing (FILE * fp, STOCK_DATA * stock); static THING_DATA * new_thing_data ( void ); static void free_thing_data ( THING_DATA * thing ); //------------------------------------------------------------------------------- // function called from interpreter //------------------------------------------------------------------------------- DO_FUN (do_clanstock) { if (!ch || !ch->in_room) return; if (!ch->clan) { char_act ("This command is for clan members only.", ch); return; } if (!IS_SET (ch->in_room->room_flags, ROOM_CLANBANK) && argument[0] != '\0' && !IS_IMMORTAL(ch)) { char_act ("You must be in the clanbank to do this.", ch); return; } // this stuff is from conquer.c if (!parse_command(ch, argument, clanstock_cmd_table)) { show_command_list (ch, clanstock_cmd_table); char_act (".", ch); char_act ("Use {CHELP CLANSTOCK{x for more information.", ch); } } static void clanstock_help ( CHAR_DATA *ch, const char *argument ) { do_help (ch, "'1.CLANSTOCK'"); } static void clanstock_list ( CHAR_DATA *ch, const char *argument ) { show_stock_list (ch, &(clan_lookup (ch->clan)->clan_stock)); } static void clanstock_empty ( CHAR_DATA *ch, const char *argument ) { } static void clanstock_clear ( CHAR_DATA *ch, const char *argument ) { } static void clanstock_put ( CHAR_DATA *ch, const char *argument ) { clan_t * clan; char filename[MAX_INPUT_LENGTH]; clan = clan_lookup (ch->clan); put_obj_stock (ch, argument, &(clan->clan_stock)); sprintf (filename, "%s", clan->name); save_stock (&(clan->clan_stock), CLANS_PATH, strcat (filename, ".stock")); save_char_obj (ch, FALSE, FALSE); } static void clanstock_get ( CHAR_DATA *ch, const char *argument ) { clan_t * clan; char filename[MAX_INPUT_LENGTH]; clan = clan_lookup (ch->clan); get_obj_stock (ch, argument, &(clan_lookup (ch->clan)->clan_stock)); sprintf (filename, "%s", clan->name); save_stock (&(clan->clan_stock), CLANS_PATH, strcat (filename, ".stock")); save_char_obj (ch, FALSE, FALSE); } static void clanstock_stat ( CHAR_DATA *ch, const char *argument ) { BUFFER * output; int i; STOCK_DATA stock; output = buf_new(ch->lang); buf_add (output, "Clan stock information:\n"); for (i = 1; i < clans.nused; ++i) { stock = CLAN(i)->clan_stock; if (stock.curr_things == 0) buf_printf(output, "{W[{Y%-12.12s{W]{x: empty.\n", CLAN(i)->name); else buf_printf(output, "{W[{Y%-12.12s{W]{x: %d of %d things.\n", CLAN(i)->name, stock.curr_things, stock.max_things == 0 ? 50 : stock.max_things); } page_to_char(buf_string(output), ch); buf_free(output); } //------------------------------------------------------------------------------- static void show_stock_list (CHAR_DATA * ch, STOCK_DATA * stock) { THING_DATA * thing; BUFFER * output; int i; if (stock->curr_things <= 0) { char_act ("The stock is empty.", ch); return; } output = buf_new(ch->lang); for (thing = stock->things, i = 1; thing != NULL; thing = thing->next, ++i) { buf_printf (output, "%3d. %s %s\n", i, fmt_color_str(mlstr_cval(thing->obj->short_descr, ch), 40), thing->owner); } char_act(buf_string(output), ch); buf_free(output); } static void put_obj_stock (CHAR_DATA * ch, const char *argument, STOCK_DATA * stock) { char arg[MAX_INPUT_LENGTH]; OBJ_DATA * obj; THING_DATA * thing; argument = one_argument(argument, arg, sizeof(arg)); if (stock->max_things == 0) stock->max_things = 50; if (arg[0] == '\0') { char_act("Put in the stock what?", ch); return; } if ((obj = get_obj_carry(ch, arg)) == NULL) { char_act("You do not have that item.", ch); return; } if (!can_drop_obj(ch, obj)) { char_act("You can't let go of it.", ch); return; } if (obj->pIndexData->limit > 0) { char_act("You can't put limited objects into the stock.", ch); return; } if (!IS_NULLSTR (obj->owner)) { char_printf(ch, "This object belongs to %s. You can't put it into the stock.\n", obj->owner); return; } if (is_clan_item(obj)) { char_act("You can't put clan items into the stock.", ch); return; } if ((obj->pIndexData->item_type == ITEM_CONTAINER) && (!IS_SET (muddy_mode, MUDDY_STOCK_CONT))) { char_act("You can't put containers into the stock.", ch); return; } if (stock->curr_things >= stock->max_things) { char_act("Sorry, but the stock is full.", ch); return; } if (IS_OBJ_STAT(obj, ITEM_QUEST)) { char_act("You can't put quest objects into the stock.", ch); return; } thing = new_thing_data (); if (thing == NULL) return; thing->obj = obj; thing->owner = str_dup (ch->name); thing->next = NULL; if (stock->things == NULL) { stock->things = thing; stock->last_thing = thing; stock->curr_things = 1; } else { stock->last_thing->next = thing; stock->last_thing = thing; stock->curr_things++; } obj_from_char(obj); act("$n puts $p into the stock.", ch, obj, NULL, TO_ROOM | (IS_AFFECTED(ch, AFF_SNEAK) ? ACT_NOMORTAL : 0)); act_puts("You put $p into the stock.", ch, obj, NULL, TO_CHAR, POS_DEAD); } static void get_obj_stock (CHAR_DATA * ch, const char *argument, STOCK_DATA * stock) { int num, i; THING_DATA * thing, * prev; if (stock->curr_things <= 0) { char_act ("The stock is empty.", ch); return; } if (is_number (argument)) { num = atoi (argument); if ((num <= 0) || (num > stock->curr_things)) { char_printf (ch, "There are only %d things in the stock.\n", stock->curr_things); return; } thing = stock->things; prev = stock->things; for (i = 1; i < num; ++i) { prev = thing; thing = thing->next; } // todo: checks obj_to_char (thing->obj, ch); act("$n gets $p from the stock.", ch, thing->obj, NULL, TO_ROOM | (IS_AFFECTED(ch, AFF_SNEAK) ? ACT_NOMORTAL : 0)); act_puts("You get $p from the stock.", ch, thing->obj, NULL, TO_CHAR, POS_DEAD); if (thing != stock->things) { prev->next = thing->next; if (thing == stock->last_thing) stock->last_thing = prev; } else { stock->things = thing->next; } --stock->curr_things; free_thing_data (thing); } } static void save_stock (STOCK_DATA * stock, const char * path, const char * filename) { FILE * fp; THING_DATA * thing; if (!(fp = dfopen(path, filename, "w"))) { log_printf("ERROR!!! save_stock: can't open output file %s/%s", path, filename); return; } for (thing = stock->things; thing != NULL; thing = thing->next) { fprintf (fp, "#THING\n"); fwrite_string(fp, "Owner", thing->owner); fprintf (fp, "End\n\n"); fwrite_obj (NULL, thing->obj, fp, 0, FALSE, "#O"); } fprintf(fp, "#END\n"); fclose(fp); } void load_clan_stocks ( void ) { int i; char filename[MAX_INPUT_LENGTH]; for (i = 1; i < clans.nused; ++i) { sprintf (filename, "%s", CLAN(i)->name); load_stock (&(CLAN(i)->clan_stock), CLANS_PATH, strcat (filename, ".stock")); } } void load_stock (STOCK_DATA * stock, const char * path, const char * filename) { FILE * fp; OBJ_DATA * obj; if ((fp = dfopen(path, filename, "r"))) { for (;;) { char letter ; char * word ; letter = fread_letter (fp) ; if (letter == '*') { fread_to_eol (fp) ; continue ; } if (letter != '#') { log_printf ("Load_stat_record: # not found in %s.", filename) ; break ; } word = fread_word (fp) ; if (!str_cmp (word, "THING")) fread_thing (fp, stock); else if (!str_cmp (word, "O")) { obj = fread_obj (NULL, fp); if (obj != NULL) stock->last_thing->obj = obj; } else if (!str_cmp (word, "END")) break ; else { bug ("Load_stat_record: bad section.", 0) ; break ; } } fclose (fp) ; } } static void fread_thing (FILE * fp, STOCK_DATA * stock) { char * word; bool fMatch; THING_DATA * thing; thing = new_thing_data (); for (;;) { word = feof(fp) ? "End" : fread_word(fp); fMatch = FALSE; switch (UPPER(word[0])) { case '*': fMatch = TRUE; fread_to_eol(fp); break; case 'E': if (!str_cmp(word, "End")) { if (stock->things == NULL) { stock->things = thing; stock->last_thing = thing; stock->curr_things = 1; } else { stock->last_thing->next = thing; stock->last_thing = thing; stock->curr_things++; } return; } break; case 'O': SKEY("Owner", thing->owner); break; } if (!fMatch) { bug("Fread_thing: no match.", 0); fread_to_eol(fp); } } } //------------------------------------------------------------------------------- // recycling //------------------------------------------------------------------------------- static THING_DATA * new_thing_data ( void ) { THING_DATA * thing; thing = calloc(1, sizeof(*thing)); if (thing) // just to be sure { thing->next = NULL; thing->obj = NULL; } return thing; } static void free_thing_data ( THING_DATA * thing ) { free_string(thing->owner); thing->owner = NULL; free (thing); }