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/
 ************/
"""

from merc import *
import const
import update
import magic

# used to get new skills */
def do_gain(self, argument):
    ch = self
    if IS_NPC(ch):
        return
    trainer = [t for t in ch.in_room.people if IS_NPC(t) and IS_SET(t.act,ACT_GAIN)]
    # find a trainer */
    if not trainer or not ch.can_see(trainer):
        ch.send("You can't do that here.\n")
        return
   
    argmod, arg = read_word(argument)

    if not arg:
        trainer.do_say("Pardon me?")
        return

    if "list".startswith(arg):
        col = 0
        ch.send("%-18s %-5s %-18s %-5s %-18s %-5s\n" % ("group","cost","group","cost","group","cost") )
        for gn,group in const.group_table.items():
            if gn not in ch.pcdata.group_known and  group.rating[ch.guild.name] > 0:
                ch.send("%-18s %-5d " % group.name,group.rating[ch.guild.name])
                col+=1
                if (col % 3) == 0:
                    ch.send("\n")
        if (col % 3) != 0:
            ch.send("\n")
    
        ch.send("\n")        

        col = 0

        ch.send("%-18s %-5s %-18s %-5s %-18s %-5s\n" % ("skill","cost","skill","cost","skill","cost"))
 
        for sn,skill in const.skill_table.items():
            if sn not in ch.pcdata.learned \
            and  skill.rating[ch.guild.name] > 0 \
            and  skill.spell_fun == magic.spell_null:
                ch.send("%-18s %-5d " % (const.skill_table[sn].name,skill.rating[ch.guild.name]))
                col += 1
                if (col % 3) == 0:
                    ch.send("\n")
        if (col % 3) != 0:
            ch.send("\n")
        return

    if "convert".startswith(arg):
        if ch.practice < 10:
            act("$N tells you 'You are not yet ready.'",ch,None,trainer,TO_CHAR)
            return
        act("$N helps you apply your practice to training", ch,None,trainer,TO_CHAR)
        ch.practice -= 10
        ch.train +=1 
        return

    if "points".startswith(arg):
        if ch.train < 2:
            act("$N tells you 'You are not yet ready.'", ch,None,trainer,TO_CHAR)
            return

        if ch.pcdata.points <= 40:
            act("$N tells you 'There would be no point in that.'", ch,None,trainer,TO_CHAR)
            return
        act("$N trains you, and you feel more at ease with your skills.", ch,None,trainer,TO_CHAR)

        ch.train -= 2
        ch.pcdata.points -= 1
        ch.exp = ch.exp_per_level(ch.pcdata.points) * ch.level
        return

    
    
    if argument.lower() in const.group_table:
        gn = const.group_table[argument.lower()]
        if gn.name in ch.pcdata.group_known:
            act("$N tells you 'You already know that group!'", ch,None,trainer,TO_CHAR)
            return
        if gn.rating[ch.guild.name] <= 0:
            act("$N tells you 'That group is beyond your powers.'", ch,None,trainer,TO_CHAR)
            return

        if ch.train < gn.rating[ch.guild.name]:
            act("$N tells you 'You are not yet ready for that group.'", ch,None,trainer,TO_CHAR)
            return

        # add the group */
        gn_add(ch,gn)
        act("$N trains you in the art of $t", ch,gn.name,trainer,TO_CHAR)
        ch.train -= gn.rating[ch.guild.name]
        return

    if argument.lower() in const.skill_table:
        sn = const.skill_table[argument.lower()]
        if sn.spell_fun != magic.spell_null:
            act("$N tells you 'You must learn the full group.'", ch,None,trainer,TO_CHAR)
            return
        
        if sn.name in ch.pcdata.learned:
            act("$N tells you 'You already know that skill!'", ch,None,trainer,TO_CHAR)
            return

        if sn.rating[ch.guild.name] <= 0:
            act("$N tells you 'That skill is beyond your powers.'", ch,None,trainer,TO_CHAR)
            return

 
        if ch.train < sn.rating[ch.guild.name]:
            act("$N tells you 'You are not yet ready for that skill.'", ch,None,trainer,TO_CHAR)
            return
        # add the skill */
        ch.pcdata.learned[sn.name] = 1
        act("$N trains you in the art of $t", sn.name,trainer,TO_CHAR)
        ch.train -= sn.rating[ch.guild.name]
        return

    act("$N tells you 'I do not understand...'",ch,None,trainer,TO_CHAR)
    return

# RT spells and skills show the players spells (or skills) */
def do_spells(self, argument):
    ch = self
    fAll = False
    min_lev = 1
    max_lev = LEVEL_HERO
    level = 0
    skill = None

    if IS_NPC(ch):
      return
    argument = argument.lower()
    if argument:
        fAll = True

        if not "all".startswith(argument):
            argument, arg = read_word(argument)
            if not arg.isdigit():
                ch.send("Arguments must be numerical or all.\n")
                return

            max_lev = int(arg)

            if max_lev < 1 or max_lev > LEVEL_HERO:
                ch.send("Levels must be between 1 and %d.\n" % LEVEL_HERO)
                return

            if argument:
                argument, arg = read_word(argument)
                if not arg.isdigit():
                    ch.send("Arguments must be numerical or all.\n")
                    return
                
                min_lev = max_lev
                max_lev = int(arg)

                if max_lev < 1 or max_lev > LEVEL_HERO:
                    ch.send("Levels must be between 1 and %d.\n" % LEVEL_HERO)
                    return

                if min_lev > max_lev:
                    ch.send("That would be silly.\n")
                    return

    found = False
    spell_list = {} 
    spell_column = {}
    for sn, skill in const.skill_table.items():
        level = skill.skill_level[ch.guild.name]
        if level < LEVEL_HERO + 1 \
        and (fAll or level <= ch.level) \
        and level >= min_lev and level <= max_lev \
        and skill.spell_fun != magic.spell_null \
        and sn in ch.pcdata.learned:
            found = True
            level = skill.skill_level[ch.guild.name]
            if ch.level < level:
                buf = "%-18s  n/a      " % skill.name
            else:
                mana = max(skill.min_mana, 100/(2 + ch.level - level))
                buf = "%-18s  %3d mana  " % (skill.name,mana)
 
            if level not in spell_list:
                spell_list[level] = "\nLevel %2d: %s" % (level,buf)
                spell_column[level] = 0
            else: # append */
                spell_column[level] += 1
                if spell_column[level] % 2 == 0:
                    spell_list[level] += "\n          "
                spell_list[level] += buf

    # return results */
    if not found:
        ch.send("No spells found.\n")
        return

    for level, buf in spell_list.items():
        ch.send(buf)
    ch.send("\n")

# recursively adds a group given its number -- uses group_add */
def gn_add( ch, gn):
    ch.pcdata.group_known[gn.name] = True
    for i in gn.spells:
        if not i:
            break
        group_add(ch,i,False)

# recusively removes a group given its number -- uses group_remove */
def gn_remove( ch, gn):
    if gn.name in ch.pcdata.group_known:
        del ch.pcdata.group_known[gn.name]

    for i in gn.spells:
        if not i:
            return
        group_remove(ch,i)

# use for processing a skill or group for addition  */
def group_add( ch, name, deduct):
    if IS_NPC(ch): # NPCs do not have skills */
        return
    
    if name in const.skill_table:
        sn = const.skill_table[name]
        if sn.name not in ch.pcdata.learned: # i.e. not known */
            ch.pcdata.learned[sn.name] = 1
        if deduct:
            ch.pcdata.points += sn.rating[ch.guild.name] 
        return

    # now check groups */

    if name in const.group_table:
        gn = const.group_table[name]
        if gn.name not in ch.pcdata.group_known:
            ch.pcdata.group_known[gn.name] = True
        if deduct:
            ch.pcdata.points += gn.rating[ch.guild.name]
    
        gn_add(ch,gn) # make sure all skills in the group are known */


# used for processing a skill or group for deletion -- no points back! */

def group_remove(ch, name):
    
    if name in const.skill_table:
        sn = const.skill_table[name]
        if sn.name in ch.pcdata.learned:
            del ch.pcdata.learned[sn.name]
            return

    # now check groups */
    if name in const.group_table:
        gn = const.group_table[name]
        
        if gn.name in ch.pcdata.group_known:
            del ch.pcdata.group_known[gn.name]
            gn_remove(ch,gn) # be sure to call gn_add on all remaining groups */

def do_skills(self, argument):
    ch = self
    fAll = False
    found = False
    min_lev = 1
    max_lev = LEVEL_HERO
    level = 0
    skill = None
    if IS_NPC(ch):
      return
    argument = argument.lower()
    if argument:
        fAll = True

        if not "all".startswith(argument):
            argument, arg = read_word(argument)
            if not arg.isdigit():
                ch.send("Arguments must be numerical or all.\n")
                return

            max_lev = int(arg)

            if max_lev < 1 or max_lev > LEVEL_HERO:
                ch.send("Levels must be between 1 and %d.\n" % LEVEL_HERO)
                return

            if argument:
                argument, arg = read_word(argument)
                if not arg.isdigit():
                    ch.send("Arguments must be numerical or all.\n")
                    return
                
                min_lev = max_lev
                max_lev = int(arg)

                if max_lev < 1 or max_lev > LEVEL_HERO:
                    ch.send("Levels must be between 1 and %d.\n" % LEVEL_HERO)
                    return

                if min_lev > max_lev:
                    ch.send("That would be silly.\n")
                    return

    skill_columns = {}
    skill_list = {}
 
    for sn, skill in const.skill_table.items():
        level = skill.skill_level[ch.guild.name]
        if level < LEVEL_HERO + 1 \
        and  (fAll or level <= ch.level) \
        and  level >= min_lev and level <= max_lev \
        and  skill.spell_fun == magic.spell_null \
        and  sn in ch.pcdata.learned:
            found = True
            level = skill.skill_level[ch.guild.name]
            if ch.level < level:
                buf = "%-18s n/a      " % skill.name
            else:
                buf = "%-18s %3d%%      " % (skill.name, ch.pcdata.learned[sn])
 
            if level not in skill_list:
                skill_list[level] =  "\nLevel %2d: %s" % (level,buf)
                skill_columns[level] = 0
            else: # append */
                skill_columns[level] += 1
                if skill_columns[level] % 2 == 0:
                    skill_list[level] += "\n          "
                skill_list[level] += buf
 
    # return results */
    if not found:
        ch.send("No skills found.\n")
        return

    for level, buf in skill_list.items():
        ch.send(buf)
    ch.send("\n")


# shows skills, groups and costs (only if not bought) */
def list_group_costs(ch):
    if IS_NPC(ch):
        return
    col = 0
    ch.send("%-18s %-5s %-18s %-5s %-18s %-5s\n" % ("group","cp","group","cp","group","cp"))

    for gn, group in const.group_table.items():
        if gn not in ch.gen_data.group_chosen and gn not in ch.pcdata.group_known and group.rating[ch.guild.name] > 0:
            ch.send("%-18s %-5d " % (const.group_table[gn].name, group.rating[ch.guild.name]))
            col += 1
            if col % 3 == 0:
                ch.send("\n")
    if col % 3 != 0:
        ch.send("\n")
    ch.send("\n")
    col = 0
 
    ch.send("%-18s %-5s %-18s %-5s %-18s %-5s\n" % ("skill","cp","skill","cp","skill","cp"))
 
    for sn, skill in const.skill_table.items():
        if sn not in ch.gen_data.skill_chosen \
        and sn not in ch.pcdata.learned \
        and  skill.spell_fun == magic.spell_null \
        and  skill.rating[ch.guild.name] > 0:
            ch.send("%-18s %-5d " % (skill.name, skill.rating[ch.guild.name]))
            col += 1
            if col % 3 == 0:
                ch.send("\n")
    if  col % 3 != 0:
        ch.send( "\n" )
    ch.send("\n")

    ch.send("Creation points: %d\n" % ch.pcdata.points)
    ch.send("Experience per level: %d\n" % ch.exp_per_level(ch.gen_data.points_chosen))
    return

def list_group_chosen(ch):
    if IS_NPC(ch):
        return
    col = 0
    ch.send("%-18s %-5s %-18s %-5s %-18s %-5s" % ("group","cp","group","cp","group","cp\n"))
 
    for gn, group in const.group_table.items():
        if gn in ch.gen_data.group_chosen and group.rating[ch.guild.name] > 0:
            ch.send("%-18s %-5d " % (group.name, group.rating[ch.guild.name]) )
            col += 1
            if col % 3 == 0:
                ch.send("\n")
    if col % 3 != 0:
        ch.send( "\n" )
    ch.send("\n")
 
    col = 0
 
    ch.send("%-18s %-5s %-18s %-5s %-18s %-5s" % ("skill","cp","skill","cp","skill","cp\n"))

    for sn, skill in const.skill_table.items():
        if sn in ch.gen_data.skill_chosen and skill.rating[ch.guild.name] > 0:
            ch.send("%-18s %-5d " % ( skill.name, skill.rating[ch.guild.name]) )
            col += 1
            if col % 3 == 0:
                ch.send("\n")
    if col % 3 != 0:
        ch.send( "\n" )
    ch.send("\n")
 
    ch.send("Creation points: %d\n" % ch.gen_data.points_chosen)
    ch.send("Experience per level: %d\n" % ch.exp_per_level(ch.gen_data.points_chosen))
    return

# this procedure handles the input parsing for the skill generator */
def parse_gen_groups(ch, argument):
    if not argument.strip():
        return False

    argument, arg = read_word(argument)
    if "help".startswith(arg):
        if not argument:
            ch.do_help("group help")
            return True

        ch.do_help(argument)
        return True

    if "add".startswith(arg):
        if not argument:
            ch.send("You must provide a skill name.\n")
            return True
        argument = argument.lower()
        if argument in const.group_table:
            gn = const.group_table[argument]
            if gn.name in ch.gen_data.group_chosen or gn.name in ch.pcdata.group_known:
                ch.send("You already know that group!\n")
                return True
            
            if gn.rating[ch.guild.name] < 1:
                ch.send("That group is not available.\n")
                return True

            # Close security hole */
            if ch.gen_data.points_chosen + gn.rating[ch.guild.name] > 300:
                ch.send("You cannot take more than 300 creation points.\n")
                return True
            
            ch.send("%s group added\n" % gn.name)
            ch.gen_data.group_chosen[gn.name] = True
            ch.gen_data.points_chosen += gn.rating[ch.guild.name]
            gn_add(ch,gn)
            ch.pcdata.points += gn.rating[ch.guild.name]
            return True

        if argument in const.skill_table:
            sn = const.skill_table[argument]
            if sn.name in ch.gen_data.skill_chosen or sn.name in ch.pcdata.learned:
                ch.send("You already know that skill!\n")
                return True

            if sn.rating[ch.guild.name] < 1 or sn.spell_fun != magic.spell_null:
                ch.send("That skill is not available.\n")
                return True
            # Close security hole */
            if ch.gen_data.points_chosen + sn.rating[ch.guild.name] > 300:
                ch.send("You cannot take more than 300 creation points.\n")
                return True
            
            ch.send("%s skill added\n" % sn.name)
            ch.gen_data.skill_chosen[sn.name] = True
            ch.gen_data.points_chosen += sn.rating[ch.guild.name]
            ch.pcdata.learned[sn] = 1
            ch.pcdata.points += sn.rating[ch.guild.name]
            return True

        ch.send("No skills or groups by that name...\n")
        return True

    if "drop".startswith(arg):
        if not argument:
            ch.send("You must provide a skill to drop.\n")
            return True
    
        argument = argument.lower()
        if argument in const.group_table and argument in ch.gen_data.group_chosen:
            gn = const.group_table[argument]
            ch.send("Group dropped.\n")
            del ch.gen_data.group_chosen[gn.name]
            ch.gen_data.points_chosen -= gn.rating[ch.guild.name]
            gn_remove(ch,gn)
            for k,v in ch.gen_data.group_chosen:
                gn_add(ch,const.group_table[k])
            ch.pcdata.points -= gn.rating[ch.guild.name]
            return True
     
        if argument in const.skill_table and argument in ch.gen_data.skill_chosen:
            sn = const.skill_table[argument]
            ch.send("Skill dropped.\n")
            del ch.gen_data.skill_chosen[sn.name]
            ch.gen_data.points_chosen -= sn.rating[ch.guild.name]
            del ch.pcdata.learned[sn]
            ch.pcdata.points -= sn.rating[ch.guild.name]
            return True

        ch.send("You haven't bought any such skill or group.\n")
        return True

    if "premise".startswith(arg):
        ch.do_help("premise")
        return True

    if "list".startswith(arg):
        list_group_costs(ch)
        return True

    if "learned".startswith(arg):
        list_group_chosen(ch)
        return True

    if "info".startswith(arg):
        ch.do_groups(argument)
        return True

    return False

# shows all groups, or the sub-members of a group */
def do_groups(self, argument):
    ch = self
    if IS_NPC(ch):
        return
    col = 0

    if not argument:
        # show all groups */
        for gn, group in const.group_table.items():
            if gn in ch.pcdata.group_known:
                ch.send("%-20s " % group.name)
                col += 1
                if col % 3 == 0:
                    ch.send("\n")
        if col % 3 != 0:
            ch.send( "\n" )
        ch.send("Creation points: %d\n" % ch.pcdata.points)
        return

    if "all" == argument.lower():
        for gn,group in const.group_table.items():
            ch.send("%-20s " % group.name)
            col += 1
            if col % 3 == 0:
                ch.send("\n")
        if col % 3 != 0:
            ch.send( "\n" )
        return
     
    # show the sub-members of a group */
    if argument.lower() not in const.group_table:
        ch.send("No group of that name exist.\n")
        ch.send("Type 'groups all' or 'info all' for a full listing.\n")
        return

    gn = const.group_table[argument.lower()]
    for sn in group.spells:
        if not sn:
            break
        ch.send("%-20s " % sn)
        col += 1
        if col % 3 == 0:
            ch.send("\n")
    if col % 3 != 0:
        ch.send( "\n" )


# checks for skill improvement */
def check_improve( ch, sn, success, multiplier ):
    if IS_NPC(ch):
        return
    if type(sn) == str:
        sn = const.skill_table[sn]

    if ch.level < sn.skill_level[ch.guild.name] \
    or sn.rating[ch.guild.name] == 0 \
    or sn.name not in ch.pcdata.learned \
    or ch.pcdata.learned[sn.name] == 100:
        return  # skill is not known */ 

    # check to see if the character has a chance to learn */
    chance = 10 * const.int_app[ch.get_curr_stat(STAT_INT)].learn
    chance /= (multiplier * sn.rating[ch.guild.name] * 4)
    chance += ch.level

    if random.randint(1,1000) > chance:
        return

    # now that the character has a CHANCE to learn, see if they really have */ 

    if success:
        chance = max(5, min(100 - ch.pcdata.learned[sn.name], 95))
        if random.randint(1,99) < chance:
            ch.send("You have become better at %s!\n" % sn.name)
            ch.pcdata.learned[sn.name] += 1
            update.gain_exp(ch,2 * sn.rating[ch.guild.name])
    else:
        chance = max(5, min(ch.pcdata.learned[sn.name]/2,30))
        if random.randint(1,99) < chance:
            ch.send("You learn from your mistakes, and your %s skill improves.\n" % sn.name)
            ch.pcdata.learned[sn.name] += random.randint(1,3)
            ch.pcdata.learned[sn.name] = min(ch.pcdata.learned[sn.name],100)
            update.gain_exp(ch,2 * sn.rating[ch.guild.name])