Skillmodification
From Rafermand 2.0
[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 = " ";
};
};
};
};
