/*
* $Id: db_area.c,v 1.21 1998/12/22 18:00:14 fjoe Exp $
*/
/***************************************************************************
* ANATOLIA 2.1 is copyright 1996-1997 Serdar BULUT, Ibrahim CANPUNAR *
* ANATOLIA has been brought to you by ANATOLIA consortium *
* Serdar BULUT {Chronos} bulut@rorqual.cc.metu.edu.tr *
* Ibrahim Canpunar {Asena} canpunar@rorqual.cc.metu.edu.tr *
* Murat BICER {KIO} mbicer@rorqual.cc.metu.edu.tr *
* D.Baris ACAR {Powerman} dbacar@rorqual.cc.metu.edu.tr *
* By using this code, you have agreed to follow the terms of the *
* ANATOLIA license, in the file Anatolia/anatolia.licence *
***************************************************************************/
/***************************************************************************
* Original Diku Mud copyright (C) 1990, 1991 by Sebastian Hammer, *
* Michael Seifert, Hans Henrik St{rfeldt, Tom Madsen, and Katja Nyboe. *
* *
* Merc Diku Mud improvments copyright (C) 1992, 1993 by Michael *
* Chastain, Michael Quan, and Mitchell Tse. *
* *
* In order to use any part of this Merc Diku Mud, you must comply with *
* both the original Diku license in 'license.doc' as well the Merc *
* license in 'license.txt'. In particular, you may not remove either of *
* these copyright notices. *
* *
* 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. *
***************************************************************************/
/***************************************************************************
* ROM 2.4 is copyright 1993-1995 Russ Taylor *
* ROM has been brought to you by the ROM consortium *
* Russ Taylor (rtaylor@pacinfo.com) *
* Gabrielle Taylor (gtaylor@pacinfo.com) *
* Brian Moore (rom@rom.efn.org) *
* By using this code, you have agreed to follow the terms of the *
* ROM license, in the file Rom24/doc/rom.license *
***************************************************************************/
#include <stdio.h>
#include <string.h>
#include "merc.h"
#include "obj_prog.h"
#include "db.h"
DECLARE_DBLOAD_FUN(load_area);
DECLARE_DBLOAD_FUN(load_areadata);
DECLARE_DBLOAD_FUN(load_helps);
DECLARE_DBLOAD_FUN(load_old_mob);
DECLARE_DBLOAD_FUN(load_mobiles);
DECLARE_DBLOAD_FUN(load_mobprogs);
DECLARE_DBLOAD_FUN(load_old_obj);
DECLARE_DBLOAD_FUN(load_objects);
DECLARE_DBLOAD_FUN(load_resets);
DECLARE_DBLOAD_FUN(load_rooms);
DECLARE_DBLOAD_FUN(load_shops);
DECLARE_DBLOAD_FUN(load_socials);
DECLARE_DBLOAD_FUN(load_omprogs);
DECLARE_DBLOAD_FUN(load_olimits);
DECLARE_DBLOAD_FUN(load_specials);
DECLARE_DBLOAD_FUN(load_practicers);
DECLARE_DBLOAD_FUN(load_resetmsg);
DECLARE_DBLOAD_FUN(load_aflag);
DBFUN db_load_areas[] = {
{ "AREA", load_area },
{ "AREADATA", load_areadata },
{ "HELPS", load_helps },
{ "MOBOLD", load_old_mob },
{ "MOBILES", load_mobiles },
{ "MOBPROGS", load_mobprogs },
{ "OBJOLD", load_old_obj },
{ "OBJECTS", load_objects },
{ "RESETS", load_resets },
{ "ROOMS", load_rooms },
{ "SHOPS", load_shops },
{ "SOCIALS", load_socials },
{ "OMPROGS", load_omprogs },
{ "OLIMITS", load_olimits },
{ "SPECIALS", load_specials },
{ "PRACTICERS", load_practicers },
{ "RESETMESSAGE", load_resetmsg },
{ "FLAG", load_aflag },
{ NULL }
};
AREA_DATA * area_current;
const HELP_DATA * help_greeting;
struct social_type social_table [MAX_SOCIALS];
int social_count;
static int slot_lookup (int slot);
static void convert_mobile (MOB_INDEX_DATA *pMobIndex);
DBINIT_FUN(init_area)
{
area_current = NULL;
}
/*
* Snarf an 'area' header line.
*/
DBLOAD_FUN(load_area)
{
AREA_DATA *pArea;
pArea = alloc_perm(sizeof(*pArea));
pArea->reset_first = NULL;
pArea->reset_last = NULL;
pArea->help_first = NULL;
pArea->help_last = NULL;
free_string(fread_string(fp)); /* file name */
pArea->file_name = get_filename(filename);
pArea->builders = str_empty;
pArea->security = 9;
pArea->vnum = top_area;
pArea->name = fread_string(fp);
fread_letter(fp); /* '{' */
pArea->min_level = fread_number(fp);
pArea->max_level = fread_number(fp);
fread_letter(fp); /* '}' */
pArea->credits = str_dup(fread_word(fp));
free_string(fread_string(fp));
pArea->min_vnum = fread_number(fp);
pArea->max_vnum = fread_number(fp);
pArea->age = 15;
pArea->nplayer = 0;
pArea->empty = FALSE;
pArea->count = 0;
pArea->resetmsg = NULL;
pArea->flags = 0;
if (area_first == NULL)
area_first = pArea;
if (area_last != NULL)
area_last->next = pArea;
area_last = pArea;
pArea->next = NULL;
area_current = pArea;
top_area++;
}
/* OLC
* Snarf an 'area' header line. Check this format. MUCH better. Add fields
* too.
*
* #AREAFILE
* Name { All } Locke Newbie School~
* Repop A teacher pops in the room and says, 'Repop coming!'~
* Recall 3001
* End
*/
DBLOAD_FUN(load_areadata)
{
AREA_DATA * pArea;
char * word;
bool fMatch;
pArea = alloc_perm(sizeof(*pArea));
pArea->age = 15;
pArea->nplayer = 0;
pArea->file_name = get_filename(filename);
pArea->builders = str_empty;
pArea->vnum = top_area;
pArea->name = str_dup("New Area");
pArea->security = 9; /* 9 -- Hugin */
pArea->min_vnum = 0;
pArea->max_vnum = 0;
pArea->flags = 0;
pArea->min_level = 0;
pArea->max_level = 0;
pArea->resetmsg = NULL;
/* pArea->recall = ROOM_VNUM_TEMPLE; ROM OLC */
for (; ;) {
word = feof(fp) ? "End" : fread_word(fp);
fMatch = FALSE;
switch (UPPER(word[0])) {
case 'B':
SKEY("Builders", pArea->builders);
break;
case 'C':
KEY("Clan", pArea->clan, fread_clan(fp));
SKEY("Credits", pArea->credits);
break;
case 'E':
if (!str_cmp(word, "End")) {
fMatch = TRUE;
if (area_first == NULL)
area_first = pArea;
if (area_last != NULL)
area_last->next = pArea;
area_last = pArea;
pArea->next = NULL;
area_current = pArea;
top_area++;
return;
}
break;
case 'F':
KEY("Flags", pArea->flags,
fread_fstring(area_flags, fp));
break;
case 'L':
if (!str_cmp(word, "LevelRange")) {
pArea->min_level = fread_number(fp);
pArea->max_level = fread_number(fp);
}
break;
case 'N':
SKEY("Name", pArea->name);
break;
case 'R':
MLSKEY("ResetMessage", pArea->resetmsg);
break;
case 'S':
KEY("Security", pArea->security, fread_number(fp));
break;
case 'V':
if (!str_cmp(word, "VNUMs")) {
pArea->min_vnum = fread_number(fp);
pArea->max_vnum = fread_number(fp);
}
break;
}
}
}
/*
* Snarf a help section.
*/
DBLOAD_FUN(load_helps)
{
HELP_DATA *pHelp;
int level;
const char *keyword;
if (!area_current) { /* OLC */
log("load_helps: no #AREA seen yet.");
exit(1);
}
for (; ;) {
level = fread_number(fp);
keyword = fread_string(fp);
if (keyword[0] == '$')
break;
pHelp = help_new();
pHelp->level = level;
pHelp->keyword = keyword;
pHelp->text = mlstr_fread(fp);
if (!str_cmp(pHelp->keyword, "greeting"))
help_greeting = pHelp;
help_add(area_current, pHelp);
}
}
/*
* Snarf a mob section. old style
*/
DBLOAD_FUN(load_old_mob)
{
MOB_INDEX_DATA *pMobIndex;
/* for race updating */
int race;
char name[MAX_STRING_LENGTH];
if (!area_current) { /* OLC */
log("load_old_mob: no #AREA seen yet.");
exit(1);
}
for (; ;) {
int vnum;
char letter;
int iHash;
letter = fread_letter(fp);
if (letter != '#') {
log("load_old_mob: # not found.");
exit(1);
}
vnum = fread_number(fp);
if (vnum == 0)
break;
fBootDb = FALSE;
if (get_mob_index(vnum)) {
log_printf("load_old_mob: vnum %d duplicated.", vnum);
exit(1);
}
fBootDb = TRUE;
pMobIndex = alloc_perm(sizeof(*pMobIndex));
pMobIndex->short_descr = NULL;
pMobIndex->long_descr = NULL;
pMobIndex->description = NULL;
pMobIndex->vnum = vnum;
pMobIndex->name = fread_string(fp);
pMobIndex->short_descr = mlstr_fread(fp);
pMobIndex->long_descr = mlstr_fread(fp);
pMobIndex->description = mlstr_fread(fp);
pMobIndex->act = fread_flags(fp) | ACT_NPC;
pMobIndex->affected_by = fread_flags(fp);
pMobIndex->practicer = 0;
pMobIndex->pShop = NULL;
pMobIndex->alignment = fread_number(fp);
letter = fread_letter(fp);
pMobIndex->level = fread_number(fp);
/*
* The unused stuff is for imps who want to use the old-style
* stats-in-files method.
*/
fread_number(fp); /* Unused */
fread_number(fp); /* Unused */
fread_number(fp); /* Unused */
/* 'd' */ fread_letter(fp); /* Unused */
fread_number(fp); /* Unused */
/* '+' */ fread_letter(fp); /* Unused */
fread_number(fp); /* Unused */
fread_number(fp); /* Unused */
/* 'd' */ fread_letter(fp); /* Unused */
fread_number(fp); /* Unused */
/* '+' */ fread_letter(fp); /* Unused */
fread_number(fp); /* Unused */
pMobIndex->wealth = fread_number(fp)/20;
/* xp can't be used! */ fread_number(fp); /* Unused */
pMobIndex->start_pos = fread_number(fp); /* Unused */
pMobIndex->default_pos = fread_number(fp); /* Unused */
if (pMobIndex->start_pos < POS_SLEEPING)
pMobIndex->start_pos = POS_STANDING;
if (pMobIndex->default_pos < POS_SLEEPING)
pMobIndex->default_pos = POS_STANDING;
/*
* Back to meaningful values.
*/
pMobIndex->sex = fread_number(fp);
/* compute the race BS */
one_argument(pMobIndex->name, name);
if (name[0] == '\0' || (race = rn_lookup(name)) == 0) {
RACE_DATA *r;
/* fill in with blanks */
pMobIndex->race = rn_lookup("human");
r = RACE(pMobIndex->race);
pMobIndex->affected_by = pMobIndex->affected_by |
r->aff;
pMobIndex->off_flags = OFF_DODGE | OFF_DISARM |
OFF_TRIP | ASSIST_VNUM;
pMobIndex->imm_flags = 0;
pMobIndex->res_flags = 0;
pMobIndex->vuln_flags = 0;
pMobIndex->form = FORM_EDIBLE | FORM_SENTIENT |
FORM_BIPED | FORM_MAMMAL;
pMobIndex->parts = PART_HEAD | PART_ARMS | PART_LEGS |
PART_HEART | PART_BRAINS | PART_GUTS;
}
else {
RACE_DATA *r = RACE(race);
pMobIndex->race = race;
pMobIndex->affected_by =
pMobIndex->affected_by | r->aff;
pMobIndex->off_flags = OFF_DODGE | OFF_DISARM |
OFF_TRIP | ASSIST_RACE | r->off;
pMobIndex->imm_flags = r->imm;
pMobIndex->res_flags = r->res;
pMobIndex->vuln_flags = r->vuln;
pMobIndex->form = r->form;
pMobIndex->parts = r->parts;
}
if (letter != 'S') {
log_printf("load_old_mob: vnum %d non-S.", vnum);
exit(1);
}
convert_mobile(pMobIndex); /* ROM OLC */
iHash = vnum % MAX_KEY_HASH;
pMobIndex->next = mob_index_hash[iHash];
mob_index_hash[iHash] = pMobIndex;
top_mob_index++;
/* OLC */
top_vnum_mob = top_vnum_mob < vnum ? vnum : top_vnum_mob;
vnum_check(area_current, vnum); /* OLC */
kill_table[URANGE(0, pMobIndex->level, MAX_LEVEL-1)].number++;
}
}
/*
* Load mobprogs section
*/
DBLOAD_FUN(load_mobprogs)
{
MPCODE *mpcode;
if (area_current == NULL)
{
log("load_mobprogs: no #AREA seen yet.");
exit(1);
}
for (; ;)
{
int vnum;
const char *code;
char letter;
letter = fread_letter(fp);
if (letter != '#')
{
log("load_mobprogs: # not found.");
exit(1);
}
vnum = fread_number(fp);
if (vnum == 0)
break;
if (mpcode_lookup(vnum) != NULL)
{
log_printf("load_mobprogs: vnum %d duplicated.", vnum);
exit(1);
}
code = fread_string(fp);
mpcode = mpcode_new();
mpcode->vnum = vnum;
mpcode->code = code;
mpcode_add(mpcode);
}
}
/*
* Snarf an obj section. old style
*/
DBLOAD_FUN(load_old_obj)
{
OBJ_INDEX_DATA *pObjIndex;
if (!area_current)
db_error("load_old_obj", "no #AREA seen yet.");
for (; ;) {
int vnum;
char letter;
int iHash;
letter = fread_letter(fp);
if (letter != '#')
db_error("load_old_obj", "# not found.");
vnum = fread_number(fp);
if (vnum == 0)
break;
fBootDb = FALSE;
if (get_obj_index(vnum)) {
db_error("load_old_obj", "vnum %d duplicated.", vnum);
exit(1);
}
fBootDb = TRUE;
pObjIndex = alloc_perm(sizeof(*pObjIndex));
pObjIndex->short_descr = NULL;
pObjIndex->description = NULL;
pObjIndex->vnum = vnum;
pObjIndex->reset_num = 0;
pObjIndex->name = fread_string(fp);
pObjIndex->short_descr = mlstr_fread(fp);
pObjIndex->description = mlstr_fread(fp);
/* Action description */ fread_string(fp);
pObjIndex->material = str_dup("copper");
pObjIndex->item_type = fread_number(fp);
pObjIndex->extra_flags = fread_flags(fp) | ITEM_OLDSTYLE;
pObjIndex->wear_flags = fread_flags(fp);
pObjIndex->value[0] = fread_number(fp);
pObjIndex->value[1] = fread_number(fp);
pObjIndex->value[2] = fread_number(fp);
pObjIndex->value[3] = fread_number(fp);
pObjIndex->value[4] = 0;
pObjIndex->level = 0;
pObjIndex->condition = 100;
pObjIndex->weight = fread_number(fp);
pObjIndex->cost = fread_number(fp); /* Unused */
/* Cost per day */ fread_number(fp);
pObjIndex->limit = -1;
pObjIndex->oprogs = NULL;
if (pObjIndex->item_type == ITEM_WEAPON)
if (is_name("two",pObjIndex->name)
|| is_name("two-handed",pObjIndex->name)
|| is_name("claymore",pObjIndex->name))
SET_BIT(pObjIndex->value[4], WEAPON_TWO_HANDS);
for (; ;) {
char letter;
letter = fread_letter(fp);
if (letter == 'A') {
AFFECT_DATA *paf;
paf = alloc_perm(sizeof(*paf));
paf->where = TO_OBJECT;
paf->type = -1;
paf->level = 20; /* RT temp fix */
paf->duration = -1;
paf->location = fread_number(fp);
paf->modifier = fread_number(fp);
paf->bitvector = 0;
SLIST_ADD(AFFECT_DATA,
pObjIndex->affected, paf);
top_affect++;
}
else if (letter == 'E')
ed_fread(fp, &pObjIndex->ed);
else {
xungetc(letter, fp);
break;
}
}
/* fix armors */
if (pObjIndex->item_type == ITEM_ARMOR) {
pObjIndex->value[1] = pObjIndex->value[0];
pObjIndex->value[2] = pObjIndex->value[1];
}
/*
* Translate spell "slot numbers" to internal "skill numbers."
*/
switch (pObjIndex->item_type) {
case ITEM_PILL:
case ITEM_POTION:
case ITEM_SCROLL:
pObjIndex->value[1] = slot_lookup(pObjIndex->value[1]);
pObjIndex->value[2] = slot_lookup(pObjIndex->value[2]);
pObjIndex->value[3] = slot_lookup(pObjIndex->value[3]);
pObjIndex->value[4] = slot_lookup(pObjIndex->value[4]);
break;
case ITEM_STAFF:
case ITEM_WAND:
pObjIndex->value[3] = slot_lookup(pObjIndex->value[3]);
break;
}
iHash = vnum % MAX_KEY_HASH;
pObjIndex->next = obj_index_hash[iHash];
obj_index_hash[iHash] = pObjIndex;
top_obj_index++;
/* OLC */
top_vnum_obj = top_vnum_obj < vnum ? vnum : top_vnum_obj;
vnum_check(area_current, vnum); /* OLC */
}
}
/*
* Snarf a reset section. Adjust levels of ITEM_OLDSTYLE objects on the fly.
* if loading an old-style area it's assumed that #SHOPS section
* (if any) has already been parsed
*/
DBLOAD_FUN(load_resets)
{
MOB_INDEX_DATA *pLastMob = NULL;
ROOM_INDEX_DATA *pLastRoom = NULL;
if (area_current == NULL) {
db_error("load_resets", "no #AREA seen yet.");
return;
}
for (; ;) {
RESET_DATA *pReset;
ROOM_INDEX_DATA *pRoom;
EXIT_DATA *pexit = NULL;
char letter;
OBJ_INDEX_DATA *pObj;
if ((letter = fread_letter(fp)) == 'S')
break;
if (letter == '*') {
fread_to_eol(fp);
continue;
}
pReset = alloc_perm(sizeof(*pReset));
pReset->command = letter;
/* if_flag */ fread_number(fp);
pReset->arg1 = fread_number(fp);
pReset->arg2 = fread_number(fp);
pReset->arg3 = (letter == 'G' || letter == 'R') ?
0 : fread_number(fp);
pReset->arg4 = (letter == 'P' || letter == 'M') ?
fread_number(fp) : 0;
fread_to_eol(fp);
/*
* Validate parameters.
* We're calling the index functions for the side effect.
*/
switch (letter) {
default:
db_error("load_resets", "bad command '%c'.", letter);
break;
case 'M':
if ((pLastMob = get_mob_index(pReset->arg1)) == NULL
|| (pRoom = get_room_index(pReset->arg3)) == NULL)
break;
new_reset(pRoom, pReset);
pLastRoom = pRoom;
break;
case 'O':
if ((pObj = get_obj_index(pReset->arg1)) == NULL
|| (pRoom = get_room_index(pReset->arg3)) == NULL)
break;
pObj->reset_num++;
new_reset(pRoom, pReset);
pLastRoom = pRoom;
if (IS_SET(pObj->extra_flags, ITEM_OLDSTYLE)) {
if (!pLastMob) {
db_error("load_resets",
"can't calculate obj level: "
"no mob reset yet");
break;
}
pObj->level = pObj->level < 1 ?
pLastMob->level :
UMIN(pLastMob->level, pObj->level);
}
break;
case 'P': {
OBJ_INDEX_DATA *pObjTo;
if ((pObj = get_obj_index(pReset->arg1)) == NULL
|| (pObjTo = get_obj_index(pReset->arg3)) == NULL)
break;
if (!pLastRoom) {
db_error("load_resets", "room undefined");
break;
}
new_reset(pLastRoom, pReset);
pObj->reset_num++;
if (IS_SET(pObj->extra_flags, ITEM_OLDSTYLE))
pObj->level = pObj->level < 1 ?
pObjTo->level :
UMIN(pObjTo->level, pObj->level);
break;
}
case 'G':
case 'E':
if ((pObj = get_obj_index(pReset->arg1)) == NULL)
break;
if (!pLastRoom) {
db_error("load_resets", "room undefined");
break;
}
pObj->reset_num++;
new_reset(pLastRoom, pReset);
if (IS_SET(pObj->extra_flags, ITEM_OLDSTYLE)) {
if (!pLastMob) {
db_error("load_resets",
"can't calculate obj level: "
"no mob reset yet");
break;
}
if (pLastMob->pShop) {
switch(pObj->item_type) {
default:
pObj->level =
UMAX(0, pObj->level);
break;
case ITEM_PILL:
case ITEM_POTION:
pObj->level =
UMAX(5, pObj->level);
break;
case ITEM_SCROLL:
case ITEM_ARMOR:
case ITEM_WEAPON:
pObj->level =
UMAX(10, pObj->level);
break;
case ITEM_WAND:
case ITEM_TREASURE:
pObj->level =
UMAX(15, pObj->level);
break;
case ITEM_STAFF:
pObj->level =
UMAX(20, pObj->level);
break;
}
}
else
pObj->level = pObj->level < 1 ?
pLastMob->level :
UMIN(pObj->level,
pLastMob->level);
}
break;
case 'D':
if ((pRoom = get_room_index(pReset->arg1)) == NULL)
break;
if (pReset->arg2 < 0
|| pReset->arg2 >= MAX_DIR
|| (pexit = pRoom->exit[pReset->arg2]) == NULL
|| !IS_SET(pexit->rs_flags, EX_ISDOOR)) {
db_error("load_resets",
"'D': exit %d not door.",
pReset->arg2);
break;
}
switch (pReset->arg3) {
default:
db_error("load_resets",
"'D': bad 'locks': %d.",
pReset->arg3);
/* FALLTHRU */
case 0:
break;
case 1:
SET_BIT(pexit->rs_flags, EX_CLOSED);
SET_BIT(pexit->exit_info, EX_CLOSED);
break;
case 2:
SET_BIT(pexit->rs_flags, EX_CLOSED | EX_LOCKED);
SET_BIT(pexit->exit_info,
EX_CLOSED | EX_LOCKED);
break;
}
break;
case 'R':
if ((pRoom = get_room_index(pReset->arg1)) == NULL)
break;
if (pReset->arg2 < 0 || pReset->arg2 > MAX_DIR) {
db_error("load_resets", "'R': bad exit %d.",
pReset->arg2);
break;
}
if (pRoom)
new_reset(pRoom, pReset);
break;
}
}
}
/*
* Snarf a room section.
*/
DBLOAD_FUN(load_rooms)
{
ROOM_INDEX_DATA *pRoomIndex;
if (area_current == NULL)
db_error("load_rooms", "no #AREA seen yet.");
for (; ;) {
int vnum;
char letter;
int door;
int iHash;
letter = fread_letter(fp);
if (letter != '#') {
log("load_rooms: # not found.");
exit(1);
}
vnum = fread_number(fp);
if (vnum == 0)
break;
fBootDb = FALSE;
if (get_room_index(vnum)) {
db_error("load_rooms", "vnum %d duplicated.", vnum);
exit(1);
}
fBootDb = TRUE;
pRoomIndex = alloc_perm(sizeof(*pRoomIndex));
pRoomIndex->name = NULL;
pRoomIndex->description = NULL;
pRoomIndex->owner = str_dup(str_empty);
pRoomIndex->people = NULL;
pRoomIndex->contents = NULL;
pRoomIndex->ed = NULL;
pRoomIndex->history = NULL;
pRoomIndex->area = area_current;
pRoomIndex->vnum = vnum;
pRoomIndex->name = mlstr_fread(fp);
pRoomIndex->description = mlstr_fread(fp);
/* Area number */ fread_number(fp);
pRoomIndex->room_flags = fread_flags(fp);
pRoomIndex->sector_type = fread_fword(sector_types, fp);
pRoomIndex->light = 0;
for (door = 0; door <= 5; door++)
pRoomIndex->exit[door] = NULL;
/* defaults */
pRoomIndex->heal_rate = 100;
pRoomIndex->mana_rate = 100;
pRoomIndex->affected = NULL;
pRoomIndex->affected_by = 0;
pRoomIndex->aff_next = NULL;
for (; ;) {
letter = fread_letter(fp);
if (letter == 'S')
break;
if (letter == 'H') /* healing room */
pRoomIndex->heal_rate = fread_number(fp);
else if (letter == 'M') /* mana room */
pRoomIndex->mana_rate = fread_number(fp);
else if (letter == 'D') {
EXIT_DATA *pexit;
int locks;
door = fread_number(fp);
if (door < 0 || door > 5) {
log_printf("load_rooms: vnum %d has "
"bad door number.", vnum);
exit(1);
}
pexit = alloc_perm(sizeof(*pexit));
pexit->description = mlstr_fread(fp);
pexit->keyword = fread_string(fp);
pexit->exit_info = 0;
pexit->rs_flags = 0; /* OLC */
locks = fread_flags(fp);
pexit->key = fread_number(fp);
pexit->u1.vnum = fread_number(fp);
pexit->orig_door = door; /* OLC */
if (!IS_SET(locks, EX_BITVAL)) {
switch (locks) {
case 1:
pexit->exit_info = EX_ISDOOR;
pexit->rs_flags = EX_ISDOOR;
break;
case 2:
pexit->exit_info = EX_ISDOOR |
EX_PICKPROOF;
pexit->rs_flags = EX_ISDOOR |
EX_PICKPROOF;
break;
case 3:
pexit->exit_info = EX_ISDOOR |
EX_NOPASS;
pexit->rs_flags = EX_ISDOOR |
EX_NOPASS;
break;
case 4:
pexit->exit_info = EX_ISDOOR |
EX_NOPASS |
EX_PICKPROOF;
pexit->rs_flags = EX_ISDOOR |
EX_NOPASS |
EX_PICKPROOF;
break;
}
}
else {
pexit->exit_info = locks;
pexit->rs_flags = locks;
}
pRoomIndex->exit[door] = pexit;
top_exit++;
}
else if (letter == 'E')
ed_fread(fp, &pRoomIndex->ed);
else if (letter == 'O') {
if (pRoomIndex->owner[0] != '\0') {
log("load_rooms: duplicate owner.");
exit(1);
}
pRoomIndex->owner = fread_string(fp);
}
else if (letter == 'C') {
if (pRoomIndex->clan) {
log("load_rooms: duplicate clan.");
exit(1);
}
pRoomIndex->clan = fread_clan(fp);
}
else {
log_printf("load_rooms: vnum %d has flag "
"'%c' (not 'DES').",
vnum, letter);
exit(1);
}
}
iHash = vnum % MAX_KEY_HASH;
pRoomIndex->next = room_index_hash[iHash];
room_index_hash[iHash] = pRoomIndex;
top_room++;
/* OLC */
top_vnum_room = top_vnum_room < vnum ? vnum : top_vnum_room;
vnum_check(area_current, vnum); /* OLC */
}
}
/*
* Snarf a shop section.
*/
DBLOAD_FUN(load_shops)
{
SHOP_DATA *pShop;
for (; ;) {
MOB_INDEX_DATA *pMobIndex;
int iTrade;
pShop = alloc_perm(sizeof(*pShop));
pShop->keeper = fread_number(fp);
if (pShop->keeper == 0)
break;
for (iTrade = 0; iTrade < MAX_TRADE; iTrade++)
pShop->buy_type[iTrade] = fread_number(fp);
pShop->profit_buy = fread_number(fp);
pShop->profit_sell = fread_number(fp);
pShop->open_hour = fread_number(fp);
pShop->close_hour = fread_number(fp);
fread_to_eol(fp);
pMobIndex = get_mob_index(pShop->keeper);
pMobIndex->pShop = pShop;
if (shop_first == NULL)
shop_first = pShop;
if (shop_last != NULL)
shop_last->next = pShop;
shop_last = pShop;
pShop->next = NULL;
top_shop++;
}
return;
}
/*
* Snarf spec proc declarations.
*/
DBLOAD_FUN(load_specials)
{
for (; ;)
{
MOB_INDEX_DATA *pMobIndex;
char letter;
switch (letter = fread_letter(fp))
{
default:
log_printf("load_specials: letter '%c' not *MS.", letter);
exit(1);
case 'S':
return;
case '*':
break;
case 'M':
pMobIndex = get_mob_index (fread_number (fp));
pMobIndex->spec_fun = spec_lookup (fread_word (fp));
if (pMobIndex->spec_fun == 0) {
log_printf("load_specials: 'M': vnum %d.",
pMobIndex->vnum);
exit(1);
}
break;
}
fread_to_eol(fp);
}
}
/*
* Snarf can prac declarations.
*/
DBLOAD_FUN(load_practicers)
{
for (; ;) {
MOB_INDEX_DATA *pMobIndex;
char letter;
switch (letter = fread_letter(fp)) {
default:
log_printf("load_practicers: letter '%c' not *MS.",
letter);
exit(1);
case 'S':
return;
case '*':
break;
case 'M':
pMobIndex = get_mob_index(fread_number(fp));
SET_BIT(pMobIndex->practicer,
fread_fstring(skill_groups, fp));
break;
}
fread_to_eol(fp);
}
}
DBLOAD_FUN(load_olimits)
{
int vnum;
int limit;
char ch;
OBJ_INDEX_DATA *pIndex;
for (ch = fread_letter(fp); ch != 'S'; ch = fread_letter(fp))
{
switch(ch)
{
case 'O':
vnum = fread_number(fp);
limit = fread_number(fp);
if ((pIndex = get_obj_index(vnum)) == NULL)
{
bug("Load_olimits: bad vnum %d",vnum);
exit(1);
}
else pIndex->limit = limit;
break;
case '*':
fread_to_eol(fp);
break;
default:
bug("Load_olimits: bad command '%c'",ch);
exit(1);
}
}
}
DBLOAD_FUN(load_resetmsg)
{
area_current->resetmsg = mlstr_fread(fp);
}
DBLOAD_FUN(load_aflag)
{
area_current->flags = fread_flags(fp);
}
/* snarf a socials file */
DBLOAD_FUN(load_socials)
{
for (; ;) {
struct social_type social;
int i;
if (social_count >= MAX_SOCIALS) {
bug("load_socials: social_table overflow", 0);
return;
}
for (i = 0; i < SOC_MAX; i++)
social.val[i] = NULL;
social.name = fread_string(fp);
if (!strcmp(social.name, "#")) {
free_string(social.name);
social.name = NULL;
return; /* done */
}
#if defined(social_debug)
else
fprintf(stderr,"%s\n",temp);
#endif
for (i = 0; i < SOC_MAX; i++) {
social.val[i] = fread_string(fp);
if (!strcmp(social.val[i], "#")) {
free_string(social.val[i]);
social.val[i] = NULL;
break;
}
}
social_table[social_count++] = social;
}
}
/*
* Snarf a mob section. new style
*/
DBLOAD_FUN(load_mobiles)
{
MOB_INDEX_DATA *pMobIndex;
if (!area_current)
db_error("load_mobiles", "no #AREA seen yet.");
for (; ;) {
RACE_DATA *r;
int vnum;
char letter;
int iHash;
letter = fread_letter(fp);
if (letter != '#')
db_error("load_mobiles", "# not found.");
vnum = fread_number(fp);
if (vnum == 0)
break;
fBootDb = FALSE;
if (get_mob_index(vnum)) {
db_error("load_mobiles", "vnum %d duplicated.", vnum);
exit(1);
}
fBootDb = TRUE;
pMobIndex = alloc_perm(sizeof(*pMobIndex));
pMobIndex->short_descr = NULL;
pMobIndex->long_descr = NULL;
pMobIndex->description = NULL;
pMobIndex->vnum = vnum;
newmobs++;
pMobIndex->name = fread_string(fp);
pMobIndex->short_descr = mlstr_fread(fp);
pMobIndex->long_descr = mlstr_fread(fp);
pMobIndex->description = mlstr_fread(fp);
pMobIndex->race = rn_lookup(fread_string(fp));
r = RACE(pMobIndex->race);
pMobIndex->act = fread_flags(fp) | ACT_NPC | r->act;
pMobIndex->affected_by = fread_flags(fp) | r->aff;
pMobIndex->practicer = 0;
pMobIndex->pShop = NULL;
pMobIndex->alignment = fread_number(fp);
pMobIndex->group = fread_number(fp);
pMobIndex->level = fread_number(fp);
pMobIndex->hitroll = fread_number(fp);
/* read hit dice */
pMobIndex->hit[DICE_NUMBER] = fread_number(fp);
/* 'd' */ fread_letter(fp);
pMobIndex->hit[DICE_TYPE] = fread_number(fp);
/* '+' */ fread_letter(fp);
pMobIndex->hit[DICE_BONUS] = fread_number(fp);
/* read mana dice */
pMobIndex->mana[DICE_NUMBER] = fread_number(fp);
fread_letter(fp);
pMobIndex->mana[DICE_TYPE] = fread_number(fp);
fread_letter(fp);
pMobIndex->mana[DICE_BONUS] = fread_number(fp);
/* read damage dice */
pMobIndex->damage[DICE_NUMBER] = fread_number(fp);
fread_letter(fp);
pMobIndex->damage[DICE_TYPE] = fread_number(fp);
fread_letter(fp);
pMobIndex->damage[DICE_BONUS] = fread_number(fp);
pMobIndex->dam_type = attack_lookup(fread_word(fp));
/* read armor class */
pMobIndex->ac[AC_PIERCE] = fread_number(fp) * 10;
pMobIndex->ac[AC_BASH] = fread_number(fp) * 10;
pMobIndex->ac[AC_SLASH] = fread_number(fp) * 10;
pMobIndex->ac[AC_EXOTIC] = fread_number(fp) * 10;
/* read flags and add in data from the race table */
pMobIndex->off_flags = fread_flags(fp) | r->off;
pMobIndex->imm_flags = fread_flags(fp) | r->imm;
pMobIndex->res_flags = fread_flags(fp) | r->res;
pMobIndex->vuln_flags = fread_flags(fp) | r->vuln;
/* vital statistics */
pMobIndex->start_pos = flag_value(position_table,
fread_word(fp));
pMobIndex->default_pos = flag_value(position_table,
fread_word(fp));
pMobIndex->sex = flag_value(sex_table, fread_word(fp));
pMobIndex->wealth = fread_number(fp);
pMobIndex->form = fread_flags(fp) | r->form;
pMobIndex->parts = fread_flags(fp) | r->parts;
/* size */
CHECK_POS(pMobIndex->size, size_lookup(fread_word(fp)), "size");
/* pMobIndex->size = size_lookup(fread_word(fp)); */
pMobIndex->material = str_dup(fread_word(fp));
for (; ;)
{
letter = fread_letter(fp);
if (letter == 'A') {
char *word;
long vector;
word = fread_word(fp);
vector = fread_flags(fp);
if (!str_prefix(word,"det"))
SET_BIT(pMobIndex->affected_by, vector);
}
else if (letter == 'C') {
if (pMobIndex->clan) {
log("load_objects: duplicate clan.");
exit(1);
}
pMobIndex->clan = fread_clan(fp);
}
else if (letter == 'I')
pMobIndex->invis_level = fread_number(fp);
else if (letter == 'F') {
char *word;
long vector;
word = fread_word(fp);
vector = fread_flags(fp);
if (!str_prefix(word,"act"))
REMOVE_BIT(pMobIndex->act,vector);
else if (!str_prefix(word,"aff"))
REMOVE_BIT(pMobIndex->affected_by,vector);
else if (!str_prefix(word,"off"))
REMOVE_BIT(pMobIndex->affected_by,vector);
else if (!str_prefix(word,"imm"))
REMOVE_BIT(pMobIndex->imm_flags,vector);
else if (!str_prefix(word,"res"))
REMOVE_BIT(pMobIndex->res_flags,vector);
else if (!str_prefix(word,"vul"))
REMOVE_BIT(pMobIndex->vuln_flags,vector);
else if (!str_prefix(word,"for"))
REMOVE_BIT(pMobIndex->form,vector);
else if (!str_prefix(word,"par"))
REMOVE_BIT(pMobIndex->parts,vector);
else
db_error("flag remove", "flag not found.");
}
else if ( letter == 'M' )
{
MPTRIG *mptrig;
char *word;
int type;
const char *phrase;
int vnum;
word = fread_word(fp);
if ((type = flag_value(mptrig_types, word)) == 0)
db_error("load_mobiles", "vnum %d: "
"'%s': invalid mob prog trigger",
pMobIndex->vnum, word);
vnum = fread_number(fp);
phrase = fread_string(fp);
mptrig = mptrig_new(type, phrase, vnum);
mptrig_add(pMobIndex, mptrig);
free_string(phrase);
}
else
{
xungetc(letter,fp);
break;
}
}
iHash = vnum % MAX_KEY_HASH;
pMobIndex->next = mob_index_hash[iHash];
mob_index_hash[iHash] = pMobIndex;
top_mob_index++;
top_vnum_mob = top_vnum_mob < vnum ? vnum : top_vnum_mob; /* OLC */
vnum_check(area_current, vnum); /* OLC */
kill_table[URANGE(0, pMobIndex->level, MAX_LEVEL-1)].number++;
}
}
/*
* Snarf an obj section. new style
*/
DBLOAD_FUN(load_objects)
{
OBJ_INDEX_DATA *pObjIndex;
if (!area_current)
db_error("load_objects", "no #AREA seen yet.");
for (; ;)
{
char *p;
int vnum;
char letter;
int iHash;
letter = fread_letter(fp);
if (letter != '#')
db_error("load_objects", "# not found.");
vnum = fread_number(fp);
if (vnum == 0)
break;
fBootDb = FALSE;
if (get_obj_index(vnum)) {
db_error("load_objects", "vnum %d duplicated.", vnum);
exit(1);
}
fBootDb = TRUE;
pObjIndex = alloc_perm(sizeof(*pObjIndex));
pObjIndex->short_descr = NULL;
pObjIndex->description = NULL;
pObjIndex->vnum = vnum;
pObjIndex->reset_num = 0;
newobjs++;
pObjIndex->name = fread_string(fp);
pObjIndex->short_descr = mlstr_fread(fp);
pObjIndex->description = mlstr_fread(fp);
pObjIndex->material = fread_string(fp);
pObjIndex->oprogs = NULL;
p = fread_word(fp);
pObjIndex->item_type = item_lookup(p);
if (pObjIndex->item_type < 0)
log_printf("load_objects: vnum %d: unknown item type '%s'",
pObjIndex->vnum, p);
/* pObjIndex->item_type = item_lookup(fread_word(fp)); */
pObjIndex->extra_flags = fread_flags(fp);
pObjIndex->wear_flags = fread_flags(fp);
switch(pObjIndex->item_type)
{
case ITEM_WEAPON:
pObjIndex->value[0] = flag_value(weapon_class,
fread_word(fp));
pObjIndex->value[1] = fread_number(fp);
pObjIndex->value[2] = fread_number(fp);
pObjIndex->value[3] = attack_lookup(fread_word(fp));
pObjIndex->value[4] = fread_flags(fp);
break;
case ITEM_CONTAINER:
pObjIndex->value[0] = fread_number(fp);
pObjIndex->value[1] = fread_flags(fp);
pObjIndex->value[2] = fread_number(fp);
pObjIndex->value[3] = fread_number(fp);
pObjIndex->value[4] = fread_number(fp);
break;
case ITEM_DRINK_CON:
case ITEM_FOUNTAIN:
pObjIndex->value[0] = fread_number(fp);
pObjIndex->value[1] = fread_number(fp);
CHECK_POS(pObjIndex->value[2], liq_lookup(fread_word(fp)), "liq_lookup" );
/* pObjIndex->value[2] = liq_lookup(fread_word(fp)); */
pObjIndex->value[3] = fread_number(fp);
pObjIndex->value[4] = fread_number(fp);
break;
case ITEM_WAND:
case ITEM_STAFF:
pObjIndex->value[0] = fread_number(fp);
pObjIndex->value[1] = fread_number(fp);
pObjIndex->value[2] = fread_number(fp);
pObjIndex->value[3] = sn_lookup(fread_word(fp));
pObjIndex->value[4] = fread_number(fp);
break;
case ITEM_POTION:
case ITEM_PILL:
case ITEM_SCROLL:
pObjIndex->value[0] = fread_number(fp);
pObjIndex->value[1] = sn_lookup(fread_word(fp));
pObjIndex->value[2] = sn_lookup(fread_word(fp));
pObjIndex->value[3] = sn_lookup(fread_word(fp));
pObjIndex->value[4] = sn_lookup(fread_word(fp));
break;
default:
pObjIndex->value[0] = fread_flags(fp);
pObjIndex->value[1] = fread_flags(fp);
pObjIndex->value[2] = fread_flags(fp);
pObjIndex->value[3] = fread_flags(fp);
pObjIndex->value[4] = fread_flags(fp);
break;
}
pObjIndex->level = fread_number(fp);
pObjIndex->weight = fread_number(fp);
pObjIndex->cost = fread_number(fp);
pObjIndex->limit = -1;
/* condition */
letter = fread_letter(fp);
switch (letter)
{
case ('P') : pObjIndex->condition = 100; break;
case ('G') : pObjIndex->condition = 90; break;
case ('A') : pObjIndex->condition = 75; break;
case ('W') : pObjIndex->condition = 50; break;
case ('D') : pObjIndex->condition = 25; break;
case ('B') : pObjIndex->condition = 10; break;
case ('R') : pObjIndex->condition = 0; break;
default: pObjIndex->condition = 100; break;
}
for (; ;)
{
char letter;
letter = fread_letter(fp);
if (letter == 'A')
{
AFFECT_DATA *paf;
paf = alloc_perm(sizeof(*paf));
paf->where = TO_OBJECT;
paf->type = -1;
paf->level = pObjIndex->level;
paf->duration = -1;
paf->location = fread_number(fp);
paf->modifier = fread_number(fp);
paf->bitvector = 0;
SLIST_ADD(AFFECT_DATA, pObjIndex->affected, paf);
top_affect++;
}
else if (letter == 'C') {
if (pObjIndex->clan) {
log("load_objects: duplicate clan.");
exit(1);
}
pObjIndex->clan = fread_clan(fp);
}
else if (letter == 'F')
{
AFFECT_DATA *paf;
paf = alloc_perm(sizeof(*paf));
letter = fread_letter(fp);
switch (letter)
{
case 'A':
paf->where = TO_AFFECTS;
break;
case 'I':
paf->where = TO_IMMUNE;
break;
case 'R':
paf->where = TO_RESIST;
break;
case 'V':
paf->where = TO_VULN;
break;
case 'D':
paf->where = TO_AFFECTS;
break;
default:
db_error("load_objects", "vnum %d: '%c': bad where on flag.",
pObjIndex->vnum, letter);
}
paf->type = -1;
paf->level = pObjIndex->level;
paf->duration = -1;
paf->location = fread_number(fp);
paf->modifier = fread_number(fp);
paf->bitvector = fread_flags(fp);
SLIST_ADD(AFFECT_DATA, pObjIndex->affected, paf);
top_affect++;
}
else if (letter == 'E')
ed_fread(fp, &pObjIndex->ed);
else
{
xungetc(letter, fp);
break;
}
}
iHash = vnum % MAX_KEY_HASH;
pObjIndex->next = obj_index_hash[iHash];
obj_index_hash[iHash] = pObjIndex;
top_obj_index++;
top_vnum_obj = top_vnum_obj < vnum ? vnum : top_vnum_obj; /* OLC */
vnum_check(area_current, vnum); /* OLC */
}
}
/*
* Snarf a mprog section
*/
DBLOAD_FUN(load_omprogs)
{
char progtype[MAX_INPUT_LENGTH];
char progname[MAX_INPUT_LENGTH];
for (; ;) {
OBJ_INDEX_DATA *pObjIndex;
char letter;
switch (letter = fread_letter(fp)) {
default:
db_error("load_omprogs", "letter '%c' not *IMS.", letter);
exit(1);
case 'S':
return;
case '*':
break;
case 'O':
pObjIndex = get_obj_index (fread_number (fp));
strcpy(progtype, fread_word(fp));
strcpy(progname, fread_word(fp));
oprog_set(pObjIndex, progtype, progname);
break;
case 'M':
/* will be removed at all after new mob prog code integration */
break;
}
fread_to_eol(fp);
}
}
/*
* Lookup a skill by slot number.
* Used for object loading.
*/
static int slot_lookup(int slot)
{
int sn;
if (slot <= 0)
return -1;
for (sn = 0; sn < skills.nused; sn++)
if (slot == SKILL(sn)->slot)
return sn;
db_error("slot_lookup", "bad slot %d.", slot);
return -1;
}
/*****************************************************************************
Name: convert_mobile
Purpose: Converts an old format mob into new format
Called by: load_old_mob (db.c).
Note: Dug out of create_mob (db.c)
Author: Hugin
****************************************************************************/
void convert_mobile(MOB_INDEX_DATA *pMobIndex)
{
int i;
int type, number, bonus;
int level;
level = pMobIndex->level;
pMobIndex->act |= ACT_WARRIOR;
/*
* Calculate hit dice. Gives close to the hitpoints
* of old format mobs created with create_mob() (db.c)
* A high number of dice makes for less variance in mobiles
* hitpoints.
* (might be a good idea to reduce the max number of dice)
*
* The conversion below gives:
level: dice min max diff mean
1: 1d2+6 7 (7) 8 (8) 1 (1) 8 (8)
2: 1d3+15 16 (15) 18 (18) 2 (3) 17 (17)
3: 1d6+24 25 (24) 30 (30) 5 (6) 27 (27)
5: 1d17+42 43 (42) 59 (59) 16 (17) 51 (51)
10: 3d22+96 99 (95) 162 (162) 63 (67) 131 ()
15: 5d30+161 166 (159) 311 (311) 145 (150) 239 ()
30: 10d61+416 426 (419) 1026 (1026) 600 (607) 726 ()
50: 10d169+920 930 (923) 2610 (2610) 1680 (1688) 1770 ()
The values in parenthesis give the values generated in create_mob.
Diff = max - min. Mean is the arithmetic mean.
(hmm.. must be some roundoff error in my calculations.. smurfette got
1d6+23 hp at level 3 ? -- anyway.. the values above should be
approximately right..)
*/
type = level*level*27/40;
number = UMIN(type/40 + 1, 10); /* how do they get 11 ??? */
type = UMAX(2, type/number);
bonus = UMAX(0, level*(8 + level)*.9 - number*type);
pMobIndex->hit[DICE_NUMBER] = number;
pMobIndex->hit[DICE_TYPE] = type;
pMobIndex->hit[DICE_BONUS] = bonus;
pMobIndex->mana[DICE_NUMBER] = level;
pMobIndex->mana[DICE_TYPE] = 10;
pMobIndex->mana[DICE_BONUS] = 100;
/*
* Calculate dam dice. Gives close to the damage
* of old format mobs in damage() (fight.c)
*/
type = level*7/4;
number = UMIN(type/8 + 1, 5);
type = UMAX(2, type/number);
bonus = UMAX(0, level*9/4 - number*type);
pMobIndex->damage[DICE_NUMBER] = number;
pMobIndex->damage[DICE_TYPE] = type;
pMobIndex->damage[DICE_BONUS] = bonus;
switch (number_range(1, 3)) {
case (1): pMobIndex->dam_type = 3; break; /* slash */
case (2): pMobIndex->dam_type = 7; break; /* pound */
case (3): pMobIndex->dam_type = 11; break; /* pierce */
}
for (i = 0; i < 3; i++)
pMobIndex->ac[i]= interpolate(level, 100, -100);
pMobIndex->ac[3] = interpolate(level, 100, 0); /* exotic */
pMobIndex->wealth /= 100;
pMobIndex->size = SIZE_MEDIUM;
pMobIndex->material = str_dup("none");
++newmobs;
}