Skillmodification

From Rafermand 2.0

Jump to: navigation, search

Contents

[edit] Warning

This is an early revision and I did not document my work too well and I am going from memory (I am hoping to get SVN setup for code changes soon to solve this issue). I would avoid this unless you know what you are doing and until it has been tested to work without any issue.

--Xerves

[edit] Brief List of Changes

This works on top of the the previous changes I made to the skill GUI and is a requirement for this snippet. Once you have it installed follow the directions here to make modifications to the already present code and new existing changes. Below is what you can expect with the change:

1. Affects for skills/spells listed in the Informational Window. I used a different Font that is evenly spaced so I could flush values directly. It isn't as nice of a font, but I feel it makes the window look clearner and more organized. All the information available via the Encylopedia is now available in the Info Window.

2. Client now has a lot more information about skills available including icon, passive, maxreuse, spellid, maxvalue, levelcapped, classes, and most spell data if a spell is associated with it. Example of how to use a GHOST class is available through the one used here for the skill data.

3. Skillinfo.py has been removed and the icons/level information is now being called from the world server via the client ghost information in #2

[edit] Actual Changes

Please make sure to save any of your files so you can go back if you need to (in particular if you are testing this before it confirmed to work properly). Thanks.

[edit] mud/world/character.py

Find the following class

class CharacterSkill(Persistent):

Replace it with the following

class CharacterSkill(Persistent):
    character = ForeignKey('Character')
    skillname = StringCol()
    level = IntCol(default = 1)
    
    #Persistent data for the client with skill information
    def _init(self,*args,**kw):
        Persistent._init(self, *args, **kw)
        self.skillInfo = None

[edit] mud/world/shard/playdata.py

Find the following keyed array

#
# Pretty stat prints are represented in a map with a key equal
# to the stat name and a value tuple of stat print name and a 
# bool indicating if the stat prints as a percent.
#
STAT_PRETTY = dict([stat.upper(), (stat , False)] for stat in RPG_STATS)

I am going to list my update to this. It contains all of the stat affects I could find so far. If you have added some to your game, make sure to update this list. It is used for affects for items, skills, and spells. It will create a dictionary for all the values in RPG_STATS and then manual entries for the rest. It probably should be moved to core.py at some point.

STAT_PRETTY = dict([stat.upper(), (stat , False)] for stat in RPG_STATS)
STAT_PRETTY["MAXHEALTH"]    = ("HP", False)
STAT_PRETTY["HEALTH"]       = ("HP", False)
STAT_PRETTY["MAXSTAMINA"]   = ("STA", False)
STAT_PRETTY["STAMINA"]      = ("STA", False)
STAT_PRETTY["MAXMANA"]      = ("MP", False)
STAT_PRETTY["PRE"]          = ("PRE", False)
STAT_PRETTY["REGENHEALTH"]  = ("Regen", False)
STAT_PRETTY["REGENSTAMINA"] = ("Revit", False)
STAT_PRETTY["REGENMANA"]    = ("MP Regen", False)
STAT_PRETTY["DEFENSE"]      = ("Defense", False)
STAT_PRETTY["OFFENSE"]      = ("Offense", False)
STAT_PRETTY["ARMOR"]        = ("Armor", False)
STAT_PRETTY["AGGRORANGE"]   = ("Aggro Range", False)
STAT_PRETTY["HASTE"]        = ("Melee Haste", True)
STAT_PRETTY["CASTHASTE"]    = ("Casting Haste", True)
STAT_PRETTY["MOVE"]         = ("Movement", True)
STAT_PRETTY["CASTHEALMOD"]  = ("Heal Mod", True)
STAT_PRETTY["CASTDMGMOD"]   = ("Cast Dmg Mod", True)
STAT_PRETTY["CRITICAL"]     = ("Critical", True)
STAT_PRETTY["VISIBILITY"]   = ("Visibility", True)
STAT_PRETTY["SIZE"]         = ("Size", True)
STAT_PRETTY["INNATEHASTE"]  = ("Innate Haste", True)
STAT_PRETTY["MELEEDMGMOD"]  = ("Melee Dmg Mod", True)
STAT_PRETTY["WATERBREATHING"] = ("Water Breathing", False)
STAT_PRETTY["SEEINVISIBILE"] = ("See Invis", True)                 

In the CharacterInfo class find the following

        spells = {}
        for cspell in character.spells:
            if not cspell.spellInfo:
                cspell.spellInfo = CharSpellInfo(character,cspell)
            spells[cspell.slot] = cspell.spellInfo

After it add the following

        nskills = {}
        for nskill in character.skills:
            if not nskill.skillInfo:
                nskill.skillInfo = NSkillInfo(character,nskill)
            nskills[nskill.skillname] = nskill.skillInfo

        # new skills Ghost Data
        state['NSKILLS'] = nskills

A few hundred lines down in the same class find the following

        spells = {}
        for cspell in character.spells:
            if not cspell.spellInfo:
                cspell.spellInfo = CharSpellInfo(character,cspell)
            else:
                cspell.spellInfo.refresh()
            
            spells[cspell.slot]=cspell.spellInfo
        
        if state['SPELLS']!=spells:
            changed['SPELLS']=state['SPELLS']=spells

After it add the following

        #Refreshes the skill data state when a change is made.  Already triggered via the old skills data code
        nskills = {}
        for nskill in character.skills:
            if not nskill.skillInfo:
                nskill.skillInfo = NSkillInfo(character,nskill)
            else:
                nskill.skillInfo.refresh()
                
            nskills[nskill.skillname] = nskill.skillInfo
        
        if state['NSKILLS']!=nskills:
            changed['NSKILLS']=state['NSKILLS']=nskills

Find the following class SpellInfoGhost and before it add this function (it is not part of a class so make sure you don't indent it into one). This function is used by both skills and spells to spit out info about the spells. Instead of updating it in two places I figured it would be best to have it in 1.

def get_spell_info_window(ghost, isSpell):
    text = []
        
    if isSpell:
        if ghost.LEVEL:
            ghost.NAME = ' '.join([ghost.BASENAME,ROMAN[ghost.LEVEL-1]])
            text.append(r'\cp\c3Level: \c0%s            '%ROMAN[ghost.LEVEL-1])
        
        # Skill
        if ghost.SKILLNAME:
            text.append(r'\c3Skill: \c0%s '%ghost.SKILLNAME)
            
        if ghost.LEVEL or ghost.SKILLNAME:
            text.append(r'\n')
        
    # Target
    if ghost.SPELLTYPE&RPG_SPELL_HARMFUL:
        text.append(r'\c3Target: \c1%-11s '%RPG_TARGET_TEXT[ghost.TARGET])
    else:
        text.append(r'\c3Target: \c2%-11s '%RPG_TARGET_TEXT[ghost.TARGET])
      
    # Range
    if ghost.TARGET != RPG_TARGET_SELF:
        text.append(r'\c3Range: \c0%im '%ghost.CASTRANGE)
     
    text.append(r'\n')
    # AOE Range
    if ghost.AOERANGE:
        text.append(r'\c3AoE Range: \c0%-3im     '%ghost.AOERANGE)
        
    # Duration
    if not ghost.DURATION:
        text.append(r'\c3Duration: \c0Instant ')
    else:
        d = ghost.DURATION/NEWDURSECOND
        if d > 60:
            m,s = divmod(d,10)
            text.append(r'\c3Duration: \c0%im %is '%(m,s))
        else:
            text.append(r'\c3Duration: \c0%is '%d)
    text.append(r'\n')
    if isSpell:        
        # Casting Time
        if not ghost.CASTTIME:
            text.append(r'\c3Cast Time: \c0Instant   ')
        else:
            d = ghost.CASTTIME/NEWDURSECOND
            if d > 60:
                m,s = divmod(d,60)
                tbuf = "%im %is"%(m,s)
                text.append(r'\c3Cast Time: \c0%-8s '%tbuf)
            else:
                tbuf = "%is"%d
                text.append(r'\c3Cast Time: \c0%-8s '%tbuf)
        
        # Mana Cost
        text.append(r'\c3Mana: \c0%i\n'%ghost.MANACOST)
        
        # Classes
        classtext = ' '.join(r'\c0%s\c3(\c0%i\c3)'%(cl,level) for cl,level in ghost.CLASSES)
        if classtext:
            text.append(r'\c3Classes: %s\n'%classtext)
        
    # Negate
    if ghost.NEGATE and ghost.NEGATEMAXLEVEL:
        text.append(r'\n\c3Negate: \c0%i \c3of max level \c0%i \n'%(ghost.NEGATE,ghost.NEGATEMAXLEVEL))
        
    # Components
    comptext = ' '.join(r'\c0%s\c3(\c0%i\c3)'%(c,count) for c,count in ghost.COMPONENTS)
    if comptext:
        text.append(r'\c3Components: %s\n'%comptext)
        
    if ghost.SPELLID:                        
        from mud.client.playermind import GetMoMClientDBConnection
        con = GetMoMClientDBConnection()
        count=1
        for effectID in con.execute('SELECT effect_proto_id FROM effect_proto_spell_proto WHERE spell_proto_id = %i;'%ghost.SPELLID):
            id,leech_id,drain_id,regen_id,size,pet_id,teleport,teleport_dst,dam_ref_per,dam_ref_max,rez,resist,invis,spell_ref_per,spell_ref_max,seeinvis,absorb,light,item_id,flags,absorb_type,illusion_id = con.execute('SELECT id,leech_effect_id,drain_effect_id,regen_effect_id,size,summon_pet_id,teleport,teleport_dst,dmg_reflection_percent,dmg_reflection_max,resurrection_x_p,resist,invisibility,spell_reflection_percent,spell_reflection_max,seeinvisibile,absorb_count,light,summon_item_id,flags,absorb_type,illusion_id FROM effect_proto WHERE id = %i;'%effectID).fetchone()
            
            # Pet
            if pet_id:
                pet_level,pet_name,pet_class,pet_race = con.execute('SELECT plevel,name,pclass_internal,race FROM spawn WHERE id = %i;'%pet_id).fetchone()
                if pet_level:
                    #2 spots taken, need to return if needed
                    if (count % 2 == 0):
                        text.append(r'\n')
                    newstring = "\\c3PET: \\c2L%s %s (%s %s)"%(pet_level,pet_name,pet_race,pet_class) 
                    text.append(r'%-40s    '%newstring)
                    text.append(r'\n')
                    count += 2
            # Item
            if item_id:
                item_level,item_name = con.execute('SELECT level,name FROM item_proto WHERE id = %i;'%item_id).fetchone()
                if item_level:
                    #2 spots taken, need to return if needed
                    if (count % 2 == 0):
                        text.append(r'\n')
                    newstring = "\\c3ITEM: \\c2L%s %s"%(item_level, item_name) 
                    text.append(r'%-40s    '%newstring)
                    text.append(r'\n')
                    count += 2
            # Illusion
            if illusion_id:
                text.append(r"ILLUSION")
                if (count % 2 == 0):
                    text.append(r'\n')
                count += 1
            # Resurrection
            if flags&RPG_EFFECT_RESURRECTION:
                text.append(r"REZ: %i%%"%(int(rez)))
                if (count % 2 == 0):
                    text.append(r'\n')
                count += 1
            # BANISH
            if flags&RPG_EFFECT_BANISH:
                text.append(r"BANISH PET")
                if (count % 2 == 0):
                    text.append(r'\n')
                count += 1
            # INTERRUPT
            if flags&RPG_EFFECT_INTERRUPT:
                text.append(r"SPELL INTERRUPT")
                if (count % 2 == 0):
                    text.append(r'\n')
                count += 1
        
            #damage
            for dam_type,dam_amount in con.execute('SELECT type,amount from effect_damage WHERE effect_proto_id = %i;'%id):
                newstring = "\\c3DAM: \\c2%s (%i)"%(RPG_RESIST_TEXT_SHORT[RESISTFORDAMAGE[dam_type]], dam_amount)
                text.append(r'%-25s  '%newstring)
                if (count % 2 == 0):
                    text.append(r'\n')
                count += 1
            #leech
            if leech_id:
                leech_rate,leech_tick,leech_type = con.execute('SELECT leech_tick_rate,leech_tick,leech_type FROM effect_leech WHERE id = %i;'%leech_id).fetchone()
                if leech_rate:
                    #2 spots taken, need to return if needed
                    if (count % 2 == 0):
                        text.append(r'\n')
                    s = leech_rate/NEWDURSECOND
                    newstring = "\\c3REGEN: \\c2%i %s per %is"%(leech_tick, leech_type, s) 
                    text.append(r'%-40s    '%newstring)
                    text.append(r'\n')
                    count += 2
            #regen
            if regen_id:
                regen_rate,regen_tick,regen_type = con.execute('SELECT regen_tick_rate,regen_tick,regen_type FROM effect_regen WHERE id = %i;'%regen_id).fetchone()
                if regen_rate:
                    #2 spots taken, need to return if needed
                    if (count % 2 == 0):
                        text.append(r'\n')
                    s = regen_rate/NEWDURSECOND
                    newstring = "\\c3REGEN: \\c2%i %s per %is"%(regen_tick, regen_type, s) 
                    text.append(r'%-40s    '%newstring)
                    text.append(r'\n')
                    count += 2
            #drain
            if drain_id:
                drain_rate,drain_tick,drain_type = con.execute('SELECT drain_tick_rate,drain_tick,drain_type FROM effect_drain WHERE id = %i;'%drain_id).fetchone()
                if drain_rate:
                    #2 spots taken, need to return if needed
                    if (count % 2 == 0):
                        text.append(r'\n')
                    s = drain_rate/NEWDURSECOND
                    newstring = "\\c3DRAIN: \\c2%i %s per %is"%(drain_tick, drain_type, s) 
                    text.append(r'%-34s    '%newstring)
                    text.append(r'\n')
                    count += 2
            #stats
            for stat_name,stat_value in con.execute('SELECT statname,value from effect_stat WHERE effect_proto_id = %i;'%id):        
                statupper = stat_name.upper()
                try:
                    prettyPrint, isPercent = STAT_PRETTY[statupper]
                    if isPercent:
                        if 0.0 < stat_value:
                            statstr = (r'\c3%s \c2%i%%'%(prettyPrint, stat_value * 100))
                            text.append(r'%-25s  '%(statstr))         
                        else:
                            statstr = (r'\c3%s \c1%i%%'%(prettyPrint, stat_value * 100)) 
                            text.append(r'%-25s  '%(statstr))   
                    else:
                        if 0 < stat_value:
                            statstr = (r'\c3%s \c2%i'%(prettyPrint, stat_value))
                            text.append(r'%-25s  '%(statstr))   
                        else:
                            statstr = (r'\c3%s \c1%i'%(prettyPrint, stat_value))
                            text.append(r'%-25s  '%(statstr))   
                    if (count % 2 == 0):
                        text.append(r'\n')
                    count += 1
                    continue;
                except:
                    pass
                    
                try:
                    prettyPrint = RPG_RESIST_TEXT[RPG_RESISTLOOKUP[stat_name]]
                    if 0 < stat_value:
                        statstr = (r'\c3RES %s \c2%i'%(prettyPrint, stat_value))
                        text.append(r'%-25s  '%(statstr))   
                    else:
                        statstr = (r'\c3RES %s \c1%i'%(prettyPrint, stat_value))
                        text.append(r'%-25s  '%(statstr))   
                    if (count % 2 == 0):
                        text.append(r'\n')
                    count += 1
                    continue
                except:
                    pass    
        if (count % 2 == 0):
           text.append(r'\n')            
    if isSpell:
        desctext = ghost.DESC
        if desctext:
            if len(text):
                text.append(r'\n%s'%desctext)
            else:
                text.append(desctext)        
    return text

In the SpellInfoGhost class replace the generateItemText function with this new one. It mainly moves most of the generation to the new function

    def generateItemText(self):
        from mud.client.playermind import GetMoMClientDBConnection
        con = GetMoMClientDBConnection()
        self.BASENAME,self.SPELLBOOKPIC,self.DESC,self.TARGET,self.CASTTIME,self.RECASTTIME,self.DURATION,self.CASTRANGE,self.AOERANGE,self.MANACOST,self.SKILLNAME,self.SPELLTYPE = con.execute('SELECT name,spellbook_pic,desc,target,cast_time,recast_time,duration,cast_range,aoe_range,mana_cost,skillname,spell_type FROM spell_proto WHERE id = %i LIMIT 1;'%self.ID).fetchone()
        self.CLASSES = tuple((classname,level) for classname,level in con.execute('SELECT classname,level FROM spell_class WHERE spell_proto_id = %i;'%self.ID))
        self.COMPONENTS = []
        for protoID,count in con.execute('SELECT item_proto_id,count FROM spell_component WHERE spell_proto_id = %i;'%self.ID):
            self.COMPONENTS.append((con.execute('SELECT name FROM item_proto WHERE id = %i LIMIT 1;'%protoID).fetchone()[0],count))
        negate = negatemax = 0
            
        for neg,negMax in con.execute('SELECT negate,negate_max_level FROM effect_proto WHERE id in (SELECT effect_proto_id FROM effect_proto_spell_proto WHERE spell_proto_id = %i);'%self.ID):
            if neg > negate:
                negate = neg
            if negMax > negatemax:
                negatemax = negMax
        self.NEGATE = negate
        self.NEGATEMAXLEVEL = negatemax
        self.SPELLID = self.ID
        text = get_spell_info_window(self, True)       
        self.text = ''.join(text)

Find the following line after the class we were just in

pb.setUnjellyableForClass(SpellInfo, SpellInfoGhost)  

Immediately after it add these new classes

#Character Skills
class NSkillInfo(pb.Cacheable):
    def __init__(self,character,charSkill):
        self.observers = []
        self.char = character
        self.charSkill = charSkill
        self.state = None
        
    def stoppedObserving(self, perspective, observer):
        #if observer in self.observers:
        self.observers.remove(observer)

    def getFullState(self):
        state = self.state = {}

        state['LEVEL'] = self.charSkill.level
        state['NAME'] = self.charSkill.skillname
        return state
        
    def refresh(self):
        state = self.state
        if state == None:
            return
        changed = {}
        level = self.charSkill.level
        
        if level != state['LEVEL']:
            state['LEVEL']=changed['LEVEL']=level
        
        if not len(changed):
            return
        
        for o in self.observers: o.callRemote('updateChanged', changed)
        
    def getStateToCacheAndObserveFor(self, perspective, observer):
        self.observers.append(observer)
        return self.getFullState()
        
    
    def fullRefresh(self):
        for o in self.observers: o.callRemote('updateChanged', self.getFullState())

            
class NSkillInfoGhost(pb.RemoteCache):    
    def generateItemText(self):
        from mud.client.playermind import GetMoMClientDBConnection
        con = GetMoMClientDBConnection()
        self.ICON,self.PASSIVE,self.MAXREUSE,self.MINREUSE,self.SPELLID,self.MAXVALUE,self.LEVELCAPPED,self.ID = con.execute('SELECT icon, passive,max_reuse_time,min_reuse_time,spell_proto_id,max_value,level_capped,id FROM class_skill WHERE lower(skillname)=lower("%s") LIMIT 1;'%self.NAME).fetchone()
        self.CLASSES = tuple((classname) for classname in con.execute('select class_proto.name FROM class_proto, class_proto_class_skill WHERE class_proto_class_skill.class_skill_id = %i AND class_proto_class_skill.class_proto_id = class_proto.id;'%self.ID))
        
        text = []
        
        if (self.PASSIVE):
            text.append(r'\c3Type:  \c0Passive      ')
        else:
            text.append(r'\c3Type:  \c2Active       ')
            
        if (self.MINREUSE):    
            d = (self.MINREUSE+self.MAXREUSE/2)/NEWDURSECOND
            if d > 60:
                m,s = divmod(d,60)
                tbuf = "%im %is"%(m,s)
                text.append(r'\c3Reuse: \c1%-8s'%tbuf)
            else:
                tbuf = "%is"%d
                text.append(r'\c3Reuse: \c1%-8s'%tbuf)    
        text.append(r'\n')        
        text.append(r'\c3LevelCap:  \c0%-3d      '%self.LEVELCAPPED)
        text.append(r'\c3MaxValue:  \c0%d\n'%self.MAXVALUE)
        
        classtext = ' '.join(r'\c0%s'%(cl) for cl in self.CLASSES)
        if (len(self.CLASSES) == len(RPG_CLASS_ABBR)):
            classtext = "\c2All"
        if classtext:
            text.append(r'\c3Classes: %s\n'%classtext)
        self.text = ''.join(text)
        
        #Spell Info
        if self.SPELLID:
            self.TARGET,self.DURATION,self.CASTRANGE,self.AOERANGE,self.SPELLTYPE = con.execute('SELECT target,duration,cast_range,aoe_range,spell_type FROM spell_proto WHERE id = %i LIMIT 1;'%self.SPELLID).fetchone()
            self.COMPONENTS = []
            for protoID,count in con.execute('SELECT item_proto_id,count FROM spell_component WHERE spell_proto_id = %i;'%self.SPELLID):
                self.COMPONENTS.append((con.execute('SELECT name FROM item_proto WHERE id = %i LIMIT 1;'%protoID).fetchone()[0],count))
            negate = negatemax = 0
            for neg,negMax in con.execute('SELECT negate,negate_max_level FROM effect_proto WHERE id in (SELECT effect_proto_id FROM effect_proto_spell_proto WHERE spell_proto_id = %i);'%self.SPELLID):
                if neg > negate:
                    negate = neg
                if negMax > negatemax:
                    negatemax = negMax
            self.NEGATE = negate
            self.NEGATEMAXLEVEL = negatemax
            text = get_spell_info_window(self, False)
            spellstring = ''.join(text)
            self.text += '\\c2            ====SPELLINFO====\\n' + spellstring
            
    
    def setCopyableState(self, state):
        for k,v in state.iteritems():
            self.__dict__[k]=v
        
        self.generateItemText()
    
    
    def observe_updateChanged(self,changed):
        for k,v in changed.iteritems():
            setattr(self,k,v)


pb.setUnjellyableForClass(NSkillInfo, NSkillInfoGhost)     

[edit] /mud/client/gui/partyWnd.py

We are going to replace some functions in the SkillPane class. You will be replacing some changes previously made (mainly removing skillinfo). Make sure only to replace the functions in the code below, not the whole class itself.

    def setFromCharacterInfo(self,cinfo):
        self.charInfo = cinfo
        skills = cinfo.NSKILLS.keys()
        sindex = self.currentPage*17
        x = 0
        
        if not len(skills):
            return
        skills.sort()
        
        askills = []
        for sk in skills:
            askills.append(sk)
            self.skillName[x] = sk
            x = x+1
          
        x = 0  
        for x in xrange(sindex,sindex+17):
            button = self.skillButtons[x-sindex]
            textstat = self.skillTextInfo[x-sindex]
            button.pulseGreen = False
            button.SetValue(0)
            button.toggleLocked = False
            
            if x < len(askills):
                skinfo = cinfo.NSKILLS[askills[x]]
                textstat.setText(str(skinfo.LEVEL))
                
                icon = skinfo.ICON
                if icon.startswith("SPELLICON_"):
                    split = icon.split("_")
                    index = int(split[2])
                    u0 = (float(index%6)*40.0)/256.0
                    v0 = (float(index/6)*40.0)/256.0
                    u1 = (40.0/256.0)
                    v1 = (40.0/256.0)
                    
                    button.setBitmapUV("~/data/ui/icons/spells0%s"%split[1],u0,v0,u1,v1)
                else:
                    button.setBitmap("~/data/ui/icons/%s"%icon)
                
                if cinfo.SKILLREUSE.has_key(askills[x]) or cinfo.DEAD or skinfo.PASSIVE:
                   button.setValue(1)
                   button.toggleLocked = True
                else:
                   button.SetValue(0)
                   button.toggleLocked = False
                   
            else:
                button.SetBitmap("")
                textstat.setText("")
        
        TGEObject("SKILLPANE_PAGETEXT").setText("Page %i"%(self.currentPage+1))

    def onSkillButton(self,slot):
        bnum = slot;
        slot = self.currentPage * 17 + slot
        cinfo = PARTYWND.charInfos[PARTYWND.curIndex]
        #Skillname has a list of a all skills, the rest is a partial
        if slot+1 > len(self.skillName):
            return;
        if int(self.skillButtons[bnum].toggleLocked):
            #already down
            return
           
        skill = self.skillName[slot] 
        skinfo = cinfo.NSKILLS[skill]
        if skinfo.PASSIVE:
            return
        
        self.skillButtons[bnum].toggleLocked = True
        self.skillButtons[bnum].setValue(1)
        
        macro.AttachMacroButtons()
        macro.EnableSkillMacro(PARTYWND.curIndex,skill,False)
        PyDoCommand(['PyDoCommand','/SKILL %i %s'%(PARTYWND.curIndex,skill)],False)
        
    def onSkillButtonAlt(self,index):
        cinfo = PARTYWND.charInfos[PARTYWND.curIndex]
        slot = self.currentPage * 17 + index
        button = self.skillButtons[index]
        skillname = self.skillName[slot]
        skinfo = cinfo.NSKILLS[skillname]
        if skinfo.PASSIVE:
            return
        
        macro.SetCursorMacro("SKILL",skillname,button,PARTYWND.curIndex)
        return

Remove the following include from this file

from skillinfo import GetSkillInfo

[edit] mud/client/gui/itemInfoWnd.py

Find the following bit of code we added before

            sindex = PARTYWND.skillPane.currentPage*17
            for slot,button in self.skillButtons.iteritems():

Replace the for statement and all of its code with the following

            for slot,button in self.skillButtons.iteritems():
                if int(button.mouseOver):
                    skills = cinfo.NSKILLS.keys()
                    skills.sort()
                    askills = []
                    for sk in skills:
                       askills.append(sk)
                    if slot+sindex < len(askills):
                        found = True
                        ghost = cinfo.NSKILLS[askills[slot+sindex]]
                        isSkill = True
                        break
                    else:
                        break

Just a few lines down you will see self.setSkill. Replace it to look like this.

                self.setSkill(ghost)

A few more lines down replace the setSkill function with this

    def setSkill(self,ghost):
        if self.ghost == ghost:
            return
        
        self.isItem = False
        self.isLoot = False
        self.isCraft = False
        self.ghost = ghost
        
        self.skillText.setText(TEXT_HEADER+ghost.NAME+"\n"+str(ghost.LEVEL))
        
        icon = ghost.ICON
        if icon.startswith("SPELLICON_"):
            split = icon.split("_")
            index=int(split[2])
            u0=(float(index%6)*40.0)/256.0
            v0=(float(index/6)*40.0)/256.0
            u1=(40.0/256.0)
            v1=(40.0/256.0)
            
            self.skillPic.SetBitmapUV("~/data/ui/icons/spells0%s"%split[1],u0,v0,u1,v1)
            self.bitmap.SetBitmapUV("~/data/ui/icons/spells0%s"%split[1],u0,v0,u1,v1)
            self.lastBitmap = ""
        else:
            self.skillPic.SetBitmap("~/data/ui/icons/%s"%icon)
            self.bitmap.SetBitmap("~/data/ui/icons/%s"%icon)
            self.lastBitmap = ""    
            
        eval = 'ItemInfoWnd_Window.setText("%s");'%(ghost.NAME) #<<<<
        TGEEval(eval) #<<<<
        eval = 'ItemInfoWnd_FlagsText.setText("");'
        TGEEval(eval)
        eval = 'ItemInfoWnd_InfoText.setText("%s");'%(TEXT_HEADER+ghost.text)
        TGEEval(eval)     

Find the following a bit further down

            self.spellText.setText("")
            self.spellPic.SetBitmap("")

You should have the two lines after it (I believe 1 is missing)

            self.skillText.setText("")
            self.skillPic.SetBitmap("")

[edit] mud/world/skill.py

In the ClassSkill class add the following. It adds the passive and icon values to the skill DB so it can be used along with the rest of the skill creation code

    passive = BoolCol(default = True)
    icon = StringCol(default = "enhancedmeleeupgrade")

[edit] mud/client/gui/customMacroWnd.py

Find the little bit of code

        ClearMacroEditor()
        #fill from one of the other macros
        if m and m.skill:

Replace everything in the if statement with the following (this moves the icon/name calls to the client ghost)

        if m and m.skill:
            sinfo = cinfo.NSKILLS[m.skill]
            if not sinfo:
                return
            
            text = sinfo.NAME
            icon = sinfo.ICON
            cmd = "/skill %s"%m.skill
            TGEObject("CM_LINE1").setText(cmd)
            TGEObject("CM_NAME").setText(text)
            SetIcon(icon)

[edit] mud/client/gui/macro.py

In the Macro class in the setControls function find these lines

            elif self.skill:
                sinfo = GetSkillInfo(self.skill)
                text = sinfo.name
                icon = sinfo.icon

Replace it with the following

            elif self.skill:
                sinfo = cinfo.NSKILLS[self.skill]
                text = sinfo.NAME
                icon = sinfo.ICON

Remove the following include fromt he beginning of the file

from skillinfo import GetSkillInfo

[edit] mud/client/gui/__init__.py

remove skillinfo.py from this file so it is no longer compiled. Do a search through your project to make sure GetSkillInfo is no longer present. It should of all be removed at this time.

[edit] Skills in test.game/genesis/skills

You need to modify all skills in your game with a new icon and ones that are not passive. If you fail to do this it will work with no issue since there are default values, but if you want a different icon or the skill is active, you need to make the changes to each skill.

skill.icon = "enhancedmovementupgrade"
skill.passive = False
<pre>

The icon is the name of the file located in this spot:

<pre>
test.game/data/ui/icons

You can also use SPELLICON values like spells. An example

skill.icon = "SPELLICON_5_22"

This would use spells05 as the picture and the 22nd icon.

[edit] test.game/client/ui/ParthWnd.gui

Add the following to each SKILLBUTTON (0-16)

rightClickCommand = "ToggleItemInfoWnd();";

[edit] mud/client/gui/itemInfoWnd.py - Optional GUI Style Changes

This is the first of optional GUI Style changes. If you want it to look like the picture you might want to add these. If you do not the formatting might be a tad off, but you can work with it afterwards if you like.

Replace TEXT_BIG_HEADER and TEXT_HEADER with the following lines. Lucida Console is used for fixed width formatting while Arial is used for for non fixed width items.

TEXT_BIG_HEADER = """<font:Arial Bold:16><just:center><shadow:1:1><shadowcolor:000000>"""
TEXT_HEADER = """<font:Arial Bold:14><just:center><shadow:1:1><shadowcolor:000000>"""

TEXT_BIG_HEADER_N = """<font:Lucida Console:14><shadow:1:1><shadowcolor:000000>"""
TEXT_HEADER_N = """<font:Lucida Console:12><shadow:1:1><shadowcolor:000000>"""

The following are changes in a variety of places where HEADER is replaced with HEADER_N for the new text


Bottom of setSpell

eval = 'ItemInfoWnd_InfoText.setText("%s");'%(TEXT_HEADER_N+sinfo.text)

Bottom of setSkill

eval = 'ItemInfoWnd_InfoText.setText("%s");'%(TEXT_HEADER_N+ghost.text)

In setItem for Flags and Info

eval = 'ItemInfoWnd_FlagsText.setText("%s%s");'%(TEXT_HEADER_N,text)

val = 'ItemInfoWnd_InfoText.setText("%s%s");'%(TEXT_HEADER_N,ghost.text)

[edit] mud/world/shared/playdata.py - Optional GUI Style Changes

This is what the front part of my GUI looks like for items (the generateItemText routine). It is slightly reformatted for affects and resistances. You can modify or use this if you wish. This is not the whole generateItemText routine, just the part of it with the stats/resists so you will have to hack this in on your own if you wish.

class ItemInfoGhost(pb.RemoteCache):
    
    def __init__(self):
        self.text = ""
        self.infoDirty = True
    
    def generateItemText(self):
        # Prepare stats
        stattext = [r'\c4Stats:\n']
        rtext = [r'\c4Resists:\n']
        wpntext = []
        gotResist = False
        gotStat = False
        statcnt = 1
        rcnt = 1
        for stat, value in self.STATS:
            # Skip if there is no value to print.
            if not value:
                continue
            
            # Print regular stat.  2 stats per line
            statupper = stat.upper()
            try:
                prettyPrint, isPercent = STAT_PRETTY[statupper]
                gotStat = True
                if isPercent:
                    if 0.0 < value:
                        statstr = (r'\c3%s \c2%i%%'%(prettyPrint, value * 100))
                        stattext.append(r'%-25s  '%(statstr))         
                    else:
                        statstr = (r'\c3%s \c1%i%%'%(prettyPrint, value * 100)) 
                        stattext.append(r'%-25s  '%(statstr))   
                else:
                    if 0 < value:
                        statstr = (r'\c3%s \c2%i'%(prettyPrint, value))
                        stattext.append(r'%-25s  '%(statstr))   
                    else:
                        statstr = (r'\c3%s \c1%i'%(prettyPrint, value))
                        stattext.append(r'%-25s  '%(statstr))   
                if statcnt % 2 == 0:
                    stattext.append(r'\n')
                statcnt += 1
                continue
            except:
                pass

            # Print to resist text.
            try:
                prettyPrint = RPG_RESIST_TEXT[RPG_RESISTLOOKUP[stat]]
                gotResist = True
                if value > 0:
                    rstr = (r'\c3%s \c2%i'%(prettyPrint, value))
                    rtext.append(r'%-25s  '%(rstr))   
                else:
                    rstr = (r'\c3%s \c1%i'%(prettyPrint, value))
                    rtext.append(r'%-25s  '%(rstr)) 
                if rcnt % 2 == 0:
                    rtext.append(r'\n')
                rcnt += 1
                continue
            except:
                pass

            # Print to weapon text.
            # Currently not working for some reason or another - Xerves

            if stat == "dmgBonusOffhand":
                wpntext.append(r'\c3%s \c2%i '%("Dmg Bonus(Offhand)",value))
            elif stat == "dmgBonusPrimary":
                wpntext.append(r'\c3%s \c2%i '%("Dmg Bonus",value))

            # Incase nothing else caught the print, print it.
            else:
                print "Warning!  Item stat print style not defined: %s" % stat
                stattext.append(r'\c3%s \c2%i '%(stat,value))
        # Need a new line added or not?
        if statcnt > 1 and statcnt % 2 != 1:    
            stattext.append(r'\n')
        if rcnt > 1 and rcnt % 2 != 1:    
            rtext.append(r'\n')
        if gotStat == False:
            stattext = ''
        if gotResist:
            stattext.extend(rtext)

[edit] test.game/client/ui/ItemInfoWnd.gui - Optional GUI Change

I modified the core object here with a slightly different width and height and moved the icon to the upper right hand side. Here is that bit:

new GuiControl(ItemInfoWnd) {
   profile = "GuiModelessDialogProfile";
   horizSizing = "right";
   vertSizing = "bottom";
   position = "0 0";
   extent = "640 480";
   minExtent = "8 2";
   visible = "1";

   new GuiWindowCtrl(ItemInfoWnd_Window) {
      profile = "MoMWndAlwaysHLProfile";
      horizSizing = "right";
      vertSizing = "bottom";
      position = "211 41";
      extent = "320 270";
      minExtent = "233 270";
      visible = "1";
      text = "Information";
      maxLength = "255";
      dropShadow = "0";
      resizeWidth = "0";
      resizeHeight = "0";
      canMove = "1";
      canClose = "1";
      canMinimize = "0";
      canMaximize = "0";
      isClickThru = "0";
      minSize = "233 300";
      closeCommand = "canvas.popDialog(ItemInfoWnd);";

      new GuiBitmapCtrl(ITEMINFOWND_BITMAP) {
         profile = "GuiDefaultProfile";
         horizSizing = "right";
         vertSizing = "bottom";
         position = "262 31";
         extent = "50 50";
         minExtent = "8 2";
         visible = "1";
         wrap = "0";
         modulation = "1.000000 1.000000 1.000000 1.000000";
      };
      new GuiScrollCtrl() {
         profile = "MoMScrollProfile";
         horizSizing = "right";
         vertSizing = "bottom";
         position = "10 87";
         extent = "300 177";
         minExtent = "8 2";
         visible = "1";
         willFirstRespond = "0";
         hScrollBar = "alwaysOff";
         vScrollBar = "dynamic";
         constantThumbHeight = "0";
         childMargin = "0 0";
         childRelPos = "0 0";
         childPos = "2 2";
         contentPos = "2 2";

         new GuiMLTextCtrl(ItemInfoWnd_InfoText) {
            profile = "MoMStatText";
            horizSizing = "right";
            vertSizing = "bottom";
            position = "2 2";
            extent = "292 14";
            minExtent = "8 2";
            visible = "1";
            lineSpacing = "2";
            allowColorChars = "1";
            renderML = "1";
            maxChars = "-1";
         };
      };
      new GuiControl() {
         profile = "GuiDefaultProfile";
         horizSizing = "left";
         vertSizing = "top";
         position = "10 31";
         extent = "244 51";
         minExtent = "8 2";
         visible = "1";

         new GuiMLTextCtrl(ItemInfoWnd_FlagsText) {
            profile = "MoMStatText";
            horizSizing = "left";
            vertSizing = "top";
            position = "2 6";
            extent = "238 14";
            minExtent = "8 2";
            visible = "1";
            lineSpacing = "2";
            allowColorChars = "1";
            renderML = "1";
            maxChars = "-1";
            text = " ";
         };
      };
   };
};
Personal tools