/*___________________________________________________________________________* )()( 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. */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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. */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 ); } }