/**************************************************************************
* Original Diku Mud copyright (C) 1990, 1991 by Sebastian Hammer, *
* Michael Seifert, Hans Henrik St{rfeldt, Tom Madsen, and Katja Nyboe. *
* *
* Merc Diku Mud improvements 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 *
* benefiting. We hope that you share your changes too. What goes *
* around, comes around. *
***************************************************************************
* ROM 2.4 is copyright 1993-1998 Russ Taylor *
* ROM has been brought to you by the ROM consortium *
* Russ Taylor (rtaylor@hypercube.org) *
* Gabrielle Taylor (gtaylor@hypercube.org) *
* Brian Moore (zump@rom.org) *
* By using this code, you have agreed to follow the terms of the *
* ROM license, in the file Rom24/doc/rom.license *
***************************************************************************
* 1stMud ROM Derivative (c) 2001-2004 by Markanth *
* http://www.firstmud.com/ <markanth@firstmud.com> *
* By using this code you have agreed to follow the term of *
* the 1stMud license in ../doc/1stMud/LICENSE *
***************************************************************************/
#define IN_DB_C 1
#include "merc.h"
#include "recycle.h"
#include "tables.h"
#include "olc.h"
#include "interp.h"
#include "data_table.h"
#include "vnums.h"
#include "special.h"
#undef IN_DB_C
AreaData *current_area;
FileData *fpArea;
char strArea[MAX_INPUT_LENGTH];
Proto(void init_mm, (void));
Declare_Boot_F(load_old_area);
Declare_Boot_F(load_area);
Declare_Boot_F(load_old_helps);
Declare_Boot_F(load_old_mob);
Declare_Boot_F(load_old_obj);
Declare_Boot_F(load_resets);
Declare_Boot_F(load_rooms);
Declare_Boot_F(load_shops);
Declare_Boot_F(load_specials);
Declare_Boot_F(load_mobprogs);
Declare_Boot_F(load_objprogs);
Declare_Boot_F(load_roomprogs);
Proto(void fix_objprogs, (void));
Proto(void fix_roomprogs, (void));
Proto(void init_area_weather, (void));
Proto(void fix_exits, (void));
Proto(void fix_mobprogs, (void));
Proto(void build_player_index, (void));
DataTable time_data_table[] = {
{"hour", FIELD_INT, (void *) &time_zero.hour, NULL, NULL, olced_int,
NULL},
{"day", FIELD_INT, (void *) &time_zero.day, NULL, NULL, olced_int, NULL},
{
"month", FIELD_INT, (void *) &time_zero.month, NULL, NULL, olced_int,
NULL},
{"year", FIELD_INT, (void *) &time_zero.year, NULL, NULL, olced_int,
NULL},
{"sunlight", FIELD_INT, (void *) &time_zero.sunlight, NULL, NULL,
olced_int, NULL},
{NULL, (field_t) - 1, NULL, NULL, NULL, NULL, NULL}
};
TableSave_Fun(rw_time_data)
{
rw_single(type, TIME_FILE, time);
}
void setup_myrlims(void)
{
#ifdef HAVE_SETRLIMIT
#define getsetlimit(res) \
do { \
struct rlimit limit; \
getrlimit(res, &limit); \
limit.rlim_cur = limit.rlim_max = RLIM_INFINITY; \
setrlimit(res, &limit); \
} while(0)
log_string("Setting user limits...");
getsetlimit(RLIMIT_CPU);
getsetlimit(RLIMIT_FSIZE);
getsetlimit(RLIMIT_DATA);
getsetlimit(RLIMIT_STACK);
getsetlimit(RLIMIT_CORE);
#ifdef RLIMIT_RSS
getsetlimit(RLIMIT_RSS);
#endif
#if 0
getsetlimit(RLIMIT_NPROC);
#endif
#if 0
getsetlimit(RLIMIT_NOFILE);
#endif
#ifdef RLIMIT_MEMLOCK
getsetlimit(RLIMIT_MEMLOCK);
#endif
#ifdef RLIMIT_AS
getsetlimit(RLIMIT_AS);
#endif
#endif
}
void load_area_db(void)
{
FileData *fpList;
const struct bootf_type
{
const char *header;
Boot_F *fun;
} bootf_table[] =
{
{
"AREA", load_old_area}
,
{
"AREADATA", load_area}
,
{
"HELPS", load_old_helps}
,
{
"MOBOLD", load_old_mob}
,
{
"MOBILES", load_mobiles}
,
{
"MOBPROGS", load_mobprogs}
,
{
"OBJPROGS", load_objprogs}
,
{
"ROOMPROGS", load_roomprogs}
,
{
"OBJOLD", load_old_obj}
,
{
"OBJECTS", load_objects}
,
{
"RESETS", load_resets}
,
{
"ROOMS", load_rooms}
,
{
"SHOPS", load_shops}
,
{
"SPECIALS", load_specials}
,
{
NULL, NULL}
};
if ((fpList = f_open(AREA_LIST, "r")) == NULL)
{
log_error(AREA_LIST);
exit(1);
}
while (true)
{
char buf[MIL];
strcpy(strArea, read_word(fpList));
if (strArea[0] == '$')
break;
sprintf(buf, AREA_DIR "%s", strArea);
if ((fpArea = f_open(buf, "r")) == NULL)
{
log_error(strArea);
exit(1);
}
logf("Loading %s...", strArea);
current_area = NULL;
while (true)
{
char *word;
int i;
if (read_letter(fpArea) != '#')
{
bug("Boot_db: # not found.");
exit(1);
}
word = read_word(fpArea);
if (word[0] == '$')
break;
for (i = 0; bootf_table[i].header != NULL; i++)
{
if (!str_cmp(word, bootf_table[i].header))
break;
}
if (bootf_table[i].fun != NULL)
{
(*bootf_table[i].fun) (fpArea);
}
else
{
bug("Boot_db: bad section name.");
exit(1);
}
}
f_close(fpArea);
}
f_close(fpList);
fpArea = NULL;
logf("Loaded %d areas.", top_area);
}
void boot_db(void)
{
run_level = RUNLEVEL_BOOTING;
setup_myrlims();
init_mm();
#ifndef DISABLE_MYSQL
init_db_first_run();
#endif
rw_time_data(act_read);
rw_class_data(act_read);
rw_skill_data(act_read);
rw_group_data(act_read);
rw_cmd_data(act_read);
rw_race_data(act_read);
rw_clan_data(act_read);
rw_deity_data(act_read);
rw_color_data(act_read);
rw_color_template_data(act_read);
#ifndef DISABLE_MYSQL
db_load_areas();
#else
load_area_db();
#endif
rw_help_data(act_read);
fix_exits();
fix_mobprogs();
fix_objprogs();
fix_roomprogs();
run_level = RUNLEVEL_SAFE_BOOT;
convert_objects();
area_update();
build_player_index();
rw_note_data(act_read);
rw_ban_data(act_read);
rw_song_data(act_read);
rw_disabled_data(act_read);
rw_social_data(act_read);
rw_change_data(act_read);
rw_gquest_data(act_read);
rw_war_data(act_read);
rw_mbr_data(act_read);
rw_channel_data(act_read);
rw_name_profile_data(act_read);
#ifndef DISABLE_WEBSRV
init_www_history();
#endif
examine_crash_log();
load_corpses();
load_room_objs();
rw_wpwd_data(act_read);
init_area_weather();
#ifndef DISABLE_MYSQL
finish_db_first_run();
#endif
logf("Stored %d Areas, %d Rooms, %d Mobs, %d Objects & %d Helps.",
top_area, top_room_index, top_char_index, top_obj_index, top_help);
logf("Finished. Bootup took %s.",
timestr(getcurrenttime() - boot_time, false));
#ifndef DISABLE_WEBSRV
if (web_is_connected())
logf("Integrated world wide web server running on port %d.", webport);
#endif
return;
}
Proto(void convert_area_credits, (AreaData *));
Boot_Fun(load_old_area)
{
AreaData *pArea;
pArea = new_area();
read_strfree(fp, &pArea->file_name);
pArea->area_flags = AREA_LOADING;
read_strfree(fp, &pArea->name);
read_strfree(fp, &pArea->credits);
pArea->min_vnum = read_number(fp);
pArea->max_vnum = read_number(fp);
add_area(pArea);
current_area = pArea;
convert_area_credits(pArea);
top_area++;
return;
}
Boot_Fun(load_area)
{
AreaData *pArea;
const char *word;
bool fMatch;
pArea = new_area();
replace_str(&pArea->file_name, strArea);
while (true)
{
word = f_eof(fp) ? "End" : read_word(fp);
fMatch = false;
switch (toupper(word[0]))
{
case 'L':
Key_Str("LvlComment", pArea->lvl_comment);
break;
case 'M':
Key("MinLevel", pArea->min_level, read_number(fp));
Key("MaxLevel", pArea->max_level, read_number(fp));
break;
case 'N':
Key_Str("Name", pArea->name);
break;
case 'F':
Key("Flags", pArea->area_flags, read_flag(fp));
break;
case 'R':
Key("ResetMsg", pArea->resetmsg, read_string(fp));
Key("Recall", pArea->recall, read_number(fp));
break;
case 'S':
Key("Security", pArea->security, read_number(fp));
Key("Sound", pArea->sound, read_sound(fp));
if (!str_cmp(word, "Stats"))
{
pArea->kills = read_long(fp);
pArea->deaths = read_long(fp);
fMatch = true;
break;
}
break;
case 'V':
Key("Version", pArea->version, read_number(fp));
if (!str_cmp(word, "VNUMs"))
{
pArea->min_vnum = read_number(fp);
pArea->max_vnum = read_number(fp);
fMatch = true;
break;
}
break;
case 'E':
if (!str_cmp(word, "End"))
{
fMatch = true;
add_area(pArea);
current_area = pArea;
convert_area_credits(pArea);
return;
}
break;
case 'B':
Key_Str("Builders", pArea->builders);
break;
case 'C':
Key_Str("Credits", pArea->credits);
if (!str_cmp(word, "Climate"))
{
pArea->weather.climate_temp = read_number(fp);
pArea->weather.climate_precip = read_number(fp);
pArea->weather.climate_wind = read_number(fp);
fMatch = true;
break;
}
Key_SFun("Clan", pArea->clan, clan_lookup);
break;
}
}
}
void assign_area_vnum(vnum_t vnum)
{
if (current_area->min_vnum == 0 || current_area->max_vnum == 0)
current_area->min_vnum = current_area->max_vnum = vnum;
if (vnum != Range(current_area->min_vnum, vnum, current_area->max_vnum))
{
if (vnum < current_area->min_vnum)
current_area->min_vnum = vnum;
else
current_area->max_vnum = vnum;
}
return;
}
Boot_Fun(load_old_helps)
{
HelpData *pHelp;
int level;
const char *keyword;
while (true)
{
level = read_number(fp);
keyword = read_string(fp);
if (keyword[0] == '$')
break;
pHelp = new_help();
pHelp->level = level;
pHelp->keyword = keyword;
read_strfree(fp, &pHelp->text);
add_help(pHelp);
}
return;
}
Boot_Fun(load_old_mob)
{
CharIndex *pMobIndex;
RaceData *race;
char name[MAX_STRING_LENGTH];
if (!current_area)
{
bug("Load_mobiles: no #AREA seen yet.");
exit(1);
}
while (true)
{
vnum_t vnum;
char letter;
int iHash;
letter = read_letter(fp);
if (letter != '#')
{
bug("Load_mobiles: # not found.");
exit(1);
}
vnum = read_number(fp);
if (vnum == 0)
break;
run_level = RUNLEVEL_SAFE_BOOT;
if (get_char_index(vnum) != NULL)
{
bugf("Load_mobiles: vnum %ld duplicated.", vnum);
exit(1);
}
run_level = RUNLEVEL_BOOTING;
pMobIndex = new_char_index();
pMobIndex->vnum = vnum;
pMobIndex->area = current_area;
pMobIndex->new_format = false;
read_strfree(fp, &pMobIndex->player_name);
read_strfree(fp, &pMobIndex->short_descr);
read_strfree(fp, &pMobIndex->long_descr);
read_strfree(fp, &pMobIndex->description);
pMobIndex->act = read_flag(fp) | ACT_IS_NPC;
pMobIndex->affected_by = read_flag(fp);
pMobIndex->pShop = NULL;
pMobIndex->alignment = read_number(fp);
letter = read_letter(fp);
pMobIndex->level = read_number(fp);
read_number(fp);
read_number(fp);
read_number(fp);
read_letter(fp);
read_number(fp);
read_letter(fp);
read_number(fp);
read_number(fp);
read_letter(fp);
read_number(fp);
read_letter(fp);
read_number(fp);
pMobIndex->wealth = read_number(fp) / 20;
read_number(fp);
pMobIndex->start_pos = read_enum(position_t, fp);
pMobIndex->default_pos = read_enum(position_t, fp);
if (pMobIndex->start_pos < POS_SLEEPING)
pMobIndex->start_pos = POS_STANDING;
if (pMobIndex->default_pos < POS_SLEEPING)
pMobIndex->default_pos = POS_STANDING;
pMobIndex->sex = read_enum(sex_t, fp);
one_argument(pMobIndex->player_name, name);
if (NullStr(name) || (race = race_lookup(name)) == NULL)
{
pMobIndex->race = default_race;
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
{
pMobIndex->race = race;
pMobIndex->off_flags =
OFF_DODGE | OFF_DISARM | OFF_TRIP | ASSIST_RACE | race->off;
pMobIndex->imm_flags = race->imm;
pMobIndex->res_flags = race->res;
pMobIndex->vuln_flags = race->vuln;
pMobIndex->form = race->form;
pMobIndex->parts = race->parts;
}
if (letter != 'S')
{
bugf("Load_mobiles: vnum %ld non-S.", vnum);
exit(1);
}
convert_mobile(pMobIndex);
iHash = vnum % MAX_KEY_HASH;
LinkSingle(pMobIndex, char_index_hash[iHash], next);
top_vnum_mob = Max(top_vnum_mob, vnum);
assign_area_vnum(vnum);
kill_table[Range(0, pMobIndex->level, MAX_LEVEL - 1)].number++;
}
return;
}
Boot_Fun(load_old_obj)
{
ObjIndex *pObjIndex;
if (!current_area)
{
bug("Load_objects: no #AREA seen yet.");
exit(1);
}
while (true)
{
vnum_t vnum;
char letter;
int iHash = -1;
const char *str;
letter = read_letter(fp);
if (letter != '#')
{
bug("Load_objects: # not found.");
exit(1);
}
vnum = read_number(fp);
if (vnum == 0)
break;
run_level = RUNLEVEL_SAFE_BOOT;
if (get_obj_index(vnum) != NULL)
{
bugf("Load_objects: vnum %ld duplicated.", vnum);
exit(1);
}
run_level = RUNLEVEL_BOOTING;
pObjIndex = new_obj_index();
pObjIndex->vnum = vnum;
pObjIndex->area = current_area;
pObjIndex->new_format = false;
pObjIndex->reset_num = 0;
read_strfree(fp, &pObjIndex->name);
str = read_string(fp);
replace_str(&pObjIndex->short_descr, Upper(str));
free_string(str);
str = read_string(fp);
replace_str(&pObjIndex->description, Upper(str));
free_string(str);
read_string(fp);
pObjIndex->item_type = read_enum(item_t, fp);
pObjIndex->extra_flags = read_flag(fp);
pObjIndex->wear_flags = read_flag(fp);
pObjIndex->value[0] = read_number(fp);
pObjIndex->value[1] = read_number(fp);
pObjIndex->value[2] = read_number(fp);
pObjIndex->value[3] = read_number(fp);
pObjIndex->value[4] = 0;
pObjIndex->level = 0;
pObjIndex->condition = 100;
pObjIndex->weight = read_number(fp);
pObjIndex->cost = read_number(fp);
read_number(fp);
if (pObjIndex->item_type == ITEM_WEAPON)
{
if (is_name("two", pObjIndex->name)
|| is_name("two-handed", pObjIndex->name)
|| is_name("claymore", pObjIndex->name))
SetBit(pObjIndex->value[4], WEAPON_TWO_HANDS);
}
while (iHash == -1)
{
letter = read_letter(fp);
switch (letter)
{
case 'A':
{
AffectData *paf;
paf = new_affect();
paf->where = TO_OBJECT;
paf->type = -1;
paf->level = 20;
paf->duration = -1;
paf->location = read_enum(apply_t, fp);
paf->modifier = read_number(fp);
paf->bitvector = 0;
Link(paf, pObjIndex->affect, next, prev);
}
break;
case 'E':
{
ExDescrData *ed;
ed = new_ed();
read_strfree(fp, &ed->keyword);
read_strfree(fp, &ed->description);
Link(ed, pObjIndex->ed, next, prev);
}
break;
default:
{
iHash = vnum % MAX_KEY_HASH;
f_ungetc(letter, fp);
break;
}
}
}
if (pObjIndex->item_type == ITEM_ARMOR)
{
pObjIndex->value[1] = pObjIndex->value[0];
pObjIndex->value[2] = pObjIndex->value[1];
}
LinkSingle(pObjIndex, obj_index_hash[iHash], next);
top_vnum_obj = Max(top_vnum_obj, vnum);
assign_area_vnum(vnum);
}
return;
}
Boot_Fun(load_resets)
{
ResetData *pReset;
ExitData *pexit;
RoomIndex *pRoomIndex;
vnum_t rVnum = -1;
flag_t arg5;
if (!current_area)
{
bug("Load_resets: no #AREA seen yet.");
exit(1);
}
while (true)
{
char letter;
if ((letter = read_letter(fp)) == 'S')
break;
if (letter == '*')
{
read_to_eol(fp);
continue;
}
pReset = new_reset();
pReset->command = letter;
read_number(fp);
pReset->arg1 = read_number(fp);
pReset->arg2 = read_number(fp);
pReset->arg3 = (letter == 'G'
|| (current_area->version < 3
&& letter == 'R')) ? 0 : read_number(fp);
pReset->arg4 = (letter == 'P' || letter == 'M') ? read_number(fp) : 0;
arg5 = (letter == 'F') ? read_flag(fp) : 0;
read_to_eol(fp);
switch (pReset->command)
{
case 'M':
case 'O':
rVnum = pReset->arg3;
break;
case 'P':
case 'G':
case 'E':
break;
case 'D':
pRoomIndex = get_room_index((rVnum = pReset->arg1));
if (pReset->arg2 < 0 || pReset->arg2 >= MAX_DIR || !pRoomIndex
|| !(pexit = pRoomIndex->exit[pReset->arg2])
|| !IsSet(pexit->rs_flags, EX_ISDOOR))
{
bugf("Load_resets: 'D': exit %d, room %ld not door.",
pReset->arg2, pReset->arg1);
exit(1);
}
switch (pReset->arg3)
{
default:
bugf("Load_resets: 'D': bad 'locks': %ld.",
pReset->arg3);
break;
case 0:
break;
case 1:
SetBit(pexit->rs_flags, EX_CLOSED);
SetBit(pexit->exit_info, EX_CLOSED);
break;
case 2:
SetBit(pexit->rs_flags, EX_CLOSED | EX_LOCKED);
SetBit(pexit->exit_info, EX_CLOSED | EX_LOCKED);
break;
}
break;
case 'F':
pRoomIndex = get_room_index((rVnum = pReset->arg1));
if (pReset->arg2 < 0 || pReset->arg2 > (MAX_DIR - 1)
|| !pRoomIndex
|| !(pexit = pRoomIndex->exit[pReset->arg2]))
{
bugf("'F': Nonexistent exit [%ld:%d].", pRoomIndex->vnum,
pReset->arg2);
break;
}
pexit->rs_flags = arg5;
pexit->exit_info = arg5;
break;
case 'R':
rVnum = pReset->arg1;
break;
}
if (rVnum == -1)
{
bugf("load_resets : rVnum == -1");
exit(1);
}
if (pReset->command != 'D' && pReset->command != 'F')
add_reset(get_room_index(rVnum), pReset, 0);
else
free_reset(pReset);
}
return;
}
Boot_Fun(load_rooms)
{
RoomIndex *pRoomIndex;
if (current_area == NULL)
{
bug("Load_resets: no #AREA seen yet.");
exit(1);
}
while (true)
{
vnum_t vnum;
char letter;
int door;
int iHash = -1;
letter = read_letter(fp);
if (letter != '#')
{
bug("Load_rooms: # not found.");
exit(1);
}
vnum = read_number(fp);
if (vnum == 0)
break;
run_level = RUNLEVEL_SAFE_BOOT;
if (get_room_index(vnum) != NULL)
{
bugf("Load_rooms: vnum %ld duplicated.", vnum);
exit(1);
}
run_level = RUNLEVEL_BOOTING;
pRoomIndex = new_room_index();
pRoomIndex->person_first = NULL;
pRoomIndex->content_first = NULL;
pRoomIndex->ed_first = NULL;
pRoomIndex->area = current_area;
pRoomIndex->vnum = vnum;
read_strfree(fp, &pRoomIndex->name);
read_strfree(fp, &pRoomIndex->description);
read_number(fp);
pRoomIndex->room_flags = read_flag(fp);
if (3000 <= vnum && vnum < 3400)
SetBit(pRoomIndex->room_flags, ROOM_LAW);
pRoomIndex->sector_type = read_enum(sector_t, fp);
pRoomIndex->light = 0;
for (door = 0; door <= 5; door++)
pRoomIndex->exit[door] = NULL;
pRoomIndex->heal_rate = 100;
pRoomIndex->mana_rate = 100;
while (iHash == -1)
{
letter = read_letter(fp);
switch (letter)
{
case 'S':
iHash = vnum % MAX_KEY_HASH;
break;
case 'H':
pRoomIndex->heal_rate = read_number(fp);
break;
case 'M':
pRoomIndex->mana_rate = read_number(fp);
break;
case 'C':
{
const char *tmp = read_string(fp);
free_string(tmp);
}
break;
case 'G':
if (pRoomIndex->guild > -1
&& pRoomIndex->guild < top_class)
{
bug("Duplicate guild.");
exit(1);
}
pRoomIndex->guild = read_number(fp);
break;
case 'D':
{
ExitData *pexit;
door = read_number(fp);
if (door < 0 || door > 5)
{
bugf("Fread_rooms: vnum %ld has bad door number.",
vnum);
exit(1);
}
pexit = new_exit();
read_strfree(fp, &pexit->description);
read_strfree(fp, &pexit->keyword);
pexit->exit_info = 0;
pexit->rs_flags = 0;
if (pRoomIndex->area->version < 2)
{
switch (read_number(fp))
{
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->rs_flags = read_flag(fp);
if (IsSet(pexit->rs_flags, EX_TEMP))
RemBit(pexit->rs_flags, EX_TEMP);
pexit->exit_info = pexit->rs_flags;
pexit->key = read_number(fp);
pexit->u1.vnum = read_number(fp);
pexit->orig_door = door;
pRoomIndex->exit[door] = pexit;
}
break;
case 'E':
{
ExDescrData *ed;
ed = new_ed();
read_strfree(fp, &ed->keyword);
read_strfree(fp, &ed->description);
Link(ed, pRoomIndex->ed, next, prev);
}
break;
case 'O':
if (!NullStr(pRoomIndex->owner))
{
bug("Load_rooms: duplicate owner.");
exit(1);
}
pRoomIndex->owner = read_string(fp);
SetBit(pRoomIndex->room_flags, ROOM_NOEXPLORE);
break;
case 'R':
{
ProgList *pRprog;
const char *word;
flag_t trigger = 0;
pRprog = new_prog_list();
word = read_word(fp);
if ((trigger = flag_value(rprog_flags, word)) == NO_FLAG)
{
bug("ROOMprogs: invalid trigger.");
exit(1);
}
SetBit(pRoomIndex->rprog_flags, trigger);
pRprog->trig_type = trigger;
pRprog->prog = (ProgCode *) read_long(fp);
read_strfree(fp, &pRprog->trig_phrase);
Link(pRprog, pRoomIndex->rprog, next, prev);
}
break;
default:
bugf("Load_rooms: vnum %ld has invalid flag %c.", vnum,
letter);
exit(1);
break;
}
}
LinkSingle(pRoomIndex, room_index_hash[iHash], next);
if (!IsSet(pRoomIndex->room_flags, ROOM_NOEXPLORE))
top_explored++;
top_vnum_room = Max(top_vnum_room, vnum);
assign_area_vnum(vnum);
}
return;
}
Boot_Fun(load_shops)
{
ShopData *pShop;
while (true)
{
CharIndex *pMobIndex;
int iTrade;
pShop = new_shop();
pShop->keeper = read_number(fp);
if (pShop->keeper == 0)
break;
for (iTrade = 0; iTrade < MAX_TRADE; iTrade++)
pShop->buy_type[iTrade] = read_number(fp);
pShop->profit_buy = read_number(fp);
pShop->profit_sell = read_number(fp);
pShop->open_hour = read_number(fp);
pShop->close_hour = read_number(fp);
read_to_eol(fp);
pMobIndex = get_char_index(pShop->keeper);
pMobIndex->pShop = pShop;
Link(pShop, shop, next, prev);
}
return;
}
Boot_Fun(load_specials)
{
while (true)
{
CharIndex *pMobIndex;
char letter = read_letter(fp);
switch (letter)
{
default:
bugf("Load_specials: letter '%c' not *MS.", letter);
exit(1);
case 'S':
return;
case '*':
break;
case 'M':
pMobIndex = get_char_index(read_number(fp));
pMobIndex->spec_fun = spec_lookup(read_word(fp));
if (pMobIndex->spec_fun == 0)
{
bugf("Load_specials: 'M': vnum %ld.", pMobIndex->vnum);
exit(1);
}
break;
}
read_to_eol(fp);
}
}
void fix_exits(void)
{
RoomIndex *pRoomIndex;
ExitData *pexit;
ResetData *pReset;
RoomIndex *iLastRoom, *iLastObj;
int iHash;
int door;
log_string("Fixing exits...");
for (iHash = 0; iHash < MAX_KEY_HASH; iHash++)
{
for (pRoomIndex = room_index_hash[iHash]; pRoomIndex != NULL;
pRoomIndex = pRoomIndex->next)
{
bool fexit;
iLastRoom = iLastObj = NULL;
for (pReset = pRoomIndex->reset_first; pReset;
pReset = pReset->next)
{
switch (pReset->command)
{
default:
bugf("fix_exits : cuarto %ld con reset cmd %c",
pRoomIndex->vnum, pReset->command);
exit(1);
break;
case 'M':
get_char_index(pReset->arg1);
iLastRoom = get_room_index(pReset->arg3);
break;
case 'O':
get_obj_index(pReset->arg1);
iLastObj = get_room_index(pReset->arg3);
break;
case 'P':
get_obj_index(pReset->arg1);
if (iLastObj == NULL)
{
bugf
("fix_exits : reset en cuarto %ld con iLastObj NULL",
pRoomIndex->vnum);
exit(1);
}
break;
case 'G':
case 'E':
get_obj_index(pReset->arg1);
if (iLastRoom == NULL)
{
bugf
("fix_exits : reset en cuarto %ld con iLastRoom NULL",
pRoomIndex->vnum);
exit(1);
}
iLastObj = iLastRoom;
break;
case 'D':
bugf("???");
break;
case 'R':
get_room_index(pReset->arg1);
if (pReset->arg2 < 0 || pReset->arg2 > MAX_DIR)
{
bugf
("fix_exits : reset en cuarto %ld con arg2 %d >= MAX_DIR",
pRoomIndex->vnum, pReset->arg2);
exit(1);
}
break;
}
}
fexit = false;
for (door = 0; door <= 5; door++)
{
if ((pexit = pRoomIndex->exit[door]) != NULL)
{
if (pexit->u1.vnum <= 0
|| get_room_index(pexit->u1.vnum) == NULL)
pexit->u1.to_room = NULL;
else
{
fexit = true;
pexit->u1.to_room = get_room_index(pexit->u1.vnum);
}
}
}
if (!fexit)
SetBit(pRoomIndex->room_flags, ROOM_NO_MOB);
}
}
return;
}
Boot_Fun(load_mobprogs)
{
ProgCode *pMprog;
if (current_area == NULL)
{
bug("Load_mobprogs: no #AREA seen yet.");
exit(1);
}
while (true)
{
vnum_t vnum;
char letter;
letter = read_letter(fp);
if (letter != '#')
{
bug("Load_mobprogs: # not found.");
exit(1);
}
vnum = read_number(fp);
if (vnum == 0)
break;
run_level = RUNLEVEL_SAFE_BOOT;
if (get_prog_index(vnum, PRG_MPROG) != NULL)
{
bugf("Load_mobprogs: vnum %ld duplicated.", vnum);
exit(1);
}
run_level = RUNLEVEL_BOOTING;
pMprog = new_mprog();
pMprog->vnum = vnum;
read_strfree(fp, &pMprog->code);
pMprog->area = current_area;
Link(pMprog, mprog, next, prev);
}
return;
}
void fix_mobprogs(void)
{
CharIndex *pMobIndex;
ProgList *list;
ProgCode *prog;
int iHash;
log_string("Fixing mob programs...");
for (iHash = 0; iHash < MAX_KEY_HASH; iHash++)
{
for (pMobIndex = char_index_hash[iHash]; pMobIndex != NULL;
pMobIndex = pMobIndex->next)
{
for (list = pMobIndex->mprog_first; list != NULL;
list = list->next)
{
if ((prog = get_prog_index((vnum_t) list->prog, PRG_MPROG)) ==
NULL)
{
bugf("Fix_roomprogs: code vnum %ld not found.",
(vnum_t) list->prog);
exit(1);
}
else
list->prog = prog;
}
}
}
}
void area_update(void)
{
AreaData *pArea;
int hash;
RoomIndex *room;
if (run_level == RUNLEVEL_BOOTING)
log_string("Updating areas...");
for (pArea = area_first; pArea != NULL; pArea = pArea->next)
{
if (++pArea->age < 3)
continue;
if ((!pArea->empty && (pArea->nplayer == 0 || pArea->age >= 15))
|| pArea->age >= 31)
{
RoomIndex *pRoomIndex;
const char *msg = NULL;
reset_area(pArea);
new_wiznet(NULL, NULL, WIZ_RESETS, false, 0,
"%s has just been reset.", pArea->name);
if (IsSet(pArea->area_flags, OLC_CHANGED))
{
save_area(pArea);
new_wiznet(NULL, NULL, WIZ_RESETS, true, 0,
"%s has just been saved.", pArea->name);
}
pArea->age = number_range(0, 3);
pRoomIndex = get_room_index(ROOM_VNUM_SCHOOL);
if (pRoomIndex != NULL && pArea == pRoomIndex->area)
pArea->age = 15 - 2;
else if (pArea->nplayer == 0)
pArea->empty = true;
if (!NullStr(pArea->resetmsg))
msg = pArea->resetmsg;
else if (!pRoomIndex || pRoomIndex->area != pArea)
{
switch (number_range(0, 4))
{
default:
msg = "The area repopulates itself.";
break;
case 1:
msg = "You notice a change in the area.";
break;
case 2:
msg =
"Time completes another cycle bringing life to the area.";
break;
case 3:
msg =
"You feel a sudden deja-vu bringing change to the area.";
break;
case 4:
msg = "You hear noises off in the distance...";
break;
}
}
if (!NullStr(msg))
{
CharData *ch;
for (ch = player_first; ch != NULL; ch = ch->next_player)
{
if (ch->desc && ch->desc->connected == CON_PLAYING
&& IsAwake(ch) && ch->in_room
&& ch->in_room->area == pArea)
chprintlnf(ch, "{?%s{x", msg);
}
}
}
}
for (hash = 0; hash < MAX_KEY_HASH; hash++)
for (room = room_index_hash[hash]; room; room = room->next)
{
if (room->area->empty)
continue;
if (HasTriggerRoom(room, TRIG_DELAY) && room->rprog_delay > 0)
{
if (--room->rprog_delay <= 0)
p_percent_trigger(NULL, NULL, room, NULL, NULL, NULL,
TRIG_DELAY);
}
else if (HasTriggerRoom(room, TRIG_RANDOM))
p_percent_trigger(NULL, NULL, room, NULL, NULL, NULL,
TRIG_RANDOM);
}
return;
}
void reset_room(RoomIndex * pRoom)
{
ResetData *pReset;
CharData *pMob;
CharData *mob;
ObjData *pObj;
CharData *LastMob = NULL;
ObjData *LastObj = NULL;
int iExit;
int level = 0;
bool last;
if (!pRoom)
return;
pMob = NULL;
last = false;
for (iExit = 0; iExit < MAX_DIR; iExit++)
{
ExitData *pExit;
if ((pExit = pRoom->exit[iExit]))
{
pExit->exit_info = pExit->rs_flags;
if ((pExit->u1.to_room != NULL)
&& ((pExit = pExit->u1.to_room->exit[rev_dir[iExit]])))
{
pExit->exit_info = pExit->rs_flags;
}
}
}
for (pReset = pRoom->reset_first; pReset != NULL; pReset = pReset->next)
{
CharIndex *pMobIndex;
ObjIndex *pObjIndex;
ObjIndex *pObjToIndex;
RoomIndex *pRoomIndex;
char buf[MAX_STRING_LENGTH];
int count, limit = 0;
switch (pReset->command)
{
default:
bugf("Reset_room: bad command %c.", pReset->command);
break;
case 'M':
if (!(pMobIndex = get_char_index(pReset->arg1)))
{
bugf("Reset_room: 'M': bad vnum %ld.", pReset->arg1);
continue;
}
if ((pRoomIndex = get_room_index(pReset->arg3)) == NULL)
{
bugf("Reset_area: 'R': bad vnum %ld.", pReset->arg3);
continue;
}
if (pMobIndex->count >= pReset->arg2)
{
last = false;
break;
}
count = 0;
for (mob = pRoomIndex->person_first; mob != NULL;
mob = mob->next_in_room)
if (mob->pIndexData == pMobIndex)
{
count++;
if (count >= pReset->arg4)
{
last = false;
break;
}
}
if (count >= pReset->arg4)
break;
pMob = create_mobile(pMobIndex);
if (room_is_dark(pRoom))
SetBit(pMob->affected_by, AFF_INFRARED);
{
RoomIndex *pRoomIndexPrev;
pRoomIndexPrev = get_room_index(pRoom->vnum - 1);
if (pRoomIndexPrev
&& IsSet(pRoomIndexPrev->room_flags, ROOM_PET_SHOP))
SetBit(pMob->act, ACT_PET);
}
char_to_room(pMob, pRoom);
LastMob = pMob;
level = Range(0, pMob->level - 2, MAX_MORTAL_LEVEL - 1);
last = true;
break;
case 'O':
if (!(pObjIndex = get_obj_index(pReset->arg1)))
{
bugf("Reset_room: 'O' 1 : bad vnum %ld", pReset->arg1);
sprintf(buf, "%ld %d %ld %d", pReset->arg1, pReset->arg2,
pReset->arg3, pReset->arg4);
bugf(buf, 1);
continue;
}
if (!(pRoomIndex = get_room_index(pReset->arg3)))
{
bugf("Reset_room: 'O' 2 : bad vnum %ld.", pReset->arg3);
sprintf(buf, "%ld %d %ld %d", pReset->arg1, pReset->arg2,
pReset->arg3, pReset->arg4);
bugf(buf, 1);
continue;
}
if (pRoom->area->nplayer > 0
|| count_obj_list(pObjIndex, pRoom->content_first) > 0)
{
last = false;
break;
}
pObj =
create_object(pObjIndex,
Min(number_fuzzy(level),
MAX_MORTAL_LEVEL - 1));
pObj->cost = 0;
obj_to_room(pObj, pRoom);
last = true;
break;
case 'P':
if (!(pObjIndex = get_obj_index(pReset->arg1)))
{
bugf("Reset_room: 'P': bad vnum %ld.", pReset->arg1);
continue;
}
if (!(pObjToIndex = get_obj_index(pReset->arg3)))
{
bugf("Reset_room: 'P': bad vnum %ld.", pReset->arg3);
continue;
}
if (pReset->arg2 > 50)
limit = 6;
else if (pReset->arg2 == -1)
limit = 999;
else
limit = pReset->arg2;
if (pRoom->area->nplayer > 0
|| (LastObj = get_obj_type(pObjToIndex)) == NULL
|| (LastObj->in_room == NULL && !last)
|| (pObjIndex->count >= limit)
|| (count =
count_obj_list(pObjIndex,
LastObj->content_first)) >
pReset->arg4)
{
last = false;
break;
}
while (count < pReset->arg4)
{
pObj =
create_object(pObjIndex,
number_fuzzy(LastObj->level));
obj_to_obj(pObj, LastObj);
count++;
if (pObjIndex->count >= limit)
break;
}
LastObj->value[1] = LastObj->pIndexData->value[1];
last = true;
break;
case 'G':
case 'E':
if (!(pObjIndex = get_obj_index(pReset->arg1)))
{
bugf("Reset_room: 'E' or 'G': bad vnum %ld.",
pReset->arg1);
continue;
}
if (!last)
break;
if (!LastMob)
{
bugf("Reset_room: 'E' or 'G': null mob for vnum %ld.",
pReset->arg1);
last = false;
break;
}
if (LastMob->pIndexData->pShop)
{
int olevel = 0, i, j;
if (!pObjIndex->new_format)
switch (pObjIndex->item_type)
{
default:
olevel = 0;
break;
case ITEM_PILL:
case ITEM_POTION:
case ITEM_SCROLL:
olevel = ANGEL;
for (i = 1; i < 5; i++)
{
if (pObjIndex->value[i] > 0)
{
for (j = 0; j < top_class; j++)
{
olevel =
Min(olevel,
skill_table
[pObjIndex->value[i]].
skill_level[j]);
}
}
}
olevel = Max(0, (olevel * 3 / 4) - 2);
break;
case ITEM_WAND:
olevel = number_range(10, 20);
break;
case ITEM_STAFF:
olevel = number_range(15, 25);
break;
case ITEM_ARMOR:
olevel = number_range(5, 15);
break;
case ITEM_WEAPON:
olevel = number_range(5, 15);
break;
case ITEM_TREASURE:
olevel = number_range(10, 20);
break;
}
pObj = create_object(pObjIndex, olevel);
SetBit(pObj->extra_flags, ITEM_INVENTORY);
}
else
{
int plimit;
if (pReset->arg2 > 50)
plimit = 6;
else if (pReset->arg2 == -1 || pReset->arg2 == 0)
plimit = 999;
else
plimit = pReset->arg2;
if (pObjIndex->count < plimit || number_range(0, 4) == 0)
{
pObj =
create_object(pObjIndex,
Min(number_fuzzy(level),
MAX_MORTAL_LEVEL - 1));
}
else
break;
}
obj_to_char(pObj, LastMob);
if (pReset->command == 'E')
equip_char(LastMob, pObj, (wloc_t) pReset->arg3);
last = true;
break;
case 'D':
break;
case 'R':
if (!(pRoomIndex = get_room_index(pReset->arg1)))
{
bugf("Reset_room: 'R': bad vnum %ld.", pReset->arg1);
continue;
}
{
ExitData *pExit;
int d0;
int d1;
switch (pReset->arg3)
{
default:
for (d0 = 0; d0 < pReset->arg2 - 1; d0++)
{
d1 = number_range(d0, pReset->arg2 - 1);
pExit = pRoomIndex->exit[d0];
pRoomIndex->exit[d0] = pRoomIndex->exit[d1];
pRoomIndex->exit[d1] = pExit;
}
break;
case 1:
add_random_exit(pRoomIndex, pReset, true);
break;
case 2:
add_random_exit(pRoomIndex, pReset, false);
break;
}
}
break;
}
}
return;
}
void reset_area(AreaData * pArea)
{
RoomIndex *pRoom;
vnum_t vnum;
for (vnum = pArea->min_vnum; vnum <= pArea->max_vnum; vnum++)
{
if ((pRoom = get_room_index(vnum)))
reset_room(pRoom);
}
return;
}
CharData *create_mobile(CharIndex * pMobIndex)
{
CharData *mob;
int i;
AffectData af;
mobile_count++;
if (pMobIndex == NULL)
{
bug("Create_mobile: NULL pMobIndex.");
exit(1);
}
mob = new_char();
mob->pIndexData = pMobIndex;
mob->name = str_dup(pMobIndex->player_name);
mob->short_descr = str_dup(pMobIndex->short_descr);
mob->long_descr = str_dup(pMobIndex->long_descr);
mob->description = str_dup(pMobIndex->description);
mob->id = get_mob_id();
mob->spec_fun = pMobIndex->spec_fun;
mob->prompt = NULL;
mob->mprog_target = NULL;
if (pMobIndex->wealth == 0)
{
mob->silver = 0;
mob->gold = 0;
}
else
{
money_t wealth;
wealth =
number_range(pMobIndex->wealth / 2, 3 * pMobIndex->wealth / 2);
mob->gold = number_range(wealth / 200, wealth / 100);
mob->silver = wealth - (mob->gold * 100);
}
mob->act = pMobIndex->act;
mob->affected_by = pMobIndex->affected_by;
mob->alignment = pMobIndex->alignment;
mob->level = pMobIndex->level;
mob->hitroll = pMobIndex->hitroll;
if (pMobIndex->random > 0)
mob->level =
number_range(Max(1, pMobIndex->level - pMobIndex->random),
pMobIndex->level + pMobIndex->random);
else
mob->level = pMobIndex->level;
mob->race = pMobIndex->race;
mob->off_flags = pMobIndex->off_flags;
mob->imm_flags = pMobIndex->imm_flags;
mob->res_flags = pMobIndex->res_flags;
mob->vuln_flags = pMobIndex->vuln_flags;
mob->start_pos = pMobIndex->start_pos;
mob->default_pos = pMobIndex->default_pos;
mob->sex = pMobIndex->sex;
if (mob->sex == SEX_RANDOM)
mob->sex = (sex_t) number_range(SEX_MALE, SEX_FEMALE);
mob->form = pMobIndex->form;
mob->parts = pMobIndex->parts;
if (pMobIndex->new_format)
{
mob->group = pMobIndex->group;
mob->comm = COMM_NOCHANNELS | COMM_NOSHOUT | COMM_NOTELL;
mob->damroll = pMobIndex->damage[DICE_BONUS];
mob->max_hit =
dice(pMobIndex->hit[DICE_NUMBER],
pMobIndex->hit[DICE_TYPE]) + pMobIndex->hit[DICE_BONUS];
mob->hit = mob->max_hit;
mob->max_mana =
dice(pMobIndex->mana[DICE_NUMBER],
pMobIndex->mana[DICE_TYPE]) + pMobIndex->mana[DICE_BONUS];
mob->mana = mob->max_mana;
mob->damage[DICE_NUMBER] = pMobIndex->damage[DICE_NUMBER];
mob->damage[DICE_TYPE] = pMobIndex->damage[DICE_TYPE];
mob->dam_type = pMobIndex->dam_type;
if (mob->dam_type == 0)
switch (number_range(1, 3))
{
case (1):
mob->dam_type = 3;
break;
case (2):
mob->dam_type = 7;
break;
case (3):
mob->dam_type = 11;
break;
}
for (i = 0; i < MAX_AC; i++)
mob->armor[i] = pMobIndex->ac[i];
mob->material = str_dup(pMobIndex->material);
for (i = 0; i < STAT_MAX; i++)
mob->perm_stat[i] = Min(25, 11 + mob->level / 4);
{
int stance = number_range(STANCE_NORMAL, STANCE_SWALLOW);
SetStance(mob, STANCE_CURRENT, STANCE_NONE);
SetStance(mob, STANCE_AUTODROP, stance);
}
if (IsSet(mob->act, ACT_WARRIOR))
{
mob->perm_stat[STAT_STR] += 3;
mob->perm_stat[STAT_INT] -= 1;
mob->perm_stat[STAT_CON] += 2;
}
if (IsSet(mob->act, ACT_THIEF))
{
mob->perm_stat[STAT_DEX] += 3;
mob->perm_stat[STAT_INT] += 1;
mob->perm_stat[STAT_WIS] -= 1;
}
if (IsSet(mob->act, ACT_CLERIC))
{
mob->perm_stat[STAT_WIS] += 3;
mob->perm_stat[STAT_DEX] -= 1;
mob->perm_stat[STAT_STR] += 1;
}
if (IsSet(mob->act, ACT_MAGE))
{
mob->perm_stat[STAT_INT] += 3;
mob->perm_stat[STAT_STR] -= 1;
mob->perm_stat[STAT_DEX] += 1;
}
if (IsSet(mob->off_flags, OFF_FAST))
mob->perm_stat[STAT_DEX] += 2;
mob->perm_stat[STAT_STR] += mob->size - SIZE_MEDIUM;
mob->perm_stat[STAT_CON] += (mob->size - SIZE_MEDIUM) / 2;
if (IsAffected(mob, AFF_SANCTUARY))
{
af.where = TO_AFFECTS;
af.type = skill_lookup("sanctuary");
af.level = mob->level;
af.duration = -1;
af.location = APPLY_NONE;
af.modifier = 0;
af.bitvector = AFF_SANCTUARY;
affect_to_char(mob, &af);
}
if (IsAffected(mob, AFF_HASTE))
{
af.where = TO_AFFECTS;
af.type = skill_lookup("haste");
af.level = mob->level;
af.duration = -1;
af.location = APPLY_DEX;
af.modifier =
1 + (mob->level >= 18) + (mob->level >= 25) + (mob->level >=
32);
af.bitvector = AFF_HASTE;
affect_to_char(mob, &af);
}
if (IsAffected(mob, AFF_PROTECT_EVIL))
{
af.where = TO_AFFECTS;
af.type = skill_lookup("protection evil");
af.level = mob->level;
af.duration = -1;
af.location = APPLY_SAVES;
af.modifier = -1;
af.bitvector = AFF_PROTECT_EVIL;
affect_to_char(mob, &af);
}
if (IsAffected(mob, AFF_PROTECT_GOOD))
{
af.where = TO_AFFECTS;
af.type = skill_lookup("protection good");
af.level = mob->level;
af.duration = -1;
af.location = APPLY_SAVES;
af.modifier = -1;
af.bitvector = AFF_PROTECT_GOOD;
affect_to_char(mob, &af);
}
}
else
{
mob->damroll = 0;
mob->max_hit =
mob->level * 8 + number_range(mob->level * mob->level / 4,
mob->level * mob->level);
mob->max_hit = mob->max_hit * 9 / 10;
mob->hit = mob->max_hit;
mob->max_mana = 100 + dice(mob->level, 10);
mob->mana = mob->max_mana;
switch (number_range(1, 3))
{
case (1):
mob->dam_type = 3;
break;
case (2):
mob->dam_type = 7;
break;
case (3):
mob->dam_type = 11;
break;
}
for (i = 0; i < 3; i++)
mob->armor[i] = interpolate(mob->level, 100, -100);
mob->armor[3] = interpolate(mob->level, 100, 0);
mob->size = SIZE_MEDIUM;
mob->material = "";
for (i = 0; i < STAT_MAX; i++)
mob->perm_stat[i] = 11 + mob->level / 4;
}
mob->position = mob->start_pos;
Link(mob, char, next, prev);
pMobIndex->count++;
return mob;
}
void clone_mobile(CharData * parent, CharData * clone)
{
int i;
AffectData *paf;
if (parent == NULL || clone == NULL || !IsNPC(parent))
return;
replace_str(&clone->name, parent->name);
clone->version = parent->version;
replace_str(&clone->short_descr, parent->short_descr);
replace_str(&clone->long_descr, parent->long_descr);
replace_str(&clone->description, parent->description);
clone->group = parent->group;
clone->sex = parent->sex;
for (i = 0; i < MAX_MCLASS; i++)
clone->Class[i] = parent->Class[i];
clone->race = parent->race;
clone->level = parent->level;
clone->trust = 0;
clone->timer = parent->timer;
clone->wait = parent->wait;
clone->hit = parent->hit;
clone->max_hit = parent->max_hit;
clone->mana = parent->mana;
clone->max_mana = parent->max_mana;
clone->move = parent->move;
clone->max_move = parent->max_move;
clone->gold = parent->gold;
clone->silver = parent->silver;
clone->exp = parent->exp;
clone->act = parent->act;
clone->comm = parent->comm;
clone->imm_flags = parent->imm_flags;
clone->res_flags = parent->res_flags;
clone->vuln_flags = parent->vuln_flags;
clone->invis_level = parent->invis_level;
clone->affected_by = parent->affected_by;
clone->position = parent->position;
clone->practice = parent->practice;
clone->train = parent->train;
clone->saving_throw = parent->saving_throw;
clone->alignment = parent->alignment;
clone->hitroll = parent->hitroll;
clone->damroll = parent->damroll;
clone->wimpy = parent->wimpy;
clone->form = parent->form;
clone->parts = parent->parts;
clone->size = parent->size;
replace_str(&clone->material, parent->material);
clone->off_flags = parent->off_flags;
clone->dam_type = parent->dam_type;
clone->start_pos = parent->start_pos;
clone->default_pos = parent->default_pos;
clone->spec_fun = parent->spec_fun;
for (i = 0; i < MAX_AC; i++)
clone->armor[i] = parent->armor[i];
for (i = 0; i < STAT_MAX; i++)
{
clone->perm_stat[i] = parent->perm_stat[i];
clone->mod_stat[i] = parent->mod_stat[i];
}
for (i = 0; i < 3; i++)
clone->damage[i] = parent->damage[i];
for (paf = parent->affect_first; paf != NULL; paf = paf->next)
affect_to_char(clone, paf);
}
ObjData *create_object(ObjIndex * pObjIndex, int level)
{
AffectData *paf;
ObjData *obj;
int i;
if (pObjIndex == NULL)
{
bug("Create_object: NULL pObjIndex.");
exit(1);
}
obj = new_obj();
obj->pIndexData = pObjIndex;
obj->in_room = NULL;
obj->enchanted = false;
if (pObjIndex->new_format)
obj->level = pObjIndex->level;
else
obj->level = Max(0, level);
obj->wear_loc = WEAR_NONE;
obj->name = str_dup(pObjIndex->name);
obj->short_descr = str_dup(pObjIndex->short_descr);
obj->description = str_dup(pObjIndex->description);
obj->material = str_dup(pObjIndex->material);
obj->item_type = pObjIndex->item_type;
obj->extra_flags = pObjIndex->extra_flags;
obj->wear_flags = pObjIndex->wear_flags;
obj->value[0] = pObjIndex->value[0];
obj->value[1] = pObjIndex->value[1];
obj->value[2] = pObjIndex->value[2];
obj->value[3] = pObjIndex->value[3];
obj->value[4] = pObjIndex->value[4];
obj->weight = pObjIndex->weight;
if (level == -1 || pObjIndex->new_format)
obj->cost = pObjIndex->cost;
else
obj->cost =
number_fuzzy(10) * number_fuzzy(level) * number_fuzzy(level);
switch (obj->item_type)
{
default:
bugf("Read_object: vnum %ld bad type.", pObjIndex->vnum);
break;
case ITEM_LIGHT:
if (obj->value[2] == 999)
obj->value[2] = -1;
break;
case ITEM_FURNITURE:
case ITEM_TRASH:
case ITEM_CONTAINER:
case ITEM_DRINK_CON:
case ITEM_KEY:
case ITEM_FOOD:
case ITEM_BOAT:
case ITEM_CORPSE_NPC:
case ITEM_CORPSE_PC:
case ITEM_FOUNTAIN:
case ITEM_MAP:
case ITEM_CLOTHING:
case ITEM_PORTAL:
if (!pObjIndex->new_format)
obj->cost /= 5;
break;
case ITEM_TREASURE:
case ITEM_WARP_STONE:
case ITEM_ROOM_KEY:
case ITEM_GEM:
case ITEM_JEWELRY:
break;
case ITEM_JUKEBOX:
for (i = 0; i < 5; i++)
obj->value[i] = -1;
break;
case ITEM_SCROLL:
if (level != -1 && !pObjIndex->new_format)
obj->value[0] = number_fuzzy(obj->value[0]);
break;
case ITEM_WAND:
case ITEM_STAFF:
if (level != -1 && !pObjIndex->new_format)
{
obj->value[0] = number_fuzzy(obj->value[0]);
obj->value[1] = number_fuzzy(obj->value[1]);
obj->value[2] = obj->value[1];
}
if (!pObjIndex->new_format)
obj->cost *= 2;
break;
case ITEM_WEAPON:
if (level != -1 && !pObjIndex->new_format)
{
obj->value[1] = number_fuzzy(number_fuzzy(1 * level / 4 + 2));
obj->value[2] = number_fuzzy(number_fuzzy(3 * level / 4 + 6));
}
break;
case ITEM_ARMOR:
if (level != -1 && !pObjIndex->new_format)
{
obj->value[0] = number_fuzzy(level / 5 + 3);
obj->value[1] = number_fuzzy(level / 5 + 3);
obj->value[2] = number_fuzzy(level / 5 + 3);
}
break;
case ITEM_POTION:
case ITEM_PILL:
if (level != -1 && !pObjIndex->new_format)
obj->value[0] = number_fuzzy(number_fuzzy(obj->value[0]));
break;
case ITEM_MONEY:
if (!pObjIndex->new_format)
obj->value[0] = obj->cost;
break;
}
for (paf = pObjIndex->affect_first; paf != NULL; paf = paf->next)
if (paf->location == APPLY_SPELL_AFFECT)
affect_to_obj(obj, paf);
Link(obj, obj, next, prev);
pObjIndex->count++;
return obj;
}
void clone_object(ObjData * parent, ObjData * clone)
{
int i;
AffectData *paf;
ExDescrData *ed, *ed_new;
if (parent == NULL || clone == NULL)
return;
replace_str(&clone->name, parent->name);
replace_str(&clone->short_descr, parent->short_descr);
replace_str(&clone->description, parent->description);
clone->item_type = parent->item_type;
clone->extra_flags = parent->extra_flags;
clone->wear_flags = parent->wear_flags;
clone->weight = parent->weight;
clone->cost = parent->cost;
clone->level = parent->level;
clone->condition = parent->condition;
replace_str(&clone->material, parent->material);
clone->timer = parent->timer;
for (i = 0; i < 5; i++)
clone->value[i] = parent->value[i];
clone->enchanted = parent->enchanted;
for (paf = parent->affect_first; paf != NULL; paf = paf->next)
affect_to_obj(clone, paf);
for (ed = parent->ed_first; ed != NULL; ed = ed->next)
{
ed_new = new_ed();
ed_new->keyword = str_dup(ed->keyword);
ed_new->description = str_dup(ed->description);
Link(ed_new, clone->ed, next, prev);
}
}
const char *get_ed(const char *name, ExDescrData * ed)
{
for (; ed != NULL; ed = ed->next)
{
if (is_name(name, ed->keyword))
return ed->description;
}
return NULL;
}
CharIndex *get_char_index(vnum_t vnum)
{
CharIndex *pMobIndex;
for (pMobIndex = char_index_hash[vnum % MAX_KEY_HASH]; pMobIndex != NULL;
pMobIndex = pMobIndex->next)
{
if (pMobIndex->vnum == vnum)
return pMobIndex;
}
if (run_level == RUNLEVEL_BOOTING)
{
bugf("Get_char_index: bad vnum %ld.", vnum);
exit(1);
}
return NULL;
}
ObjIndex *get_obj_index(vnum_t vnum)
{
ObjIndex *pObjIndex;
for (pObjIndex = obj_index_hash[vnum % MAX_KEY_HASH]; pObjIndex != NULL;
pObjIndex = pObjIndex->next)
{
if (pObjIndex->vnum == vnum)
return pObjIndex;
}
if (run_level == RUNLEVEL_BOOTING)
{
bugf("Get_obj_index: bad vnum %ld.", vnum);
exit(1);
}
return NULL;
}
RoomIndex *get_room_index(vnum_t vnum)
{
RoomIndex *pRoomIndex;
for (pRoomIndex = room_index_hash[vnum % MAX_KEY_HASH];
pRoomIndex != NULL; pRoomIndex = pRoomIndex->next)
{
if (pRoomIndex->vnum == vnum)
return pRoomIndex;
}
if (run_level == RUNLEVEL_BOOTING)
{
bugf("Get_room_index: bad vnum %ld.", vnum);
exit(1);
}
return NULL;
}
ProgCode *get_prog_index(vnum_t vnum, prog_t type)
{
ProgCode *prg;
switch (type)
{
case PRG_MPROG:
prg = mprog_first;
break;
case PRG_OPROG:
prg = oprog_first;
break;
case PRG_RPROG:
prg = rprog_first;
break;
default:
return NULL;
}
for (; prg; prg = prg->next)
{
if (prg->vnum == vnum)
return (prg);
}
return NULL;
}
flag_t flag_convert(char letter)
{
flag_t bitsum = 0;
char i;
if ('A' <= letter && letter <= 'Z')
{
bitsum = ((flag_t) 1 << 0);
for (i = letter; i > 'A'; i--)
bitsum <<= 1;
}
else if ('a' <= letter && letter <= 'z')
{
bitsum = ((flag_t) 1 << 26);
for (i = letter; i > 'a'; i--)
bitsum <<= 1;
}
return bitsum;
}
const char *str_dup(const char *pstr)
{
if (NullStr(pstr))
return &str_empty[0];
sAllocString += strlen(pstr);
nAllocString += 1;
return strdup(pstr);
}
const char *str_dupf(const char *pstr, ...)
{
va_list args;
char str_new[MPL];
if (NullStr(pstr))
return &str_empty[0];
va_start(args, pstr);
sAllocString += vsnprintf(str_new, sizeof(str_new), pstr, args);
va_end(args);
nAllocString += 1;
return strdup(str_new);
}
void replace_str(const char **pstr, const char *nstr)
{
free_string(*pstr);
if (NullStr(nstr))
*pstr = &str_empty[0];
else
{
sAllocString += strlen(nstr);
nAllocString += 1;
*pstr = strdup(nstr);
}
}
void replace_strf(const char **pstr, const char *nstr, ...)
{
va_list args;
char str_new[MPL];
free_string(*pstr);
if (NullStr(nstr))
{
*pstr = &str_empty[0];
return;
}
va_start(args, nstr);
sAllocString += vsnprintf(str_new, sizeof(str_new), nstr, args);
va_end(args);
nAllocString += 1;
*pstr = strdup(str_new);
}
void free_string(const char *pstr)
{
if (NullStr(pstr))
return;
sAllocString -= strlen(pstr);
nAllocString -= 1;
free_mem(pstr);
return;
}
void newarea_insert_level_sort(AreaData * a)
{
AreaData *lsort = area_first_sorted;
AreaData *lsort_prev = NULL;
if (!area_first_sorted)
{
area_first_sorted = a;
return;
}
for (; lsort; lsort_prev = lsort, lsort = lsort->next_sort)
{
if (NullStr(a->lvl_comment))
{
if (NullStr(lsort->lvl_comment))
{
if (lsort->min_level > 0)
{
if (a->min_level <= 0 || a->min_level > lsort->min_level)
{
continue;
}
if (a->min_level == lsort->min_level
&& a->max_level > lsort->max_level)
{
continue;
}
}
else
{
if (a->min_level < lsort->min_level)
{
continue;
}
}
}
}
else
{
int i;
if (NullStr(lsort->lvl_comment))
{
continue;
}
i = str_cmp(a->lvl_comment, lsort->lvl_comment);
if (i > 0)
{
continue;
}
if (i == 0 && str_cmp(a->name, lsort->name) > 0)
{
continue;
}
}
if (lsort_prev)
{
a->next_sort = lsort;
lsort_prev->next_sort = a;
}
else
{
a->next_sort = area_first_sorted;
area_first_sorted = a;
}
return;
}
lsort_prev->next_sort = a;
}
void add_area(AreaData * pArea)
{
newarea_insert_level_sort(pArea);
Link(pArea, area, next, prev);
}
void unlink_area(AreaData * pArea)
{
UnlinkSingle(pArea, AreaData, area_first_sorted, next_sort);
UnLink(pArea, area, next, prev);
}
const char *print_area_levels(AreaData * pArea)
{
static char buf[8];
char low[4], high[4];
if (!NullStr(pArea->lvl_comment))
return str_align(7, Center, pArea->lvl_comment);
if (pArea->min_level >= LEVEL_HERO && pArea->max_level >= LEVEL_HERO)
return str_align(7, Center, "HERO+");
if (pArea->min_level >= LEVEL_HERO)
strncpy(low, "HRO", sizeof(low));
else
snprintf(low, sizeof(low), "%03d", pArea->min_level);
if (pArea->max_level >= LEVEL_HERO)
strncpy(high, "HRO", sizeof(high));
else
snprintf(high, sizeof(high), "%03d", pArea->max_level);
snprintf(buf, sizeof(buf), "%s %s", low, high);
return buf;
}
int convert_level(const char *arg)
{
if (NullStr(arg))
return 0;
else if (is_number(arg))
return atoi(arg);
else if (is_name("IMM", arg))
return LEVEL_IMMORTAL;
else if (is_name("HERO", arg) || is_name("HRO", arg))
return MAX_MORTAL_LEVEL;
else
return 0;
}
Do_Fun(do_areas)
{
AreaData *pArea;
Buffer *output;
int lo_lv, hi_lv, count;
char arg1[MIL], arg2[MIL];
lo_lv = 0;
hi_lv = 0;
count = 0;
if (!NullStr(argument))
{
argument = one_argument(argument, arg1);
one_argument(argument, arg2);
lo_lv = convert_level(arg1);
hi_lv = convert_level(arg2);
}
lo_lv = lo_lv > 0 ? Range(1, lo_lv, MAX_LEVEL) : 0;
hi_lv = hi_lv > 0 ? Range(1, hi_lv, MAX_LEVEL) : MAX_LEVEL;
output = new_buf();
bprintlnf(output, NEWLINE "{W%s{x",
stringf(ch, 0, Center, "oO", "[ {RAREAS ON %s{W ]",
strupper(mud_info.name)));
for (pArea = area_first_sorted; pArea != NULL; pArea = pArea->next_sort)
{
if (pArea->max_level <= hi_lv && pArea->min_level >= lo_lv
&& !AreaFlag(pArea, AREA_CLOSED))
{
if (!MudFlag(DISABLE_AREA_DIRECTIONS))
{
bprintlnf(output, "%s{W[{B%-7s{W] {r%s {C%-23s {W({M%s{W){x",
(AreaClan(pArea) != CharClan(ch)) ? "{G*" : " ",
print_area_levels(pArea), str_width(7,
pArea->credits),
pArea->name, path_to_area(ch, pArea));
}
else
{
bprintlnf(output, "%s{W[{B%-7s{W] {r%s {C%s{x",
(AreaClan(pArea) != CharClan(ch)) ? "{G*" : " ",
print_area_levels(pArea), str_width(7,
pArea->credits),
pArea->name);
}
count++;
}
}
if (!count)
{
bprintlnf(output, "{W%s{x",
stringf(ch, 0, Center, "oO",
"[ {RNo areas meeting those criteria.{W ]"));
}
else
{
bprintlnf(output, "{W%s{x",
stringf(ch, 0, Center, "oO", "[ {R%d areas found{W ]",
count));
bprintln(output, "{G*{x = Area has restrictions that affect you.{x");
bprintln(output, "All directions are from your current position.");
}
sendpage(ch, buf_string(output));
free_buf(output);
return;
}
void examine_crash_log(void)
{
FileData *fp;
char date[MIL];
EXTERN time_t last_crash;
fp = f_open(CRASH_FILE, "r");
if (!fp)
{
return;
}
last_crash = read_long(fp);
unlink(CRASH_FILE);
sprintf(date, "Crash Log %s", str_time(-1, -1, "%D"));
make_note("Immortal", "System", "Imm", date, 5, fp->str, NULL, NULL);
f_close(fp);
}
int number_fuzzy(int number)
{
switch (number_bits(2))
{
case 0:
number -= 1;
break;
case 3:
number += 1;
break;
}
return Max(1, number);
}
int number_fuzzier(int number)
{
switch (number_bits(2))
{
case 0:
number -= 2;
break;
case 1:
number -= 1;
break;
case 3:
number += 1;
break;
case 4:
number += 2;
break;
}
return Max(1, number);
}
int number_range(int from, int to)
{
int power;
int number;
if (from == 0 && to == 0)
return 0;
if ((to = to - from + 1) <= 1)
return from;
for (power = 2; power < to; power <<= 1)
;
while ((number = number_mm() & (power - 1)) >= to)
;
return from + number;
}
int number_percent(void)
{
int percent;
while ((percent = number_mm() & (128 - 1)) > 99)
;
return 1 + percent;
}
int level_percent(void)
{
return number_range(1, MAX_MORTAL_LEVEL);
}
int number_door(void)
{
int door;
while ((door = number_mm() & (8 - 1)) > 5)
;
return door;
}
int number_bits(int width)
{
return number_mm() & ((1 << width) - 1);
}
#ifdef OLD_RAND
static int rgiState[2 + 55];
#endif
void init_mm()
{
log_string("Starting random number generator...");
#ifdef OLD_RAND
int *piState;
int iState;
piState = &rgiState[2];
piState[-2] = 55 - 55;
piState[-1] = 55 - 24;
piState[0] = ((int) current_time) & ((1 << 30) - 1);
piState[1] = 1;
for (iState = 2; iState < 55; iState++)
{
piState[iState] =
(piState[iState - 1] + piState[iState - 2]) & ((1 << 30) - 1);
}
#else
srandom(time(NULL) ^ getpid());
#endif
return;
}
long number_mm(void)
{
#ifdef OLD_RAND
int *piState;
int iState1;
int iState2;
int iRand;
piState = &rgiState[2];
iState1 = piState[-2];
iState2 = piState[-1];
iRand = (piState[iState1] + piState[iState2]) & ((1 << 30) - 1);
piState[iState1] = iRand;
if (++iState1 == 55)
iState1 = 0;
if (++iState2 == 55)
iState2 = 0;
piState[-2] = iState1;
piState[-1] = iState2;
return iRand >> 6;
#else
return random() >> 6;
#endif
}
int dice(int number, int size)
{
int idice;
int sum;
switch (size)
{
case 0:
return 0;
case 1:
return number;
}
for (idice = 0, sum = 0; idice < number; idice++)
sum += number_range(1, size);
return sum;
}
int interpolate(int level, int value_00, int value_32)
{
return value_00 + level * (value_32 - value_00) / 32;
}
int str_cmp(const char *astr, const char *bstr)
{
if (astr == NULL)
return bstr == NULL ? 0 : -1;
if (bstr == NULL)
return 1;
return strcasecmp(astr, bstr);
}
int str_casecmp(const char *astr, const char *bstr)
{
if (astr == NULL)
return bstr == NULL ? 0 : -1;
if (bstr == NULL)
return 1;
return strcmp(astr, bstr);
}
int str_ncmp(const char *astr, const char *bstr, size_t len)
{
if (astr == NULL)
return bstr == NULL ? 0 : -1;
if (bstr == NULL)
return 1;
return strncasecmp(astr, bstr, len);
}
int str_ncasecmp(const char *astr, const char *bstr, size_t len)
{
if (astr == NULL)
return bstr == NULL ? 0 : -1;
if (bstr == NULL)
return 1;
return strncmp(astr, bstr, len);
}
bool str_prefix(const char *astr, const char *bstr)
{
if (astr == NULL)
{
bug("Str_prefix: null astr.");
return true;
}
if (bstr == NULL)
{
bug("Str_prefix: null bstr.");
return true;
}
for (; *astr; astr++, bstr++)
{
if (tolower(*astr) != tolower(*bstr))
return true;
}
return false;
}
bool str_infix(const char *astr, const char *bstr)
{
int sstr1;
int sstr2;
int ichar;
char c0;
if ((c0 = tolower(astr[0])) == '\0')
return false;
sstr1 = strlen(astr);
sstr2 = strlen(bstr);
for (ichar = 0; ichar <= sstr2 - sstr1; ichar++)
{
if (c0 == tolower(bstr[ichar]) && !str_prefix(astr, bstr + ichar))
return false;
}
return true;
}
bool str_suffix(const char *astr, const char *bstr)
{
int sstr1;
int sstr2;
sstr1 = strlen(astr);
sstr2 = strlen(bstr);
if (sstr1 <= sstr2 && !str_cmp(astr, bstr + sstr2 - sstr1))
return false;
else
return true;
}
const char *Upper(const char *str)
{
size_t i;
static char up[3][MSL * 2];
static int u;
if (NullStr(str))
return "";
u++;
u %= 3;
strcpy(up[u], str);
i = skipcol(up[u]);
up[u][i] = toupper(up[u][i]);
return up[u];
}
const char *Lower(const char *str)
{
size_t i;
static char low[3][MSL * 2];
static int l;
if (NullStr(str))
return "";
l++;
l %= 3;
strcpy(low[l], str);
i = skipcol(low[l]);
low[l][i] = tolower(low[l][i]);
return low[l];
}
char *capitalize(const char *str)
{
static char result[5][MSL * 5];
static int i;
size_t c;
if (NullStr(str))
return "";
i++;
i %= 5;
strcpy(result[i], strlower(str));
c = skipcol(result[i]);
result[i][c] = toupper(result[i][c]);
return result[i];
}
char *strlower(const char *str)
{
static char strlow[5][MSL * 5];
static int s;
char *result;
size_t i;
if (NullStr(str))
return "";
s++;
s %= 5;
result = strlow[s];
for (i = 0; str[i] != NUL; i++)
{
if (str[i] == COLORCODE)
{
int k = ansi_skip(&str[i]);
while (k-- > 0)
result[i] = str[i++];
}
else if (str[i] == CUSTOMSTART)
{
do
{
result[i] = str[i];
i++;
}
while (str[i] != NUL && str[i] != CUSTOMEND);
}
else if (str[i] == MXP_BEGc)
{
do
{
result[i] = str[i];
i++;
}
while (str[i] != NUL && str[i] != MXP_ENDc);
}
else
result[i] = isalpha(str[i]) ? tolower(str[i]) : str[i];
}
result[i] = NUL;
return result;
}
char *strupper(const char *str)
{
static char strup[5][MSL * 5];
static int s;
char *result;
size_t i;
if (NullStr(str))
return "";
s++;
s %= 5;
result = strup[s];
for (i = 0; str[i] != NUL; i++)
{
if (str[i] == COLORCODE)
{
int k = ansi_skip(&str[i]);
while (k-- > 0)
result[i] = str[i++];
}
else if (str[i] == CUSTOMSTART)
{
do
{
result[i] = str[i];
i++;
}
while (str[i] != NUL && str[i] != CUSTOMEND);
}
else if (str[i] == MXP_BEGc)
{
do
{
result[i] = str[i];
i++;
}
while (str[i] != NUL && str[i] != MXP_ENDc);
}
else
result[i] = isalpha(str[i]) ? toupper(str[i]) : str[i];
}
result[i] = NUL;
return result;
}
bool isavowel(char letter)
{
char c;
c = tolower(letter);
if (c == 'a' || c == 'e' || c == 'i' || c == 'o' || c == 'u')
return true;
else
return false;
}
char *aoran(const char *str)
{
static char temp[MAX_STRING_LENGTH];
if (NullStr(str))
return "";
if (isavowel(str[0])
|| (strlen(str) > 1 && tolower(str[0]) == 'y' && !isavowel(str[1])))
strcpy(temp, "an ");
else
strcpy(temp, "a ");
strcat(temp, str);
return temp;
}
void append_file(const char *file, const char *str, bool newline)
{
FILE *fp;
if (NullStr(str) || NullStr(file))
return;
if ((fp = file_open(file, "a")) == NULL)
{
log_error(file);
}
else
{
if (newline)
fprintf(fp, "%s" LF, str);
else
fprintf(fp, "%s", str);
}
file_close(fp);
}
void bug(const char *str)
{
char buf[MAX_STRING_LENGTH];
if (fpArea != NULL)
{
size_t iLine, iChar;
char c;
iChar = f_tell(fpArea);
f_seek(fpArea, 0, SEEK_SET);
for (iLine = 0; (size_t) f_tell(fpArea) < iChar; iLine++)
{
while ((c = f_getc(fpArea)) != '\n' && c != EOF)
;
}
f_seek(fpArea, iChar, SEEK_SET);
logf("[*****] FILE: %s LINE: %d", strArea, iLine);
}
sprintf(buf, "[*****] BUG: %s", str);
if (run_level == RUNLEVEL_MAIN_LOOP)
{
wiznet(buf, NULL, NULL, WIZ_BUGS, true, 0);
}
else
log_string(buf);
return;
}
void tail_chain(void)
{
return;
}
char *casemix(const char *str)
{
static char out[4][MSL];
static int o;
char *result;
size_t i;
bool wascap = false;
if (NullStr(str))
return "";
++o, o %= 4;
result = out[o];
for (i = 0; str[i] != NUL; i++)
{
if (isalpha(str[i]))
{
if (wascap)
result[i] = tolower(str[i]);
else
result[i] = toupper(str[i]);
wascap = !wascap;
}
else
{
result[i] = str[i];
}
}
result[i] = NUL;
return (result);
}