Pyom.1.00a/
Pyom.1.00a/pysrc/miniboa/
"""
#**************************************************************************
 *  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-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			               *
***************************************************************************/
#***********
 * Ported to Python by Davion of MudBytes.net
 * Using Miniboa https://code.google.com/p/miniboa/
 * Now using Python 3 version https://code.google.com/p/miniboa-py3/
 ************/
"""
import os, sys, random
from settings import AREA_DIR, AREA_LIST
from merc import *
from handler import *
from special import spec_table
from tables import sex_table, position_table
import const

def boot_db():
    print ("Loading Areas...")
    init_time()
    load_areas()
    fix_exits()
    area_update()
    print ("\t...Loaded %d Helpfiles" % len(help_list))
    print ("\t...Loaded %d Areas" % len(area_list))
    print ("\t...Loaded %d Mobile Indexes" % len(mob_index_hash))
    print ("\t...Loaded %d Object Indexes" % len(obj_index_hash))
    print ("\t...Loaded %d Room Indexes" % len(room_index_hash))
    print ("\t...Loaded %d Resets" % len(reset_list))
    print ("\t...Loaded %d Shops" % len(shop_list))
    print ("\t...Loaded %d Socials" % len(social_list))

def load_areas():
    area_list = os.path.join(AREA_DIR, AREA_LIST)
    fp = open(area_list, 'r')
    area = fp.readline().strip()
    while area != "$":
        afp = open(os.path.join(AREA_DIR, area), 'r' )
        load_area( afp.read() )
        area = fp.readline().strip()
        afp.close()
    fp.close()

def load_area(area):
    if not area.strip():
        return

    area, w = read_word(area,False)
    pArea = None
    while ( area ):
        if w == "#AREA":
            pArea = AREA_DATA()
            area, pArea.file_name = read_string(area)
            area, pArea.name = read_string(area)
            area, pArea.credits = read_string(area)
            area, pArea.min_vnum = read_int(area)
            area, pArea.max_vnum = read_int(area)
            area_list.append(pArea)
            print ("\t...%s" % pArea)

        elif w == "#HELPS":
            area = load_helps(area)
        elif w == "#MOBILES":
            area = load_mobiles(area)
        elif w == "#OBJECTS":
            area = load_objects(area)
        elif w == "#RESETS":
            area = load_resets(area, pArea)
        elif w == "#ROOMS":
            area = load_rooms(area, pArea)
        elif w == "#SHOPS":
            area = load_shops(area)
        elif w == "#SOCIALS":
            area = load_socials(area)
        elif w == "#SPECIALS":
            area = load_specials(area)
        elif w == '#$':
            break
        else:
            print ("Bad section name: " + w)

        area, w = read_word(area,False)
    

def load_helps(area):
    while True:
        help = HELP_DATA()
        area, help.level = read_int(area)
        area, help.keyword = read_string(area)
        
        if help.keyword == '$':
            del help
            break

        area, help.text = read_string(area)
        
        if help.keyword == "GREETING":
            greeting_list.append(help)
            
        help_list.append(help)
    return area
         

def load_mobiles(area):
    area, w = read_word(area,False)
    w = w[1:] # strip the pound

    while w != '0':
        mob = MOB_INDEX_DATA()
        mob.vnum = int(w)
        mob_index_hash[mob.vnum] = mob
        area, mob.player_name = read_string(area)
        area, mob.short_descr = read_string(area)
        area, mob.long_descr = read_string(area)
        area, mob.description = read_string(area)
        area, mob.race = read_string(area)
        mob.race = const.race_table[mob.race]
        area, mob.act = read_flags(area)
        mob.act = mob.act | ACT_IS_NPC | mob.race.act
        area, mob.affected_by = read_flags(area)
        mob.affected_by = mob.affected_by | mob.race.aff
        area, mob.alignment = read_int(area)
        area, mob.group = read_int(area)
        area, mob.level = read_int(area)
        area, mob.hitroll = read_int(area)
        area, mob.hit[0] = read_int(area)
        area = read_forward(area)
        area, mob.hit[1] = read_int(area)
        area = read_forward(area)
        area, mob.hit[2] = read_int(area)
        area, mob.mana[0] = read_int(area)
        area = read_forward(area)
        area, mob.mana[1] = read_int(area)
        area = read_forward(area)
        area, mob.mana[2] = read_int(area)
        area, mob.damage[0] = read_int(area)
        area = read_forward(area)
        area, mob.damage[1] = read_int(area)
        area = read_forward(area)
        area, mob.damage[2] = read_int(area)
        area, mob.dam_type = read_word(area,False)
        mob.dam_type = name_lookup(const.attack_table, mob.dam_type)
        area, mob.ac[0] = read_int(area)
        area, mob.ac[1] = read_int(area)
        area, mob.ac[2] = read_int(area)
        area, mob.ac[3] = read_int(area)
        area, mob.off_flags = read_flags(area)
        mob.off_flags = mob.off_flags | mob.race.off
        area, mob.imm_flags = read_flags(area)
        mob.imm_flags = mob.imm_flags | mob.race.imm
        area, mob.res_flags = read_flags(area)
        mob.res_flags = mob.res_flags | mob.race.res
        area, mob.vuln_flags = read_flags(area)
        mob.vuln_flags = mob.vuln_flags | mob.race.vuln
        area, mob.start_pos = read_word(area,False)
        area, mob.default_pos = read_word(area,False)
        mob.start_pos = name_lookup(position_table, mob.start_pos, 'short_name')
        mob.default_pos = name_lookup(position_table, mob.default_pos, 'short_name')
        area, sex = read_word(area,False)
        mob.sex = value_lookup(sex_table, sex)
        area, mob.wealth = read_int(area)
        area, mob.form = read_flags(area)
        mob.form = mob.form | mob.race.form
        area, mob.parts = read_flags(area)
        mob.parts = mob.parts | mob.race.parts
        area, mob.size = read_word(area,False)
        area, mob.material = read_word(area,False)
        area, w = read_word(area,False)
        mob.size = size_table.index(mob.size)
        while w == 'F':
            area, word = read_word(area,False)
            area, vector = read_flags(area)
            area, w = read_word(area,False)

        w = w[1:] # strip the pound         
    return area

def load_objects(area):
    area, w = read_word(area,False)
    w = w[1:] # strip the pound
    while w != '0':
        obj = OBJ_INDEX_DATA()
        obj.vnum = int(w)
        obj_index_hash[obj.vnum] = obj
        area, obj.name = read_string(area)
        area, obj.short_descr = read_string(area)
        
        area, obj.description = read_string(area)
        area, obj.material = read_string(area)
        area, item_type = read_word(area,False)
        area, obj.extra_flags = read_flags(area)
        area, obj.wear_flags = read_flags(area)
        obj.item_type = item_type
        
        if obj.item_type == ITEM_WEAPON:
            area, obj.value[0] = read_word(area,False)
            area, obj.value[1] = read_int(area)
            area, obj.value[2] = read_int(area)
            area, obj.value[3] = read_word(area,False)
            obj.value[3] = name_lookup(const.attack_table, obj.value[3])
            area, obj.value[4] = read_flags(area)
        elif obj.item_type == ITEM_CONTAINER:
            area, obj.value[0] = read_int(area)
            area, obj.value[1] = read_flags(area)
            area, obj.value[2] = read_int(area)
            area, obj.value[3] = read_int(area)
            area, obj.value[4] = read_int(area)
        elif obj.item_type == ITEM_DRINK_CON or obj.item_type == ITEM_FOUNTAIN:
            area, obj.value[0] = read_int(area)
            area, obj.value[1] = read_int(area)
            area, obj.value[2] = read_word(area,False)
            area, obj.value[3] = read_int(area)
            area, obj.value[4] = read_int(area)
        elif obj.item_type == ITEM_WAND or obj.item_type == ITEM_STAFF:
            area, obj.value[0] = read_int(area)
            area, obj.value[1] = read_int(area)
            area, obj.value[2] = read_int(area)
            area, obj.value[3] = read_word(area,False)
            area, obj.value[4] = read_int(area)
        elif obj.item_type == ITEM_POTION or obj.item_type == ITEM_POTION or obj.item_type == ITEM_PILL:
            area, obj.value[0] = read_int(area)
            area, obj.value[1] = read_word(area,False)
            area, obj.value[2] = read_word(area,False)
            area, obj.value[3] = read_word(area,False)
            area, obj.value[4] = read_word(area,False)
        else:
            area, obj.value[0] = read_flags(area)
            area, obj.value[1] = read_flags(area)
            area, obj.value[2] = read_flags(area)
            area, obj.value[3] = read_flags(area)
            area, obj.value[4] = read_flags(area)
        
        area, obj.level = read_int(area)
        area, obj.weight = read_int(area)
        area, obj.cost = read_int(area)
        area, obj.condition = read_word(area,False)
        if obj.condition == 'P':
            obj.condition = 100
        elif obj.condition == 'G':
            obj.condition = 90
        elif obj.condition == 'A':
            obj.condition = 75
        elif obj.condition == 'W':
            obj.condition = 50
        elif obj.condition == 'D':
            obj.condition = 25
        elif obj.condition == 'B':
            obj.condition = 10
        elif obj.condition == 'R':
            obj.condition = 0
        else:
            obj.condition = 100

        area, w = read_word(area,False)

        while w == 'F' or w == 'A' or w == 'E':
            if w == 'F':
                area, word = read_word(area,False)
                area, number = read_int(area)
                area, number = read_int(area)
                area, flags = read_flags(area)
            elif w == 'A':
                area, number = read_int(area)
                area, number = read_int(area)
            elif w == 'E':
                ed = EXTRA_DESCR_DATA()
                area, ed.keyword = read_string(area)
                area, ed.description = read_string(area)
                obj.extra_descr.append(ed)

            area, w = read_word(area,False)

        w = w[1:] # strip the pound         
    return area

def load_resets(area, pArea):
    while True:
        area, letter = read_letter(area)
        if letter == 'S':
            break

        if letter == '*':
            area, t = read_to_eol(area)
            continue

        reset = RESET_DATA()
        reset.command = letter
        area, number = read_int(area) #if_flag
        area, reset.arg1 = read_int(area)
        area, reset.arg2 = read_int(area)
        area, reset.arg3 = (area, 0) if letter == 'G' or letter == 'R' else read_int(area)
        area, reset.arg4 = read_int(area) if letter == 'P' or letter == 'M' else (area, 0)
        area, t = read_to_eol(area)
        pArea.reset_list.append(reset)
        reset_list.append(reset)
    return area


def load_rooms(area, pArea):
    area, w = read_word(area,False)
    w = w[1:] # strip the pound
    while w != '0':
        room = ROOM_INDEX_DATA()
        room.vnum = int(w)
        if room.vnum in room_index_hash:
            print ("Dupicate room Vnum: %d" % room.vnum)
            sys.exit(1)

        room_index_hash[room.vnum] = room
        room.area = pArea
        area, room.name = read_string(area)
        area, room.description = read_string(area)
        area, number = read_int(area) #area number
        area, room.room_flags = read_flags(area)
        area, room.sector_type = read_int(area)
        while True:
            area, letter = read_letter(area)
            
            if letter == 'S':
                break
            elif letter == 'H': #Healing Room
                area, room.heal_rate = read_int(area)
            elif letter == 'M': #Mana Room
                area, room.mana_rate = read_int(area)
            elif letter == 'C': #Clan
                area, room.clan = read_string(area)
            elif letter == 'D': #exit
                exit = EXIT_DATA()
                area, door = read_int(area)
                area, exit.description = read_string(area)
                area, exit.keyword = read_string(area)
                area, locks = read_int(area)
                area, exit.key = read_int(area)
                area, exit.to_room = read_int(area)
                room.exit[door] = exit
            elif letter == 'E':
                ed = EXTRA_DESCR_DATA()
                area, ed.keyword = read_string(area)
                area, ed.description = read_string(area)
                room.extra_descr.append(ed)
            elif letter == 'O':
                area, room.owner = read_string(area)
            else:
                print ("RoomIndexData(%d) has flag other than SHMCDEO: %s" % ( room.vnum, letter ))
                sys.exit(1)
        area, w = read_word(area,False)
        w = w[1:] # strip the pound         
    return area

def load_shops(area):
    while True:
        area, keeper = read_int(area)

        if keeper == 0:
            break
        shop = SHOP_DATA()
        shop.keeper = keeper
        for r in range(MAX_TRADE):
            area, shop.buy_type[r] = read_int(area)
        area, shop.profit_buy = read_int(area)            
        area, shop.profit_sell = read_int(area)
        area, shop.open_hour = read_int(area)
        area, shop.close_hour = read_int(area)
        area, t = read_to_eol(area)
        mob_index_hash[keeper].pShop = shop
        shop_list.append(shop)
    return area

def load_socials(area):
    while True:
        area, word = read_word(area,False)

        if word == '#0':
            return
        social = SOCIAL_DATA()
        social.name = word
        area, throwaway = read_to_eol(area)
        area, line = read_to_eol(area)
        if line == '$':
            social.char_no_arg = None
        elif line == '#':
            if social not in social_list:
                social_list.append(social)
            continue
        else:
            social.char_no_arg = line

        area, line = read_to_eol(area)

        if line == '$':
            social.others_no_arg = None
        elif line == '#':
            if social not in social_list:
                social_list.append(social)
            continue
        else:
            social.others_no_arg = line
        area, line = read_to_eol(area)

        if line == '$':
            social.char_found = None
        elif line == '#':
            if social not in social_list:
                social_list.append(social)
            continue
        else:
            social.char_found = line
        area, line = read_to_eol(area)

        if line == '$':
            social.others_found = None
        elif line == '#':
            if social not in social_list:
                social_list.append(social)
            continue
        else:
            social.others_found = line
        area, line = read_to_eol(area)

        if line == '$':
            social.vict_found = None
        elif line == '#':
            if social not in social_list:
                social_list.append(social)
            continue
        else:
            social.vict_found = line
        area, line = read_to_eol(area)

        if line == '$':
            social.char_not_found = None
        elif line == '#':
            if social not in social_list:
                social_list.append(social)
            continue
        else:
            social.char_not_found = line
        area, line = read_to_eol(area)

        if line == '$':
            social.char_auto = None
        elif line == '#':
            if social not in social_list:
                social_list.append(social)
            continue
        else:
            social.char_auto = line
        area, line = read_to_eol(area)

        if line == '$':
            social.others_auto = None
        elif line == '#':
            if social not in social_list:
                social_list.append(social)
            continue
        else:
            social.others_auto = line

        if social not in social_list:
            social_list.append(social)
    return area

def load_specials(area):
    while True:
        area, letter = read_letter(area)

        if letter == '*':
            area, t = read_to_eol(area)
            continue
        elif letter == 'S':
            return area
        elif letter == 'M':
            area, vnum = read_int(area)
            area, mob_index_hash[vnum].spec_fun = read_word(area,False)
        else:
            print ("Load_specials: letter noth *SM: " + letter)
    
    return area

def fix_exits():
    for k, r in room_index_hash.items():
        for e in r.exit[:]:
            if e and type(e.to_room) == int:
                if e.to_room not in room_index_hash:
                    print ("Fix_exits: Failed to find to_room for %d: %d" % (r.vnum, e.to_room))
                    e.to_room = None
                    r.exit.remove(e)
                else:
                    e.to_room = room_index_hash[e.to_room]

# * Repopulate areas periodically.
def area_update( ):
    for pArea in area_list:
        pArea.age += 1
        if pArea.age < 3:
            continue
        #
        #* Check age and reset.
        #* Note: Mud School resets every 3 minutes (not 15).
        #*/
        if(not pArea.empty and (pArea.nplayer == 0 or pArea.age >= 15)) or pArea.age >= 31:
            reset_area( pArea )
            wiznet("%s has just been reset." % pArea.name,None,None,WIZ_RESETS,0,0)
    
        pArea.age = random.randint( 0, 3 )
        pRoomIndex = room_index_hash[ROOM_VNUM_SCHOOL]
        if pRoomIndex and pArea == pRoomIndex.area:
            pArea.age = 15 - 2
        elif pArea.nplayer == 0:
            pArea.empty = True

#
# * Reset one area.
def reset_area( pArea ):
    mob     = None
    last    = True
    level   = 0
    for pReset in pArea.reset_list:
        if pReset.command == 'M':
            if pReset.arg1 not in mob_index_hash:
                print ("Reset_area: 'M': bad vnum %d." % pReset.arg1)
                continue
            pMobIndex = mob_index_hash[pReset.arg1]

            if pReset.arg3 not in room_index_hash:
                print ("Reset_area: 'R': bad vnum %d." % pReset.arg3)
                continue
            pRoomIndex = room_index_hash[pReset.arg3]

            if pMobIndex.count >= pReset.arg2:
                last = False
                break
            count = 0
            for mob in pRoomIndex.people:
                if mob.pIndexData == pMobIndex:
                    count += 1
                    if count >= pReset.arg4:
                        last = False
                        break

            if count >= pReset.arg4:
                continue

            mob = create_mobile( pMobIndex )

            #
            #* Check for pet shop.
            # */
            
            
            if pRoomIndex.vnum-1 in room_index_hash:
                pRoomIndexPrev = room_index_hash[pRoomIndex.vnum-1]
                if IS_SET(pRoomIndexPrev.room_flags, ROOM_PET_SHOP):
                    mob.act = SET_BIT(mob.act, ACT_PET)

            # set area */
            mob.zone = pRoomIndex.area

            mob.to_room(pRoomIndex)
            level = max(0, min(mob.level - 2, LEVEL_HERO - 1 ) )
            last  = True

        elif pReset.command ==  'O':
            if pReset.arg1 not in obj_index_hash:
                print ("Reset_area: 'O': bad vnum %d." % pReset.arg1)
                continue
            pObjIndex = obj_index_hash[pReset.arg1]

            if pReset.arg3 not in room_index_hash:
                print ("Reset_area: 'R': bad vnum %d." % pReset.arg3)
                continue
            pRoomIndex = room_index_hash[pReset.arg3]

            if pArea.nplayer > 0 or count_obj_list( pObjIndex, pRoomIndex.contents ) > 0:
                last = False
                continue

            obj = create_object( pObjIndex, min(number_fuzzy(level), LEVEL_HERO - 1) )
            obj.cost = 0
            obj.to_room(pRoomIndex)
            last = True
            continue

        elif pReset.command == 'P':
            if pReset.arg1 not in obj_index_hash:
                print ("Reset_area: 'P': bad vnum %d." % pReset.arg1)
                continue
            pObjIndex = obj_index_hash[pReset.arg1]

            if pReset.arg3 not in obj_index_hash:
                print ("Reset_area: 'P': bad vnum %d." % pReset.arg3)
                continue
            pObjToIndex = obj_index_hash[pReset.arg3]
            if pReset.arg2 > 50: # old format */
                limit = 6
            elif pReset.arg2 == -1: # no limit */
                limit = 999
            else:
                limit = pReset.arg2
            
            obj_to = get_obj_type(pObjToIndex)
            
            if pArea.nplayer > 0 \
            or not obj_to \
            or (obj_to.in_room == None and not last) \
            or ( pObjIndex.count >= limit and random.randint(0,4) != 0) \
            or count_obj_list(pObjIndex, obj_to.contains) > pReset.arg4:
                last = False
                break
            count = count_obj_list(pObjIndex, obj_to.contains)
            while count < pReset.arg4:
                obj = create_object( pObjIndex, number_fuzzy(obj_to.level) )
                obj.to_obj(obj_to)
                count += 1
                if pObjIndex.count >= limit:
                    break

            # fix object lock state! */
            obj_to.value[1] = obj_to.pIndexData.value[1]
            last = True
        elif pReset.command == 'G' or pReset.command == 'E':
            if pReset.arg1 not in obj_index_hash:
                print ("Reset_area: 'E' or 'G': bad vnum %d." % pReset.arg1)
                continue
            pObjIndex = obj_index_hash[pReset.arg1]
            if not last:
                continue

            if not mob:
                print ("Reset_area: 'E' or 'G': None mob for vnum %d." % pReset.arg1)
                last = False
                continue
            olevel = 0
            if mob.pIndexData.pShop:
                if not pObjIndex.new_format:
                    if pObjIndex.item_type == ITEM_PILL \
                    or pObjIndex.item_type == ITEM_POTION \
                    or pObjIndex.item_type == ITEM_SCROLL:
                        olevel = 53
                        for i in pObjIndex.value:
                            if i > 0:
                                for j in skill_table[pObjIndex.value[i]].skill_level:
                                    olevel = min(olevel, j)
                       
                        olevel = max(0,(olevel * 3 // 4) - 2)
                        
                    elif pObjIndex.item_type == ITEM_WAND: olevel = random.randint( 10, 20 )
                    elif pObjIndex.item_type == ITEM_STAFF: olevel = random.randint( 15, 25 )
                    elif pObjIndex.item_type == ITEM_ARMOR: olevel = random.randint(  5, 15 )
                    elif pObjIndex.item_type == ITEM_WEAPON: olevel = random.randint(  5, 15 )
                    elif pObjIndex.item_type == ITEM_TREASURE: olevel = random.randint( 10, 20 )


                obj = create_object( pObjIndex, olevel )
                obj.extra_flags = SET_BIT(obj.extra_flags, ITEM_INVENTORY)
            else:
                if pReset.arg2 > 50: # old format */
                    limit = 6
                elif pReset.arg2 == -1: # no limit */
                    limit = 999
                else:
                    limit = pReset.arg2

                if pObjIndex.count < limit or random.randint(0,4) == 0:
                    obj = create_object(pObjIndex,min(number_fuzzy(level), LEVEL_HERO - 1))
                # error message if it is too high */
                if obj.level > mob.level + 3 \
                or  (obj.item_type == ITEM_WEAPON  \
                and   pReset.command == 'E' \
                and   obj.level < mob.level -5 and obj.level < 45):
                    print ("Err: obj %s (%d) -- %d, mob %s (%d) -- %d\n" % (
                    obj.short_descr,obj.pIndexData.vnum,obj.level,
                    mob.short_descr,mob.pIndexData.vnum,mob.level))
                else:
                    continue
            obj.to_char(mob)
            if pReset.command == 'E':
                mob.equip(obj, pReset.arg3)
                last = True
                continue

        elif pReset.command == 'D':
            if pReset.arg1 not in room_index_hash:
                print ("Reset_area: 'D': bad vnum %d." % pReset.arg1)
                continue
            pRoomIndex = room_index_hash[pReset.arg1]
            pexit = pRoomIndex.exit[pReset.arg2]
            if not pexit:
                continue

            if pReset.arg3 == 0:
                pexit.exit_info = REMOVE_BIT(pexit.exit_info, EX_CLOSED)
                pexit.exit_info = REMOVE_BIT(pexit.exit_info, EX_LOCKED)
                continue
            elif pReset.arg3 == 1:
                pexit.exit_info = SET_BIT(pexit.exit_info, EX_CLOSED )
                pexit.exit_info = REMOVE_BIT(pexit.exit_info, EX_LOCKED )
                continue
            elif pReset.arg3 == 2:
                pexit.exit_info = SET_BIT(pexit.exit_info, EX_CLOSED )
                pexit.exit_info = SET_BIT(pexit.exit_info, EX_LOCKED )
                continue
            last = True
            continue

        elif pReset.command == 'R':
            if pReset.arg1 not in room_index_hash:
                print ("Reset_area: 'R': bad vnum %d." % pReset.arg1)
                continue
            pRoomIndex = room_index_hash[pReset.arg1]
            for d0 in range(pReset.arg2 - 1):
                d1                   = random.randint( d0, pReset.arg2-1 )
                pexit                = pRoomIndex.exit[d0]
                pRoomIndex.exit[d0] = pRoomIndex.exit[d1]
                pRoomIndex.exit[d1] = pexit
                break
        else:
            print ("Reset_area: bad command %c." % pReset.command)


#
# * Create an instance of a mobile.

def create_mobile( pMobIndex ):
    if pMobIndex == None:
        print ("Create_mobile: None pMobIndex.")
        sys.exit( 1 )
    
    mob = CHAR_DATA()

    mob.pIndexData = pMobIndex

    mob.name = pMobIndex.player_name
    mob.id = get_mob_id()
    mob.short_descr = pMobIndex.short_descr
    mob.long_descr = pMobIndex.long_descr
    mob.description = pMobIndex.description
    if pMobIndex.spec_fun:
        mob.spec_fun = spec_table[pMobIndex.spec_fun]
    mob.prompt = None

    if pMobIndex.wealth == 0:
        mob.silver = 0
        mob.gold   = 0
    else:
        wealth = random.randint(pMobIndex.wealth // 2, 3 * pMobIndex.wealth // 2)
        mob.gold = random.randint(wealth // 200, wealth // 100)
        mob.silver = wealth - (mob.gold * 100)


    if pMobIndex.new_format:
    # load in new style */
        # read from prototype */
        mob.group = pMobIndex.group
        mob.act = pMobIndex.act
        mob.comm = COMM_NOCHANNELS|COMM_NOSHOUT|COMM_NOTELL
        mob.affected_by = pMobIndex.affected_by
        mob.alignment = pMobIndex.alignment
        mob.level = pMobIndex.level
        mob.hitroll = pMobIndex.hitroll
        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:
            num = random.randint(1,3)
            if num == 1: mob.dam_type = 3 # slash */
            elif num == 2: mob.dam_type = 7 # pound */
            elif num == 3: mob.dam_type = 11 # pierce */
        for i in range(4):
            mob.armor[i] = pMobIndex.ac[i] 
        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 type(pMobIndex.sex) != int or mob.sex == 3: # random sex */
            mob.sex = random.randint(1,2)
        mob.race = pMobIndex.race
        mob.form = pMobIndex.form
        mob.parts = pMobIndex.parts
        mob.size = int(pMobIndex.size)
        mob.material = pMobIndex.material

        # computed on the spot */
        for i in range(MAX_STATS):
            mob.perm_stat[i] = min(25, 11 + mob.level // 4)
            
        if IS_SET(mob.act,ACT_WARRIOR):
            mob.perm_stat[STAT_STR] += 3
            mob.perm_stat[STAT_INT] -= 1
            mob.perm_stat[STAT_CON] += 2
        
        if IS_SET(mob.act,ACT_THIEF):
            mob.perm_stat[STAT_DEX] += 3
            mob.perm_stat[STAT_INT] += 1
            mob.perm_stat[STAT_WIS] -= 1
        
        if IS_SET(mob.act,ACT_CLERIC):
            mob.perm_stat[STAT_WIS] += 3
            mob.perm_stat[STAT_DEX] -= 1
            mob.perm_stat[STAT_STR] += 1
        
        if IS_SET(mob.act,ACT_MAGE):
            mob.perm_stat[STAT_INT] += 3
            mob.perm_stat[STAT_STR] -= 1
            mob.perm_stat[STAT_DEX] += 1
        
        if IS_SET(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
        af = AFFECT_DATA()
        # let's get some spell action */
        if IS_AFFECTED(mob,AFF_SANCTUARY):
            af.where     = TO_AFFECTS
            af.type      = "sanctuary"
            af.level     = mob.level
            af.duration  = -1
            af.location  = APPLY_NONE
            af.modifier  = 0
            af.bitvector = AFF_SANCTUARY
            mob.affect_add(af)

        if IS_AFFECTED(mob,AFF_HASTE):
            af.where     = TO_AFFECTS
            af.type      = "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
            mob.affect_add(af)

        if IS_AFFECTED(mob,AFF_PROTECT_EVIL):
            af.where     = TO_AFFECTS
            af.type  = "protection evil"
            af.level     = mob.level
            af.duration  = -1
            af.location  = APPLY_SAVES
            af.modifier  = -1
            af.bitvector = AFF_PROTECT_EVIL
            mob.affect_add(af)

        if IS_AFFECTED(mob,AFF_PROTECT_GOOD):
            af.where     = TO_AFFECTS
            af.type      = "protection good"
            af.level     = mob.level
            af.duration  = -1
            af.location  = APPLY_SAVES
            af.modifier  = -1
            af.bitvector = AFF_PROTECT_GOOD
            mob.affect_add(af)
    else: # read in old format and convert */
        mob.act        = pMobIndex.act
        mob.affected_by    = pMobIndex.affected_by
        mob.alignment      = pMobIndex.alignment
        mob.level      = pMobIndex.level
        mob.hitroll        = pMobIndex.hitroll
        mob.damroll        = 0
        mob.max_hit        = mob.level * 8 + random.randint( mob.level * mob.level // 4, mob.level * mob.level)
        mob.max_hit *= .9
        mob.hit        = mob.max_hit
        mob.max_mana       = 100 + dice(mob.level,10)
        mob.mana       = mob.max_mana
        num = random.randint(1,3)
        if num == 1: mob.dam_type = 3 # slash */
        elif num == 2: mob.dam_type = 7  # pound */
        elif num == 3: mob.dam_type = 11  # pierce */
        for i in range(3):
            mob.armor[i] = interpolate(mob.level,100,-100)
        mob.armor[3] = interpolate(mob.level,100,0)
        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
        mob.form       = pMobIndex.form
        mob.parts      = pMobIndex.parts
        mob.size       = SIZE_MEDIUM
        mob.material       = ""

        for i in MAX_STATS:
            mob.perm_stat[i] = 11 + mob.level // 4
    mob.position = mob.start_pos


    # link the mob to the world list */
    char_list.append(mob)
    return mob

# duplicate a mobile exactly -- except inventory */
def clone_mobile(parent, clone):
    if not parent or not clone or not IS_NPC(parent):
        return
    
    # start fixing values */ 
    clone.name     = parent.name
    clone.version  = parent.version
    clone.short_descr  = parent.short_descr
    clone.long_descr   = parent.long_descr
    clone.description  = parent.description
    clone.group    = parent.group
    clone.sex      = parent.sex
    clone.guild    = parent.guild
    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
    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 in range(4):
        clone.armor[i] = parent.armor[i]

    for i in range(MAX_STATS):
        clone.perm_stat[i] = parent.perm_stat[i]
        clone.mod_stat[i]  = parent.mod_stat[i]
    
    for i in range(3):
        clone.damage[i]    = parent.damage[i]

    # now add the affects */
    for paf in parent.affected:
        clone.affect_add(paf)

# * Create an instance of an object.
def create_object( pObjIndex, level ):
    if not pObjIndex:
        print ("Create_object: None pObjIndex.")
        sys.exit( 1 )

    obj = OBJ_DATA()

    obj.pIndexData = pObjIndex
    obj.in_room    = None
    obj.enchanted  = False

    if pObjIndex.new_format == True:
        obj.level = pObjIndex.level
    else:
        obj.level      = max(0,level)
    obj.wear_loc   = -1

    obj.name       = pObjIndex.name
    obj.short_descr    = pObjIndex.short_descr
    obj.description    = pObjIndex.description
    obj.material   = pObjIndex.material
    obj.item_type  = pObjIndex.item_type
    obj.extra_flags    = pObjIndex.extra_flags
    obj.wear_flags = pObjIndex.wear_flags
    obj.value = pObjIndex.value[:]
    obj.weight     = pObjIndex.weight

    if level == -1 or pObjIndex.new_format:
        obj.cost   = pObjIndex.cost
    else:
        obj.cost   = number_fuzzy( 10 ) * number_fuzzy( level ) * number_fuzzy( level )


     # Mess with object properties.
    if obj.item_type == ITEM_LIGHT:
        if obj.value[2] == 999:
            obj.value[2] = -1
    elif obj.item_type == ITEM_FURNITURE \
      or obj.item_type == ITEM_TRASH \
      or obj.item_type == ITEM_CONTAINER \
      or obj.item_type == ITEM_DRINK_CON \
      or obj.item_type == ITEM_KEY \
      or obj.item_type == ITEM_FOOD \
      or obj.item_type == ITEM_BOAT \
      or obj.item_type == ITEM_CORPSE_NPC \
      or obj.item_type == ITEM_CORPSE_PC \
      or obj.item_type == ITEM_FOUNTAIN \
      or obj.item_type == ITEM_MAP \
      or obj.item_type == ITEM_CLOTHING \
      or obj.item_type == ITEM_PORTAL:
        if not pObjIndex.new_format:
            obj.cost //= 5
    elif obj.item_type == ITEM_TREASURE \
      or obj.item_type == ITEM_WARP_STONE \
      or obj.item_type == ITEM_ROOM_KEY \
      or obj.item_type == ITEM_GEM \
      or obj.item_type == ITEM_JEWELRY:
        pass
    elif obj.item_type == ITEM_JUKEBOX:
        obj.value = [-1 for i in range(5)]
    elif obj.item_type == ITEM_SCROLL:
        if level != -1 and not pObjIndex.new_format:
            obj.value[0]   = number_fuzzy( obj.value[0])
    elif obj.item_type == ITEM_WAND \
      or obj.item_type == ITEM_STAFF:
        if level != -1 and not 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 not pObjIndex.new_format:
            obj.cost *= 2
    elif obj.item_type == ITEM_WEAPON:
        if level != -1 and not 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 ) )
    elif obj.item_type == ITEM_ARMOR:
        if level != -1 and not 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 )
    elif obj.item_type == ITEM_POTION \
      or obj.item_type == ITEM_PILL:
        if level != -1 and not pObjIndex.new_format:
            obj.value[0] = number_fuzzy( number_fuzzy( obj.value[0] ) )
    elif obj.item_type == ITEM_MONEY:
        if not pObjIndex.new_format:
            obj.value[0]   = obj.cost
    else:
        print ("Bad item_type pObjIndex vnum: %s(%s)" % (pObjIndex.vnum, obj.item_type ))
  
    for paf in pObjIndex.affected:
        if paf.location == APPLY_SPELL_AFFECT:
            obj.affect_add(paf)
    obj.extra_descr = pObjIndex.extra_descr
    object_list.append(obj)
    return obj


# duplicate an object exactly -- except contents */
def clone_object(parent, clone):
    if not parent or not clone:
        return

    # start fixing the object */
    clone.name     = parent.name
    clone.short_descr  = parent.short_descr
    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
    clone.material = parent.material
    clone.timer    = parent.timer

    for i in parent.value:
        clone.value[i] = i

    # affects */
    clone.enchanted    = parent.enchanted
  
    for paf in parent.affected:
        clone.affect_add(paf)

    # extended desc */
    for ed in parent.extra_descr:
        ed_new                  = EXTRA_DESCR_DATA()
        ed_new.keyword     =  ed.keyword
        ed_new.description     = ed.description
        clone.extra_descr.append(ed)

#
# * Clear a new character.
# */
def clear_char( ch ):
    ch.name            = ""
    ch.short_descr     = ""
    ch.long_descr      = ""
    ch.description     = ""
    ch.prompt          = ""
    ch.logon           = time.time()
    ch.lines           = 22
    for i in range(4):
        ch.armor[i]        = 100
    ch.position        = POS_STANDING
    ch.hit         = 20
    ch.max_hit         = 20
    ch.mana            = 100
    ch.max_mana        = 100
    ch.move            = 100
    ch.max_move        = 100
    ch.on          = None
    for i in MAX_STATS:
        ch.perm_stat[i] = 13 
        ch.mod_stat[i] = 0
    return

# * Create a 'money' obj.
def create_money(gold, silver):
    if gold < 0 or silver < 0 or (gold == 0 and silver == 0):
        print ("BUG: Create_money: zero or negative money. %d " % min(gold,silver))
        gold = max(1,gold)
        silver = max(1,silver)

    if gold == 0 and silver == 1:
        obj = create_object(obj_index_hash[OBJ_VNUM_SILVER_ONE], 0)
    elif gold == 1 and silver == 0:
        obj = create_object(obj_index_hash[OBJ_VNUM_GOLD_ONE], 0)
    elif silver == 0:
        obj = create_object(obj_index_hash[OBJ_VNUM_GOLD_SOME], 0)
        obj.short_descr += " %d" % gold
        obj.value[1] = gold
        obj.cost = gold
        obj.weight = gold // 5
    elif gold == 0:
        obj = create_object(obj_index_hash[OBJ_VNUM_SILVER_SOME], 0)
        obj.short_descr += " %d" % silver
        obj.value[0] = silver
        obj.cost = silver
        obj.weight = silver // 20
    else:
        obj = create_object(obj_index_hash[OBJ_VNUM_COINS], 0)
        obj.short_descr += " %d %d" % (gold, silver)
        obj.value[0] = silver
        obj.value[1] = gold
        obj.cost = 100 * gold + silver
        obj.weight = gold // 5 + silver // 20
    return obj

# * Get an extra description from a list.
def get_extra_descr(name, edlist):
    if not edlist: return None
    for ed in edlist:
        if name.lower() in ed.keyword:
            return ed.description
    return None

def init_time():
    lhour = (time.time() - 650336715) // (PULSE_TICK // PULSE_PER_SECOND)
    lhour = int(lhour)
    time_info.hour = lhour % 24
    lday = lhour // 24
    time_info.day = int(lday % 35)
    lmonth = lday // 35
    time_info.month = lmonth % 17
    time_info.year = lmonth // 17

    if time_info.hour <  5:
        weather_info.sunlight = SUN_DARK
    elif time_info.hour <  6:
        weather_info.sunlight = SUN_RISE
    elif time_info.hour < 19:
        weather_info.sunlight = SUN_LIGHT
    elif time_info.hour < 20:
        weather_info.sunlight = SUN_SET
    else:
        weather_info.sunlight = SUN_DARK
    weather_info.change = 0
    weather_info.mmhg   = 960
    if time_info.month >= 7 and time_info.month <= 12:
        weather_info.mmhg += random.randint(1, 50)
    else:
        weather_info.mmhg += random.randint(1, 80)

    if weather_info.mmhg <= 980:
        weather_info.sky = SKY_LIGHTNING
    elif weather_info.mmhg <= 1000:
        weather_info.sky = SKY_RAINING
    elif weather_info.mmhg <= 1020:
        weather_info.sky = SKY_CLOUDY
    else:
        weather_info.sky = SKY_CLOUDLESS