/*___________________________________________________________________________*
)()( DalekenMUD 1.12 (C) 2000 )()(
`][' by Martin Thomson, Lee Brooks, `]['
|| Ken Herbert and David Jacques ||
|| ----------------------------------------------------------------- ||
|| Envy Diku Mud improvements copyright (C) 1994 by Michael Quan, ||
|| David Love, Guilherme 'Willie' Arnold, and Mitchell Tse. ||
|| Merc Diku Mud improvments copyright (C) 1992, 1993 by Michael ||
|| Chastain, Michael Quan, and Mitchell Tse. ||
|| Original Diku Mud copyright (C) 1990, 1991 ||
|| by Sebastian Hammer, Michael Seifert, Hans Henrik St{rfeldt, ||
|| Tom Madsen, and Katja Nyboe. ||
|| ----------------------------------------------------------------- ||
|| Any use of this software must follow the licenses of the ||
|| creators. Much time and thought has gone into this software and ||
|| you are benefitting. We hope that you share your changes too. ||
|| What goes around, comes around. ||
|| ----------------------------------------------------------------- ||
|| db_io.c ||
|| This file contains generic data loading and saving functions. ||
*_/<>\_________________________________________________________________/<>\_*/
#include "mud.h"
#include "olc.h"
#include "event.h"
#include "db.h"
/**
* Note: All functions that return bool in the reading/writing of data will
* return FALSE upon an error. This also means that the error could not be
* handled properly. This can mean irreversible problems as the reading of
* the file will have to be halted.
*
* Look for places where functions return TRUE when they handle an error.
*/
static struct
{
struct sysinfo_type sys;
PLANE_DATA plane;
AREA_DATA area;
ROOM_INDEX_DATA room;
MOB_INDEX_DATA mob_index;
OBJ_INDEX_DATA obj_index;
MPROG_GLOBAL gprog;
CHAR_DATA ch;
PC_DATA pcdata;
OBJ_DATA obj;
AFFECT_DATA aff;
EVENT event;
QUEST_DATA quest;
ALIAS_DATA alias;
EXTRA_DESCR_DATA exdesc;
MPROG_DATA mprog;
SHOP_DATA shop;
EXIT_DATA exit;
HELP_DATA help;
SOCIAL_DATA soc;
POSE_DATA pose;
RELIGION_DATA rel;
CLAN_DATA clan;
RELIGION_SKILL relskill;
NOTE_DATA note;
HIGHEST_DATA high;
HIGHEST_ENTRY highent;
} sdb;
int file_version;
time_t file_date;
/*
* The controlling table for all reading and writing through this file.
*/
static struct top_data_type global_data_table[] = {
{
"Affect", affect_data_table,
&sdb.aff, sizeof( AFFECT_DATA ), dbrwf_affect
},
{
"Alias", alias_data_table,
&sdb.alias, sizeof( ALIAS_DATA ), dbrwf_alias
},
{
"Area", area_data_table,
&sdb.area, sizeof( AREA_DATA ), dbrwf_area
},
{
"Char", char_data_table,
&sdb.ch, sizeof( CHAR_DATA ), dbrwf_char
},
{
"Clan", clan_data_table,
&sdb.clan, sizeof( CLAN_DATA ), dbrwf_clan
},
{
"Event", event_data_table,
&sdb.event, sizeof( EVENT ), dbrwf_event
},
{
"ExDesc", exdesc_data_table,
&sdb.exdesc, sizeof( EXTRA_DESCR_DATA ), dbrwf_exdesc
},
{
"Exit", exit_data_table,
&sdb.exit, sizeof( EXIT_DATA ), dbrwf_exit
},
{
"GProg", gprog_data_table,
&sdb.gprog, sizeof( MPROG_GLOBAL ), dbrwf_gprog
},
{
"Help", help_data_table,
&sdb.help, sizeof( HELP_DATA ), dbrwf_help
},
{
"High", high_data_table,
&sdb.high, sizeof( HIGHEST_DATA ), dbrwf_high
},
{
"HighEnt", highent_data_table,
&sdb.highent, sizeof( struct highest_entry ), dbrwf_highent
},
{
"Mobile", mobile_data_table,
&sdb.mob_index, sizeof( MOB_INDEX_DATA ), dbrwf_mob_index
},
{
"MudProg", mudprog_data_table,
&sdb.mprog, sizeof( MPROG_DATA ), dbrwf_mudprog
},
{
"Note", note_data_table,
&sdb.note, sizeof( NOTE_DATA ), dbrwf_note
},
{
"Obj", obj_data_table,
&sdb.obj, sizeof( OBJ_DATA ), dbrwf_obj
},
{
"Object", object_data_table,
&sdb.obj_index, sizeof( OBJ_INDEX_DATA ), dbrwf_obj_index
},
{
"PcData", pcdata_data_table,
&sdb.pcdata, sizeof( PC_DATA ), dbrwf_pcdata
},
{
"Plane", plane_data_table,
&sdb.plane, sizeof( PLANE_DATA ), dbrwf_plane
},
{
"Pose", pose_data_table,
&sdb.pose, sizeof( POSE_DATA ), dbrwf_pose
},
{
"Religion", religion_data_table,
&sdb.rel, sizeof( RELIGION_DATA ), dbrwf_religion
},
{
"Quest", quest_data_table,
&sdb.quest, sizeof( QUEST_DATA ), dbrwf_quest
},
{
"RelSkill", relskill_data_table,
&sdb.relskill, sizeof( RELIGION_SKILL ), dbrwf_relskill
},
{
"Room", room_data_table,
&sdb.room, sizeof( ROOM_INDEX_DATA ), dbrwf_room
},
{
"Shop", shop_data_table,
&sdb.shop, sizeof( SHOP_DATA ), dbrwf_shop
},
{
"Social", social_data_table,
&sdb.soc, sizeof( SOCIAL_DATA ), dbrwf_social
},
{
"SysInfo", sysinfo_data_table,
&sdb.sys, sizeof( struct sysinfo_type ), dbrwf_sysinfo
},
{
NULL, NULL, NULL, 0, NULL
}
};
/****************************************************************************
* Load/Save tables for all types.
*
* Note objects of type DFLAG_ARRAY, MUST HAVE A RWF FUNCTION.
*/
/* Plane */
static struct data_desc_type plane_data_table[] = {
{
"Name", DTYPE_STRING | DFLAG_MAND, &sdb.plane.name,
{ 0 }, NULL, NULL
},
{
"Minimum", DTYPE_NUMBER, &sdb.plane.min_level,
{ 1000 }, NULL, NULL
},
{
NULL, 0, NULL, { 0 }, NULL, NULL
}
};
/* Area */
static struct data_desc_type area_data_table[] = {
{
"Name", DTYPE_STRING | DFLAG_MAND, &sdb.area.name,
{ 0 }, NULL, NULL
},
{
"Plane", DTYPE_COMPLEX | DFLAG_SPECIAL, &sdb.area.plane,
{ 0 }, NULL, dbrwf_area_plane
},
{
"Builders", DTYPE_STRING, &sdb.area.builders,
{ 0 }, NULL, NULL
},
{
"Repop", DTYPE_STRING, &sdb.area.repop,
{ 0 }, NULL, NULL
},
{
"Age", DTYPE_NUMBER, &sdb.area.age,
{ 15 }, NULL, NULL
},
{
"LVnum", DTYPE_NUMBER, &sdb.area.lvnum,
{ 0 }, NULL, NULL
},
{
"UVnum", DTYPE_NUMBER, &sdb.area.uvnum,
{ 0 }, NULL, NULL
},
{
"Security", DTYPE_NUMBER, &sdb.area.security,
{ 10 }, NULL, NULL
},
{
"Recall", DTYPE_NUMBER, &sdb.area.recall,
{ ROOM_VNUM_TEMPLE }, NULL, NULL
},
{
"Temp", DTYPE_NUMBER, &sdb.area.ave_temp,
{ 0 }, NULL, NULL
},
{
"Flags", DTYPE_NUMBER | DFLAG_SPECWRITE, &sdb.area.area_flags,
{ 0 }, "area", dbrwf_area_flags
},
{
"Order", DTYPE_COMPLEX | DFLAG_SPECIAL, &sdb.area.order,
{ 0 }, NULL, dbrwf_all_clan
},
{
"TokenRoom", DTYPE_NUMBER, &sdb.area.token_room,
{ -1 }, NULL, dbrwf_check_room
},
{
"Economy", DTYPE_NUMBER, &sdb.area.economy,
{ 0 }, NULL, NULL
},
{
"Desc", DTYPE_STRING, &sdb.area.description,
{ 0 }, NULL, NULL
},
{
NULL, 0, NULL, { 0 }, NULL, NULL
}
};
/* Help */
static struct data_desc_type help_data_table[] = {
{
"Level", DTYPE_NUMBER, &sdb.help.level,
{ 0 }, NULL, NULL
},
{
"Name", DTYPE_STRING | DFLAG_MAND, &sdb.help.keyword,
{ 0 }, NULL, NULL
},
{
"Text", DTYPE_STRING | DFLAG_MAND, &sdb.help.text,
{ 0 }, NULL, NULL
},
{
NULL, 0, NULL, { 0 }, NULL, NULL
}
};
/* Mobile Index */
static struct data_desc_type mobile_data_table[] = {
{
"Vnum", DTYPE_NUMBER | DFLAG_MAND, &sdb.mob_index.vnum,
{ 0 }, NULL, NULL
},
{
"Name", DTYPE_STRING | DFLAG_MAND, &sdb.mob_index.name,
{ 0 }, NULL, NULL
},
{
"Short", DTYPE_STRING | DFLAG_MAND, &sdb.mob_index.short_descr,
{ 0 }, NULL, NULL
},
{
"Long", DTYPE_STRING | DFLAG_MAND, &sdb.mob_index.long_descr,
{ 0 }, NULL, NULL
},
{
"Desc", DTYPE_STRING, &sdb.mob_index.description,
{ 0 }, NULL, NULL
},
{
"Level", DTYPE_NUMBER, &sdb.mob_index.level,
{ 1 }, NULL, NULL
},
{
"Align", DTYPE_NUMBER, &sdb.mob_index.alignment,
{ 0 }, NULL, NULL
},
{
"Repop", DTYPE_NUMBER, &sdb.mob_index.reset_chance,
{ 1000 }, NULL, NULL
},
{
"Class", DTYPE_NUMBER, &sdb.mob_index.class,
{ CLASS_NONE }, "class", NULL
},
{
"Act", DTYPE_VECTOR, sdb.mob_index.act,
{ 0 }, "act", NULL
},
{
"Affected", DTYPE_VECTOR, sdb.mob_index.affected_by,
{ 0 }, "affect", NULL
},
{
"Sex", DTYPE_NUMBER, &sdb.mob_index.sex,
{ SEX_NEUTRAL }, "sex", NULL
},
{
"Race", DTYPE_NUMBER, &sdb.mob_index.race,
{ 0 }, "race", NULL
},
{
"Parts", DTYPE_NUMBER | DFLAG_CHKDEFAULT | DFLAG_NEEDPARENT,
&sdb.mob_index.body_parts,
{ -1 }, "limbs", dbrwf_mob_parts
},
{
"Specfun", DTYPE_NUMBER | DFLAG_SPECIAL, &sdb.mob_index.spec_fun,
{ 0 }, NULL, dbrwf_mob_spec
},
{
"Shop", DTYPE_COMPLEX, &sdb.mob_index.pShop,
{ 0 }, NULL, NULL
},
{
"MudProg", DTYPE_LLIST, &sdb.mob_index.mudprogs,
{ 0 }, NULL, NULL
},
{
NULL, 0, NULL, { 0 }, NULL, NULL
}
};
/* Mobile : Shop */
static struct data_desc_type shop_data_table[] = {
{
"Trade",
DTYPE_NUMBER | DFLAG_ARRAY | DFLAG_SPECWRITE | ( MAX_TRADE << DSHIFT_ARRAY ),
sdb.shop.buy_type,
{ -1 }, "type", dbrwf_shop_trade
},
{
"Markup", DTYPE_NUMBER, &sdb.shop.profit_buy,
{ 150 }, NULL, NULL
},
{
"Markdown", DTYPE_NUMBER, &sdb.shop.profit_sell,
{ 0 }, NULL, NULL
},
{
"Open", DTYPE_NUMBER, &sdb.shop.open_hour,
{ 0 }, NULL, NULL
},
{
"Close", DTYPE_NUMBER, &sdb.shop.close_hour,
{ 23 }, NULL, NULL
},
{
NULL, 0, NULL, { 0 }, NULL, NULL
}
};
/* Mobile/Object/Room : MudProg */
static struct data_desc_type mudprog_data_table[] = {
{
"Type", DTYPE_NUMBER, &sdb.mprog.type,
{ -1 }, "mudprogs", NULL
},
{
"Args", DTYPE_STRING, &sdb.mprog.arglist,
{ 0 }, NULL, NULL
},
{
"Comlist", DTYPE_STRING, &sdb.mprog.comlist,
{ 0 }, NULL, NULL
},
{
NULL, 0, NULL, { 0 }, NULL, NULL
}
};
/* Object Index */
static struct data_desc_type object_data_table[] = {
{
"Vnum", DTYPE_NUMBER | DFLAG_MAND, &sdb.obj_index.vnum,
{ 0 }, NULL, NULL
},
{
"Name", DTYPE_STRING, &sdb.obj_index.name,
{ 0 }, NULL, NULL
},
{
"Short", DTYPE_STRING, &sdb.obj_index.short_descr,
{ 0 }, NULL, NULL
},
{
"Long", DTYPE_STRING, &sdb.obj_index.description,
{ 0 }, NULL, NULL
},
{
"Action", DTYPE_STRING, &sdb.obj_index.action,
{ 0 }, NULL, NULL
},
{
"Level", DTYPE_NUMBER, &sdb.obj_index.level,
{ LEVEL_HERO }, NULL, NULL
},
{
"Cost", DTYPE_NUMBER, &sdb.obj_index.cost,
{ 0 }, NULL, NULL
},
{
"Weight", DTYPE_NUMBER, &sdb.obj_index.weight,
{ 1 }, NULL, NULL
},
{
"Repop", DTYPE_NUMBER, &sdb.obj_index.reset_chance,
{ 1000 }, NULL, NULL
},
{
"Type", DTYPE_NUMBER, &sdb.obj_index.item_type,
{ ITEM_TRASH }, "type", NULL
},
{
"Wear", DTYPE_NUMBER, &sdb.obj_index.wear_flags,
{ 0 }, "wear", NULL
},
{
"Extra", DTYPE_NUMBER, &sdb.obj_index.extra_flags,
{ 0 }, "extra", NULL
},
{
"Material", DTYPE_NUMBER, &sdb.obj_index.material,
{ 100 }, "material", NULL
},
{
"Condition", DTYPE_NUMBER, &sdb.obj_index.condition,
{ 1000 }, NULL, NULL
},
{
"Required", DTYPE_NUMBER, &sdb.obj_index.required_skill,
{ -1 }, "skill", NULL
},
{
"Values",
DTYPE_NUMBER | DFLAG_ARRAY | DFLAG_SPECIAL | DFLAG_NEEDPARENT
| ( 4 << DSHIFT_ARRAY ),
&sdb.obj_index.value[0],
{ 0 }, "skill", dbrwf_obj_index_values
},
{
"Affect", DTYPE_LLIST | DFLAG_SPECWRITE, &sdb.obj_index.affected,
{ 0 }, NULL, dbrwf_all_affect
},
{
"ExDesc", DTYPE_LLIST, &sdb.obj_index.extra_descr,
{ 0 }, NULL, NULL
},
{
"MudProg", DTYPE_LLIST, &sdb.obj_index.mudprogs,
{ 0 }, NULL, NULL
},
{
NULL, 0, NULL, { 0 }, NULL, NULL
}
};
/* Affect - NOTE: This shouldn't really be used to write data. */
static struct data_desc_type affect_data_table[] = {
{
"Name", DTYPE_NUMBER, &sdb.aff.type,
{ -1 }, "skill", NULL
},
{
"Duration", DTYPE_NUMBER, &sdb.aff.duration,
{ -1 }, NULL, NULL
},
{
"Level", DTYPE_NUMBER, &sdb.aff.level,
{ 0 }, NULL, NULL
},
{
"Location", DTYPE_NUMBER, &sdb.aff.location,
{ APPLY_NONE }, "apply", NULL
},
{
"Modifier", DTYPE_NUMBER, &sdb.aff.modifier,
{ 0 }, NULL, NULL
},
{
"Bits", DTYPE_NUMBER, sdb.aff.bitvector,
{ 0 }, "affect", NULL
},
{
NULL, 0, NULL, { 0 }, NULL, NULL
}
};
/* Object/Room : ExDesc */
static struct data_desc_type exdesc_data_table[] = {
{
"Keyword", DTYPE_STRING | DFLAG_MAND, &sdb.exdesc.keyword,
{ 0 }, NULL, NULL
},
{
"Text", DTYPE_STRING, &sdb.exdesc.description,
{ 0 }, NULL, NULL
},
{
NULL, 0, NULL, { 0 }, NULL, NULL
}
};
/* Room */
static struct data_desc_type room_data_table[] = {
{
"Vnum", DTYPE_NUMBER | DFLAG_MAND, &sdb.room.vnum,
{ 0 }, NULL, NULL
},
{
"Name", DTYPE_STRING, &sdb.room.name,
{ 0 }, NULL, NULL
},
{
"Desc", DTYPE_STRING, &sdb.room.description,
{ 0 }, NULL, NULL
},
{
"Flags", DTYPE_NUMBER, &sdb.room.room_flags,
{ 0 }, "room", NULL
},
{
"Sector", DTYPE_NUMBER, &sdb.room.sector_type,
{ 0 }, "sector", NULL
},
{
"Exit",
DTYPE_COMPLEX | DFLAG_ARRAY | DFLAG_SPECWRITE
| DFLAG_CHKDEFAULT | ( MAX_DIR << DSHIFT_ARRAY ),
&sdb.room.exit[0],
{ 0 }, NULL, dbrwf_room_exits
},
{
"ExDesc", DTYPE_LLIST, &sdb.room.extra_descr,
{ 0 }, NULL, NULL
},
{
"Resets", DTYPE_COMPLEX | DFLAG_SPECIAL, &sdb.room.reset_first,
{ 0 }, NULL, dbrwf_room_resets
},
{
"MudProg", DTYPE_LLIST, &sdb.room.mudprogs,
{ 0 }, NULL, NULL
},
{
NULL, 0, NULL, { 0 }, NULL, NULL
}
};
/* Room : Exit */
static struct data_desc_type exit_data_table[] = {
{
"Desc", DTYPE_STRING, &sdb.exit.description,
{ 0 }, NULL, NULL
},
{
"Keyword", DTYPE_STRING, &sdb.exit.keyword,
{ 0 }, NULL, NULL
},
{
"Key", DTYPE_NUMBER, &sdb.exit.key,
{ -1 }, NULL, NULL
},
{
"ToRoom", DTYPE_NUMBER, &sdb.exit.vnum,
{ -1 }, NULL, NULL
},
{
"Flags", DTYPE_NUMBER, &sdb.exit.rs_flags,
{ 0 }, "exit", NULL
},
{
NULL, 0, NULL, { 0 }, NULL, NULL
}
};
/* Global Program */
static struct data_desc_type gprog_data_table[] = {
{
"Vnum", DTYPE_NUMBER | DFLAG_MAND, &sdb.gprog.vnum,
{ 0 }, NULL, NULL
},
{
"Type", DTYPE_NUMBER, &sdb.gprog.type,
{ 0 }, "mudprogs", NULL
},
{
"Allowed", DTYPE_NUMBER, &sdb.gprog.allowed,
{ 0 }, "mor", NULL
},
{
"Args", DTYPE_STRING, &sdb.gprog.arglist,
{ 0 }, NULL, NULL
},
{
"Comlist", DTYPE_STRING, &sdb.gprog.comlist,
{ 0 }, NULL, NULL
},
{
NULL, 0, NULL, { 0 }, NULL, NULL
}
};
/* Social */
static struct data_desc_type social_data_table[] = {
{
"Name", DTYPE_STRING | DFLAG_MAND, &sdb.soc.name,
{ 0 }, NULL, NULL
},
{
"CNA", DTYPE_STRING, &sdb.soc.char_no_arg,
{ 0 }, NULL, NULL
},
{
"ONA", DTYPE_STRING, &sdb.soc.others_no_arg,
{ 0 }, NULL, NULL
},
{
"CF", DTYPE_STRING, &sdb.soc.char_found,
{ 0 }, NULL, NULL
},
{
"OF", DTYPE_STRING, &sdb.soc.others_found,
{ 0 }, NULL, NULL
},
{
"VF", DTYPE_STRING, &sdb.soc.vict_found,
{ 0 }, NULL, NULL
},
{
"CA", DTYPE_STRING, &sdb.soc.char_auto,
{ 0 }, NULL, NULL
},
{
"OA", DTYPE_STRING, &sdb.soc.others_auto,
{ 0 }, NULL, NULL
},
{
NULL, 0, NULL, { 0 }, NULL, NULL
}
};
/* Religion */
static struct data_desc_type religion_data_table[] = {
{
"Name", DTYPE_STRING | DFLAG_MAND, &sdb.rel.name,
{ 0 }, NULL, NULL
},
{
"Display", DTYPE_STRING, &sdb.rel.display_name,
{ 0 }, NULL, NULL
},
{
"God", DTYPE_STRING, &sdb.rel.god_name,
{ 0 }, NULL, NULL
},
{
"AlignMin", DTYPE_NUMBER, &sdb.rel.align_min,
{ -1000 }, NULL, NULL
},
{
"AlignMaxn", DTYPE_NUMBER, &sdb.rel.align_max,
{ 1000 }, NULL, NULL
},
{
"Token", DTYPE_NUMBER, &sdb.rel.token,
{ -1 }, NULL, NULL
},
{
"Sacrifice", DTYPE_NUMBER, &sdb.rel.sac_events,
{ 0 }, "sacrifice", NULL
},
{
"RelSkill", DTYPE_LLIST, &sdb.rel.skills,
{ 0 }, NULL, NULL
},
{
NULL, 0, NULL, { 0 }, NULL, NULL
}
};
/* Clan */
static struct data_desc_type clan_data_table[] = {
{
"Name", DTYPE_STRING | DFLAG_MAND, &sdb.clan.name,
{ 0 }, NULL, NULL
},
{
"Display", DTYPE_STRING, &sdb.clan.display_name,
{ 0 }, NULL, NULL
},
{
"Motto", DTYPE_STRING, &sdb.clan.motto,
{ 0 }, NULL, NULL
},
{
"Desc", DTYPE_STRING, &sdb.clan.description,
{ 0 }, NULL, NULL
},
{
"Rules", DTYPE_STRING, &sdb.clan.rules,
{ 0 }, NULL, NULL
},
{
"Overlord", DTYPE_STRING, &sdb.clan.overlord,
{ 0 }, NULL, NULL
},
{
"Chiefs", DTYPE_STRING, &sdb.clan.chieftains,
{ 0 }, NULL, NULL
},
{
"Enemies", DTYPE_STRING, &sdb.clan.enemies,
{ 0 }, NULL, NULL
},
{
"Type", DTYPE_NUMBER, &sdb.clan.clan_type,
{ CLAN_NORMAL }, "clan", NULL
},
{
"Heroes", DTYPE_NUMBER, &sdb.clan.clanheros,
{ 0 }, NULL, NULL
},
{
"Members", DTYPE_NUMBER, &sdb.clan.members,
{ 0 }, NULL, NULL
},
{
"Kills", DTYPE_NUMBER, &sdb.clan.kills,
{ 0 }, NULL, NULL
},
{
"Deaths", DTYPE_NUMBER, &sdb.clan.deaths,
{ 0 }, NULL, NULL
},
{
"Recall", DTYPE_NUMBER, &sdb.clan.recall,
{ ROOM_VNUM_TEMPLE }, NULL, NULL
},
{
"Religion", DTYPE_COMPLEX | DFLAG_SPECIAL, &sdb.clan.religion,
{ 0 }, NULL, dbrwf_all_religion
},
{
"Class", DTYPE_NUMBER, &sdb.clan.class,
{ CLASS_NONE }, "class", NULL
},
{
"Karma", DTYPE_NUMBER, &sdb.clan.karma,
{ 0 }, NULL, NULL
},
{
"RelSkill", DTYPE_LLIST, &sdb.clan.skills,
{ 0 }, NULL, NULL
},
{
NULL, 0, NULL, { 0 }, NULL, NULL
}
};
/* Religion/Clan : RelSkill */
static struct data_desc_type relskill_data_table[] = {
{
"Name", DTYPE_NUMBER | DFLAG_MAND, &sdb.relskill.sn,
{ 0 }, "skill", NULL
},
{
"Level", DTYPE_NUMBER, &sdb.relskill.level,
{ 10 }, NULL, NULL
},
{
NULL, 0, NULL, { 0 }, NULL, NULL
}
};
/* Note */
static struct data_desc_type note_data_table[] = {
{
"Sender", DTYPE_STRING | DFLAG_MAND, &sdb.note.sender,
{ 0 }, NULL, NULL
},
{
"Date", DTYPE_NUMBER, &sdb.note.date,
{ 0 }, NULL, NULL
},
{
"Stamp", DTYPE_NUMBER, &sdb.note.date_stamp,
{ 0 }, NULL, NULL
},
{
"Expire", DTYPE_NUMBER, &sdb.note.expire,
{ 0 }, NULL, NULL
},
{
"To", DTYPE_STRING | DFLAG_MAND, &sdb.note.to_list,
{ 0 }, NULL, NULL
},
{
"Subject", DTYPE_STRING, &sdb.note.subject,
{ 0 }, NULL, NULL
},
{
"Text", DTYPE_STRING, &sdb.note.text,
{ 0 }, NULL, NULL
},
{
NULL, 0, NULL, { 0 }, NULL, NULL
}
};
/* Pose */
static struct data_desc_type pose_data_table[] = {
{
"Char", DTYPE_STRING, &sdb.pose.to_char,
{ 0 }, NULL, NULL
},
{
"Room", DTYPE_STRING, &sdb.pose.to_room,
{ 0 }, NULL, NULL
},
{
NULL, 0, NULL, { 0 }, NULL, NULL
}
};
/* SysInfo */
static struct data_desc_type sysinfo_data_table[] = {
{
"Name", DTYPE_STRING, &sdb.sys.name,
{ 0 }, NULL, NULL
},
{
"Version", DTYPE_NUMBER, &sdb.sys.version,
{ 1 }, NULL, NULL
},
{
"Minor", DTYPE_NUMBER, &sdb.sys.minor,
{ 0 }, NULL, NULL
},
{
"Build", DTYPE_NUMBER, &sdb.sys.build,
{ 1 }, NULL, NULL
},
{
"Date", DTYPE_STRING, &sdb.sys.build_date,
{ 0 }, NULL, NULL
},
{
"Platform", DTYPE_STRING, &sdb.sys.platform,
{ 0 }, NULL, NULL
},
{
"SaveAt", DTYPE_NUMBER, &sdb.sys.saveat,
{ 2 }, NULL, NULL
},
{
"File", DTYPE_NUMBER, &sdb.sys.file_version,
{ 0 }, NULL, NULL
},
{
"Dictionary", DTYPE_STRING, &sdb.sys.dictionary,
{ 0 }, NULL, NULL
},
{
"Numlock", DTYPE_NUMBER, &sdb.sys.numlock,
{ 0 }, NULL, NULL
},
{
"Flags", DTYPE_NUMBER, &sdb.sys.flags,
{ 0 }, "sysinfo", NULL
},
{
"Hour", DTYPE_NUMBER, &sdb.sys.levels,
{ 0 }, NULL, NULL
},
{
"Minute", DTYPE_NUMBER, &sdb.sys.deaths,
{ 0 }, NULL, NULL
},
{
NULL, 0, NULL, { 0 }, NULL, NULL
}
};
/* Char */
static struct data_desc_type char_data_table[] = {
{
"Name", DTYPE_STRING | DFLAG_MAND, &sdb.ch.name,
{ 0 }, NULL, NULL
},
{
"Level", DTYPE_NUMBER | DFLAG_MAND, &sdb.ch.level,
{ 0 }, NULL, NULL
},
{
"Trust", DTYPE_NUMBER, &sdb.ch.trust,
{ 0 }, NULL, NULL
},
{
"SubLevel", DTYPE_NUMBER, &sdb.ch.sublevel,
{ 0 }, NULL, NULL
},
{
"Race", DTYPE_NUMBER | DFLAG_SPECWRITE | DFLAG_NEEDPARENT,
&sdb.ch.race,
{ 0 }, "race", dbrwf_char_race
},
{
"Class", DTYPE_NUMBER, &sdb.ch.class,
{ 0 }, "class", NULL
},
{
"ShortDesc", DTYPE_STRING, &sdb.ch.short_descr,
{ 0 }, NULL, NULL
},
{
"LongDesc", DTYPE_STRING, &sdb.ch.long_descr,
{ 0 }, NULL, NULL
},
{
"Desc", DTYPE_STRING, &sdb.ch.description,
{ 0 }, NULL, NULL
},
{
"Sex", DTYPE_NUMBER | DFLAG_SPECWRITE | DFLAG_NEEDPARENT,
&sdb.ch.sex,
{ 0 }, "sex", dbrwf_char_sex
},
{
"InRoom", DTYPE_COMPLEX | DFLAG_SPECIAL | DFLAG_NEEDPARENT,
&sdb.ch.in_room,
{ 0 }, NULL, dbrwf_char_in_room
},
{
"Recall", DTYPE_NUMBER, &sdb.ch.recall_room,
{ -1 }, NULL, dbrwf_check_room
},
{
"Played", DTYPE_TIME | DFLAG_SPECWRITE | DFLAG_NEEDPARENT,
&sdb.ch.played,
{ 0 }, NULL, dbrwf_char_played
},
{
"Hp", DTYPE_NUMBER, &sdb.ch.hit,
{ 0 }, NULL, NULL
},
{
"MaxHp", DTYPE_NUMBER | DFLAG_SPECWRITE | DFLAG_NEEDPARENT,
&sdb.ch.max_hit,
{ 0 }, NULL, dbrwf_char_max_hit
},
{
"Mana", DTYPE_NUMBER | DFLAG_ARRAY | DFLAG_SPECWRITE
| DFLAG_CHKDEFAULT | ( MAGIC_MAX << DSHIFT_ARRAY ),
&sdb.ch.mana[0],
{ 0 }, NULL, dbrwf_magic_mana
},
{
"MaxMana", DTYPE_NUMBER | DFLAG_ARRAY | DFLAG_SPECWRITE
| DFLAG_CHKDEFAULT | DFLAG_NEEDPARENT | ( MAGIC_MAX << DSHIFT_ARRAY ),
&sdb.ch.max_mana[0],
{ 0 }, NULL, dbrwf_char_max_mana
},
{
"Move", DTYPE_NUMBER, &sdb.ch.move,
{ 0 }, NULL, NULL
},
{
"MaxMove", DTYPE_NUMBER | DFLAG_SPECWRITE | DFLAG_NEEDPARENT,
&sdb.ch.max_move,
{ 0 }, NULL, dbrwf_char_max_move
},
{
"Gold", DTYPE_NUMBER, &sdb.ch.gold,
{ 0 }, NULL, NULL
},
{
"Tnl", DTYPE_NUMBER, &sdb.ch.exp,
{ 1000 }, NULL, NULL
},
{
"Pos", DTYPE_NUMBER | DFLAG_CHKDEFAULT, &sdb.ch.position,
{ POS_STANDING }, "position", dbrwf_char_position
},
{
"Prac", DTYPE_NUMBER, &sdb.ch.practice,
{ 0 }, NULL, NULL
},
{
"Align", DTYPE_NUMBER, &sdb.ch.alignment,
{ 0 }, NULL, NULL
},
{
"Wimpy", DTYPE_NUMBER, &sdb.ch.wimpy,
{ 0 }, NULL, NULL
},
{
"Deaf", DTYPE_NUMBER, &sdb.ch.deaf,
{ 0 }, "channel", NULL
},
{
"Parts", DTYPE_NUMBER | DFLAG_CHKDEFAULT | DFLAG_NEEDPARENT,
&sdb.ch.body_parts,
{ 0 }, "limbs", dbrwf_char_parts
},
{
"Damaged", DTYPE_NUMBER, &sdb.ch.damaged_parts,
{ 0 }, "limbs", NULL
},
{
"Act", DTYPE_VECTOR, sdb.ch.act,
{ 0 }, "pcact", NULL
},
{
"Affect", DTYPE_LLIST | DFLAG_SPECWRITE, &sdb.ch.affected,
{ 0 }, NULL, dbrwf_all_affect
},
{
"Event", DTYPE_LLIST, &sdb.ch.events,
{ 0 }, NULL, NULL
},
{
"PcData", DTYPE_COMPLEX, &sdb.ch.pcdata,
{ 0 }, NULL, NULL
},
{
"Obj", DTYPE_COMPLEX | DFLAG_SPECIAL | DFLAG_NEEDPARENT,
&sdb.ch.carrying,
{ 0 }, NULL, dbrwf_char_obj
},
{
NULL, 0, NULL, { 0 }, NULL, NULL
}
};
/* Char : PcData */
static struct data_desc_type pcdata_data_table[] = {
{
"Title", DTYPE_STRING, &sdb.pcdata.title,
{ 0 }, NULL, NULL
},
{
"Prompt", DTYPE_STRING, &sdb.pcdata.prompt,
{ 0 }, NULL, NULL
},
{
"Password", DTYPE_STRING | DFLAG_MAND, &sdb.pcdata.pwd,
{ 0 }, NULL, NULL
},
{
"ImmName", DTYPE_STRING, &sdb.pcdata.immname,
{ 0 }, NULL, NULL
},
{
"Bamfin", DTYPE_STRING, &sdb.pcdata.bamfin,
{ 0 }, NULL, NULL
},
{
"Bamfout", DTYPE_STRING, &sdb.pcdata.bamfout,
{ 0 }, NULL, NULL
},
{
"Setmin", DTYPE_STRING, &sdb.pcdata.setmin,
{ 0 }, NULL, NULL
},
{
"Setmout", DTYPE_STRING, &sdb.pcdata.setmout,
{ 0 }, NULL, NULL
},
{
"Immskill", DTYPE_STRING, &sdb.pcdata.immskll,
{ 0 }, NULL, NULL
},
{
"Familiar", DTYPE_NUMBER, &sdb.pcdata.familiar,
{ 0 }, NULL, NULL
},
{
"Bounty", DTYPE_NUMBER, &sdb.pcdata.bounty,
{ 0 }, NULL, NULL
},
{
"Killed", DTYPE_NUMBER, &sdb.pcdata.killed,
{ 0 }, NULL, NULL
},
{
"Died", DTYPE_NUMBER, &sdb.pcdata.died,
{ 0 }, NULL, NULL
},
{
"Strength", DTYPE_NUMBER, &sdb.pcdata.perm_str,
{ 15 }, NULL, NULL
},
{
"Intelligence", DTYPE_NUMBER, &sdb.pcdata.perm_int,
{ 15 }, NULL, NULL
},
{
"Wisdom", DTYPE_NUMBER, &sdb.pcdata.perm_wis,
{ 15 }, NULL, NULL
},
{
"Dexterity", DTYPE_NUMBER, &sdb.pcdata.perm_dex,
{ 15 }, NULL, NULL
},
{
"Constitution", DTYPE_NUMBER, &sdb.pcdata.perm_con,
{ 15 }, NULL, NULL
},
{
"Magic", DTYPE_NUMBER | DFLAG_ARRAY | DFLAG_SPECWRITE
| DFLAG_CHKDEFAULT | ( MAGIC_MAX << DSHIFT_ARRAY ),
&sdb.pcdata.perm_magic[0],
{ 0 }, NULL, dbrwf_magic_mana
},
{
"Thirst", DTYPE_NUMBER, &sdb.pcdata.condition[COND_THIRST],
{ 1000 }, NULL, NULL
},
{
"Full", DTYPE_NUMBER, &sdb.pcdata.condition[COND_FULL],
{ 1000 }, NULL, NULL
},
{
"Drunk", DTYPE_NUMBER, &sdb.pcdata.condition[COND_DRUNK],
{ 0 }, NULL, NULL
},
{
"Bank", DTYPE_NUMBER, &sdb.pcdata.banked,
{ 0 }, NULL, NULL
},
{
"Page", DTYPE_NUMBER, &sdb.pcdata.pagelen,
{ 20 }, NULL, NULL
},
{
"Security", DTYPE_NUMBER, &sdb.pcdata.security,
{ 0 }, NULL, NULL
},
{
"Language", DTYPE_NUMBER, &sdb.pcdata.language,
{ LANG_COMMON }, "language", NULL
},
{
"Quest", DTYPE_COMPLEX, &sdb.pcdata.quest,
{ 0 }, NULL, NULL
},
{
"Board", DTYPE_TIME | DFLAG_ARRAY | DFLAG_SPECWRITE
| ( MAX_BOARD << DSHIFT_ARRAY ),
&sdb.pcdata.last_note[0],
{ 0 }, NULL, dbrwf_pcdata_board
},
{
"Religion", DTYPE_COMPLEX | DFLAG_SPECIAL, &sdb.pcdata.religion,
{ 0 }, NULL, dbrwf_all_religion
},
{
"Clan", DTYPE_COMPLEX | DFLAG_SPECIAL, &sdb.pcdata.clan,
{ 0 }, NULL, dbrwf_all_clan
},
{
"MultiClass", DTYPE_NUMBER | DFLAG_ARRAY | DFLAG_SPECWRITE
| ( NUM_MULTI_CLASS << DSHIFT_ARRAY ),
&sdb.pcdata.multi_class[0],
{ CLASS_UNKNOWN }, NULL, dbrwf_pcdata_multi_class
},
{
"Skill", DTYPE_NUMBER | DFLAG_ARRAY | DFLAG_SPECWRITE
| ( MAX_SKILL << DSHIFT_ARRAY ),
&sdb.pcdata.learned[0],
{ 0 }, NULL, dbrwf_pcdata_skills
},
{
"Alias", DTYPE_LLIST, &sdb.pcdata.aliases,
{ 0 }, NULL, NULL
},
{
NULL, 0, NULL, { 0 }, NULL, NULL
}
};
/* Char : PcData : Quest */
static struct data_desc_type quest_data_table[] = {
{
"Time", DTYPE_NUMBER, &sdb.quest.time,
{ 0 }, NULL, NULL
},
{
"Score", DTYPE_NUMBER, &sdb.quest.score,
{ 0 }, NULL, NULL
},
{
NULL, 0, NULL, { 0 }, NULL, NULL
}
};
/* Char : PcData : Alias */
static struct data_desc_type alias_data_table[] = {
{
"Name", DTYPE_STRING, &sdb.alias.name,
{ 0 }, NULL, NULL
},
{
"Command", DTYPE_STRING, &sdb.alias.command,
{ 0 }, NULL, NULL
},
{
NULL, 0, NULL, { 0 }, NULL, NULL
}
};
/* Char : Event */
static struct data_desc_type event_data_table[] = {
{
"When", DTYPE_TIME | DFLAG_SPECWRITE | DFLAG_NEEDPARENT,
&sdb.event.when,
{ 0 }, NULL, dbrwf_event_when
},
{
"Type", DTYPE_NUMBER, &sdb.event.type,
{ 0 }, "event", NULL
},
{
"Flags", DTYPE_NUMBER, &sdb.event.flags,
{ 0 }, "evextra", NULL
},
{
"Text", DTYPE_STRING, &sdb.event.text,
{ 0 }, NULL, NULL
},
{
"Data", DTYPE_NUMBER | DFLAG_ARRAY | DFLAG_SPECWRITE
| ( MAX_EVENT_DATA << DSHIFT_ARRAY ), &sdb.event.data[0],
{ 0 }, NULL, dbrwf_event_data
},
{
NULL, 0, NULL, { 0 }, NULL, NULL
}
};
/* Char : Obj */
static struct data_desc_type obj_data_table[] = {
{
"Vnum", DTYPE_COMPLEX | DFLAG_MAND | DFLAG_SPECIAL,
&sdb.obj.pIndexData,
{ 0 }, NULL, dbrwf_obj_vnum
},
{
"Key", DTYPE_NUMBER | DFLAG_MAND, &sdb.obj.unique_key,
{ 0 }, NULL, NULL
},
{
"Name", DTYPE_STRING | DFLAG_MAND, &sdb.obj.name,
{ 0 }, NULL, NULL
},
{
"Short", DTYPE_STRING, &sdb.obj.short_descr,
{ 0 }, NULL, NULL
},
{
"Desc", DTYPE_STRING, &sdb.obj.description,
{ 0 }, NULL, NULL
},
{
"Action", DTYPE_STRING, &sdb.obj.action,
{ 0 }, NULL, NULL
},
{
"Required", DTYPE_NUMBER, &sdb.obj.required_skill,
{ -1 }, "skill", NULL
},
{
"Extra", DTYPE_NUMBER, &sdb.obj.extra_flags,
{ 0 }, "extra", NULL
},
{
"Wear", DTYPE_NUMBER, &sdb.obj.wear_flags,
{ 0 }, "wear", NULL
},
{
"Location", DTYPE_NUMBER, &sdb.obj.wear_loc,
{ 0 }, "wear-loc", NULL
},
{
"Type", DTYPE_NUMBER, &sdb.obj.item_type,
{ ITEM_TRASH }, "type", NULL
},
{
"Level", DTYPE_NUMBER, &sdb.obj.level,
{ LEVEL_HERO }, NULL, NULL
},
{
"Weight", DTYPE_NUMBER, &sdb.obj.weight,
{ 1 }, NULL, NULL
},
{
"Cost", DTYPE_NUMBER, &sdb.obj.cost,
{ 300 }, NULL, NULL
},
{
"Condition", DTYPE_NUMBER, &sdb.obj.condition,
{ 1000 }, NULL, NULL
},
{
"Affect", DTYPE_LLIST | DFLAG_SPECWRITE, &sdb.obj.affected,
{ 0 }, NULL, dbrwf_all_affect
},
{
"ExDesc", DTYPE_LLIST, &sdb.obj.extra_descr,
{ 0 }, NULL, NULL
},
{
"Event", DTYPE_LLIST, &sdb.obj.events,
{ 0 }, NULL, NULL
},
{
"Values",
DTYPE_NUMBER | DFLAG_ARRAY | DFLAG_SPECIAL | DFLAG_NEEDPARENT
| ( 4 << DSHIFT_ARRAY ),
&sdb.obj.value[0],
{ 0 }, "skill", dbrwf_obj_values
},
{
"Obj", DTYPE_COMPLEX | DFLAG_SPECIAL | DFLAG_NEEDPARENT,
&sdb.obj.contains,
{ 0 }, NULL, dbrwf_obj_obj
},
{
NULL, 0, NULL, { 0 }, NULL, NULL
}
};
/* High */
static struct data_desc_type high_data_table[] = {
{
"Type", DTYPE_STRING, &sdb.high.type,
{ 0 }, NULL, NULL
},
{
"HighEnt", DTYPE_COMPLEX | DFLAG_ARRAY | DFLAG_SPECWRITE
| ( 10 << DSHIFT_ARRAY ),
&sdb.high.entries,
{ 0 }, NULL, dbrwf_high_entries
},
{
NULL, 0, NULL, { 0 }, NULL, NULL
}
};
/* High : HighEnt */
static struct data_desc_type highent_data_table[] = {
{
"Name", DTYPE_STRING, &sdb.highent.name,
{ 0 }, NULL, NULL
},
{
"Level", DTYPE_NUMBER, &sdb.highent.level,
{ 0 }, NULL, NULL
},
{
"SubLevel", DTYPE_NUMBER, &sdb.highent.sublevel,
{ 0 }, NULL, NULL
},
{
"Class", DTYPE_NUMBER, &sdb.highent.class,
{ 0 }, "class", NULL
},
{
"Race", DTYPE_NUMBER, &sdb.highent.race,
{ 0 }, "race", NULL
},
{
NULL, 0, NULL, { 0 }, NULL, NULL
}
};
/*
* Local functions.
*/
bool is_default args( ( const struct top_data_type *block,
const struct data_desc_type *entry ) );
void fix_data_desc_table args( ( struct data_desc_type *table ) );
int get_desc_entry args( ( const struct data_desc_type *table,
const char *name, int start ) );
int get_top_entry args( ( const char *name ) );
bool dbrwf_all_obj args( ( FILE *fp, CHAR_DATA *ch,
OBJ_DATA *obj_cont, db_action action ) );
/*
* This returns an index to the global_data_table element that matches
* 'name'.
*/
int get_top_entry( const char *name )
{
int i;
for( i = 0; global_data_table[i].name != NULL; ++i )
if( !str_cmp( global_data_table[i].name, name ) )
break;
return i;
}
/*
* This retrieves an entry with the name mentioned from the table.
* The start value is used to increase the speed of the search where
* this function is used for consecutive entries.
* Returns: the index of the entry, -1 on error.
*/
int get_desc_entry( const struct data_desc_type *table, const char *name,
int start )
{
int i;
for( i = start; table[i].name != NULL; ++i )
if( !str_cmp( table[i].name, name ) )
return i;
for( i = 0; i < start; ++i )
if( !str_cmp( table[i].name, name ) )
return i;
return -1;
}
/*
* This function assigns all of the default values to the data_desc tables.
* This is needed as some compilers cannot handle the initialisation of
* unions.
* This should be run before any loading or saving occurs.
*/
void init_data_desc_tables()
{
int i;
for( i = 0; global_data_table[i].name != NULL; ++i )
fix_data_desc_table( global_data_table[i].table );
/* AREA */
i = get_desc_entry( area_data_table, "Builders", 0 );
area_data_table[i].deflt.string = "none";
/* MOBILE */
i = get_desc_entry( mobile_data_table, "Act", 0 );
xSET_BIT( mobile_data_table[i].deflt.vector, ACT_IS_NPC );
}
/*
* Helper for the above function, fills in default default values.
*/
void fix_data_desc_table( struct data_desc_type *table )
{
int i;
for( i = 0; table[i].name; ++i )
{
if( !( table[i].type & DFLAG_MAND ) )
switch( table[i].type & DTYPE_BASIC )
{
case DTYPE_STRING:
table[i].deflt.string = &str_empty[0];
break;
case DTYPE_VECTOR:
vzero( table[i].deflt.vector );
break;
case DTYPE_COMPLEX:
case DTYPE_LLIST:
table[i].deflt.table = global_data_table + get_top_entry( table[i].name );
break;
}
}
}
/****************************************************************************
* File opening helper for versioning.
*/
FILE *open_file( const char *name, const char *mode, bool version )
{
FILE *fp;
if( fpReserve )
fclose( fpReserve );
fpReserve = NULL;
fp = fopen( name, mode );
if( !fp )
{
fpReserve = fopen( NULL_FILE, "r" );
return NULL;
}
if( version )
{
if( mode[0] == 'r' )
{
if( SysInfo )
file_version = SysInfo->file_version;
else
file_version = 1;
file_date = current_time;
}
else if( mode[0] == 'w' )
{
fprintf( fp, "# This file has been autogenerated, you can edit this online.\n" );
fprintf( fp, "-Version %d;\n", SysInfo->file_version );
fprintf( fp, "-Date %lu;\n\n", (unsigned long)current_time );
}
}
return fp;
}
/* Neat function for re-opening reserve file. */
void close_file( FILE *fp )
{
fclose( fp );
fpReserve = fopen( NULL_FILE, "r" );
}
/****************************************************************************
* Loading functions.
*/
/*
* Load a list of files and from there load the files listed.
*/
void load_file_list( const char *dirname, const char *listname )
{
char buf[MAX_INPUT_LENGTH];
FILE *fpList;
sprintf( buf, "%s%s", dirname, listname );
if( !( fpList = open_file( buf, "r", FALSE ) ) )
{
perror( buf );
exit( 1 );
}
for( ;; )
{
int stat;
strcpy( buf, fread_word( fpList, &stat ) );
if( buf[0] == '$' )
break;
if( buf[0] == '-' )
{
strcpy( strArea, buf+1 );
fpArea = stdin;
if( !load_file_stream( stdin ) )
exit( 1 );
fpArea = NULL;
}
else
{
strcpy( strArea, buf );
sprintf( buf, "%s%s", dirname, strArea );
if( !load_file( buf ) )
exit( 1 );
}
if( IS_SET( SysInfo->flags, SYSINFO_VERBOSE_LOG ) )
{
if( area_last )
{
fprintf( stderr, "%-14s: Vnums: %5d - %-5d\n",
area_last->filename,
area_last->lvnum, area_last->uvnum );
}
else
fprintf( stderr, "(%s)\n", strArea );
}
else
fputc( '.', stderr );
}
close_file( fpList );
}
/*
* Generic loading function that automatically does everything.
*/
bool load_file( const char *filename )
{
strcpy( strArea, filename );
if( !( fpArea = open_file( filename, "r", TRUE ) ) )
{
bug( "Cannot open file for reading '%s'.", filename );
return FALSE;
}
if( !load_file_stream( fpArea ) )
return FALSE;
close_file( fpArea );
fpArea = NULL;
strArea[0] = '\0';
return TRUE;
}
/*
* A little lower level version of the above.
*/
bool load_file_stream( FILE *fp )
{
void *value;
bool readArea = FALSE;
int entry;
for( ;; )
{
if( !( value = read_next_item( fp, &entry ) ) )
return FALSE;
if( entry < 0 )
{
if( readArea )
{
area_last->ave = (battle_min)
? battle_max / battle_min : 0;
battle_min = battle_max = 0;
}
break;
}
if( !str_cmp( global_data_table[entry].name, "Area" ) )
{
readArea = TRUE;
}
if( !global_data_table[entry].rwf
|| !(*global_data_table[entry].rwf)( NULL, value, DBACTION_ADDWORLD ) )
{
bug( "load_file_stream: Object couldn't be added to the world." );
return FALSE;
}
}
return TRUE;
}
/*
* Reads a value and returns (through the arguments) the name of the value's
* type and the value itself. Look for the name returned being "eof" or
* "end", these signify the end of the file.
*
* NULL is returned on error.
*
* The value returned through status is the index to the global_data_table
* that was read in. This value contains -1 when the end of the file is
* reached (the returned value in this case is the status value, so that a
* check on NULL is possible).
*
* This function contains code to handle the '-Version' and '-Date' values in
* files. When these values are encountered they are placed in the globals
* file_version and file_date respectively.
*/
void *read_next_item( FILE *fp, int *status )
{
char *word;
void *value = NULL;
int letter, errstatus;
do /* while( !value ) */
{
letter = fread_letter( fp );
if( letter == EOF )
{
*status = -1;
return status;
}
while( letter == '#' )
{
fread_to_eol( fp );
letter = fread_letter( fp );
if( letter == EOF )
{
*status = -1;
return status;
}
}
ungetc( letter, fp );
word = fread_word( fp, &errstatus );
if( errstatus )
{
*status = -1;
return NULL;
}
if( !str_cmp( word, "eof" ) || !str_cmp( word, "end" )
|| !str_cmp( word, "eof;" ) || !str_cmp( word, "end;" ) )
{
*status = -1;
return status;
}
else if( !str_cmp( word, "-Version" ) )
{
errstatus = (int)!fread_number_ii( fp, &file_version, NULL );
if( errstatus )
return NULL;
}
else if( !str_cmp( word, "-Date" ) )
{
file_date = fread_time( fp, &errstatus );
if( errstatus )
return NULL;
}
else
{
*status = get_top_entry( word );
if( global_data_table[*status].name == NULL )
{
bug( "Read unknown section header: %s", word );
return NULL;
}
value = load_complex_block( fp, global_data_table + *status );
if( !value )
{
bug( "read_next_item: error reading item" );
return NULL;
}
}
if( ( letter = fread_letter( fp ) != ';' ) )
{
if( letter == EOF )
bug( "read_next_item: EOF reached early." );
else
bug( "read_next_item: missing ';' character." );
return NULL;
}
}
while( !value );
return value;
}
/*
* Reads a block from the first '{' to the last '}'.
*
* Caveat: The default value for an array cannot be asserted. This value is
* used for only the first element of the array.
*
* Caveat: Complex sections cannot have a default value, they must be fixed
* up later, as they are given the default value of NULL.
*/
void *load_complex_block( FILE *fp, const struct top_data_type *block_desc )
{
struct data_desc_type *load_table = block_desc->table;
int error;
int letter;
char *word;
int i, num_keys, last_key = 0;
bool *specified;
void *value;
if( fread_letter( fp ) != '{' )
{
bug( "load_complex_block: no starting '{' character." );
return NULL;
}
memset( block_desc->data_ptr, 0, block_desc->data_size );
for( num_keys = 0; load_table[num_keys].name
&& *load_table[num_keys].name; )
num_keys++;
specified = alloc_mem( num_keys * sizeof( bool ) );
for( i = 0; i < num_keys; ++i )
specified[i] = FALSE;
while( !feof( fp ) )
{
letter = fread_letter( fp );
if( letter == EOF )
{
bug( "load_complex_block: EOF reached." );
free_mem( specified, num_keys * sizeof( bool ) );
return NULL;
}
if( letter == '}' )
break;
if( letter == '#' )
{
fread_to_eol( fp );
continue;
}
ungetc( letter, fp );
word = fread_word( fp, &error );
if( error )
{
bug( "Error reading key." );
free_mem( specified, num_keys * sizeof( bool ) );
return NULL;
}
i = get_desc_entry( load_table, word, last_key );
/*
* OHNO! not known to me! ... Error recovery mode.
*/
if( i < 0 )
{
last_key = 0;
bug( "Unknown key encountered '%s'.", word );
if( !ignore_unknown_field( fp ) )
{
free_mem( specified, num_keys * sizeof( bool ) );
return NULL;
}
continue;
}
last_key = i;
specified[i] = TRUE;
/*
* Three types of reading: special, array, single.
*/
if( IS_SET( load_table[i].type, DFLAG_SPECREAD ) )
{
if( IS_SET( load_table[i].type, DFLAG_NEEDPARENT ) )
error = !(*load_table[i].rwf)( fp, block_desc->data_ptr,
DBACTION_READ );
else
error = !(*load_table[i].rwf)( fp, load_table[i].target,
DBACTION_READ );
if( !error )
error = !(*load_table[i].rwf)( fp, load_table[i].target,
DBACTION_FIX );
}
else if( IS_SET( load_table[i].type, DFLAG_ARRAY ) )
error = !load_array( fp, load_table + i );
else
error = !load_single_field( fp, load_table + i );
if( error )
{
free_mem( specified, num_keys * sizeof( bool ) );
return NULL;
}
letter = fread_letter( fp );
if( letter != ';' )
{
if( letter == EOF )
bug( "load_complex_block: EOF reached." );
else
bug( "load_complex_block: missing ';' character." );
free_mem( specified, num_keys * sizeof( bool ) );
return NULL;
}
}
/*
* Assign default values and check for mandatory fields.
*/
for( i = 0; i < num_keys; i++ )
{
if( specified[i] == TRUE )
continue;
if( IS_SET( load_table[i].type, DFLAG_MAND ) )
{
bug( "Problem in %s section, MAND field %s missing.",
block_desc->name, load_table[i].name );
free_mem( specified, num_keys * sizeof( bool ) );
return NULL;
}
switch( load_table[i].type & DTYPE_BASIC )
{
case DTYPE_STRING:
*(char **)load_table[i].target
= str_dup( load_table[i].deflt.string );
break;
case DTYPE_NUMBER:
case DTYPE_TIME:
*(int *)load_table[i].target = load_table[i].deflt.number;
break;
case DTYPE_VECTOR:
vcopy( (int *)load_table[i].target, load_table[i].deflt.vector );
break;
case DTYPE_COMPLEX:
case DTYPE_LLIST:
*(void **)load_table[i].target = NULL;
break;
default:
break;
}
}
free_mem( specified, num_keys * sizeof( bool ) );
value = alloc_perm( block_desc->data_size );
memcpy( value, block_desc->data_ptr, block_desc->data_size );
if( block_desc->rwf
&& !(*block_desc->rwf)( NULL, value, DBACTION_FIX ) )
{
dalloc_last( block_desc->data_size );
return NULL;
}
return value;
}
bool load_single_field( FILE *fp, const struct data_desc_type *entry )
{
int error, letter;
void **ptr;
if( !entry || !entry->target )
{
bug( "Void target for %s.", entry->name );
return FALSE;
}
error = 1;
switch( entry->type & DTYPE_BASIC )
{
case DTYPE_STRING:
*(char **)entry->target = fread_string( fp, &error );
break;
case DTYPE_NUMBER:
case DTYPE_VECTOR:
error = !fread_number_ii( fp, (int *)entry->target, entry->flag_table );
break;
case DTYPE_COMPLEX:
ptr = (void **)entry->target;
*ptr = load_complex_block( fp, entry->deflt.table );
if( *ptr )
error = 0;
break;
case DTYPE_LLIST:
ptr = (void **)entry->target;
while( *ptr )
ptr = &NEXT( *ptr );
/* Small extension to the syntax:
* Allow for linked lists to be chained together.
*
* LLName {
* Key "value";
* }{
* Key "value";
* };
*/
do
{
*ptr = load_complex_block( fp, entry->deflt.table );
if( !*ptr )
{
bug( "Error reading key %s.", entry->name );
return FALSE;
}
letter = fread_letter( fp );
ungetc( letter, fp );
ptr = &NEXT( *ptr );
error = 0;
}
while( letter == '{' );
break;
case DTYPE_TIME:
*(time_t *)entry->target = fread_time( fp, &error );
break;
}
if( error )
{
bug( "Error reading key %s.", entry->name );
return FALSE;
}
if( entry->rwf
&& !(*entry->rwf)( NULL, entry->target, DBACTION_FIX ) )
return FALSE;
return TRUE;
}
/*
* This function reads an array from a file.
* This array should be of the format:
*
* \[ [#<size>] [@<number>] <value>, [@<number>] <value> \]
*
* e.g.
* [ #12 "value[0]", @2 "value[2]", "value[3]", @10 "value[10]" ]
*
* The number following the optional @ symbol signifies the index that
* the data should be entered at.
*
* The size of an array cannot be known, except if it is given in the
* deflt.number field. If this is given default values can be assigned.
*/
bool load_array( FILE *fp, const struct data_desc_type *entry )
{
int letter, error = 0, index = 0;
struct data_desc_type ddesc;
bool *specified = NULL;
int i, num_keys;
if( fread_letter( fp ) != '[' )
{
bug( "Expecting an array for %s.", entry->name );
return FALSE;
}
memcpy( &ddesc, entry, sizeof( ddesc ) );
num_keys = entry->type >> DSHIFT_ARRAY;
if( !IS_SET( entry->type, DFLAG_MAND )
&& num_keys > 0 )
{
specified = alloc_mem( num_keys * sizeof( bool ) );
for( i = 0; i < num_keys; ++i )
specified[i] = FALSE;
}
ddesc.type &= ~( DFLAG_ARRAY | ( num_keys << DSHIFT_ARRAY ) );
do
{
letter = fread_letter( fp );
if( letter == EOF )
{
bug( "load_array: EOF encountered." );
if( specified )
free_mem( specified, num_keys * sizeof( bool ) );
return FALSE;
}
else if( letter == ']' )
break;
else if( letter == '@' )
error = !fread_number_ii( fp, &index, entry->flag_table );
else
ungetc( letter, fp );
switch( entry->type & DTYPE_BASIC )
{
case DTYPE_STRING:
ddesc.target = (void *)( ((char **)entry->target) + index );
break;
case DTYPE_NUMBER:
case DTYPE_VECTOR:
ddesc.target = (void *)( ((int *)entry->target) + index );
break;
case DTYPE_COMPLEX:
case DTYPE_LLIST:
ddesc.target = (void *)( ((void **)entry->target) + index );
break;
case DTYPE_TIME:
ddesc.target = (void *)( ((time_t *)entry->target) + index );
break;
}
if( error || !load_single_field( fp, &ddesc ) )
{
if( specified )
free_mem( specified, num_keys * sizeof( bool ) );
return FALSE;
}
specified[index] = TRUE;
letter = fread_letter( fp );
index++;
}
while( letter == ',' );
/*
* If we are looking for default values, set those that should be default
* to the proper value.
*/
if( specified )
{
for( i = 0; i < num_keys; ++i )
{
if( specified[i] == TRUE )
continue;
switch( entry->type & DTYPE_BASIC )
{
case DTYPE_STRING:
*( (char **)entry->target + i ) = str_dup( entry->deflt.string );
break;
case DTYPE_NUMBER:
case DTYPE_TIME:
*( (int *)entry->target + i ) = entry->deflt.number;
break;
case DTYPE_VECTOR:
vcopy( (int *)entry->target + i, entry->deflt.vector );
break;
case DTYPE_COMPLEX:
case DTYPE_LLIST:
*( (void **)entry->target + i ) = NULL;
break;
default:
break;
}
}
free_mem( specified, num_keys * sizeof( bool ) );
}
if( letter != ']' )
{
bug( "Expecting an end of array for %s.", entry->name );
return FALSE;
}
return TRUE;
}
/*
* The problem with human readable formats is that they often don't seem to
* be all that readable by a computer. This error recovery function is made
* complex by the fact that the format is extremely sensitive to syntax
* errors. Luckily OLC saves us from this problem occuring too often.
*/
bool ignore_unknown_field( FILE *fp )
{
int letter, error = 0;
do
{
letter = fread_letter( fp );
if( letter == EOF )
return FALSE;
else if( letter == '#' )
fread_to_eol( fp );
}
while( letter == '#' );
if( isdigit( letter ) || letter == '(' )
{
ungetc( letter, fp );
error = !fread_number_ii( fp, &letter, "skill" );
}
else if( letter == '"' )
{
ungetc( letter, fp );
free_string( fread_string( fp, &error ) );
}
else if( letter == '[' )
{
do
{
letter = fread_letter( fp );
if( letter == EOF )
return FALSE;
else if( letter == '@' )
{
error = !fread_number_ii( fp, &letter, "skill" );
letter = fread_letter( fp );
}
ungetc( letter, fp );
if( isdigit( letter ) || letter == '(' )
error = !fread_number_ii( fp, &letter, "skill" );
else if( letter == '"' )
free_string( fread_string( fp, &error ) );
letter = fread_letter( fp );
}
while( letter == ',' );
}
else if( letter == '{' )
{
do /* ignore multiple key, value pairs. */
{
do /* read the key */
{
letter = fread_letter( fp );
if( letter == EOF )
return FALSE;
else if( letter == '#' )
fread_to_eol( fp );
else if( letter != '}' )
{
ungetc( letter, fp );
fread_word( fp, &error );
}
}
while( letter == '#' );
if( letter != '}' )
ignore_unknown_field( fp );
}
while( letter != '}' );
}
else if( letter == '}' )
{
bug( "'}' found, assuming that was just junk." );
ungetc( letter, fp );
return TRUE;
}
/* else - we are stuffed anyway */
if( error || fread_letter( fp ) != ';' )
{
bug( "Unrecoverable error, no semicolon." );
return FALSE;
}
return TRUE;
}
/*
* Read a number from a file.
* Now also support hex numbers in the 0xabc123.
*/
int fread_number( FILE *fp, int *status )
{
int c;
bool sign = FALSE, hex = FALSE;
int number = 0;
*status = 0;
do
{
if( feof( fp ) )
{
*status = 1;
bug( "fread_number: EOF encountered on read." );
if( fBootDb )
exit( 1 );
return NO_FLAG;
}
c = getc( fp );
}
while( isspace( c ) );
if( c == '+' )
{
c = getc( fp );
}
else if( c == '-' )
{
sign = TRUE;
c = getc( fp );
}
if( !isdigit( c ) )
{
*status = 1;
bug( "Fread_number: bad format." );
bug( " If bad object, check for missing '~' in value[] fields." );
return NO_FLAG;
}
if( c == '0' )
{
c = getc( fp );
if( c == 'x' || c == 'X' )
hex = TRUE;
else if( isdigit( c ) )
ungetc( c, fp );
}
while( isdigit( c ) || ( hex && isxdigit( c ) ) )
{
if( hex )
{
if( isdigit( c ) )
number = number * 16 + c - '0';
else
number = number * 16 + tolower( c ) - 'a' + 10;
}
else
number = number * 10 + c - '0';
c = getc( fp );
}
if( c == EOF )
{
*status = 1;
bug( "fread_number: EOF encountered on read." );
if( fBootDb )
exit( 1 );
return NO_FLAG;
}
if( sign )
number = 0 - number;
if( c == '|' )
number += fread_number( fp, status );
else if( c != ' ' )
ungetc( c, fp );
return number;
}
/*
* Read a time (unsigned long).
*/
time_t fread_time( FILE *fp, int *status )
{
int c;
unsigned long number = 0;
*status = 0;
do
{
if( feof( fp ) )
{
*status = 1;
bug( "fread_number: EOF encountered on read." );
if( fBootDb )
exit( 1 );
return NO_FLAG;
}
c = getc( fp );
}
while( isspace( c ) );
if( !isdigit( c ) )
{
*status = 1;
bug( "Fread_time: bad format." );
bug( " If bad object, check for missing '~' in value[] fields." );
return NO_FLAG;
}
while( isdigit( c ) )
{
number = number * 10 + c - '0';
c = getc( fp );
}
if( c == EOF )
{
*status = 1;
bug( "fread_time: EOF encountered on read." );
if( fBootDb )
exit( 1 );
return NO_FLAG;
}
if( c != ' ' )
ungetc( c, fp );
return number;
}
bool fread_mapped_value( FILE *fp, int *value, const char *def_table )
{
int c;
int i;
char buf[MAX_STRING_LENGTH];
i = 0;
c = fread_letter( fp ); /* also skips leading whitespace */
if( c == EOF )
{
bug( "fread_mapped_value: EOF encountered on read." );
return FALSE;
}
if( c == ')' ) /* empty parentheses "()" */
{
*value = 0;
return TRUE;
}
while( c != ')' )
{
buf[i++] = c;
c = getc( fp );
if( c == EOF )
{
bug( "fread_mapped_value: EOF encountered on read." );
return FALSE;
}
}
buf[i] = '\0';
if( buf[0] == '<' )
{
const char *p;
char table[MAX_INPUT_LENGTH];
p = one_argument( buf, table );
get_lookup( value, table, p );
}
else if( def_table )
get_lookup( value, def_table, buf );
else
{
bug( "fread_mapped_value: No table specified." );
return FALSE;
}
return TRUE;
}
/*
* Read a number from a file.
*/
bool fread_number_ii( FILE *fp, int *value, const char *def_table )
{
int c;
int stat;
c = fread_letter( fp );
if( c != '(' )
{
ungetc( c, fp );
*value = fread_number( fp, &stat );
return !stat;
}
return fread_mapped_value( fp, value, def_table );
}
/***************************************************************************
* Saving functions.
*/
bool write_next_item( FILE *fp, const char *name, const void *value )
{
int i;
i = get_top_entry( name );
if( global_data_table[i].name == NULL )
{
bug( "Read unknown section header: %s", name );
return FALSE;
}
fprintf( fp, "%s ", global_data_table[i].name );
if( !save_complex_block( fp, global_data_table + i, value ) )
return FALSE;
fprintf( fp, ";\n" );
return TRUE;
}
bool save_complex_block( FILE *fp, const struct top_data_type *block_desc, const void *value )
{
struct data_desc_type *load_table = block_desc->table;
int i;
void *ptr;
memcpy( block_desc->data_ptr, value, block_desc->data_size );
fprintf( fp, "{\n" );
for( i = 0; load_table[i].name && *load_table[i].name; ++i )
{
if( is_default( block_desc, load_table + i ) )
continue;
/*
* Print the header if it's not a linked list, as sometime linked
* lists can be determined to be empty through other means than the
* default check and then they wont be displayed.
*/
if( ( load_table[i].type & DTYPE_BASIC ) != DTYPE_LLIST )
fprintf( fp, "%s\t", load_table[i].name );
if( IS_SET( load_table[i].type, DFLAG_SPECWRITE )
|| IS_SET( load_table[i].type, DFLAG_ARRAY ) )
{
if( IS_SET( load_table[i].type, DFLAG_NEEDPARENT ) )
{
if( !(*load_table[i].rwf)( fp, block_desc->data_ptr,
DBACTION_WRITE ) )
return FALSE;
}
else
{
if( !(*load_table[i].rwf)( fp, load_table[i].target,
DBACTION_WRITE ) )
return FALSE;
}
}
else switch( load_table[i].type & DTYPE_BASIC )
{
case DTYPE_STRING:
fwrite_quoted_string( fp, *(char**)load_table[i].target );
break;
case DTYPE_NUMBER:
if( load_table[i].flag_table )
fwrite_mapped_value( fp, (int *)load_table[i].target,
load_table[i].flag_table, FALSE );
else
fwrite_number( fp, *(int *)load_table[i].target );
break;
case DTYPE_VECTOR:
fwrite_mapped_value( fp, (int *)load_table[i].target,
load_table[i].flag_table, FALSE );
break;
case DTYPE_COMPLEX:
if( !save_complex_block( fp, load_table[i].deflt.table,
*(void **)load_table[i].target ) )
return FALSE;
break;
case DTYPE_LLIST:
ptr = *(void **)load_table[i].target;
for( ; ptr; ptr = NEXT( ptr ) )
{
if( (*load_table[i].deflt.table->rwf)( fp, ptr, DBACTION_CHKDEFAULT ) )
continue;
fprintf( fp, "%s\t", load_table[i].name );
if( !save_complex_block( fp, load_table[i].deflt.table, ptr ) )
return FALSE;
fprintf( fp, ";\n" );
}
break;
case DTYPE_TIME:
fwrite_time( fp, *(time_t *)load_table[i].target );
break;
}
if( ( load_table[i].type & DTYPE_BASIC ) != DTYPE_LLIST )
fprintf( fp, ";\n" );
}
fputc( '}', fp );
return TRUE;
}
bool is_default( const struct top_data_type *block,
const struct data_desc_type *entry )
{
if( IS_SET( entry->type, DFLAG_MAND ) )
return FALSE;
if( IS_SET( entry->type, DFLAG_CHKDEFAULT ) )
{
if( IS_SET( entry->type, DFLAG_NEEDPARENT ) )
return (*entry->rwf)( NULL, block->data_ptr, DBACTION_CHKDEFAULT );
else
return (*entry->rwf)( NULL, entry->target, DBACTION_CHKDEFAULT );
}
if( IS_SET( entry->type, DFLAG_ARRAY ) )
return FALSE;
switch( entry->type & DTYPE_BASIC )
{
case DTYPE_STRING:
if( !entry->deflt.string )
return ( *(char **)entry->target == '\0' ) ? TRUE : FALSE;
return !strcmp( *(char **)entry->target, entry->deflt.string )
? TRUE : FALSE;
case DTYPE_NUMBER:
case DTYPE_TIME:
return ( *(int *)entry->target == entry->deflt.number )
? TRUE : FALSE;
case DTYPE_VECTOR:
return vequal( (int *)entry->target, entry->deflt.vector );
case DTYPE_COMPLEX:
case DTYPE_LLIST:
return ( (*(void **)entry->target) == NULL ) ? TRUE : FALSE;
default:
break;
}
return FALSE;
}
void fwrite_number( FILE *fp, int value )
{
fprintf( fp, "%d", value );
}
void fwrite_time( FILE *fp, time_t value )
{
fprintf( fp, "%lu", (unsigned long)value );
}
void fwrite_mapped_value( FILE *fp, int *value, const char *table, bool title )
{
char buf[MAX_STRING_LENGTH];
struct flag_type *flag_table;
int i;
bool vect = FALSE, stat = FALSE;
fputc( '(', fp );
if( title )
fprintf( fp, "<%s> ", table );
buf[0] = '\0';
if( !str_cmp( table, "skill" ) )
{
if( *value > 0 && *value < MAX_SKILL )
strcpy( buf, skill_table[*value].name );
else
strcpy( buf, "." );
}
else if( !str_cmp( table, "race" ) )
strcpy( buf, race_table[*value].name );
else if( !str_cmp( table, "liquid" ) )
strcpy( buf, liq_table[*value].liq_name );
else if( !str_cmp( table, "event" ) )
strcpy( buf, event_table[*value].name );
if( buf[0] != '\0' )
{
fprintf( fp, buf );
fputc( ')', fp );
return;
}
for( i = 0; bit_table[i].desc && bit_table[i].desc[0]; ++i )
if( !str_prefix( table, bit_table[i].command ) )
break;
if( !bit_table[i].desc || bit_table[i].desc[0] == '\0' )
{
fprintf( fp, "ERROR!!)" );
return;
}
title = FALSE;
flag_table = (struct flag_type *)bit_table[i].structure;
if( is_vector( flag_table ) )
vect = TRUE;
else if( is_stat( flag_table ) )
stat = TRUE;
for( i = 0; *flag_table[i].name; i++ )
{
if( ( vect && xIS_SET( value, flag_table[i].bit ) )
|| ( !vect && !stat
&& IS_SET( *value, flag_table[i].bit ) )
|| ( !vect && flag_table[i].bit == *value ) )
{
if( title )
fputc( ' ', fp );
else
title = TRUE;
if( strchr( flag_table[i].name, ' ' ) )
{
fputc( '"', fp );
fprintf( fp, flag_table[i].name );
fputc( '"', fp );
}
else
fprintf( fp, flag_table[i].name );
if( stat )
break;
}
}
fputc( ')', fp );
return;
}
void fwrite_quoted_string( FILE *fp, const char *str )
{
fputc( '"', fp );
while( *str )
{
switch( *str )
{
case '\n':
fputc( '\\', fp );
fputc( 'n', fp );
break;
case '\r':
if( *( str + 1 ) && *( str + 1 ) != '\n' )
fputc( '\n', fp );
break;
case '\t':
fputc( '\\', fp );
fputc( 't', fp );
break;
case '"':
fputc( '\\', fp );
fputc( '"', fp );
break;
case '\\':
fputc( '\\', fp );
fputc( '\\', fp );
break;
default:
fputc( *str, fp );
break;
}
str++;
}
fputc( '"', fp );
}
/***************************************************************************
* Special functions for reading, writing and fixing data.
*
* The third argument of this function determines if the data is to be read,
* written or fixed (after reading).
*
* Quirk: For fixing of top level objects (e.g. plane/area) the vo pointer is
* a single pointer to the object. For values that are a part of a complex
* object this is a pointer to the element in the object (for int: int*; for
* char *: char **; etc...)
*
* Note: If data is to be fixed, you will not be able to use pointers to that
* data as this is not the final value of the data, this function merely
* allows for sanity checks and perhaps a few tweaks.
*
* Cases where data is valid:
* DBACTION_ADDWORLD, DBACTION_CHKDEFAULT, DBACTION_FIX and all minor
* members of the current object (unless they haven't been read yet).
*
* Array Note: This function is called for each member of the array, never
* the entire array on its own, validation of the entire array as a whole
* must be done by the enclosing object.
*
* CHKDEFAULT on the top level objects relates to linked lists only, but it
* is best to return FALSE in all cases. This is normally used to detect
* 'deleted' flags.
*/
/*
* This buffer is for convenience.
*/
char db_buf[MAX_STRING_LENGTH];
void fix_progtypes( MPROG_DATA *mprg, int *types )
{
for( ; mprg; mprg = mprg->next )
{
if( mprg->type == GLOBAL_PROG )
{
MPROG_GLOBAL *glob = get_global_prog( mprg );
if( glob )
xSET_BIT( types, glob->type );
else
bug( "WARNING: Global Mud Program doesn't exist yet: %s.",
mprg->arglist );
}
else
xSET_BIT( types, mprg->type );
}
}
bool dbrwf_affect( FILE *fp, void *vo, db_action action )
{
AFFECT_DATA *paf = (AFFECT_DATA *)vo;
if( action == DBACTION_WRITE )
{
if( paf->deleted )
return TRUE;
fprintf( fp, "{\n" );
if( paf->type > 0 && paf->type < MAX_SKILL )
{
fprintf( fp, "Name\t" );
fwrite_mapped_value( fp, &paf->type, "skill", FALSE );
fprintf( fp, ";\n" );
}
if( paf->duration >= 0 )
fprintf( fp, "Duration\t%d;\n", paf->duration );
if( paf->level )
fprintf( fp, "Level\t%d;\n", paf->level );
if( paf->type == gsn_continuous_effect
|| paf->type == gsn_racial_fatigue
|| paf->type == gsn_religious
|| paf->type == gsn_delayed_effect
|| paf->type == gsn_perm_spell )
{
fprintf( fp, "Location\t" );
fwrite_mapped_value( fp, &paf->location, "skill", TRUE );
fprintf( fp, ";\n" );
}
else
{
if( paf->location != APPLY_NONE )
{
fprintf( fp, "Location\t" );
fwrite_mapped_value( fp, &paf->location, "apply", FALSE );
fprintf( fp, ";\n" );
}
if( paf->modifier )
{
fprintf( fp, "Modifier\t" );
if( paf->location == APPLY_BODY_PART )
fwrite_mapped_value( fp, &paf->modifier, "limbs", TRUE );
else
fwrite_number( fp, paf->modifier );
fprintf( fp, ";\n" );
}
if( !vnull( paf->bitvector ) )
{
fprintf( fp, "Bits\t" );
fwrite_mapped_value( fp, paf->bitvector, "affect", FALSE );
fprintf( fp, ";\n" );
}
}
fprintf( fp, "}" );
}
else if( action == DBACTION_ADDWORLD )
{
bug( "Trying to add an affect to the world on its own." );
return FALSE;
}
else if( action == DBACTION_CHKDEFAULT )
return !paf->deleted;
return TRUE;
}
bool dbrwf_alias( FILE *fp, void *vo, db_action action )
{
ALIAS_DATA *alias = (ALIAS_DATA *)vo;
if( action == DBACTION_FIX )
{
char *p;
const char directions[] = "neswud";
if( strchr( alias->command, '%' ) )
alias->complex = ALIAS_COMPLEX;
else if( strchr( alias->command, '=' ) )
alias->complex = ALIAS_MULTIPLE;
else
{
alias->complex = ALIAS_MULTIPLE;
for( p = alias->command; *p; p++ )
{
if( !strchr( directions, LOWER( *p ) ) )
{
alias->complex = ALIAS_SIMPLE;
break;
}
}
}
}
else if( action == DBACTION_ADDWORLD )
{
bug( "Trying to add an alias to the world on its own." );
return FALSE;
}
else if( action == DBACTION_CHKDEFAULT )
return FALSE;
return TRUE;
}
bool dbrwf_area( FILE *fp, void *vo, db_action action )
{
AREA_DATA *pArea = (AREA_DATA *)vo;
if( action == DBACTION_FIX )
{
pArea->vnum = top_area++;
pArea->filename = str_dup( strArea + strlen( AREA_DIR ) );
pArea->nplayer = 0;
pArea->next = NULL;
pArea->min = MAX_LEVEL;
pArea->max = 0;
if( !pArea->plane )
pArea->plane = plane_lookup( "unfinished" );
if( pArea->order && pArea->order->clan_type != CLAN_ORDER )
{
bug( "Religious order not found or not an order." );
pArea->order = NULL;
}
}
else if( action == DBACTION_ADDWORLD )
{
if( !area_first )
area_first = pArea;
if( area_last )
{
area_last->next = pArea;
REMOVE_BIT( area_last->area_flags, AREA_LOADING );
}
area_last = pArea;
}
else if( action == DBACTION_CHKDEFAULT )
return IS_SET( pArea->area_flags, AREA_DELETED ) ? TRUE : FALSE;
return TRUE;
}
bool dbrwf_char( FILE *fp, void *vo, db_action action )
{
CHAR_DATA *ch = (CHAR_DATA *)vo;
if( action == DBACTION_FIX )
{
ROOM_INDEX_DATA *in_room;
AFFECT_DATA *paf;
OBJ_DATA *obj;
int i;
ch->logon = current_time;
ch->unique_key = SysInfo->char_key++;
if( SysInfo->char_key >= (1<<30) )
SysInfo->char_key = 1;
if( !ch->body_parts )
ch->body_parts = race_table[ch->race].body_parts;
clean_char( ch );
in_room = ch->in_room;
ch->in_room = get_room_index( ROOM_VNUM_LIMBO );
vzero( ch->affected_by );
for( paf = ch->affected; paf; paf = paf->next )
{
if( paf->deleted )
continue;
affect_modify( ch, paf, TRUE );
}
for( obj = ch->carrying; obj; obj = obj->next_content )
{
obj->carried_by = ch;
if( obj->deleted || obj->wear_loc == WEAR_NONE )
continue;
i = obj->wear_loc;
obj->wear_loc = WEAR_NONE;
equip_char( ch, obj, i );
}
inject_events( ch );
/* Update the character
switch( SysInfo->file_version - file_version )
{
case 1:
fix up.
case 0:
} */
ch->in_room = in_room;
}
else if( action == DBACTION_ADDWORLD )
{
char_to_room( ch, ch->in_room );
}
else if( action == DBACTION_CHKDEFAULT )
return !ch->deleted;
return TRUE;
}
bool dbrwf_clan( FILE *fp, void *vo, db_action action )
{
CLAN_DATA *pClan = (CLAN_DATA *)vo;
if( action == DBACTION_ADDWORLD )
{
top_clan++;
if( !clan_first )
clan_first = pClan;
if( clan_last )
clan_last->next = pClan;
clan_last = pClan;
}
else if( action == DBACTION_CHKDEFAULT )
return FALSE;
return TRUE;
}
bool dbrwf_event( FILE *fp, void *vo, db_action action )
{
EVENT *e = (EVENT *)vo;
if( action == DBACTION_FIX )
{
e->flags |= EVENT_LOADING;
top_event++;
}
else if( action == DBACTION_ADDWORLD )
{
bug( "Trying to add an extra description to the world on its own." );
return FALSE;
}
else if( action == DBACTION_CHKDEFAULT )
{
if( e->type < 0
|| IS_SET( e->flags ^ event_table[e->type].flags,
EVENT_TEMPORARY )
|| IS_SET( e->flags ^ event_table[e->type].flags,
EVENT_NO_QUIT ) )
return TRUE;
/* A broken event, forget it. */
if( !IS_SET( e->flags, EVENT_LOADING ) && e->when < SysInfo->pulse )
return TRUE;
return FALSE;
}
return TRUE;
}
bool dbrwf_exdesc( FILE *fp, void *vo, db_action action )
{
/* EXTRA_DESCR_DATA *exdesc = (EXTRA_DESCR_DATA *)vo; */
if( action == DBACTION_FIX )
{
top_ed++;
}
else if( action == DBACTION_ADDWORLD )
{
bug( "Trying to add an extra description to the world on its own." );
return FALSE;
}
else if( action == DBACTION_CHKDEFAULT )
return FALSE;
return TRUE;
}
bool dbrwf_exit( FILE *fp, void *vo, db_action action )
{
EXIT_DATA *exit = (EXIT_DATA *)vo;
if( action == DBACTION_FIX )
{
top_exit++;
exit->exit_info = exit->rs_flags;
}
else if( action == DBACTION_ADDWORLD )
{
bug( "Trying to add an exit to the world on its own." );
return FALSE;
}
else if( action == DBACTION_CHKDEFAULT )
return FALSE;
return TRUE;
}
bool dbrwf_help( FILE *fp, void *vo, db_action action )
{
HELP_DATA *pHelp = (HELP_DATA *)vo;
if( action == DBACTION_FIX )
{
top_help++;
if( area_last )
pHelp->area = area_last;
else
pHelp->area = NULL;
if( !help_greeting )
help_greeting = pHelp->text;
}
else if( action == DBACTION_ADDWORLD )
{
if( !help_first )
help_first = pHelp;
if( help_last )
help_last->next = pHelp;
help_last = pHelp;
pHelp->next = NULL;
}
else if( action == DBACTION_CHKDEFAULT )
return FALSE;
return TRUE;
}
bool dbrwf_high( FILE *fp, void *vo, db_action action )
{
HIGHEST_DATA *pHigh = (HIGHEST_DATA *)vo;
if( action == DBACTION_ADDWORLD )
{
if( !highest_first )
highest_first = pHigh;
if( highest_last )
highest_last->next = pHigh;
highest_last = pHigh;
pHigh->next = NULL;
}
return TRUE;
}
bool dbrwf_highent( FILE *fp, void *vo, db_action action )
{
if( action == DBACTION_ADDWORLD )
{
bug( "Trying to add a single entry of the highest table to the world." );
return FALSE;
}
return TRUE;
}
bool dbrwf_gprog( FILE *fp, void *vo, db_action action )
{
MPROG_GLOBAL *glob = (MPROG_GLOBAL *)vo;
if( action == DBACTION_FIX )
{
top_mprog_global++;
glob->area = area_last;
}
else if( action == DBACTION_ADDWORLD )
{
int iHash;
if( get_global_mudprog_index( glob->vnum ) )
{
bug( "dbrwf_gprog(FIX): vnum %d duplicated.", glob->vnum );
return FALSE;
}
iHash = glob->vnum % MPROG_GLOBAL_HASH;
glob->next = global_progs[iHash];
global_progs[iHash] = glob;
assign_area_vnum( glob->vnum );
}
else if( action == DBACTION_CHKDEFAULT )
return FALSE;
return TRUE;
}
bool dbrwf_mob_index( FILE *fp, void *vo, db_action action )
{
MOB_INDEX_DATA *pMob = (MOB_INDEX_DATA *)vo;
if( action == DBACTION_FIX )
{
top_mob_index++;
xSET_BIT( pMob->act, ACT_IS_NPC );
pMob->area = area_last;
pMob->long_descr[0] = UPPER( pMob->long_descr[0] );
pMob->description[0] = UPPER( pMob->description[0] );
if( pMob->body_parts == -1 )
pMob->body_parts = race_table[pMob->race].body_parts;
if( pMob->race < 0 )
pMob->race = 0;
assign_area_vnum( pMob->vnum );
area_last->min = UMIN( area_last->min, pMob->level );
area_last->max = UMAX( area_last->max, pMob->level );
fix_progtypes( pMob->mudprogs, pMob->progtypes );
}
else if( action == DBACTION_ADDWORLD )
{
int iHash;
if( get_mob_index( pMob->vnum ) )
{
bug( "dbrwf_mob_index(FIX): vnum %d duplicated.", pMob->vnum );
return FALSE;
}
iHash = pMob->vnum % MAX_KEY_HASH;
pMob->next = mob_index_hash[iHash];
mob_index_hash[iHash] = pMob;
top_vnum_mob = UMAX( top_vnum_mob, pMob->vnum );
kill_table[URANGE( 0, pMob->level, LEVEL_HERO * 2 - 1 )].number++;
}
else if( action == DBACTION_CHKDEFAULT )
return FALSE;
return TRUE;
}
bool dbrwf_mudprog( FILE *fp, void *vo, db_action action )
{
/* MPROG_DATA *mprg = (MPROG_DATA *)vo; */
if( action == DBACTION_FIX )
{
top_mprog++;
}
else if( action == DBACTION_ADDWORLD )
{
bug( "Trying to add a mudprog to the world on its own." );
return FALSE;
}
else if( action == DBACTION_CHKDEFAULT )
return FALSE;
return TRUE;
}
bool dbrwf_note( FILE *fp, void *vo, db_action action )
{
/* NOTE_DATA *pNote = (NOTE_DATA *)vo; */
if( action == DBACTION_ADDWORLD )
{
bug( "Notes shouldn't be added to the world in this way." );
return FALSE;
}
else if( action == DBACTION_CHKDEFAULT )
return FALSE;
return TRUE;
}
bool dbrwf_obj( FILE *fp, void *vo, db_action action )
{
OBJ_DATA *obj = (OBJ_DATA *)vo;
if( action == DBACTION_FIX )
{
EVENT *e;
OBJ_DATA *obj2;
obj->magic = MAGIC_NUM_OBJECT;
/* Breaking the rules a little. ADDWORLD should only be used by the
top level object. */
obj->pIndexData->count++;
obj->next = object_list;
object_list = obj;
for( e = obj->events; e; e = e->next_local )
{
e->actor.type = TARGET_OBJ;
e->actor.target.obj = obj;
}
/*
* All of these objects have been added to the static version of this
* object. So they have to be fixed to point to this.
*/
for( obj2 = obj->contains; obj2; obj2 = obj2->next_content )
obj2->in_obj = obj;
}
else if( action == DBACTION_ADDWORLD )
{
if( !obj->in_room )
{
bug( "Trying to insert an object into a non-existant room." );
return FALSE;
}
obj_to_room( obj, obj->in_room );
strip_events( &obj->events, evn_imp_grab );
}
else if( action == DBACTION_CHKDEFAULT )
{
OBJ_DATA *in_obj;
for( in_obj = obj; in_obj->in_obj; in_obj = in_obj->in_obj )
;
if( in_obj && in_obj->carried_by
&& get_trust( in_obj->carried_by ) < obj->level - 5 )
return TRUE;
return ( obj->item_type == ITEM_KEY
|| obj->deleted ) ? TRUE : FALSE;
}
return TRUE;
}
bool dbrwf_obj_index( FILE *fp, void *vo, db_action action )
{
OBJ_INDEX_DATA *pObj = (OBJ_INDEX_DATA *)vo;
if( action == DBACTION_FIX )
{
top_obj_index++;
pObj->area = area_last;
pObj->short_descr[0] = LOWER( pObj->short_descr[0] );
pObj->description[0] = UPPER( pObj->description[0] );
fix_progtypes( pObj->mudprogs, pObj->progtypes );
}
else if( action == DBACTION_ADDWORLD )
{
int iHash;
if( get_obj_index( pObj->vnum ) )
{
bug( "dbrwf_obj_index(FIX): vnum %d duplicated.", pObj->vnum );
return FALSE;
}
iHash = pObj->vnum % MAX_KEY_HASH;
pObj->next = obj_index_hash[iHash];
obj_index_hash[iHash] = pObj;
top_vnum_obj = UMAX( top_vnum_obj, pObj->vnum );
assign_area_vnum( pObj->vnum ); /* OLC */
}
else if( action == DBACTION_CHKDEFAULT )
return FALSE;
return TRUE;
}
bool dbrwf_pcdata( FILE *fp, void *vo, db_action action )
{
/* PC_DATA *pcdata = (PC_DATA *)vo; */
if( action == DBACTION_ADDWORLD )
{
bug( "Adding pcdata to the world on its own." );
return FALSE;
}
else if( action == DBACTION_CHKDEFAULT )
return FALSE;
return TRUE;
}
bool dbrwf_pose( FILE *fp, void *vo, db_action action )
{
/* POSE_DATA *pPose = (POSE_DATA *)vo; */
if( action == DBACTION_ADDWORLD )
{
bug( "Poses shouldn't be added to the world in this way." );
return FALSE;
}
else if( action == DBACTION_CHKDEFAULT )
return FALSE;
return TRUE;
}
bool dbrwf_quest( FILE *fp, void *vo, db_action action )
{
QUEST_DATA *pQuest = (QUEST_DATA *)vo;
if( action == DBACTION_FIX )
{
pQuest->target = NULL;
pQuest->type = QUEST_NONE;
}
else if( action == DBACTION_ADDWORLD )
{
bug( "Quests shouldn't be added to the world in this way." );
return FALSE;
}
else if( action == DBACTION_CHKDEFAULT )
return FALSE;
return TRUE;
}
bool dbrwf_religion( FILE *fp, void *vo, db_action action )
{
RELIGION_DATA *pReligion = (RELIGION_DATA *)vo;
if( action == DBACTION_ADDWORLD )
{
top_religion++;
if( !religion_first )
religion_first = pReligion;
if( religion_last )
religion_last->next = pReligion;
religion_last = pReligion;
}
else if( action == DBACTION_CHKDEFAULT )
return FALSE;
return TRUE;
}
bool dbrwf_relskill( FILE *fp, void *vo, db_action action )
{
/* RELIGION_SKILL *sk = (RELIGION_SKILL *)vo; */
if( action == DBACTION_ADDWORLD )
{
bug( "Trying to add a religion skill to the world on its own." );
return FALSE;
}
else if( action == DBACTION_CHKDEFAULT )
return FALSE;
return TRUE;
}
bool dbrwf_room( FILE *fp, void *vo, db_action action )
{
ROOM_INDEX_DATA *pRoom = (ROOM_INDEX_DATA *)vo;
if( action == DBACTION_FIX )
{
top_room++;
pRoom->area = area_last;
pRoom->people = NULL;
pRoom->contents = NULL;
fix_progtypes( pRoom->mudprogs, pRoom->progtypes );
}
else if( action == DBACTION_ADDWORLD )
{
int iHash;
if( get_room_index( pRoom->vnum ) )
{
bug( "dbrwf_room(FIX): vnum %d duplicated.", pRoom->vnum );
return FALSE;
}
iHash = pRoom->vnum % MAX_KEY_HASH;
pRoom->next = room_index_hash[iHash];
room_index_hash[iHash] = pRoom;
top_vnum_room = UMAX( top_vnum_room, pRoom->vnum );
assign_area_vnum( pRoom->vnum );
}
else if( action == DBACTION_CHKDEFAULT )
return FALSE;
return TRUE;
}
bool dbrwf_plane( FILE *fp, void *vo, db_action action )
{
PLANE_DATA *plane = (PLANE_DATA *)vo;
if( action == DBACTION_FIX )
{
/* Generate the new time and weather for that plane. */
plane->time.hour = number_range( 0, 23 );
plane->time.day = number_range( 0, 34 );
plane->time.month = number_range( 0, 16 );
plane->time.year = number_bits( 30 );
if( plane->time.hour < 5 )
plane->weather.sunlight = SUN_DARK;
else if( plane->time.hour < 6 )
plane->weather.sunlight = SUN_RISE;
else if( plane->time.hour < 19 )
plane->weather.sunlight = SUN_LIGHT;
else if( plane->time.hour < 20 )
plane->weather.sunlight = SUN_SET;
else
plane->weather.sunlight = SUN_DARK;
plane->weather.change = 0;
plane->weather.mmhg = 960;
if( plane->time.month >= 7 && plane->time.month <= 12 )
plane->weather.mmhg += number_range( 1, 50 );
else
plane->weather.mmhg += number_range( 1, 80 );
if( plane->weather.mmhg <= 980 )
plane->weather.sky = SKY_LIGHTNING;
else if( plane->weather.mmhg <= 1000 )
plane->weather.sky = SKY_RAINING;
else if( plane->weather.mmhg <= 1020 )
plane->weather.sky = SKY_CLOUDY;
else
plane->weather.sky = SKY_CLOUDLESS;
}
else if( action == DBACTION_ADDWORLD )
{
plane->next = plane_list;
plane_list = plane;
}
else if( action == DBACTION_CHKDEFAULT )
return FALSE;
return TRUE;
}
bool dbrwf_shop( FILE *fp, void *vo, db_action action )
{
SHOP_DATA *pShop = (SHOP_DATA *)vo;
if( action == DBACTION_FIX )
{
pShop->profit_buy = UMAX( 100, pShop->profit_buy );
pShop->profit_sell = UMIN( 100, pShop->profit_sell );
if( !shop_first )
shop_first = pShop;
if( shop_last )
shop_last->next = pShop;
shop_last = pShop;
pShop->next = NULL;
top_shop++;
}
else if( action == DBACTION_ADDWORLD )
{
bug( "Trying to add a shop to the world on its own." );
return FALSE;
}
else if( action == DBACTION_CHKDEFAULT )
return FALSE;
return TRUE;
}
bool dbrwf_social( FILE *fp, void *vo, db_action action )
{
SOCIAL_DATA *pSocial = (SOCIAL_DATA *)vo;
if( action == DBACTION_ADDWORLD )
{
add_social( pSocial );
top_social++;
}
else if( action == DBACTION_CHKDEFAULT )
return FALSE;
return TRUE;
}
bool dbrwf_sysinfo( FILE *fp, void *vo, db_action action )
{
struct sysinfo_type *si = (struct sysinfo_type *)vo;
if( action == DBACTION_FIX )
{
/* fix autoreboot/shutdown times */
si->down_time = (time_t)( si->levels * 3600 ) + (time_t)( si->deaths * 60 );
if( si->down_time > 0 )
{
if( si->down_time <= 300 )
si->down_time += (time_t)300;
si->down_time += current_time;
}
si->levels = 0;
si->deaths = 0;
}
else if( action == DBACTION_ADDWORLD )
{
SysInfo = si;
}
else if( action == DBACTION_CHKDEFAULT )
return FALSE;
return TRUE;
}
/*********************
* dbrwf functions for sub-sections.
*/
bool dbrwf_area_flags( FILE *fp, void *vo, db_action action )
{
int *flags = (int *)vo;
if( action == DBACTION_WRITE )
{
int i = *flags & AREA_SAVE;
fwrite_mapped_value( fp, &i, "area", FALSE );
}
else if( action == DBACTION_CHKDEFAULT )
return FALSE;
return TRUE;
}
bool dbrwf_area_plane( FILE *fp, void *vo, db_action action )
{
PLANE_DATA **pPlane = (PLANE_DATA **)vo;
if( action == DBACTION_READ )
{
temp_fread_string( fp, db_buf );
*pPlane = plane_lookup( db_buf );
}
else if( action == DBACTION_WRITE )
{
fwrite_quoted_string( fp, (*pPlane)->name );
}
else if( action == DBACTION_CHKDEFAULT )
{
return !str_cmp( "unfinished", (*pPlane)->name );
}
return TRUE;
}
bool dbrwf_char_in_room( FILE *fp, void *vo, db_action action )
{
CHAR_DATA *ch = (CHAR_DATA *)vo;
if( action == DBACTION_READ )
{
int rnum, stat;
rnum = fread_number( fp, &stat );
ch->in_room = get_room_index( rnum );
if( !ch->in_room )
ch->in_room = get_room_index( ROOM_VNUM_TEMPLE );
}
else if( action == DBACTION_WRITE )
{
fwrite_number( fp, ( ch->in_room->vnum == ROOM_VNUM_LIMBO
&& ch->was_in_room )
? ch->was_in_room->vnum : ch->in_room->vnum );
}
return TRUE;
}
bool dbrwf_char_max_hit( FILE *fp, void *vo, db_action action )
{
CHAR_DATA *ch = (CHAR_DATA *)vo;
if( action == DBACTION_WRITE )
{
fwrite_number( fp, get_max_hit( ch ) );
}
return TRUE;
}
bool dbrwf_char_max_mana( FILE *fp, void *vo, db_action action )
{
CHAR_DATA *ch = (CHAR_DATA *)vo;
if( action == DBACTION_WRITE )
{
bool found = FALSE;
int i;
fputc( '[', fp );
for( i = 0; i < MAGIC_MAX; ++i )
{
if( found )
fprintf( fp, ", " );
else
found = TRUE;
fwrite_number( fp, get_max_mana( ch, i ) );
}
fputc( ']', fp );
}
else if( action == DBACTION_CHKDEFAULT )
return FALSE;
return TRUE;
}
bool dbrwf_char_max_move( FILE *fp, void *vo, db_action action )
{
CHAR_DATA *ch = (CHAR_DATA *)vo;
if( action == DBACTION_WRITE )
{
fwrite_number( fp, get_max_move( ch ) );
}
return TRUE;
}
bool dbrwf_char_obj( FILE *fp, void *vo, db_action action )
{
return dbrwf_all_obj( fp, (CHAR_DATA *)vo, NULL, action );
}
bool dbrwf_char_parts( FILE *fp, void *vo, db_action action )
{
CHAR_DATA *ch = (CHAR_DATA *)vo;
if( action == DBACTION_CHKDEFAULT )
{
return ( ch->body_parts == race_table[get_orig_race( ch )].body_parts )
? TRUE : FALSE;
}
return TRUE;
}
bool dbrwf_char_played( FILE *fp, void *vo, db_action action )
{
CHAR_DATA *ch = (CHAR_DATA *)vo;
if( action == DBACTION_WRITE )
{
fwrite_time( fp, ch->played + current_time - ch->logon );
}
return TRUE;
}
bool dbrwf_char_position( FILE *fp, void *vo, db_action action )
{
int *pos = (int *)vo;
if( action == DBACTION_CHKDEFAULT )
return ( *pos == POS_STANDING || *pos == POS_FIGHTING )
? TRUE : FALSE;
return TRUE;
}
bool dbrwf_char_race( FILE *fp, void *vo, db_action action )
{
CHAR_DATA *ch = (CHAR_DATA *)vo;
if( action == DBACTION_WRITE )
{
int race = get_orig_race( ch );
fwrite_mapped_value( fp, &race, "race", FALSE );
}
return TRUE;
}
bool dbrwf_char_sex( FILE *fp, void *vo, db_action action )
{
CHAR_DATA *ch = (CHAR_DATA *)vo;
if( action == DBACTION_WRITE )
{
int sex = get_orig_sex( ch );
fwrite_mapped_value( fp, &sex, "sex", FALSE );
}
return TRUE;
}
bool dbrwf_check_room( FILE *fp, void *vo, db_action action )
{
int *rvnum = (int *)vo;
if( action == DBACTION_FIX )
{
if( !get_room_index( *rvnum ) )
{
bug( "Room vnum %d doesn't exist.", *rvnum );
*rvnum = -1;
}
}
return TRUE;
}
bool dbrwf_event_data( FILE *fp, void *vo, db_action action )
{
int *data = (int *)vo;
if( action == DBACTION_WRITE )
{
bool found = FALSE;
int i;
fputc( '[', fp );
for( i = 0; i < MAX_EVENT_DATA; ++i )
{
if( found )
fprintf( fp, ", " );
else
found = TRUE;
fwrite_number( fp, data[i] );
}
fputc( ']', fp );
}
return TRUE;
}
bool dbrwf_event_when( FILE *fp, void *vo, db_action action )
{
EVENT *e = (EVENT *)vo;
if( action == DBACTION_WRITE )
{
fwrite_time( fp, IS_SET( e->flags, EVENT_LOADING )
? e->when : ( e->when - SysInfo->pulse ) );
}
return TRUE;
}
bool dbrwf_high_entries( FILE *fp, void *vo, db_action action )
{
struct highest_entry **he = (struct highest_entry **)vo;
int i;
if( action == DBACTION_WRITE )
{
bool found = FALSE;
fputc( '[', fp );
for( i = 0; i < 10; ++i )
{
if( !he[i] )
break;
if( found )
fprintf( fp, ", " );
else
found = TRUE;
if( !save_complex_block( fp, global_data_table
+ get_top_entry( "HighEnt" ), he[i] ) )
return FALSE;
}
fputc( ']', fp );
}
return TRUE;
}
bool dbrwf_magic_mana( FILE *fp, void *vo, db_action action )
{
int *magic = (int *)vo;
if( action == DBACTION_WRITE )
{
bool found = FALSE;
int i;
fputc( '[', fp );
for( i = 0; i < MAGIC_MAX; ++i )
{
if( found )
fprintf( fp, ", " );
else
found = TRUE;
fwrite_number( fp, magic[i] );
}
fputc( ']', fp );
}
else if( action == DBACTION_CHKDEFAULT )
return FALSE;
return TRUE;
}
bool dbrwf_mob_parts( FILE *fp, void *vo, db_action action )
{
MOB_INDEX_DATA *pMob = (MOB_INDEX_DATA *)vo;
if( action == DBACTION_CHKDEFAULT )
{
return ( pMob->body_parts == race_table[pMob->race].body_parts )
? TRUE : FALSE;
}
return TRUE;
}
bool dbrwf_mob_spec( FILE *fp, void *vo, db_action action )
{
int *spec = (int *)vo;
if( action == DBACTION_READ )
{
temp_fread_string( fp, db_buf );
*spec = spec_lookup( db_buf );
}
else if( action == DBACTION_WRITE )
{
fwrite_quoted_string( fp, spec_table[*spec].spec_name );
}
return TRUE;
}
void fwrite_obj_values( FILE *fp, int type, int *value )
{
fputc( '[', fp );
switch( type )
{
default:
fprintf( fp, "%d, %d, %d, %d",
value[0], value[1], value[2], value[3] );
break;
case ITEM_DRINK_CON:
case ITEM_FOUNTAIN:
fprintf( fp, "%d, %d, ", value[0], value[1] );
fwrite_mapped_value( fp, &value[2], "liquid", TRUE );
fprintf( fp, ", %d", value[3] );
break;
case ITEM_PLANT:
case ITEM_PILL:
case ITEM_POTION:
case ITEM_SCROLL:
fprintf( fp, "%d, ", value[0] );
fwrite_mapped_value( fp, &value[1], "skill", FALSE );
fprintf( fp, ", " );
fwrite_mapped_value( fp, &value[2], "skill", FALSE );
fprintf( fp, ", " );
fwrite_mapped_value( fp, &value[3], "skill", FALSE );
break;
case ITEM_LIMB:
fwrite_mapped_value( fp, &value[0], "limb", TRUE );
fprintf( fp, ", 0, 0, %d", value[3] );
break;
case ITEM_STAFF:
case ITEM_WAND:
fprintf( fp, "%d, %d, %d, ",
value[0], value[1], value[2] );
fwrite_mapped_value( fp, &value[3], "skill", FALSE );
break;
case ITEM_WEAPON:
fwrite_mapped_value( fp, &value[0], "skill", FALSE );
fprintf( fp, ", %d, %d, ", value[1], value[2] );
fwrite_mapped_value( fp, &value[3], "weapon", TRUE );
break;
case ITEM_BOOK:
fwrite_mapped_value( fp, &value[0], "skill", FALSE );
fprintf( fp, ", %d, %d, %d",
value[1], value[2], value[3] );
break;
case ITEM_CORPSE_PC:
case ITEM_CORPSE_NPC:
fwrite_mapped_value( fp, &value[0], "race", TRUE );
fprintf( fp, ", %d, %d, %d",
value[1], value[2], value[3] );
break;
case ITEM_GEM:
fwrite_mapped_value( fp, &value[0], "magic", TRUE );
fprintf( fp, ", %d, %d, %d",
value[1], value[2], value[3] );
break;
case ITEM_FURNITURE:
fwrite_mapped_value( fp, &value[0], "furniture", TRUE );
fprintf( fp, ", %d, %d, %d",
value[1], value[2], value[3] );
break;
}
fputc( ']', fp );
}
/*
* This is a strange situation. Writing this data requires that the parent
* object is known. Thus the reading function is also affect, although we
* shortcut straight to the default reading method anyway (through some
* little hacks admittedly).
*/
bool dbrwf_obj_index_values( FILE *fp, void *vo, db_action action )
{
OBJ_INDEX_DATA *pObj = (OBJ_INDEX_DATA *)vo;
if( action == DBACTION_READ )
{
struct data_desc_type entry;
memcpy( &entry, object_data_table + get_desc_entry( object_data_table, "Values", 0 ),
sizeof( entry ) );
entry.target = &pObj->value[0];
return load_array( fp, &entry );
}
else if( action == DBACTION_WRITE )
{
fwrite_obj_values( fp, pObj->item_type, &pObj->value[0] );
}
return TRUE;
}
bool dbrwf_obj_obj( FILE *fp, void *vo, db_action action )
{
return dbrwf_all_obj( fp, NULL, (OBJ_DATA *)vo, action );
}
bool dbrwf_obj_values( FILE *fp, void *vo, db_action action )
{
OBJ_DATA *obj = (OBJ_DATA *)vo;
if( action == DBACTION_READ )
{
struct data_desc_type entry;
memcpy( &entry, obj_data_table + get_desc_entry( obj_data_table, "Values", 0 ),
sizeof( entry ) );
return load_array( fp, &entry );
}
else if( action == DBACTION_WRITE )
{
fwrite_obj_values( fp, obj->item_type, &obj->value[0] );
}
return TRUE;
}
bool dbrwf_obj_vnum( FILE *fp, void *vo, db_action action )
{
OBJ_INDEX_DATA **pObj = (OBJ_INDEX_DATA **)vo;
if( action == DBACTION_READ )
{
int vnum;
if( !fread_number_ii( fp, &vnum, NULL ) )
return FALSE;
*pObj = get_obj_index( vnum );
if( !*pObj )
{
bug( "Can't find object index for vnum %d.", vnum );
*pObj = get_obj_index( OBJ_VNUM_DUMMY );
}
}
else if( action == DBACTION_WRITE )
{
fwrite_number( fp, (*pObj)->vnum );
}
return TRUE;
}
bool dbrwf_pcdata_board( FILE *fp, void *vo, db_action action )
{
int *last_note = (int *)vo;
int i;
if( action == DBACTION_WRITE )
{
bool found = FALSE;
fputc( '[', fp );
for( i = 0; i < MAX_BOARD; ++i )
{
if( found )
fprintf( fp, ", " );
else
found = TRUE;
fwrite_time( fp, last_note[i] );
}
fputc( ']', fp );
}
return TRUE;
}
bool dbrwf_pcdata_multi_class( FILE *fp, void *vo, db_action action )
{
int *mc = (int *)vo;
int i;
if( action == DBACTION_WRITE )
{
bool found = FALSE;
fputc( '[', fp );
for( i = 0; i < NUM_MULTI_CLASS; ++i )
{
if( mc[i] <= CLASS_UNKNOWN )
continue;
if( found )
fprintf( fp, ", " );
else
found = TRUE;
fputc( '@', fp );
fwrite_mapped_value( fp, &i, "class", TRUE );
fprintf( fp, " %d", mc[i] );
}
fputc( ']', fp );
}
return TRUE;
}
bool dbrwf_pcdata_skills( FILE *fp, void *vo, db_action action )
{
int *skill = (int *)vo;
int i;
if( action == DBACTION_WRITE )
{
bool found = FALSE;
fputc( '[', fp );
for( i = 0; i < MAX_SKILL; ++i )
{
if( skill[i] <= 0 )
continue;
if( found )
fprintf( fp, ",\n" );
else
found = TRUE;
fputc( '@', fp );
fwrite_mapped_value( fp, &i, "skill", TRUE );
fprintf( fp, " %d", skill[i] );
}
fputc( ']', fp );
}
return TRUE;
}
bool dbrwf_room_exits( FILE *fp, void *vo, db_action action )
{
EXIT_DATA **exit = (EXIT_DATA **)vo;
int i;
if( action == DBACTION_WRITE )
{
bool found = FALSE;
fprintf( fp, "[ " );
for( i = 0; i < MAX_DIR; ++i )
{
if( !exit[i] || !exit[i]->to_room )
continue;
if( found )
fputc( ',', fp );
else
found = TRUE;
fputc( ' ', fp );
fputc( '@', fp );
fwrite_mapped_value( fp, &i, "dir", TRUE );
fputc( ' ', fp );
if( !save_complex_block( fp, global_data_table + get_top_entry( "Exit" ),
exit[i] ) )
return FALSE;
}
fprintf( fp, " ]" );
}
else if( action == DBACTION_FIX )
{
for( i = 0; i < MAX_DIR; ++i )
if( exit[i] && exit[i]->key > 0
&& !get_obj_index( exit[i]->key ) )
bug( "Warning: door with key %d that doesn't exist.",
exit[i]->key );
}
else if( action == DBACTION_CHKDEFAULT )
{
for( i = 0; i < MAX_DIR; ++i )
if( exit[i] )
return FALSE;
}
return TRUE;
}
bool dbrwf_room_resets( FILE *fp, void *vo, db_action action )
{
RESET_DATA **first = (RESET_DATA **)vo;
RESET_DATA **last = first + 1; /* Ewww, hack */
RESET_DATA *pReset;
if( action == DBACTION_READ )
{
int letter, stat;
letter = fread_letter( fp );
if( letter != '{' )
{
bug( "dbrwf_room_resets[READ]: no '{' found." );
return FALSE;
}
for( ;; )
{
if( ( letter = fread_letter( fp ) ) == '}' )
break;
if( letter == EOF )
{
bug( "dbrwf_room_resets[READ]: eof reached." );
return FALSE;
}
if( letter == '#' )
{
fread_to_eol( fp );
continue;
}
pReset = alloc_perm( sizeof( *pReset ) );
pReset->command = letter;
pReset->arg1 = fread_number( fp, &stat );
switch( letter )
{
case 'M':
case 'P':
pReset->arg2 = fread_number( fp, &stat );
break;
case 'R':
if( pReset->arg1 == 0 )
{
temp_fread_string( fp, db_buf );
if( str_cmp( db_buf, "none" ) )
pReset->arg2 = flag_value( NULL, direction_flags, db_buf );
else
pReset->arg2 = 0;
}
break;
case 'G':
case 'O':
break;
case 'E':
if( !fread_number_ii( fp, &pReset->arg2, "wear-loc" ) )
return FALSE;
break;
default:
bug( "Load_resets: bad command '%c'.", letter );
return FALSE;
}
letter = fread_letter( fp );
if( letter != ';' )
bug( "Loading resets without ';'" );
if( *last )
{
(*last)->next = pReset;
*last = pReset;
}
else
{
*first = pReset;
*last = pReset;
}
pReset->next = NULL;
top_reset++;
}
}
else if( action == DBACTION_WRITE )
{
bool verbose = FALSE;
if( IS_SET( SysInfo->flags, SYSINFO_VERBOSE_LOG ) )
verbose = TRUE;
fprintf( fp, "{\n" );
for( pReset = *first; pReset; pReset = pReset->next )
{
switch( pReset->command )
{
case 'M':
case 'P':
default:
if( verbose )
{
if( pReset->command == 'M' )
fprintf( fp, "# %s to room.\n",
kill_colour( db_buf, (get_mob_index( pReset->arg1 ))->short_descr ) );
else
fprintf( fp, "# %s inside %s.\n",
kill_colour( db_buf, (get_obj_index( pReset->arg1 ))->short_descr ),
kill_colour( db_buf, (get_obj_index( pReset->arg2 ))->short_descr ) );
}
fprintf( fp, " %c %d %d;\n", pReset->command,
pReset->arg1, pReset->arg2 );
break;
case 'O':
case 'G':
if( verbose )
{
if( pReset->command == 'O' )
fprintf( fp, "# %s to room.\n",
kill_colour( db_buf, (get_obj_index( pReset->arg1 ))->short_descr ) );
else
fprintf( fp, "#\t%s to inventory.\n",
kill_colour( db_buf, (get_obj_index( pReset->arg1 ))->short_descr ) );
}
fprintf( fp, " %c %d;\n", pReset->command, pReset->arg1 );
break;
case 'E':
if( verbose )
fprintf( fp, "#\tequip %s %s.\n",
kill_colour( db_buf, (get_obj_index( pReset->arg1 ))->short_descr ),
flag_string( wear_loc_flags, &pReset->arg2 ) );
fprintf( fp, " E %d (\"%s\");\n", pReset->arg1,
flag_string( wear_loc_flags, &pReset->arg2 ) );
break;
case 'R':
if( pReset->arg1 == 0 )
{
if( verbose )
fprintf( fp, "# Randomise exits %s.\n",
flag_string( direction_flags, &pReset->arg2 ) );
fprintf( fp, " %c %d ", pReset->command, pReset->arg1 );
fwrite_quoted_string( fp, flag_string( direction_flags,
&pReset->arg2 ) );
fprintf( fp, ";\n" );
}
else
{
if( verbose )
fprintf( fp, "# Randomise %d exits.\n", pReset->arg1 );
fprintf( fp, " %c %d;\n", pReset->command, pReset->arg1 );
}
break;
case 'D':
break;
}
}
fputc( '}', fp );
}
else if( action == DBACTION_FIX )
{
MOB_INDEX_DATA *pMob = NULL;
for( pReset = *first; pReset; pReset = pReset->next )
{
switch( pReset->command )
{
case 'M':
if( ( pMob = get_mob_index( pReset->arg1 ) ) )
{
battle_min++;
battle_max += pMob->level;
}
else
bug( "Reset: Mob %d doesn't yet exist.\n\r",
pReset->arg1 );
break;
case 'E':
if( !pMob )
bug( "Reset: No mob to equip in 'E'." );
else if( pReset->arg2 == NO_FLAG )
bug( "Reset: Bad equip location." );
break;
break;
case 'R':
if( pReset->arg1 < 0 || pReset->arg1 > 6 )
bug( "Reset: Bad randomising of exits %d,%d.",
pReset->arg1, pReset->arg2 );
break;
}
}
}
return TRUE;
}
bool dbrwf_shop_trade( FILE *fp, void *vo, db_action action )
{
int *trade = (int *)vo;
int i;
if( action == DBACTION_WRITE )
{
bool found = FALSE;
fputc( '[', fp );
for( i = 0; i < MAX_TRADE; ++i )
{
if( trade[i] < 1 )
continue;
if( found )
fprintf( fp, ", " );
else
found = TRUE;
fwrite_mapped_value( fp, trade + i, "type", FALSE );
}
fputc( ']', fp );
}
return TRUE;
}
bool dbrwf_all_affect( FILE *fp, void *vo, db_action action )
{
AFFECT_DATA **paf = (AFFECT_DATA **)vo;
if( action == DBACTION_WRITE )
{
AFFECT_DATA *af;
for( af = *paf; af; af = af->next )
{
if( af->deleted )
continue;
fprintf( fp, "Affect\t" );
if( !dbrwf_affect( fp, af, action ) )
return FALSE;
fprintf( fp, ";\n" );
}
}
return TRUE;
}
bool dbrwf_all_clan( FILE *fp, void *vo, db_action action )
{
CLAN_DATA **pClan = (CLAN_DATA **)vo;
if( action == DBACTION_READ )
{
temp_fread_string( fp, db_buf );
*pClan = clan_lookup( db_buf );
}
else if( action == DBACTION_WRITE )
{
fwrite_quoted_string( fp, (*pClan)->name );
}
return TRUE;
}
bool dbrwf_all_obj( FILE *fp, CHAR_DATA *ch, OBJ_DATA *obj_cont, db_action action )
{
OBJ_DATA **obj_list;
OBJ_DATA *obj;
OBJ_DATA obj_save;
if( ch )
{
obj_list = &ch->carrying;
}
else if( obj_cont )
{
obj_list = &obj_cont->contains;
}
else
return FALSE;
if( action == DBACTION_READ )
{
/*
* This sort of nesting ruins the static data used as a buffer, so we
* keep a copy of the data saved so far in a temporary buffer.
*/
memcpy( &obj_save, &sdb.obj, sizeof( OBJ_DATA ) );
obj = load_complex_block( fp, global_data_table
+ get_top_entry( "Obj" ) );
memcpy( &sdb.obj, &obj_save, sizeof( OBJ_DATA ) );
if( !obj )
return FALSE;
if( ch )
obj_to_char( obj, ch );
else
obj_to_obj( obj, obj_cont );
/* Now move the object from the head of the list to the back, so it
is in the same order as before */
if( obj->next_content )
{
OBJ_DATA *prev;
*obj_list = obj->next_content;
obj->next_content = NULL;
for( prev = *obj_list; prev->next_content; prev = prev->next_content )
;
prev->next_content = obj;
}
}
/*
* Writes an entire list of objects.
*/
else if( action == DBACTION_WRITE )
{
bool found = FALSE;
for( obj = *obj_list; obj; obj = obj->next_content )
{
if( dbrwf_obj( fp, obj, DBACTION_CHKDEFAULT ) )
continue;
if( found )
fprintf( fp, ";\nObj\t" );
else
found = TRUE;
memcpy( &obj_save, &sdb.obj, sizeof( OBJ_DATA ) );
save_complex_block( fp, global_data_table
+ get_top_entry( "Obj" ), obj );
memcpy( &sdb.obj, &obj_save, sizeof( OBJ_DATA ) );
}
}
return TRUE;
}
bool dbrwf_all_religion( FILE *fp, void *vo, db_action action )
{
RELIGION_DATA **pReligion = (RELIGION_DATA **)vo;
if( action == DBACTION_READ )
{
temp_fread_string( fp, db_buf );
*pReligion = religion_lookup( db_buf );
}
else if( action == DBACTION_WRITE )
{
fwrite_quoted_string( fp, (*pReligion)->name );
}
return TRUE;
}
/****************************************************************************
* Interface functions.
*
* See how EASY these are! What's even better is that these functions for
* saving data don't even require functions for reading it all back!
*/
void save_planes( void )
{
FILE *fp;
PLANE_DATA *pPlane;
if( !( fp = open_file( SYSTEM_DIR PLANE_FILE, "w", TRUE ) ) )
{
bug( "Cannot open planes file." );
return;
}
for( pPlane = plane_list; pPlane; pPlane = pPlane->next )
{
write_next_item( fp, "Plane", pPlane );
fputc( '\n', fp );
}
fprintf( fp, "\neof\n\n" );
close_file( fp );
return;
}
void save_socials( )
{
FILE *fp;
SOCIAL_DATA *pSocial;
int iHash;
fp = open_file( SYSTEM_DIR SOCIAL_FILE, "w", TRUE );
if( !fp )
{
bug( "Cannot open social file." );
return;
}
for( iHash = 0; iHash < 27; iHash++ )
{
for( pSocial = social_table[iHash]; pSocial; pSocial = pSocial->next )
{
write_next_item( fp, "Social", pSocial );
fputc( '\n', fp );
}
}
fprintf( fp, "\neof\n\n" );
close_file( fp );
return;
}
void save_religions( )
{
FILE *fp;
RELIGION_DATA *pReligion;
fp = open_file( SYSTEM_DIR RELIGION_FILE, "w", TRUE );
if( !fp )
{
bug( "Cannot open religion file." );
return;
}
for( pReligion = religion_first; pReligion; pReligion = pReligion->next )
{
write_next_item( fp, "Religion", pReligion );
fputc( '\n', fp );
}
fprintf( fp, "\neof\n\n" );
close_file( fp );
return;
}
void save_clans( )
{
FILE *fp;
CLAN_DATA *pClan;
fp = open_file( SYSTEM_DIR CLAN_FILE, "w", TRUE );
if( !fp )
{
bug( "Cannot open clan file." );
return;
}
for( pClan = clan_first; pClan; pClan = pClan->next )
{
write_next_item( fp, "Clan", pClan );
fputc( '\n', fp );
}
fprintf( fp, "\neof\n\n" );
close_file( fp );
return;
}
void load_poses( void )
{
char *p;
int i, stat;
POSE_DATA *pose;
strcpy( strArea, POSES_DIR );
p = strchr( strArea, '\0' );
for( i = 0; i < MAX_CLASS; ++i )
{
strcpy( p, class_table[i].who_name );
if( !( fpArea = open_file( strArea, "r", TRUE ) ) )
{
perror( strArea );
bug( "No pose file for the %s class.", class_table[i].name );
continue;
}
for( ;; )
{
pose = (POSE_DATA *)read_next_item( fpArea, &stat );
if( stat < 0 )
break;
pose->next = pose_table[i].first;
pose_table[i].first = pose;
pose_table[i].size++;
top_pose++;
}
close_file( fpArea );
fpArea = NULL;
}
return;
}
void save_poses( void )
{
int i;
FILE *fp;
char buf[ MAX_INPUT_LENGTH ];
POSE_DATA *pose;
char *p;
strcpy( buf, POSES_DIR );
p = strchr( buf, '\0' );
for( i = 0; i < MAX_CLASS; ++i )
{
strcpy( p, class_table[i].who_name );
if( !( fp = open_file( buf, "w", TRUE ) ) )
{
bug( "Bad pose table filename for class %s: %s",
class_table[i].name, buf );
continue;
}
for( pose = pose_table[i].first; pose; pose = pose->next )
write_next_item( fp, "Pose", pose );
fprintf( fp, "\neof\n" );
close_file( fp );
}
}