/* $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);
}