2710 lines
85 KiB
Python
2710 lines
85 KiB
Python
import dbg
|
|
import player
|
|
import item
|
|
import grp
|
|
import wndMgr
|
|
import skill
|
|
import shop
|
|
import exchange
|
|
import grpText
|
|
import safebox
|
|
import localeInfo
|
|
import app
|
|
import background
|
|
import nonplayer
|
|
import chr
|
|
|
|
import ui
|
|
import mouseModule
|
|
import constInfo
|
|
|
|
WARP_SCROLLS = [22011, 22000, 22010]
|
|
|
|
# Tooltip max width when descriptions are long
|
|
DESC_MAX_WIDTH = 280
|
|
|
|
def chop(n):
|
|
return round(n - 0.5, 1)
|
|
|
|
def SplitDescriptionByPixelWidth(desc, maxWidthPx, fontName):
|
|
"""
|
|
Splits description into lines that fit in maxWidthPx, measured in pixels.
|
|
Respects forced breaks: '\n' and '|'.
|
|
"""
|
|
if not desc:
|
|
return []
|
|
|
|
# Normalize breaks
|
|
desc = desc.replace("\r\n", "\n").replace("\r", "\n").replace("|", "\n")
|
|
|
|
measure = ui.TextLine()
|
|
measure.SetFontName(fontName)
|
|
|
|
out = []
|
|
for raw in desc.split("\n"):
|
|
raw = raw.strip()
|
|
if not raw:
|
|
continue
|
|
|
|
tokens = raw.split()
|
|
cur = ""
|
|
|
|
for token in tokens:
|
|
candidate = token if not cur else (cur + " " + token)
|
|
|
|
measure.SetText(candidate)
|
|
w, _ = measure.GetTextSize()
|
|
|
|
if w <= maxWidthPx:
|
|
cur = candidate
|
|
else:
|
|
# push current line if it exists
|
|
if cur:
|
|
out.append(cur)
|
|
|
|
# token alone might be wider than max: keep it as its own line
|
|
# (or you could implement character splitting, but this is safer)
|
|
cur = token
|
|
|
|
if cur:
|
|
out.append(cur)
|
|
|
|
return out
|
|
|
|
###################################################################################################
|
|
## ToolTip
|
|
## NOTE: Currently Item and Skill are specialized through inheritance
|
|
## However, this doesn't seem very meaningful
|
|
##
|
|
class ToolTip(ui.ThinBoard):
|
|
|
|
TOOL_TIP_WIDTH = 190
|
|
TOOL_TIP_HEIGHT = 10
|
|
|
|
TEXT_LINE_HEIGHT = 17
|
|
|
|
TITLE_COLOR = grp.GenerateColor(0.9490, 0.9058, 0.7568, 1.0)
|
|
SPECIAL_TITLE_COLOR = grp.GenerateColor(1.0, 0.7843, 0.0, 1.0)
|
|
NORMAL_COLOR = grp.GenerateColor(0.7607, 0.7607, 0.7607, 1.0)
|
|
FONT_COLOR = grp.GenerateColor(0.7607, 0.7607, 0.7607, 1.0)
|
|
PRICE_COLOR = 0xffFFB96D
|
|
|
|
HIGH_PRICE_COLOR = SPECIAL_TITLE_COLOR
|
|
MIDDLE_PRICE_COLOR = grp.GenerateColor(0.85, 0.85, 0.85, 1.0)
|
|
LOW_PRICE_COLOR = grp.GenerateColor(0.7, 0.7, 0.7, 1.0)
|
|
|
|
ENABLE_COLOR = grp.GenerateColor(0.7607, 0.7607, 0.7607, 1.0)
|
|
DISABLE_COLOR = grp.GenerateColor(0.9, 0.4745, 0.4627, 1.0)
|
|
|
|
NEGATIVE_COLOR = grp.GenerateColor(0.9, 0.4745, 0.4627, 1.0)
|
|
POSITIVE_COLOR = grp.GenerateColor(0.5411, 0.7254, 0.5568, 1.0)
|
|
SPECIAL_POSITIVE_COLOR = grp.GenerateColor(0.6911, 0.8754, 0.7068, 1.0)
|
|
SPECIAL_POSITIVE_COLOR2 = grp.GenerateColor(0.8824, 0.9804, 0.8824, 1.0)
|
|
|
|
CONDITION_COLOR = 0xffBEB47D
|
|
CAN_LEVEL_UP_COLOR = 0xff8EC292
|
|
CANNOT_LEVEL_UP_COLOR = DISABLE_COLOR
|
|
NEED_SKILL_POINT_COLOR = 0xff9A9CDB
|
|
|
|
def __init__(self, width = TOOL_TIP_WIDTH, isPickable=False):
|
|
ui.ThinBoard.__init__(self, "TOP_MOST")
|
|
|
|
if isPickable:
|
|
pass
|
|
else:
|
|
self.AddFlag("not_pick")
|
|
|
|
self.AddFlag("float")
|
|
|
|
self.followFlag = True
|
|
self.toolTipWidth = width
|
|
|
|
self.xPos = -1
|
|
self.yPos = -1
|
|
|
|
self.timeInfoList = []
|
|
|
|
self.defFontName = localeInfo.UI_DEF_FONT
|
|
self.ClearToolTip()
|
|
|
|
def __del__(self):
|
|
ui.ThinBoard.__del__(self)
|
|
|
|
def ClearToolTip(self):
|
|
self.toolTipHeight = 12
|
|
self.childrenList = []
|
|
self.timeInfoList = []
|
|
|
|
def SetFollow(self, flag):
|
|
self.followFlag = flag
|
|
|
|
def SetDefaultFontName(self, fontName):
|
|
self.defFontName = fontName
|
|
|
|
def AppendSpace(self, size):
|
|
self.toolTipHeight += size
|
|
self.ResizeToolTip()
|
|
|
|
def AppendHorizontalLine(self):
|
|
|
|
for i in range(2):
|
|
horizontalLine = ui.Line()
|
|
horizontalLine.SetParent(self)
|
|
horizontalLine.SetPosition(0, self.toolTipHeight + 3 + i)
|
|
horizontalLine.SetWindowHorizontalAlignCenter()
|
|
horizontalLine.SetSize(150, 0)
|
|
horizontalLine.Show()
|
|
|
|
if 0 == i:
|
|
horizontalLine.SetColor(0xff555555)
|
|
else:
|
|
horizontalLine.SetColor(0xff000000)
|
|
|
|
self.childrenList.append(horizontalLine)
|
|
|
|
self.toolTipHeight += 11
|
|
self.ResizeToolTip()
|
|
|
|
def AlignHorizonalCenter(self):
|
|
for child in self.childrenList:
|
|
(x, y) = child.GetLocalPosition()
|
|
|
|
child.SetPosition(self.toolTipWidth // 2, y)
|
|
|
|
self.ResizeToolTip()
|
|
|
|
def AlignTextLineHorizonalCenter(self):
|
|
for child in self.childrenList:
|
|
# MR-10: Fix element centering in tooltips
|
|
if type(child).__name__ == "TextLine" and getattr(child, "_centerAlign", False):
|
|
(x, y) = child.GetLocalPosition()
|
|
|
|
child.SetPosition(self.toolTipWidth // 2, y)
|
|
# MR-10: -- END OF -- Fix element centering in tooltips
|
|
|
|
self.ResizeToolTip()
|
|
|
|
def AutoAppendTextLine(self, text, color = FONT_COLOR, centerAlign = True):
|
|
textLine = ui.TextLine()
|
|
|
|
textLine.SetParent(self)
|
|
textLine.SetFontName(self.defFontName)
|
|
textLine.SetPackedFontColor(color)
|
|
textLine.SetText(text)
|
|
textLine.SetOutline()
|
|
textLine.SetFeather(False)
|
|
textLine.Show()
|
|
|
|
# MR-10: Fix element centering in tooltips
|
|
textLine._centerAlign = centerAlign
|
|
# MR-10: -- END OF -- Fix element centering in tooltips
|
|
|
|
if centerAlign:
|
|
textLine.SetPosition(self.toolTipWidth // 2, self.toolTipHeight)
|
|
textLine.SetHorizontalAlignCenter()
|
|
|
|
else:
|
|
textLine.SetPosition(10, self.toolTipHeight)
|
|
|
|
self.childrenList.append(textLine)
|
|
|
|
(textWidth, textHeight)=textLine.GetTextSize()
|
|
|
|
textWidth += 40
|
|
textHeight += 5
|
|
|
|
if self.toolTipWidth < textWidth:
|
|
self.toolTipWidth = textWidth
|
|
|
|
self.toolTipHeight += textHeight
|
|
|
|
return textLine
|
|
|
|
def AppendTextLine(self, text, color=FONT_COLOR, centerAlign=True, show=True):
|
|
textLine = ui.TextLine()
|
|
textLine.SetParent(self)
|
|
textLine.SetFontName(self.defFontName)
|
|
textLine.SetPackedFontColor(color)
|
|
textLine.SetText(text)
|
|
textLine.SetOutline()
|
|
textLine.SetFeather(False)
|
|
if show:
|
|
textLine.Show()
|
|
|
|
# MR-10: Fix element centering in tooltips
|
|
textLine._centerAlign = centerAlign
|
|
# MR-10: -- END OF -- Fix element centering in tooltips
|
|
|
|
textWidth, _ = textLine.GetTextSize()
|
|
textWidth += 20
|
|
|
|
tooltipWidthChanged = False
|
|
if self.toolTipWidth < textWidth:
|
|
self.toolTipWidth = textWidth
|
|
tooltipWidthChanged = True
|
|
|
|
if centerAlign:
|
|
textLine.SetHorizontalAlignCenter()
|
|
textLine.SetPosition(self.toolTipWidth // 2, self.toolTipHeight)
|
|
else:
|
|
textLine.SetPosition(10, self.toolTipHeight)
|
|
|
|
self.childrenList.append(textLine)
|
|
|
|
self.toolTipHeight += self.TEXT_LINE_HEIGHT
|
|
self.ResizeToolTip()
|
|
|
|
if tooltipWidthChanged:
|
|
self.AlignTextLineHorizonalCenter()
|
|
|
|
return textLine
|
|
|
|
def AppendDescription(self, desc, color = FONT_COLOR):
|
|
if not desc:
|
|
return
|
|
|
|
# We wrap based on pixels, not on "limit" columns.
|
|
# This makes it consistent across languages/fonts.
|
|
padding = 20 # left+right safe padding inside tooltip
|
|
maxWidthPx = max(50, self.toolTipWidth - padding)
|
|
|
|
lines = SplitDescriptionByPixelWidth(desc, maxWidthPx, self.defFontName)
|
|
if not lines:
|
|
return
|
|
|
|
self.AppendSpace(5)
|
|
for line in lines:
|
|
self.AppendTextLine(line, color)
|
|
|
|
def ResizeToolTip(self):
|
|
self.SetSize(self.toolTipWidth, self.TOOL_TIP_HEIGHT + self.toolTipHeight)
|
|
|
|
def SetTitle(self, name):
|
|
self.AppendTextLine(name, self.TITLE_COLOR)
|
|
|
|
def GetLimitTextLineColor(self, curValue, limitValue):
|
|
if curValue < limitValue:
|
|
return self.DISABLE_COLOR
|
|
|
|
return self.ENABLE_COLOR
|
|
|
|
def GetChangeTextLineColor(self, value, isSpecial=False):
|
|
if value > 0:
|
|
if isSpecial:
|
|
return self.SPECIAL_POSITIVE_COLOR
|
|
else:
|
|
return self.POSITIVE_COLOR
|
|
|
|
if 0 == value:
|
|
return self.NORMAL_COLOR
|
|
|
|
return self.NEGATIVE_COLOR
|
|
|
|
def SetToolTipPosition(self, x = -1, y = -1):
|
|
self.xPos = x
|
|
self.yPos = y
|
|
|
|
def ShowToolTip(self):
|
|
self.SetTop()
|
|
self.Show()
|
|
|
|
self.OnUpdate()
|
|
|
|
def HideToolTip(self):
|
|
self.Hide()
|
|
|
|
def OnUpdate(self):
|
|
|
|
if not self.followFlag:
|
|
return
|
|
|
|
for timeText in self.timeInfoList:
|
|
if timeText["line"]:
|
|
leftSec = max(0, timeText["value"] - app.GetGlobalTimeStamp())
|
|
if not self.isShopItem:
|
|
timeText["line"].SetText(localeInfo.LEFT_TIME + ": " + localeInfo.RTSecondToDHMS(leftSec))
|
|
|
|
x = 0
|
|
y = 0
|
|
width = self.GetWidth()
|
|
height = self.toolTipHeight
|
|
|
|
if -1 == self.xPos and -1 == self.yPos:
|
|
|
|
(mouseX, mouseY) = wndMgr.GetMousePosition()
|
|
|
|
if mouseY < wndMgr.GetScreenHeight() - 300:
|
|
y = mouseY + 40
|
|
else:
|
|
y = mouseY - height - 30
|
|
|
|
x = mouseX - width // 2
|
|
|
|
else:
|
|
|
|
x = self.xPos - width // 2
|
|
y = self.yPos - height
|
|
|
|
x = max(x, 0)
|
|
y = max(y, 0)
|
|
x = min(x + width // 2, wndMgr.GetScreenWidth() - width // 2) - width // 2
|
|
y = min(y + self.GetHeight(), wndMgr.GetScreenHeight()) - self.GetHeight()
|
|
|
|
parentWindow = self.GetParentProxy()
|
|
if parentWindow:
|
|
(gx, gy) = parentWindow.GetGlobalPosition()
|
|
x -= gx
|
|
y -= gy
|
|
|
|
self.SetPosition(x, y)
|
|
|
|
class ItemToolTip(ToolTip):
|
|
CHARACTER_NAMES = (
|
|
localeInfo.TOOLTIP_WARRIOR,
|
|
localeInfo.TOOLTIP_ASSASSIN,
|
|
localeInfo.TOOLTIP_SURA,
|
|
localeInfo.TOOLTIP_SHAMAN
|
|
)
|
|
|
|
CHARACTER_COUNT = len(CHARACTER_NAMES)
|
|
WEAR_NAMES = (
|
|
localeInfo.TOOLTIP_ARMOR,
|
|
localeInfo.TOOLTIP_HELMET,
|
|
localeInfo.TOOLTIP_SHOES,
|
|
localeInfo.TOOLTIP_WRISTLET,
|
|
localeInfo.TOOLTIP_WEAPON,
|
|
localeInfo.TOOLTIP_NECK,
|
|
localeInfo.TOOLTIP_EAR,
|
|
localeInfo.TOOLTIP_UNIQUE,
|
|
localeInfo.TOOLTIP_SHIELD,
|
|
localeInfo.TOOLTIP_ARROW,
|
|
)
|
|
WEAR_COUNT = len(WEAR_NAMES)
|
|
|
|
AFFECT_DICT = {
|
|
item.APPLY_MAX_HP : localeInfo.TOOLTIP_MAX_HP,
|
|
item.APPLY_MAX_SP : localeInfo.TOOLTIP_MAX_SP,
|
|
item.APPLY_CON : localeInfo.TOOLTIP_CON,
|
|
item.APPLY_INT : localeInfo.TOOLTIP_INT,
|
|
item.APPLY_STR : localeInfo.TOOLTIP_STR,
|
|
item.APPLY_DEX : localeInfo.TOOLTIP_DEX,
|
|
item.APPLY_ATT_SPEED : localeInfo.TOOLTIP_ATT_SPEED,
|
|
item.APPLY_MOV_SPEED : localeInfo.TOOLTIP_MOV_SPEED,
|
|
item.APPLY_CAST_SPEED : localeInfo.TOOLTIP_CAST_SPEED,
|
|
item.APPLY_HP_REGEN : localeInfo.TOOLTIP_HP_REGEN,
|
|
item.APPLY_SP_REGEN : localeInfo.TOOLTIP_SP_REGEN,
|
|
item.APPLY_POISON_PCT : localeInfo.TOOLTIP_APPLY_POISON_PCT,
|
|
item.APPLY_STUN_PCT : localeInfo.TOOLTIP_APPLY_STUN_PCT,
|
|
item.APPLY_SLOW_PCT : localeInfo.TOOLTIP_APPLY_SLOW_PCT,
|
|
item.APPLY_CRITICAL_PCT : localeInfo.TOOLTIP_APPLY_CRITICAL_PCT,
|
|
item.APPLY_PENETRATE_PCT : localeInfo.TOOLTIP_APPLY_PENETRATE_PCT,
|
|
|
|
item.APPLY_ATTBONUS_WARRIOR : localeInfo.TOOLTIP_APPLY_ATTBONUS_WARRIOR,
|
|
item.APPLY_ATTBONUS_ASSASSIN : localeInfo.TOOLTIP_APPLY_ATTBONUS_ASSASSIN,
|
|
item.APPLY_ATTBONUS_SURA : localeInfo.TOOLTIP_APPLY_ATTBONUS_SURA,
|
|
item.APPLY_ATTBONUS_SHAMAN : localeInfo.TOOLTIP_APPLY_ATTBONUS_SHAMAN,
|
|
item.APPLY_ATTBONUS_MONSTER : localeInfo.TOOLTIP_APPLY_ATTBONUS_MONSTER,
|
|
|
|
item.APPLY_ATTBONUS_HUMAN : localeInfo.TOOLTIP_APPLY_ATTBONUS_HUMAN,
|
|
item.APPLY_ATTBONUS_ANIMAL : localeInfo.TOOLTIP_APPLY_ATTBONUS_ANIMAL,
|
|
item.APPLY_ATTBONUS_ORC : localeInfo.TOOLTIP_APPLY_ATTBONUS_ORC,
|
|
item.APPLY_ATTBONUS_MILGYO : localeInfo.TOOLTIP_APPLY_ATTBONUS_MILGYO,
|
|
item.APPLY_ATTBONUS_UNDEAD : localeInfo.TOOLTIP_APPLY_ATTBONUS_UNDEAD,
|
|
item.APPLY_ATTBONUS_DEVIL : localeInfo.TOOLTIP_APPLY_ATTBONUS_DEVIL,
|
|
item.APPLY_STEAL_HP : localeInfo.TOOLTIP_APPLY_STEAL_HP,
|
|
item.APPLY_STEAL_SP : localeInfo.TOOLTIP_APPLY_STEAL_SP,
|
|
item.APPLY_MANA_BURN_PCT : localeInfo.TOOLTIP_APPLY_MANA_BURN_PCT,
|
|
item.APPLY_DAMAGE_SP_RECOVER : localeInfo.TOOLTIP_APPLY_DAMAGE_SP_RECOVER,
|
|
item.APPLY_BLOCK : localeInfo.TOOLTIP_APPLY_BLOCK,
|
|
item.APPLY_DODGE : localeInfo.TOOLTIP_APPLY_DODGE,
|
|
item.APPLY_RESIST_SWORD : localeInfo.TOOLTIP_APPLY_RESIST_SWORD,
|
|
item.APPLY_RESIST_TWOHAND : localeInfo.TOOLTIP_APPLY_RESIST_TWOHAND,
|
|
item.APPLY_RESIST_DAGGER : localeInfo.TOOLTIP_APPLY_RESIST_DAGGER,
|
|
item.APPLY_RESIST_BELL : localeInfo.TOOLTIP_APPLY_RESIST_BELL,
|
|
item.APPLY_RESIST_FAN : localeInfo.TOOLTIP_APPLY_RESIST_FAN,
|
|
item.APPLY_RESIST_BOW : localeInfo.TOOLTIP_RESIST_BOW,
|
|
item.APPLY_RESIST_FIRE : localeInfo.TOOLTIP_RESIST_FIRE,
|
|
item.APPLY_RESIST_ELEC : localeInfo.TOOLTIP_RESIST_ELEC,
|
|
item.APPLY_RESIST_MAGIC : localeInfo.TOOLTIP_RESIST_MAGIC,
|
|
item.APPLY_RESIST_WIND : localeInfo.TOOLTIP_APPLY_RESIST_WIND,
|
|
item.APPLY_REFLECT_MELEE : localeInfo.TOOLTIP_APPLY_REFLECT_MELEE,
|
|
item.APPLY_REFLECT_CURSE : localeInfo.TOOLTIP_APPLY_REFLECT_CURSE,
|
|
item.APPLY_POISON_REDUCE : localeInfo.TOOLTIP_APPLY_POISON_REDUCE,
|
|
item.APPLY_KILL_SP_RECOVER : localeInfo.TOOLTIP_APPLY_KILL_SP_RECOVER,
|
|
item.APPLY_EXP_DOUBLE_BONUS : localeInfo.TOOLTIP_APPLY_EXP_DOUBLE_BONUS,
|
|
item.APPLY_GOLD_DOUBLE_BONUS : localeInfo.TOOLTIP_APPLY_GOLD_DOUBLE_BONUS,
|
|
item.APPLY_ITEM_DROP_BONUS : localeInfo.TOOLTIP_APPLY_ITEM_DROP_BONUS,
|
|
item.APPLY_POTION_BONUS : localeInfo.TOOLTIP_APPLY_POTION_BONUS,
|
|
item.APPLY_KILL_HP_RECOVER : localeInfo.TOOLTIP_APPLY_KILL_HP_RECOVER,
|
|
item.APPLY_IMMUNE_STUN : localeInfo.TOOLTIP_APPLY_IMMUNE_STUN,
|
|
item.APPLY_IMMUNE_SLOW : localeInfo.TOOLTIP_APPLY_IMMUNE_SLOW,
|
|
item.APPLY_IMMUNE_FALL : localeInfo.TOOLTIP_APPLY_IMMUNE_FALL,
|
|
item.APPLY_BOW_DISTANCE : localeInfo.TOOLTIP_BOW_DISTANCE,
|
|
item.APPLY_DEF_GRADE_BONUS : localeInfo.TOOLTIP_DEF_GRADE,
|
|
item.APPLY_ATT_GRADE_BONUS : localeInfo.TOOLTIP_ATT_GRADE,
|
|
item.APPLY_MAGIC_ATT_GRADE : localeInfo.TOOLTIP_MAGIC_ATT_GRADE,
|
|
item.APPLY_MAGIC_DEF_GRADE : localeInfo.TOOLTIP_MAGIC_DEF_GRADE,
|
|
item.APPLY_MAX_STAMINA : localeInfo.TOOLTIP_MAX_STAMINA,
|
|
item.APPLY_MALL_ATTBONUS : localeInfo.TOOLTIP_MALL_ATTBONUS,
|
|
item.APPLY_MALL_DEFBONUS : localeInfo.TOOLTIP_MALL_DEFBONUS,
|
|
item.APPLY_MALL_EXPBONUS : localeInfo.TOOLTIP_MALL_EXPBONUS,
|
|
item.APPLY_MALL_ITEMBONUS : localeInfo.TOOLTIP_MALL_ITEMBONUS,
|
|
item.APPLY_MALL_GOLDBONUS : localeInfo.TOOLTIP_MALL_GOLDBONUS,
|
|
item.APPLY_SKILL_DAMAGE_BONUS : localeInfo.TOOLTIP_SKILL_DAMAGE_BONUS,
|
|
item.APPLY_NORMAL_HIT_DAMAGE_BONUS : localeInfo.TOOLTIP_NORMAL_HIT_DAMAGE_BONUS,
|
|
item.APPLY_SKILL_DEFEND_BONUS : localeInfo.TOOLTIP_SKILL_DEFEND_BONUS,
|
|
item.APPLY_NORMAL_HIT_DEFEND_BONUS : localeInfo.TOOLTIP_NORMAL_HIT_DEFEND_BONUS,
|
|
item.APPLY_PC_BANG_EXP_BONUS : localeInfo.TOOLTIP_MALL_EXPBONUS_P_STATIC,
|
|
item.APPLY_PC_BANG_DROP_BONUS : localeInfo.TOOLTIP_MALL_ITEMBONUS_P_STATIC,
|
|
item.APPLY_RESIST_WARRIOR : localeInfo.TOOLTIP_APPLY_RESIST_WARRIOR,
|
|
item.APPLY_RESIST_ASSASSIN : localeInfo.TOOLTIP_APPLY_RESIST_ASSASSIN,
|
|
item.APPLY_RESIST_SURA : localeInfo.TOOLTIP_APPLY_RESIST_SURA,
|
|
item.APPLY_RESIST_SHAMAN : localeInfo.TOOLTIP_APPLY_RESIST_SHAMAN,
|
|
item.APPLY_MAX_HP_PCT : localeInfo.TOOLTIP_APPLY_MAX_HP_PCT,
|
|
item.APPLY_MAX_SP_PCT : localeInfo.TOOLTIP_APPLY_MAX_SP_PCT,
|
|
item.APPLY_ENERGY : localeInfo.TOOLTIP_ENERGY,
|
|
item.APPLY_COSTUME_ATTR_BONUS : localeInfo.TOOLTIP_COSTUME_ATTR_BONUS,
|
|
|
|
item.APPLY_MAGIC_ATTBONUS_PER : localeInfo.TOOLTIP_MAGIC_ATTBONUS_PER,
|
|
item.APPLY_MELEE_MAGIC_ATTBONUS_PER : localeInfo.TOOLTIP_MELEE_MAGIC_ATTBONUS_PER,
|
|
item.APPLY_RESIST_ICE : localeInfo.TOOLTIP_RESIST_ICE,
|
|
item.APPLY_RESIST_EARTH : localeInfo.TOOLTIP_RESIST_EARTH,
|
|
item.APPLY_RESIST_DARK : localeInfo.TOOLTIP_RESIST_DARK,
|
|
item.APPLY_ANTI_CRITICAL_PCT : localeInfo.TOOLTIP_ANTI_CRITICAL_PCT,
|
|
item.APPLY_ANTI_PENETRATE_PCT : localeInfo.TOOLTIP_ANTI_PENETRATE_PCT,
|
|
}
|
|
|
|
ATTRIBUTE_NEED_WIDTH = {
|
|
23 : 230,
|
|
24 : 230,
|
|
25 : 230,
|
|
26 : 220,
|
|
27 : 210,
|
|
|
|
35 : 210,
|
|
36 : 210,
|
|
37 : 210,
|
|
38 : 210,
|
|
39 : 210,
|
|
40 : 210,
|
|
41 : 210,
|
|
|
|
42 : 220,
|
|
43 : 230,
|
|
45 : 230,
|
|
}
|
|
|
|
ANTI_FLAG_DICT = {
|
|
0 : item.ITEM_ANTIFLAG_WARRIOR,
|
|
1 : item.ITEM_ANTIFLAG_ASSASSIN,
|
|
2 : item.ITEM_ANTIFLAG_SURA,
|
|
3 : item.ITEM_ANTIFLAG_SHAMAN,
|
|
}
|
|
|
|
FONT_COLOR = grp.GenerateColor(0.7607, 0.7607, 0.7607, 1.0)
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
ToolTip.__init__(self, *args, **kwargs)
|
|
|
|
self.itemVnum = 0
|
|
self.metinSlot = []
|
|
self.isShopItem = False
|
|
# When displaying item tooltip, if the current character cannot equip the item, force it to use Disable Color (already works this way but needed ability to turn it off)
|
|
self.bCannotUseItemForceSetDisableColor = True
|
|
|
|
self.itemWindowType = None
|
|
self.itemSlotIndex = -1
|
|
self.wndDragonSoul = None
|
|
self.dsActivatedTimeCache = {}
|
|
# MR-10: Add accessorySocketTimeCache for real-time remaining time display of accessory sockets.
|
|
|
|
cache = getattr(app, "_accessorySocketTimeCache", None)
|
|
|
|
if cache is None:
|
|
cache = getattr(player, "_accessorySocketTimeCache", None)
|
|
if cache is None:
|
|
cache = constInfo.ACCESSORY_SOCKET_TIME_CACHE
|
|
|
|
app._accessorySocketTimeCache = cache
|
|
player._accessorySocketTimeCache = cache
|
|
|
|
constInfo.ACCESSORY_SOCKET_TIME_CACHE = cache
|
|
|
|
self.accessorySocketTimeCache = cache
|
|
# MR-10: -- END OF -- Add accessorySocketTimeCache for real-time remaining time display of accessory sockets.
|
|
self.hairIcon = None
|
|
|
|
def __del__(self):
|
|
ToolTip.__del__(self)
|
|
self.metinSlot = None
|
|
|
|
def SetDragonSoulWindow(self, wnd):
|
|
self.wndDragonSoul = wnd
|
|
|
|
def ClearDragonSoulTimeCache(self):
|
|
self.dsActivatedTimeCache = {}
|
|
|
|
# MR-11: Fix Dragon stones timer auto-start
|
|
def WarmDragonSoulTimeCache(self, slotNumbers):
|
|
if not slotNumbers:
|
|
return
|
|
|
|
now = app.GetGlobalTimeStamp()
|
|
|
|
for slotNumber in slotNumbers:
|
|
itemVnum = player.GetItemIndex(slotNumber)
|
|
|
|
if itemVnum == 0:
|
|
continue
|
|
|
|
item.SelectItem(itemVnum)
|
|
|
|
remainSec = None
|
|
|
|
for i in range(item.LIMIT_MAX_NUM):
|
|
(limitType, limitValue) = item.GetLimit(i)
|
|
|
|
if item.LIMIT_TIMER_BASED_ON_WEAR == limitType:
|
|
remainSec = player.GetItemMetinSocket(player.INVENTORY, slotNumber, 0)
|
|
|
|
break
|
|
|
|
if remainSec is None or remainSec <= 0:
|
|
continue
|
|
|
|
key = (itemVnum, slotNumber)
|
|
self.dsActivatedTimeCache[key] = { "remainSec": remainSec, "endTime": now + remainSec }
|
|
# MR-11: -- END OF -- Fix Dragon stones timer auto-start
|
|
|
|
def SetCannotUseItemForceSetDisableColor(self, enable):
|
|
self.bCannotUseItemForceSetDisableColor = enable
|
|
|
|
def CanEquip(self):
|
|
if not item.IsEquipmentVID(self.itemVnum):
|
|
return True
|
|
|
|
race = player.GetRace()
|
|
job = chr.RaceToJob(race)
|
|
if job not in self.ANTI_FLAG_DICT:
|
|
return False
|
|
|
|
if item.IsAntiFlag(self.ANTI_FLAG_DICT[job]):
|
|
return False
|
|
|
|
sex = chr.RaceToSex(race)
|
|
|
|
MALE = 1
|
|
FEMALE = 0
|
|
|
|
if item.IsAntiFlag(item.ITEM_ANTIFLAG_MALE) and sex == MALE:
|
|
return False
|
|
|
|
if item.IsAntiFlag(item.ITEM_ANTIFLAG_FEMALE) and sex == FEMALE:
|
|
return False
|
|
|
|
for i in range(item.LIMIT_MAX_NUM):
|
|
(limitType, limitValue) = item.GetLimit(i)
|
|
|
|
if item.LIMIT_LEVEL == limitType:
|
|
if player.GetStatus(player.LEVEL) < limitValue:
|
|
return False
|
|
"""
|
|
elif item.LIMIT_STR == limitType:
|
|
if player.GetStatus(player.ST) < limitValue:
|
|
return False
|
|
elif item.LIMIT_DEX == limitType:
|
|
if player.GetStatus(player.DX) < limitValue:
|
|
return False
|
|
elif item.LIMIT_INT == limitType:
|
|
if player.GetStatus(player.IQ) < limitValue:
|
|
return False
|
|
elif item.LIMIT_CON == limitType:
|
|
if player.GetStatus(player.HT) < limitValue:
|
|
return False
|
|
"""
|
|
|
|
return True
|
|
|
|
def AppendTextLine(self, text, color = FONT_COLOR, centerAlign = True):
|
|
if not self.CanEquip() and self.bCannotUseItemForceSetDisableColor:
|
|
color = self.DISABLE_COLOR
|
|
|
|
return ToolTip.AppendTextLine(self, text, color, centerAlign)
|
|
|
|
def AppendTextLineTime(self, endTime, getLimit):
|
|
color = self.FONT_COLOR
|
|
|
|
if not self.CanEquip() and self.bCannotUseItemForceSetDisableColor:
|
|
color = self.DISABLE_COLOR
|
|
|
|
return ToolTip.AppendTextLineTime(self, endTime, getLimit, color)
|
|
|
|
def ClearToolTip(self):
|
|
# MR-10: Fix element centering in tooltips
|
|
hairIcon = getattr(self, "hairIcon", None)
|
|
|
|
if hairIcon:
|
|
hairIcon.Hide()
|
|
self.hairIcon = None
|
|
# MR-10: -- END OF -- Fix element centering in tooltips
|
|
|
|
self.isShopItem = False
|
|
self.toolTipWidth = self.TOOL_TIP_WIDTH
|
|
self.itemWindowType = None
|
|
self.itemSlotIndex = -1
|
|
ToolTip.ClearToolTip(self)
|
|
|
|
def SetInventoryItem(self, slotIndex, window_type = player.INVENTORY):
|
|
itemVnum = player.GetItemIndex(window_type, slotIndex)
|
|
if 0 == itemVnum:
|
|
return
|
|
|
|
self.ClearToolTip()
|
|
if shop.IsOpen():
|
|
if not shop.IsPrivateShop():
|
|
item.SelectItem(itemVnum)
|
|
self.AppendSellingPrice(player.GetISellItemPrice(window_type, slotIndex))
|
|
|
|
metinSlot = [player.GetItemMetinSocket(window_type, slotIndex, i) for i in range(player.METIN_SOCKET_MAX_NUM)]
|
|
attrSlot = [player.GetItemAttribute(window_type, slotIndex, i) for i in range(player.ATTRIBUTE_SLOT_MAX_NUM)]
|
|
|
|
self.itemWindowType = window_type
|
|
self.itemSlotIndex = slotIndex
|
|
self.AddItemData(itemVnum, metinSlot, attrSlot)
|
|
|
|
def SetShopItem(self, slotIndex):
|
|
itemVnum = shop.GetItemID(slotIndex)
|
|
if 0 == itemVnum:
|
|
return
|
|
|
|
price = shop.GetItemPrice(slotIndex)
|
|
self.ClearToolTip()
|
|
self.itemWindowType = None
|
|
self.itemSlotIndex = slotIndex
|
|
self.isShopItem = True
|
|
|
|
metinSlot = []
|
|
for i in range(player.METIN_SOCKET_MAX_NUM):
|
|
metinSlot.append(shop.GetItemMetinSocket(slotIndex, i))
|
|
attrSlot = []
|
|
for i in range(player.ATTRIBUTE_SLOT_MAX_NUM):
|
|
attrSlot.append(shop.GetItemAttribute(slotIndex, i))
|
|
|
|
self.AddItemData(itemVnum, metinSlot, attrSlot)
|
|
self.AppendPrice(price)
|
|
|
|
def SetShopItemBySecondaryCoin(self, slotIndex):
|
|
itemVnum = shop.GetItemID(slotIndex)
|
|
if 0 == itemVnum:
|
|
return
|
|
|
|
price = shop.GetItemPrice(slotIndex)
|
|
self.ClearToolTip()
|
|
self.itemWindowType = None
|
|
self.itemSlotIndex = slotIndex
|
|
self.isShopItem = True
|
|
|
|
metinSlot = []
|
|
for i in range(player.METIN_SOCKET_MAX_NUM):
|
|
metinSlot.append(shop.GetItemMetinSocket(slotIndex, i))
|
|
attrSlot = []
|
|
for i in range(player.ATTRIBUTE_SLOT_MAX_NUM):
|
|
attrSlot.append(shop.GetItemAttribute(slotIndex, i))
|
|
|
|
self.AddItemData(itemVnum, metinSlot, attrSlot)
|
|
self.AppendPriceBySecondaryCoin(price)
|
|
|
|
def SetExchangeOwnerItem(self, slotIndex):
|
|
itemVnum = exchange.GetItemVnumFromSelf(slotIndex)
|
|
if 0 == itemVnum:
|
|
return
|
|
|
|
self.ClearToolTip()
|
|
self.itemWindowType = None
|
|
self.itemSlotIndex = slotIndex
|
|
|
|
metinSlot = []
|
|
for i in range(player.METIN_SOCKET_MAX_NUM):
|
|
metinSlot.append(exchange.GetItemMetinSocketFromSelf(slotIndex, i))
|
|
attrSlot = []
|
|
for i in range(player.ATTRIBUTE_SLOT_MAX_NUM):
|
|
attrSlot.append(exchange.GetItemAttributeFromSelf(slotIndex, i))
|
|
self.AddItemData(itemVnum, metinSlot, attrSlot)
|
|
|
|
def SetExchangeTargetItem(self, slotIndex):
|
|
itemVnum = exchange.GetItemVnumFromTarget(slotIndex)
|
|
if 0 == itemVnum:
|
|
return
|
|
|
|
self.ClearToolTip()
|
|
self.itemWindowType = None
|
|
self.itemSlotIndex = slotIndex
|
|
|
|
metinSlot = []
|
|
for i in range(player.METIN_SOCKET_MAX_NUM):
|
|
metinSlot.append(exchange.GetItemMetinSocketFromTarget(slotIndex, i))
|
|
attrSlot = []
|
|
for i in range(player.ATTRIBUTE_SLOT_MAX_NUM):
|
|
attrSlot.append(exchange.GetItemAttributeFromTarget(slotIndex, i))
|
|
self.AddItemData(itemVnum, metinSlot, attrSlot)
|
|
|
|
def SetPrivateShopBuilderItem(self, invenType, invenPos, privateShopSlotIndex):
|
|
itemVnum = player.GetItemIndex(invenType, invenPos)
|
|
if 0 == itemVnum:
|
|
return
|
|
|
|
item.SelectItem(itemVnum)
|
|
self.ClearToolTip()
|
|
self.itemWindowType = None
|
|
self.itemSlotIndex = privateShopSlotIndex
|
|
self.AppendSellingPrice(shop.GetPrivateShopItemPrice(invenType, invenPos))
|
|
|
|
metinSlot = []
|
|
for i in range(player.METIN_SOCKET_MAX_NUM):
|
|
metinSlot.append(player.GetItemMetinSocket(invenPos, i))
|
|
attrSlot = []
|
|
for i in range(player.ATTRIBUTE_SLOT_MAX_NUM):
|
|
attrSlot.append(player.GetItemAttribute(invenPos, i))
|
|
|
|
self.AddItemData(itemVnum, metinSlot, attrSlot)
|
|
|
|
def SetSafeBoxItem(self, slotIndex):
|
|
itemVnum = safebox.GetItemID(slotIndex)
|
|
if 0 == itemVnum:
|
|
return
|
|
|
|
self.ClearToolTip()
|
|
self.itemWindowType = None
|
|
self.itemSlotIndex = slotIndex
|
|
metinSlot = []
|
|
for i in range(player.METIN_SOCKET_MAX_NUM):
|
|
metinSlot.append(safebox.GetItemMetinSocket(slotIndex, i))
|
|
attrSlot = []
|
|
for i in range(player.ATTRIBUTE_SLOT_MAX_NUM):
|
|
attrSlot.append(safebox.GetItemAttribute(slotIndex, i))
|
|
|
|
self.AddItemData(itemVnum, metinSlot, attrSlot, safebox.GetItemFlags(slotIndex))
|
|
|
|
def SetMallItem(self, slotIndex):
|
|
itemVnum = safebox.GetMallItemID(slotIndex)
|
|
if 0 == itemVnum:
|
|
return
|
|
|
|
self.ClearToolTip()
|
|
self.itemWindowType = None
|
|
self.itemSlotIndex = slotIndex
|
|
metinSlot = []
|
|
for i in range(player.METIN_SOCKET_MAX_NUM):
|
|
metinSlot.append(safebox.GetMallItemMetinSocket(slotIndex, i))
|
|
attrSlot = []
|
|
for i in range(player.ATTRIBUTE_SLOT_MAX_NUM):
|
|
attrSlot.append(safebox.GetMallItemAttribute(slotIndex, i))
|
|
|
|
self.AddItemData(itemVnum, metinSlot, attrSlot)
|
|
|
|
def SetItemToolTip(self, itemVnum):
|
|
self.ClearToolTip()
|
|
metinSlot = []
|
|
for i in range(player.METIN_SOCKET_MAX_NUM):
|
|
metinSlot.append(0)
|
|
attrSlot = []
|
|
for i in range(player.ATTRIBUTE_SLOT_MAX_NUM):
|
|
attrSlot.append((0, 0))
|
|
|
|
self.AddItemData(itemVnum, metinSlot, attrSlot)
|
|
|
|
def __AppendAttackSpeedInfo(self, item):
|
|
atkSpd = item.GetValue(0)
|
|
|
|
if atkSpd < 80:
|
|
stSpd = localeInfo.TOOLTIP_ITEM_VERY_FAST
|
|
elif atkSpd <= 95:
|
|
stSpd = localeInfo.TOOLTIP_ITEM_FAST
|
|
elif atkSpd <= 105:
|
|
stSpd = localeInfo.TOOLTIP_ITEM_NORMAL
|
|
elif atkSpd <= 120:
|
|
stSpd = localeInfo.TOOLTIP_ITEM_SLOW
|
|
else:
|
|
stSpd = localeInfo.TOOLTIP_ITEM_VERY_SLOW
|
|
|
|
self.AppendTextLine(localeInfo.TOOLTIP_ITEM_ATT_SPEED % stSpd, self.NORMAL_COLOR)
|
|
|
|
def __AppendAttackGradeInfo(self):
|
|
atkGrade = item.GetValue(1)
|
|
self.AppendTextLine(localeInfo.TOOLTIP_ITEM_ATT_GRADE % atkGrade, self.GetChangeTextLineColor(atkGrade))
|
|
|
|
def __AppendAttackPowerInfo(self):
|
|
minPower = item.GetValue(3)
|
|
maxPower = item.GetValue(4)
|
|
addPower = item.GetValue(5)
|
|
if maxPower > minPower:
|
|
self.AppendTextLine(localeInfo.TOOLTIP_ITEM_ATT_POWER % (minPower+addPower, maxPower+addPower), self.POSITIVE_COLOR)
|
|
else:
|
|
self.AppendTextLine(localeInfo.TOOLTIP_ITEM_ATT_POWER_ONE_ARG % (minPower+addPower), self.POSITIVE_COLOR)
|
|
|
|
def __AppendMagicAttackInfo(self):
|
|
minMagicAttackPower = item.GetValue(1)
|
|
maxMagicAttackPower = item.GetValue(2)
|
|
addPower = item.GetValue(5)
|
|
|
|
if minMagicAttackPower > 0 or maxMagicAttackPower > 0:
|
|
if maxMagicAttackPower > minMagicAttackPower:
|
|
self.AppendTextLine(localeInfo.TOOLTIP_ITEM_MAGIC_ATT_POWER % (minMagicAttackPower+addPower, maxMagicAttackPower+addPower), self.POSITIVE_COLOR)
|
|
else:
|
|
self.AppendTextLine(localeInfo.TOOLTIP_ITEM_MAGIC_ATT_POWER_ONE_ARG % (minMagicAttackPower+addPower), self.POSITIVE_COLOR)
|
|
|
|
def __AppendMagicDefenceInfo(self):
|
|
magicDefencePower = item.GetValue(0)
|
|
|
|
if magicDefencePower > 0:
|
|
self.AppendTextLine(localeInfo.TOOLTIP_ITEM_MAGIC_DEF_POWER % magicDefencePower, self.GetChangeTextLineColor(magicDefencePower))
|
|
|
|
def __AppendAttributeInformation(self, attrSlot):
|
|
if 0 != attrSlot:
|
|
|
|
for i in range(player.ATTRIBUTE_SLOT_MAX_NUM):
|
|
type = attrSlot[i][0]
|
|
value = attrSlot[i][1]
|
|
|
|
if 0 == value:
|
|
continue
|
|
|
|
affectString = self.__GetAffectString(type, value)
|
|
if affectString:
|
|
affectColor = self.__GetAttributeColor(i, value)
|
|
self.AppendTextLine(affectString, affectColor)
|
|
|
|
def __GetAttributeColor(self, index, value):
|
|
if value > 0:
|
|
if index >= 5:
|
|
return self.SPECIAL_POSITIVE_COLOR2
|
|
else:
|
|
return self.SPECIAL_POSITIVE_COLOR
|
|
elif value == 0:
|
|
return self.NORMAL_COLOR
|
|
else:
|
|
return self.NEGATIVE_COLOR
|
|
|
|
def __IsPolymorphItem(self, itemVnum):
|
|
if itemVnum >= 70103 and itemVnum <= 70106:
|
|
return 1
|
|
return 0
|
|
|
|
def __SetPolymorphItemTitle(self, monsterVnum):
|
|
itemName =nonplayer.GetMonsterName(monsterVnum)
|
|
itemName+=" "
|
|
itemName+=item.GetItemName()
|
|
self.SetTitle(itemName)
|
|
|
|
def __SetNormalItemTitle(self):
|
|
self.SetTitle(item.GetItemName())
|
|
|
|
def __SetSpecialItemTitle(self):
|
|
self.AppendTextLine(item.GetItemName(), self.SPECIAL_TITLE_COLOR)
|
|
|
|
def __SetItemTitle(self, itemVnum, metinSlot, attrSlot):
|
|
if self.__IsPolymorphItem(itemVnum):
|
|
self.__SetPolymorphItemTitle(metinSlot[0])
|
|
else:
|
|
if self.__IsAttr(attrSlot):
|
|
self.__SetSpecialItemTitle()
|
|
return
|
|
|
|
self.__SetNormalItemTitle()
|
|
|
|
def __IsAttr(self, attrSlot):
|
|
if not attrSlot:
|
|
return False
|
|
|
|
for i in range(player.ATTRIBUTE_SLOT_MAX_NUM):
|
|
type = attrSlot[i][0]
|
|
|
|
if 0 != type:
|
|
return True
|
|
|
|
return False
|
|
|
|
# MR-12: Fix broken metin stones showing as empty sockets in item tooltip
|
|
def AddRefineItemData(self, itemVnum, metinSlot, attrSlot = 0):
|
|
# Separate metin slots into filled (non-broken) and empty slots
|
|
filledSlots = []
|
|
emptySlots = []
|
|
|
|
for i in range(player.METIN_SOCKET_MAX_NUM):
|
|
metinSlotData = metinSlot[i]
|
|
metin_index = self.GetMetinItemIndex(metinSlotData)
|
|
|
|
if metin_index == constInfo.ERROR_METIN_STONE:
|
|
# Broken stone - convert to empty silver socket
|
|
emptySlots.append(player.METIN_SOCKET_TYPE_SILVER)
|
|
elif metin_index == 0:
|
|
# Empty slot
|
|
emptySlots.append(metinSlotData)
|
|
else:
|
|
# Valid metin stone
|
|
filledSlots.append(metinSlotData)
|
|
|
|
# Rebuild metinSlot with filled slots first, then empty slots
|
|
newSlots = filledSlots + emptySlots
|
|
|
|
for i in range(player.METIN_SOCKET_MAX_NUM):
|
|
if i < len(newSlots):
|
|
metinSlot[i] = newSlots[i]
|
|
else:
|
|
metinSlot[i] = 0
|
|
# MR-12: -- END OF -- Fix broken metin stones showing as empty sockets in item tooltip
|
|
|
|
self.AddItemData(itemVnum, metinSlot, attrSlot)
|
|
|
|
def AddItemData_Offline(self, itemVnum, itemDesc, itemSummary, metinSlot, attrSlot):
|
|
self.__AdjustMaxWidth(attrSlot, itemDesc)
|
|
self.__SetItemTitle(itemVnum, metinSlot, attrSlot)
|
|
|
|
if self.__IsHair(itemVnum):
|
|
self.__AppendHairIcon(itemVnum)
|
|
|
|
### Description ###
|
|
self.AppendDescription(itemDesc)
|
|
self.AppendDescription(itemSummary, self.CONDITION_COLOR)
|
|
|
|
def AddItemData(self, itemVnum, metinSlot, attrSlot = 0, flags = 0, unbindTime = 0):
|
|
self.itemVnum = itemVnum
|
|
self.metinSlot = metinSlot
|
|
item.SelectItem(itemVnum)
|
|
itemType = item.GetItemType()
|
|
itemSubType = item.GetItemSubType()
|
|
|
|
if not item.GetItemDescription():
|
|
self.__CalculateToolTipWidth()
|
|
|
|
if 50026 == itemVnum:
|
|
if 0 != metinSlot:
|
|
name = item.GetItemName()
|
|
if metinSlot[0] > 0:
|
|
name += " "
|
|
name += localeInfo.NumberToMoneyString(metinSlot[0])
|
|
self.SetTitle(name)
|
|
|
|
self.ShowToolTip()
|
|
return
|
|
|
|
### Skill Book ###
|
|
elif 50300 == itemVnum:
|
|
if 0 != metinSlot:
|
|
self.__SetSkillBookToolTip(metinSlot[0], localeInfo.TOOLTIP_SKILLBOOK_NAME, 1)
|
|
|
|
self.ShowToolTip()
|
|
return
|
|
elif 70037 == itemVnum:
|
|
if 0 != metinSlot:
|
|
self.__SetSkillBookToolTip(metinSlot[0], localeInfo.TOOLTIP_SKILL_FORGET_BOOK_NAME, 0)
|
|
self.AppendDescription(item.GetItemDescription())
|
|
self.AppendDescription(item.GetItemSummary(), self.CONDITION_COLOR)
|
|
|
|
|
|
self.ShowToolTip()
|
|
return
|
|
elif 70055 == itemVnum:
|
|
if 0 != metinSlot:
|
|
self.__SetSkillBookToolTip(metinSlot[0], localeInfo.TOOLTIP_SKILL_FORGET_BOOK_NAME, 0)
|
|
self.AppendDescription(item.GetItemDescription())
|
|
self.AppendDescription(item.GetItemSummary(), self.CONDITION_COLOR)
|
|
|
|
self.ShowToolTip()
|
|
return
|
|
###########################################################################################
|
|
|
|
|
|
itemDesc = item.GetItemDescription()
|
|
itemSummary = item.GetItemSummary()
|
|
|
|
isCostumeItem = 0
|
|
isCostumeHair = 0
|
|
isCostumeBody = 0
|
|
|
|
if app.ENABLE_COSTUME_SYSTEM:
|
|
if item.ITEM_TYPE_COSTUME == itemType:
|
|
isCostumeItem = 1
|
|
isCostumeHair = item.COSTUME_TYPE_HAIR == itemSubType
|
|
isCostumeBody = item.COSTUME_TYPE_BODY == itemSubType
|
|
|
|
#dbg.TraceError("IS_COSTUME_ITEM! body(%d) hair(%d)" % (isCostumeBody, isCostumeHair))
|
|
|
|
self.__AdjustMaxWidth(attrSlot, itemDesc)
|
|
self.__SetItemTitle(itemVnum, metinSlot, attrSlot)
|
|
|
|
### Hair Preview Image ###
|
|
if self.__IsHair(itemVnum):
|
|
self.__AppendHairIcon(itemVnum)
|
|
|
|
### Description ###
|
|
self.AppendDescription(itemDesc)
|
|
self.AppendDescription(itemSummary, self.CONDITION_COLOR)
|
|
|
|
### Weapon ###
|
|
if item.ITEM_TYPE_WEAPON == itemType:
|
|
|
|
self.__AppendLimitInformation()
|
|
|
|
self.AppendSpace(5)
|
|
|
|
## For fans, display magic attack first.
|
|
if item.WEAPON_FAN == itemSubType:
|
|
self.__AppendMagicAttackInfo()
|
|
self.__AppendAttackPowerInfo()
|
|
|
|
else:
|
|
self.__AppendAttackPowerInfo()
|
|
self.__AppendMagicAttackInfo()
|
|
|
|
self.__AppendAffectInformation()
|
|
self.__AppendAttributeInformation(attrSlot)
|
|
|
|
self.AppendWearableInformation()
|
|
self.__AppendMetinSlotInfo(metinSlot)
|
|
|
|
### Armor ###
|
|
elif item.ITEM_TYPE_ARMOR == itemType:
|
|
self.__AppendLimitInformation()
|
|
|
|
## Defense
|
|
defGrade = item.GetValue(1)
|
|
defBonus = item.GetValue(5)*2 ## Fixed an issue where defense power was displayed incorrectly.
|
|
if defGrade > 0:
|
|
self.AppendSpace(5)
|
|
self.AppendTextLine(localeInfo.TOOLTIP_ITEM_DEF_GRADE % (defGrade+defBonus), self.GetChangeTextLineColor(defGrade))
|
|
|
|
self.__AppendMagicDefenceInfo()
|
|
self.__AppendAffectInformation()
|
|
self.__AppendAttributeInformation(attrSlot)
|
|
|
|
self.AppendWearableInformation()
|
|
|
|
if itemSubType in (item.ARMOR_WRIST, item.ARMOR_NECK, item.ARMOR_EAR):
|
|
self.__AppendAccessoryMetinSlotInfo(metinSlot, constInfo.GET_ACCESSORY_MATERIAL_VNUM(itemVnum, itemSubType))
|
|
else:
|
|
self.__AppendMetinSlotInfo(metinSlot)
|
|
|
|
### Ring Slot Item (Not UNIQUE) ###
|
|
elif item.ITEM_TYPE_RING == itemType:
|
|
self.__AppendLimitInformation()
|
|
self.__AppendAffectInformation()
|
|
self.__AppendAttributeInformation(attrSlot)
|
|
|
|
#Planning for the ring socket system has not yet been decided
|
|
#self.__AppendAccessoryMetinSlotInfo(metinSlot, 99001)
|
|
|
|
bHasRealtimeFlag = 0
|
|
for i in range(item.LIMIT_MAX_NUM):
|
|
(limitType, limitValue) = item.GetLimit(i)
|
|
|
|
if item.LIMIT_REAL_TIME == limitType:
|
|
bHasRealtimeFlag = 1
|
|
|
|
if 1 == bHasRealtimeFlag:
|
|
if item.LIMIT_REAL_TIME == item.GetLimitType(0) or item.LIMIT_REAL_TIME_START_FIRST_USE == item.GetLimitType(0):
|
|
self.AppendMallItemLastTime(metinSlot[0], item.GetLimitValue(0))
|
|
else:
|
|
self.AppendMallItemLastTime(metinSlot[0], item.GetLimitValue(1))
|
|
|
|
self.AppendSpace(5)
|
|
|
|
### Belt Item ###
|
|
elif item.ITEM_TYPE_BELT == itemType:
|
|
self.__AppendLimitInformation()
|
|
self.__AppendAffectInformation()
|
|
self.__AppendAttributeInformation(attrSlot)
|
|
|
|
self.__AppendAccessoryMetinSlotInfo(metinSlot, constInfo.GET_BELT_MATERIAL_VNUM(itemVnum))
|
|
|
|
## Costume Item ##
|
|
elif 0 != isCostumeItem:
|
|
self.__AppendLimitInformation()
|
|
self.__AppendAffectInformation()
|
|
self.__AppendAttributeInformation(attrSlot)
|
|
|
|
self.AppendWearableInformation()
|
|
|
|
bHasRealtimeFlag = 0
|
|
for i in range(item.LIMIT_MAX_NUM):
|
|
(limitType, limitValue) = item.GetLimit(i)
|
|
|
|
if item.LIMIT_REAL_TIME == limitType:
|
|
bHasRealtimeFlag = 1
|
|
|
|
if 1 == bHasRealtimeFlag:
|
|
if item.LIMIT_REAL_TIME == item.GetLimitType(0) or item.LIMIT_REAL_TIME_START_FIRST_USE == item.GetLimitType(0):
|
|
self.AppendMallItemLastTime(metinSlot[0], item.GetLimitValue(0))
|
|
else:
|
|
self.AppendMallItemLastTime(metinSlot[0], item.GetLimitValue(1))
|
|
|
|
## Rod ##
|
|
elif item.ITEM_TYPE_ROD == itemType:
|
|
if 0 != metinSlot:
|
|
curLevel = item.GetValue(0) // 10
|
|
curEXP = metinSlot[0]
|
|
maxEXP = item.GetValue(2)
|
|
self.__AppendLimitInformation()
|
|
self.__AppendRodInformation(curLevel, curEXP, maxEXP)
|
|
|
|
## Pick ##
|
|
elif item.ITEM_TYPE_PICK == itemType:
|
|
|
|
if 0 != metinSlot:
|
|
curLevel = item.GetValue(0) // 10
|
|
curEXP = metinSlot[0]
|
|
maxEXP = item.GetValue(2)
|
|
self.__AppendLimitInformation()
|
|
self.__AppendPickInformation(curLevel, curEXP, maxEXP)
|
|
|
|
## Lottery ##
|
|
elif item.ITEM_TYPE_LOTTERY == itemType:
|
|
if 0 != metinSlot:
|
|
|
|
ticketNumber = int(metinSlot[0])
|
|
stepNumber = int(metinSlot[1])
|
|
|
|
self.AppendSpace(5)
|
|
self.AppendTextLine(localeInfo.TOOLTIP_LOTTERY_STEP_NUMBER % (stepNumber), self.NORMAL_COLOR)
|
|
self.AppendTextLine(localeInfo.TOOLTIP_LOTTO_NUMBER % (ticketNumber), self.NORMAL_COLOR);
|
|
|
|
### Metin ###
|
|
elif item.ITEM_TYPE_METIN == itemType:
|
|
self.AppendMetinInformation()
|
|
self.AppendMetinWearInformation()
|
|
|
|
### Fish ###
|
|
elif item.ITEM_TYPE_FISH == itemType:
|
|
if 0 != metinSlot:
|
|
self.__AppendFishInfo(metinSlot[0])
|
|
|
|
## item.ITEM_TYPE_BLEND
|
|
elif item.ITEM_TYPE_BLEND == itemType:
|
|
self.__AppendLimitInformation()
|
|
|
|
if metinSlot:
|
|
affectType = metinSlot[0]
|
|
affectValue = metinSlot[1]
|
|
time = metinSlot[2]
|
|
self.AppendSpace(5)
|
|
affectText = self.__GetAffectString(affectType, affectValue)
|
|
|
|
self.AppendTextLine(affectText, self.NORMAL_COLOR)
|
|
|
|
if time > 0:
|
|
minute = (time // 60)
|
|
second = (time % 60)
|
|
timeString = localeInfo.TOOLTIP_POTION_TIME
|
|
|
|
if minute > 0:
|
|
timeString += str(minute) + localeInfo.TOOLTIP_POTION_MIN
|
|
if second > 0:
|
|
timeString += " " + str(second) + localeInfo.TOOLTIP_POTION_SEC
|
|
|
|
self.AppendTextLine(timeString)
|
|
else:
|
|
self.AppendTextLine(localeInfo.BLEND_POTION_NO_TIME)
|
|
else:
|
|
self.AppendTextLine("BLEND_POTION_NO_INFO")
|
|
|
|
elif item.ITEM_TYPE_UNIQUE == itemType:
|
|
if 0 != metinSlot:
|
|
bHasRealtimeFlag = 0
|
|
for i in range(item.LIMIT_MAX_NUM):
|
|
(limitType, limitValue) = item.GetLimit(i)
|
|
|
|
if item.LIMIT_REAL_TIME == limitType:
|
|
bHasRealtimeFlag = 1
|
|
|
|
if 1 == bHasRealtimeFlag:
|
|
if item.LIMIT_REAL_TIME == item.GetLimitType(0) or item.LIMIT_REAL_TIME_START_FIRST_USE == item.GetLimitType(0):
|
|
self.AppendMallItemLastTime(metinSlot[0], item.GetLimitValue(0))
|
|
else:
|
|
self.AppendMallItemLastTime(metinSlot[0], item.GetLimitValue(1))
|
|
else:
|
|
time = metinSlot[player.METIN_SOCKET_MAX_NUM - 1]
|
|
|
|
if 1 == item.GetValue(2): ## Real-time use flag / given even if not equipped
|
|
if item.LIMIT_REAL_TIME == item.GetLimitType(0) or item.LIMIT_REAL_TIME_START_FIRST_USE == item.GetLimitType(0):
|
|
self.AppendMallItemLastTime(time, item.GetLimitValue(0))
|
|
else:
|
|
self.AppendMallItemLastTime(time, item.GetLimitValue(1))
|
|
else:
|
|
self.AppendUniqueItemLastTime(time)
|
|
|
|
### Use ###
|
|
elif item.ITEM_TYPE_USE == itemType:
|
|
self.__AppendLimitInformation()
|
|
|
|
if item.USE_POTION == itemSubType or item.USE_POTION_NODELAY == itemSubType:
|
|
self.__AppendPotionInformation()
|
|
|
|
elif item.USE_ABILITY_UP == itemSubType:
|
|
self.__AppendAbilityPotionInformation()
|
|
|
|
|
|
## Spirit Detector
|
|
if 27989 == itemVnum or 76006 == itemVnum:
|
|
if 0 != metinSlot:
|
|
useCount = int(metinSlot[0])
|
|
|
|
self.AppendSpace(5)
|
|
self.AppendTextLine(localeInfo.TOOLTIP_REST_USABLE_COUNT % (6 - useCount), self.NORMAL_COLOR)
|
|
|
|
## Event Detector
|
|
elif 50004 == itemVnum:
|
|
if 0 != metinSlot:
|
|
useCount = int(metinSlot[0])
|
|
|
|
self.AppendSpace(5)
|
|
self.AppendTextLine(localeInfo.TOOLTIP_REST_USABLE_COUNT % (10 - useCount), self.NORMAL_COLOR)
|
|
|
|
## Automatic potion
|
|
elif constInfo.IS_AUTO_POTION(itemVnum):
|
|
if 0 != metinSlot:
|
|
# # 0: Activate, 1: Power, 2: Cooldown
|
|
isActivated = int(metinSlot[0])
|
|
usedAmount = float(metinSlot[1])
|
|
totalAmount = float(metinSlot[2])
|
|
|
|
if 0 == totalAmount:
|
|
totalAmount = 1
|
|
|
|
self.AppendSpace(5)
|
|
|
|
## 0: active, 1: usage amount, 2: total amount
|
|
if 0 != isActivated:
|
|
self.AppendTextLine("(%s)" % (localeInfo.TOOLTIP_AUTO_POTION_USING), self.SPECIAL_POSITIVE_COLOR)
|
|
self.AppendSpace(5)
|
|
|
|
self.AppendTextLine(localeInfo.TOOLTIP_AUTO_POTION_REST % (100.0 - ((usedAmount / totalAmount) * 100.0)), self.POSITIVE_COLOR)
|
|
|
|
## Return Memory
|
|
elif itemVnum in WARP_SCROLLS:
|
|
if 0 != metinSlot:
|
|
xPos = int(metinSlot[0])
|
|
yPos = int(metinSlot[1])
|
|
|
|
if xPos != 0 and yPos != 0:
|
|
(mapName, xBase, yBase) = background.GlobalPositionToMapInfo(xPos, yPos)
|
|
|
|
localeMapName=localeInfo.MINIMAP_ZONE_NAME_DICT.get(mapName, "")
|
|
|
|
self.AppendSpace(5)
|
|
|
|
if localeMapName!="":
|
|
self.AppendTextLine(localeInfo.TOOLTIP_MEMORIZED_POSITION % (localeMapName, int(xPos-xBase) // 100, int(yPos-yBase) // 100), self.NORMAL_COLOR)
|
|
else:
|
|
self.AppendTextLine(localeInfo.TOOLTIP_MEMORIZED_POSITION_ERROR % (int(xPos) // 100, int(yPos) // 100), self.NORMAL_COLOR)
|
|
dbg.TraceError("NOT_EXIST_IN_MINIMAP_ZONE_NAME_DICT: %s" % mapName)
|
|
|
|
#####
|
|
if item.USE_SPECIAL == itemSubType:
|
|
bHasRealtimeFlag = 0
|
|
for i in range(item.LIMIT_MAX_NUM):
|
|
(limitType, limitValue) = item.GetLimit(i)
|
|
|
|
if item.LIMIT_REAL_TIME == limitType:
|
|
bHasRealtimeFlag = 1
|
|
|
|
if 1 == bHasRealtimeFlag:
|
|
if item.LIMIT_REAL_TIME == item.GetLimitType(0) or item.LIMIT_REAL_TIME_START_FIRST_USE == item.GetLimitType(0):
|
|
self.AppendMallItemLastTime(metinSlot[0], item.GetLimitValue(0))
|
|
else:
|
|
self.AppendMallItemLastTime(metinSlot[0], item.GetLimitValue(1))
|
|
else:
|
|
if 0 != metinSlot:
|
|
time = metinSlot[player.METIN_SOCKET_MAX_NUM - 1]
|
|
|
|
if 1 == item.GetValue(2):
|
|
if item.LIMIT_REAL_TIME == item.GetLimitType(0) or item.LIMIT_REAL_TIME_START_FIRST_USE == item.GetLimitType(0):
|
|
self.AppendMallItemLastTime(time, item.GetLimitValue(0))
|
|
else:
|
|
self.AppendMallItemLastTime(time, item.GetLimitValue(1))
|
|
|
|
elif item.USE_TIME_CHARGE_PER == itemSubType:
|
|
bHasRealtimeFlag = 0
|
|
for i in range(item.LIMIT_MAX_NUM):
|
|
(limitType, limitValue) = item.GetLimit(i)
|
|
|
|
if item.LIMIT_REAL_TIME == limitType:
|
|
bHasRealtimeFlag = 1
|
|
|
|
if metinSlot[2]:
|
|
self.AppendTextLine(localeInfo.TOOLTIP_TIME_CHARGER_PER(metinSlot[2]))
|
|
else:
|
|
self.AppendTextLine(localeInfo.TOOLTIP_TIME_CHARGER_PER(item.GetValue(0)))
|
|
|
|
if 1 == bHasRealtimeFlag:
|
|
if item.LIMIT_REAL_TIME == item.GetLimitType(0) or item.LIMIT_REAL_TIME_START_FIRST_USE == item.GetLimitType(0):
|
|
self.AppendMallItemLastTime(metinSlot[0], item.GetLimitValue(0))
|
|
else:
|
|
self.AppendMallItemLastTime(metinSlot[0], item.GetLimitValue(1))
|
|
|
|
elif item.USE_TIME_CHARGE_FIX == itemSubType:
|
|
bHasRealtimeFlag = 0
|
|
for i in range(item.LIMIT_MAX_NUM):
|
|
(limitType, limitValue) = item.GetLimit(i)
|
|
|
|
if item.LIMIT_REAL_TIME == limitType:
|
|
bHasRealtimeFlag = 1
|
|
|
|
if metinSlot[2]:
|
|
self.AppendTextLine(localeInfo.TOOLTIP_TIME_CHARGER_FIX(metinSlot[2]))
|
|
else:
|
|
self.AppendTextLine(localeInfo.TOOLTIP_TIME_CHARGER_FIX(item.GetValue(0)))
|
|
|
|
if 1 == bHasRealtimeFlag:
|
|
if item.LIMIT_REAL_TIME == item.GetLimitType(0) or item.LIMIT_REAL_TIME_START_FIRST_USE == item.GetLimitType(0):
|
|
self.AppendMallItemLastTime(metinSlot[0], item.GetLimitValue(0))
|
|
else:
|
|
self.AppendMallItemLastTime(metinSlot[0], item.GetLimitValue(1))
|
|
|
|
elif item.ITEM_TYPE_QUEST == itemType:
|
|
bHasRealtimeFlag = 0
|
|
for i in range(item.LIMIT_MAX_NUM):
|
|
(limitType, limitValue) = item.GetLimit(i)
|
|
|
|
if item.LIMIT_REAL_TIME == limitType:
|
|
bHasRealtimeFlag = 1
|
|
|
|
if 1 == bHasRealtimeFlag:
|
|
if item.LIMIT_REAL_TIME == item.GetLimitType(0) or item.LIMIT_REAL_TIME_START_FIRST_USE == item.GetLimitType(0):
|
|
self.AppendMallItemLastTime(metinSlot[0], item.GetLimitValue(0))
|
|
else:
|
|
self.AppendMallItemLastTime(metinSlot[0], item.GetLimitValue(1))
|
|
|
|
elif item.ITEM_TYPE_DS == itemType:
|
|
self.AppendTextLine(self.__DragonSoulInfoString(itemVnum))
|
|
self.__AppendAttributeInformation(attrSlot)
|
|
else:
|
|
self.__AppendLimitInformation()
|
|
|
|
for i in range(item.LIMIT_MAX_NUM):
|
|
(limitType, limitValue) = item.GetLimit(i)
|
|
limitValue2 = item.GetLimitValue(i)
|
|
|
|
if item.LIMIT_REAL_TIME_START_FIRST_USE == limitType:
|
|
self.AppendRealTimeStartFirstUseLastTime(item, metinSlot, i, limitValue2)
|
|
|
|
elif item.LIMIT_TIMER_BASED_ON_WEAR == limitType:
|
|
self.AppendTimerBasedOnWearLastTime(metinSlot, limitValue2)
|
|
|
|
self.ShowToolTip()
|
|
|
|
def __DragonSoulInfoString (self, dwVnum):
|
|
step = (dwVnum // 100) % 10
|
|
refine = (dwVnum // 10) % 10
|
|
|
|
if 0 == step:
|
|
return localeInfo.DRAGON_SOUL_STEP_LEVEL1 + " " + localeInfo.DRAGON_SOUL_STRENGTH(refine)
|
|
elif 1 == step:
|
|
return localeInfo.DRAGON_SOUL_STEP_LEVEL2 + " " + localeInfo.DRAGON_SOUL_STRENGTH(refine)
|
|
elif 2 == step:
|
|
return localeInfo.DRAGON_SOUL_STEP_LEVEL3 + " " + localeInfo.DRAGON_SOUL_STRENGTH(refine)
|
|
elif 3 == step:
|
|
return localeInfo.DRAGON_SOUL_STEP_LEVEL4 + " " + localeInfo.DRAGON_SOUL_STRENGTH(refine)
|
|
elif 4 == step:
|
|
return localeInfo.DRAGON_SOUL_STEP_LEVEL5 + " " + localeInfo.DRAGON_SOUL_STRENGTH(refine)
|
|
else:
|
|
return ""
|
|
|
|
|
|
## Is it hair?
|
|
def __IsHair(self, itemVnum):
|
|
return (self.__IsOldHair(itemVnum) or
|
|
self.__IsNewHair(itemVnum) or
|
|
self.__IsNewHair2(itemVnum) or
|
|
self.__IsNewHair3(itemVnum) or
|
|
self.__IsCostumeHair(itemVnum)
|
|
)
|
|
|
|
def __IsOldHair(self, itemVnum):
|
|
return itemVnum > 73000 and itemVnum < 74000
|
|
|
|
def __IsNewHair(self, itemVnum):
|
|
return itemVnum > 74000 and itemVnum < 75000
|
|
|
|
def __IsNewHair2(self, itemVnum):
|
|
return itemVnum > 75000 and itemVnum < 76000
|
|
|
|
def __IsNewHair3(self, itemVnum):
|
|
return ((74012 < itemVnum and itemVnum < 74022) or
|
|
(74262 < itemVnum and itemVnum < 74272) or
|
|
(74512 < itemVnum and itemVnum < 74522) or
|
|
(74762 < itemVnum and itemVnum < 74772) or
|
|
(45000 < itemVnum and itemVnum < 47000))
|
|
|
|
def __IsCostumeHair(self, itemVnum):
|
|
return app.ENABLE_COSTUME_SYSTEM and self.__IsNewHair3(itemVnum - 100000)
|
|
|
|
def __AppendHairIcon(self, itemVnum):
|
|
itemImage = ui.ImageBox()
|
|
itemImage.SetParent(self)
|
|
itemImage.Show()
|
|
|
|
if self.__IsOldHair(itemVnum):
|
|
itemImage.LoadImage("d:/ymir work/item/quest/" + str(itemVnum) + ".tga")
|
|
elif self.__IsNewHair3(itemVnum):
|
|
itemImage.LoadImage("icon/hair/%d.sub" % (itemVnum))
|
|
elif self.__IsNewHair(itemVnum): # Use by linking to existing hair numbers. New items have numbers increased by 1000.
|
|
itemImage.LoadImage("d:/ymir work/item/quest/" + str(itemVnum - 1000) + ".tga")
|
|
elif self.__IsNewHair2(itemVnum):
|
|
itemImage.LoadImage("icon/hair/%d.sub" % (itemVnum))
|
|
elif self.__IsCostumeHair(itemVnum):
|
|
itemImage.LoadImage("icon/hair/%d.sub" % (itemVnum - 100000))
|
|
|
|
# MR-10: Fix element centering in tooltips
|
|
self.hairIcon = itemImage
|
|
xPos = max(0, (self.toolTipWidth - itemImage.GetWidth()) // 2)
|
|
|
|
itemImage.SetPosition(xPos, self.toolTipHeight)
|
|
# MR-10: -- END OF -- Fix element centering in tooltips
|
|
self.toolTipHeight += itemImage.GetHeight()
|
|
#self.toolTipWidth += itemImage.GetWidth()/2
|
|
self.childrenList.append(itemImage)
|
|
self.ResizeToolTip()
|
|
# MR-10: Fix element centering in tooltips
|
|
self.__CenterHairIcon()
|
|
# MR-10: -- END OF -- Fix element centering in tooltips
|
|
|
|
# MR-10: Fix element centering in tooltips
|
|
def __CenterHairIcon(self):
|
|
if not self.hairIcon:
|
|
return
|
|
|
|
(xPos, yPos) = self.hairIcon.GetLocalPosition()
|
|
xPos = max(0, (self.toolTipWidth - self.hairIcon.GetWidth()) // 2)
|
|
|
|
self.hairIcon.SetPosition(xPos, yPos)
|
|
# MR-10: -- END OF -- Fix element centering in tooltips
|
|
|
|
## If the Description is large, adjust the tooltip size.
|
|
def __AdjustMaxWidth(self, attrSlot, desc):
|
|
newToolTipWidth = self.toolTipWidth
|
|
newToolTipWidth = max(self.__AdjustAttrMaxWidth(attrSlot), newToolTipWidth)
|
|
newToolTipWidth = max(self.__AdjustDescMaxWidth(desc), newToolTipWidth)
|
|
if newToolTipWidth > self.toolTipWidth:
|
|
self.toolTipWidth = newToolTipWidth
|
|
self.ResizeToolTip()
|
|
# MR-10: Fix element centering in tooltips
|
|
self.AlignTextLineHorizonalCenter()
|
|
self.__CenterHairIcon()
|
|
# MR-10: -- END OF -- Fix element centering in tooltips
|
|
|
|
def __AdjustAttrMaxWidth(self, attrSlot):
|
|
if 0 == attrSlot:
|
|
return self.toolTipWidth
|
|
|
|
maxWidth = self.toolTipWidth
|
|
for i in range(player.ATTRIBUTE_SLOT_MAX_NUM):
|
|
type = attrSlot[i][0]
|
|
value = attrSlot[i][1]
|
|
|
|
attrText = self.AppendTextLine(self.__GetAffectString(type, value))
|
|
(tW, _) = attrText.GetTextSize()
|
|
self.childrenList.remove(attrText)
|
|
self.toolTipHeight -= self.TEXT_LINE_HEIGHT
|
|
|
|
maxWidth = max(tW + 12, maxWidth)
|
|
|
|
return maxWidth
|
|
|
|
def __AdjustDescMaxWidth(self, desc):
|
|
if not desc:
|
|
return self.toolTipWidth
|
|
|
|
padding = 20
|
|
maxWidthPx = max(50, self.toolTipWidth - padding)
|
|
|
|
lines = SplitDescriptionByPixelWidth(desc, maxWidthPx, self.defFontName)
|
|
if len(lines) >= 2:
|
|
return DESC_MAX_WIDTH
|
|
|
|
return self.toolTipWidth
|
|
|
|
def ResizeToolTipWidth(self, width):
|
|
self.toolTipWidth = width
|
|
|
|
# MR-10: Fix element centering in tooltips
|
|
self.AlignTextLineHorizonalCenter()
|
|
self.__CenterHairIcon()
|
|
# MR-10: -- END OF -- Fix element centering in tooltips
|
|
|
|
def __CalculateToolTipWidth(self):
|
|
affectTextLineLenList = []
|
|
|
|
metinSocket = self.metinSlot
|
|
if metinSocket:
|
|
for socketIndex in metinSocket:
|
|
if socketIndex:
|
|
item.SelectItem(socketIndex)
|
|
|
|
affectType, affectValue = item.GetAffect(0)
|
|
affectString = self.__GetAffectString(affectType, affectValue)
|
|
if affectString:
|
|
affectTextLineLenList.append(len(affectString))
|
|
|
|
if self.itemVnum:
|
|
item.SelectItem(self.itemVnum)
|
|
self.metinSlot = None
|
|
|
|
if self.toolTipWidth == self.TOOL_TIP_WIDTH:
|
|
if affectTextLineLenList:
|
|
self.toolTipWidth += max(affectTextLineLenList) + 10
|
|
|
|
self.AlignTextLineHorizonalCenter()
|
|
|
|
# MR-10: Fix element centering in tooltips
|
|
self.__CenterHairIcon()
|
|
# MR-10: -- END OF -- Fix element centering in tooltips
|
|
|
|
def __SetSkillBookToolTip(self, skillIndex, bookName, skillGrade):
|
|
skillName = skill.GetSkillName(skillIndex)
|
|
|
|
if not skillName:
|
|
return
|
|
|
|
itemName = skillName + " " + bookName
|
|
self.SetTitle(itemName)
|
|
|
|
def __AppendPickInformation(self, curLevel, curEXP, maxEXP):
|
|
self.AppendSpace(5)
|
|
self.AppendTextLine(localeInfo.TOOLTIP_PICK_LEVEL % (curLevel), self.NORMAL_COLOR)
|
|
self.AppendTextLine(localeInfo.TOOLTIP_PICK_EXP % (curEXP, maxEXP), self.NORMAL_COLOR)
|
|
|
|
if curEXP == maxEXP:
|
|
self.AppendSpace(5)
|
|
self.AppendTextLine(localeInfo.TOOLTIP_PICK_UPGRADE1, self.NORMAL_COLOR)
|
|
self.AppendTextLine(localeInfo.TOOLTIP_PICK_UPGRADE2, self.NORMAL_COLOR)
|
|
self.AppendTextLine(localeInfo.TOOLTIP_PICK_UPGRADE3, self.NORMAL_COLOR)
|
|
|
|
|
|
def __AppendRodInformation(self, curLevel, curEXP, maxEXP):
|
|
self.AppendSpace(5)
|
|
self.AppendTextLine(localeInfo.TOOLTIP_FISHINGROD_LEVEL % (curLevel), self.NORMAL_COLOR)
|
|
self.AppendTextLine(localeInfo.TOOLTIP_FISHINGROD_EXP % (curEXP, maxEXP), self.NORMAL_COLOR)
|
|
|
|
if curEXP == maxEXP:
|
|
self.AppendSpace(5)
|
|
self.AppendTextLine(localeInfo.TOOLTIP_FISHINGROD_UPGRADE1, self.NORMAL_COLOR)
|
|
self.AppendTextLine(localeInfo.TOOLTIP_FISHINGROD_UPGRADE2, self.NORMAL_COLOR)
|
|
self.AppendTextLine(localeInfo.TOOLTIP_FISHINGROD_UPGRADE3, self.NORMAL_COLOR)
|
|
|
|
def __AppendLimitInformation(self):
|
|
|
|
appendSpace = False
|
|
|
|
for i in range(item.LIMIT_MAX_NUM):
|
|
|
|
(limitType, limitValue) = item.GetLimit(i)
|
|
|
|
if limitValue > 0:
|
|
if False == appendSpace:
|
|
self.AppendSpace(5)
|
|
appendSpace = True
|
|
|
|
else:
|
|
continue
|
|
|
|
if item.LIMIT_LEVEL == limitType:
|
|
color = self.GetLimitTextLineColor(player.GetStatus(player.LEVEL), limitValue)
|
|
self.AppendTextLine(localeInfo.TOOLTIP_ITEM_LIMIT_LEVEL % (limitValue), color)
|
|
"""
|
|
elif item.LIMIT_STR == limitType:
|
|
color = self.GetLimitTextLineColor(player.GetStatus(player.ST), limitValue)
|
|
self.AppendTextLine(localeInfo.TOOLTIP_ITEM_LIMIT_STR % (limitValue), color)
|
|
elif item.LIMIT_DEX == limitType:
|
|
color = self.GetLimitTextLineColor(player.GetStatus(player.DX), limitValue)
|
|
self.AppendTextLine(localeInfo.TOOLTIP_ITEM_LIMIT_DEX % (limitValue), color)
|
|
elif item.LIMIT_INT == limitType:
|
|
color = self.GetLimitTextLineColor(player.GetStatus(player.IQ), limitValue)
|
|
self.AppendTextLine(localeInfo.TOOLTIP_ITEM_LIMIT_INT % (limitValue), color)
|
|
elif item.LIMIT_CON == limitType:
|
|
color = self.GetLimitTextLineColor(player.GetStatus(player.HT), limitValue)
|
|
self.AppendTextLine(localeInfo.TOOLTIP_ITEM_LIMIT_CON % (limitValue), color)
|
|
"""
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def __GetAffectString(self, affectType, affectValue):
|
|
if 0 == affectType:
|
|
return None
|
|
|
|
if 0 == affectValue:
|
|
return None
|
|
|
|
try:
|
|
return self.AFFECT_DICT[affectType](affectValue)
|
|
except TypeError:
|
|
return "UNKNOWN_VALUE[%s] %s" % (affectType, affectValue)
|
|
except KeyError:
|
|
return "UNKNOWN_TYPE[%s] %s" % (affectType, affectValue)
|
|
|
|
def __AppendAffectInformation(self):
|
|
for i in range(item.ITEM_APPLY_MAX_NUM):
|
|
|
|
(affectType, affectValue) = item.GetAffect(i)
|
|
|
|
affectString = self.__GetAffectString(affectType, affectValue)
|
|
if affectString:
|
|
self.AppendTextLine(affectString, self.GetChangeTextLineColor(affectValue))
|
|
|
|
def AppendWearableInformation(self):
|
|
|
|
self.AppendSpace(5)
|
|
self.AppendTextLine(localeInfo.TOOLTIP_ITEM_WEARABLE_JOB, self.NORMAL_COLOR)
|
|
|
|
flagList = (
|
|
not item.IsAntiFlag(item.ITEM_ANTIFLAG_WARRIOR),
|
|
not item.IsAntiFlag(item.ITEM_ANTIFLAG_ASSASSIN),
|
|
not item.IsAntiFlag(item.ITEM_ANTIFLAG_SURA),
|
|
not item.IsAntiFlag(item.ITEM_ANTIFLAG_SHAMAN))
|
|
|
|
characterNames = ""
|
|
for i in range(self.CHARACTER_COUNT):
|
|
|
|
name = self.CHARACTER_NAMES[i]
|
|
flag = flagList[i]
|
|
|
|
if flag:
|
|
characterNames += " "
|
|
characterNames += name
|
|
|
|
textLine = self.AppendTextLine(characterNames, self.NORMAL_COLOR, True)
|
|
textLine.SetFeather()
|
|
|
|
if item.IsAntiFlag(item.ITEM_ANTIFLAG_MALE):
|
|
textLine = self.AppendTextLine(localeInfo.FOR_FEMALE, self.NORMAL_COLOR, True)
|
|
textLine.SetFeather()
|
|
|
|
if item.IsAntiFlag(item.ITEM_ANTIFLAG_FEMALE):
|
|
textLine = self.AppendTextLine(localeInfo.FOR_MALE, self.NORMAL_COLOR, True)
|
|
textLine.SetFeather()
|
|
|
|
def __AppendPotionInformation(self):
|
|
self.AppendSpace(5)
|
|
|
|
healHP = item.GetValue(0)
|
|
healSP = item.GetValue(1)
|
|
healStatus = item.GetValue(2)
|
|
healPercentageHP = item.GetValue(3)
|
|
healPercentageSP = item.GetValue(4)
|
|
|
|
if healHP > 0:
|
|
self.AppendTextLine(localeInfo.TOOLTIP_POTION_PLUS_HP_POINT % healHP, self.GetChangeTextLineColor(healHP))
|
|
if healSP > 0:
|
|
self.AppendTextLine(localeInfo.TOOLTIP_POTION_PLUS_SP_POINT % healSP, self.GetChangeTextLineColor(healSP))
|
|
if healStatus != 0:
|
|
self.AppendTextLine(localeInfo.TOOLTIP_POTION_CURE)
|
|
if healPercentageHP > 0:
|
|
self.AppendTextLine(localeInfo.TOOLTIP_POTION_PLUS_HP_PERCENT % healPercentageHP, self.GetChangeTextLineColor(healPercentageHP))
|
|
if healPercentageSP > 0:
|
|
self.AppendTextLine(localeInfo.TOOLTIP_POTION_PLUS_SP_PERCENT % healPercentageSP, self.GetChangeTextLineColor(healPercentageSP))
|
|
|
|
def __AppendAbilityPotionInformation(self):
|
|
|
|
self.AppendSpace(5)
|
|
|
|
abilityType = item.GetValue(0)
|
|
time = item.GetValue(1)
|
|
point = item.GetValue(2)
|
|
|
|
if abilityType == item.APPLY_ATT_SPEED:
|
|
self.AppendTextLine(localeInfo.TOOLTIP_POTION_PLUS_ATTACK_SPEED % point, self.GetChangeTextLineColor(point))
|
|
elif abilityType == item.APPLY_MOV_SPEED:
|
|
self.AppendTextLine(localeInfo.TOOLTIP_POTION_PLUS_MOVING_SPEED % point, self.GetChangeTextLineColor(point))
|
|
|
|
if time > 0:
|
|
minute = (time // 60)
|
|
second = (time % 60)
|
|
timeString = localeInfo.TOOLTIP_POTION_TIME
|
|
|
|
if minute > 0:
|
|
timeString += " " + str(minute) + localeInfo.TOOLTIP_POTION_MIN
|
|
if second > 0:
|
|
timeString += " " + str(second) + localeInfo.TOOLTIP_POTION_SEC
|
|
|
|
self.AppendTextLine(timeString)
|
|
|
|
def GetPriceColor(self, price):
|
|
if price >= constInfo.HIGH_PRICE:
|
|
return self.HIGH_PRICE_COLOR
|
|
|
|
if price >= constInfo.MIDDLE_PRICE:
|
|
return self.MIDDLE_PRICE_COLOR
|
|
else:
|
|
return self.LOW_PRICE_COLOR
|
|
|
|
def AppendPrice(self, price):
|
|
self.AppendSpace(5)
|
|
self.AppendTextLine(localeInfo.TOOLTIP_BUYPRICE % (localeInfo.NumberToMoneyString(price)), self.GetPriceColor(price))
|
|
|
|
def AppendPriceBySecondaryCoin(self, price):
|
|
self.AppendSpace(5)
|
|
self.AppendTextLine(localeInfo.TOOLTIP_BUYPRICE % (localeInfo.NumberToSecondaryCoinString(price)), self.GetPriceColor(price))
|
|
|
|
def AppendSellingPrice(self, price):
|
|
if item.IsAntiFlag(item.ITEM_ANTIFLAG_SELL):
|
|
self.AppendTextLine(localeInfo.TOOLTIP_ANTI_SELL, self.DISABLE_COLOR)
|
|
self.AppendSpace(5)
|
|
else:
|
|
self.AppendTextLine(localeInfo.TOOLTIP_SELLPRICE % (localeInfo.NumberToMoneyString(price)), self.GetPriceColor(price))
|
|
self.AppendSpace(5)
|
|
|
|
def AppendMetinInformation(self):
|
|
affectType, affectValue = item.GetAffect(0)
|
|
#affectType = item.GetValue(0)
|
|
#affectValue = item.GetValue(1)
|
|
|
|
affectString = self.__GetAffectString(affectType, affectValue)
|
|
|
|
if affectString:
|
|
self.AppendSpace(5)
|
|
self.AppendTextLine(affectString, self.GetChangeTextLineColor(affectValue))
|
|
|
|
def AppendMetinWearInformation(self):
|
|
|
|
self.AppendSpace(5)
|
|
self.AppendTextLine(localeInfo.TOOLTIP_SOCKET_REFINABLE_ITEM, self.NORMAL_COLOR)
|
|
|
|
flagList = (item.IsWearableFlag(item.WEARABLE_BODY),
|
|
item.IsWearableFlag(item.WEARABLE_HEAD),
|
|
item.IsWearableFlag(item.WEARABLE_FOOTS),
|
|
item.IsWearableFlag(item.WEARABLE_WRIST),
|
|
item.IsWearableFlag(item.WEARABLE_WEAPON),
|
|
item.IsWearableFlag(item.WEARABLE_NECK),
|
|
item.IsWearableFlag(item.WEARABLE_EAR),
|
|
item.IsWearableFlag(item.WEARABLE_UNIQUE),
|
|
item.IsWearableFlag(item.WEARABLE_SHIELD),
|
|
item.IsWearableFlag(item.WEARABLE_ARROW))
|
|
|
|
wearNames = ""
|
|
for i in range(self.WEAR_COUNT):
|
|
|
|
name = self.WEAR_NAMES[i]
|
|
flag = flagList[i]
|
|
|
|
if flag:
|
|
wearNames += " "
|
|
wearNames += name
|
|
|
|
textLine = ui.TextLine()
|
|
textLine.SetParent(self)
|
|
textLine.SetFontName(self.defFontName)
|
|
textLine.SetPosition(self.toolTipWidth // 2, self.toolTipHeight)
|
|
textLine.SetHorizontalAlignCenter()
|
|
textLine.SetPackedFontColor(self.NORMAL_COLOR)
|
|
textLine.SetText(wearNames)
|
|
textLine.Show()
|
|
self.childrenList.append(textLine)
|
|
|
|
self.toolTipHeight += self.TEXT_LINE_HEIGHT
|
|
self.ResizeToolTip()
|
|
|
|
def GetMetinSocketType(self, number):
|
|
if player.METIN_SOCKET_TYPE_NONE == number:
|
|
return player.METIN_SOCKET_TYPE_NONE
|
|
elif player.METIN_SOCKET_TYPE_SILVER == number:
|
|
return player.METIN_SOCKET_TYPE_SILVER
|
|
elif player.METIN_SOCKET_TYPE_GOLD == number:
|
|
return player.METIN_SOCKET_TYPE_GOLD
|
|
else:
|
|
item.SelectItem(number)
|
|
if item.METIN_NORMAL == item.GetItemSubType():
|
|
return player.METIN_SOCKET_TYPE_SILVER
|
|
elif item.METIN_GOLD == item.GetItemSubType():
|
|
return player.METIN_SOCKET_TYPE_GOLD
|
|
elif "USE_PUT_INTO_ACCESSORY_SOCKET" == item.GetUseType(number):
|
|
return player.METIN_SOCKET_TYPE_SILVER
|
|
elif "USE_PUT_INTO_RING_SOCKET" == item.GetUseType(number):
|
|
return player.METIN_SOCKET_TYPE_SILVER
|
|
elif "USE_PUT_INTO_BELT_SOCKET" == item.GetUseType(number):
|
|
return player.METIN_SOCKET_TYPE_SILVER
|
|
|
|
return player.METIN_SOCKET_TYPE_NONE
|
|
|
|
def GetMetinItemIndex(self, number):
|
|
if player.METIN_SOCKET_TYPE_SILVER == number:
|
|
return 0
|
|
if player.METIN_SOCKET_TYPE_GOLD == number:
|
|
return 0
|
|
|
|
return number
|
|
|
|
def __AppendAccessoryMetinSlotInfo(self, metinSlot, mtrlVnum):
|
|
ACCESSORY_SOCKET_MAX_SIZE = 3
|
|
|
|
cur = min(metinSlot[0], ACCESSORY_SOCKET_MAX_SIZE)
|
|
end = min(metinSlot[1], ACCESSORY_SOCKET_MAX_SIZE)
|
|
|
|
affectType1, affectValue1 = item.GetAffect(0)
|
|
affectList1=[0, max(1, affectValue1 * 10 // 100), max(2, affectValue1 * 20 // 100), max(3, affectValue1 * 40 // 100)]
|
|
|
|
affectType2, affectValue2 = item.GetAffect(1)
|
|
affectList2 = [0, max(1, affectValue2 * 10 // 100), max(2, affectValue2 * 20 // 100), max(3, affectValue2 * 40 // 100)]
|
|
|
|
mtrlPos = 0
|
|
mtrlList = [mtrlVnum] * cur + [player.METIN_SOCKET_TYPE_SILVER] * (end-cur)
|
|
|
|
for mtrl in mtrlList:
|
|
affectString1 = self.__GetAffectString(affectType1, affectList1[mtrlPos + 1] - affectList1[mtrlPos])
|
|
affectString2 = self.__GetAffectString(affectType2, affectList2[mtrlPos + 1] - affectList2[mtrlPos])
|
|
|
|
leftTime = 0
|
|
|
|
if cur == mtrlPos + 1:
|
|
leftTime = metinSlot[2]
|
|
|
|
self.__AppendMetinSlotInfo_AppendMetinSocketData(mtrlPos, mtrl, affectString1, affectString2, leftTime)
|
|
|
|
mtrlPos += 1
|
|
|
|
def __AppendMetinSlotInfo(self, metinSlot):
|
|
if self.__AppendMetinSlotInfo_IsEmptySlotList(metinSlot):
|
|
return
|
|
|
|
for i in range(player.METIN_SOCKET_MAX_NUM):
|
|
self.__AppendMetinSlotInfo_AppendMetinSocketData(i, metinSlot[i])
|
|
|
|
def __AppendMetinSlotInfo_IsEmptySlotList(self, metinSlot):
|
|
if 0 == metinSlot:
|
|
return 1
|
|
|
|
for i in range(player.METIN_SOCKET_MAX_NUM):
|
|
metinSlotData=metinSlot[i]
|
|
if 0 != self.GetMetinSocketType(metinSlotData):
|
|
if 0 != self.GetMetinItemIndex(metinSlotData):
|
|
return 0
|
|
|
|
return 1
|
|
|
|
def __AppendMetinSlotInfo_AppendMetinSocketData(self, index, metinSlotData, custumAffectString="", custumAffectString2="", leftTime=0):
|
|
|
|
slotType = self.GetMetinSocketType(metinSlotData)
|
|
itemIndex = self.GetMetinItemIndex(metinSlotData)
|
|
|
|
if 0 == slotType:
|
|
return
|
|
|
|
self.AppendSpace(5)
|
|
|
|
slotImage = ui.ImageBox()
|
|
slotImage.SetParent(self)
|
|
slotImage.Show()
|
|
|
|
## Name
|
|
nameTextLine = ui.TextLine()
|
|
nameTextLine.SetParent(self)
|
|
nameTextLine.SetFontName(self.defFontName)
|
|
nameTextLine.SetPackedFontColor(self.NORMAL_COLOR)
|
|
nameTextLine.SetOutline()
|
|
nameTextLine.SetFeather()
|
|
nameTextLine.Show()
|
|
|
|
self.childrenList.append(nameTextLine)
|
|
|
|
if player.METIN_SOCKET_TYPE_SILVER == slotType:
|
|
slotImage.LoadImage("d:/ymir work/ui/game/windows/metin_slot_silver.sub")
|
|
elif player.METIN_SOCKET_TYPE_GOLD == slotType:
|
|
slotImage.LoadImage("d:/ymir work/ui/game/windows/metin_slot_gold.sub")
|
|
|
|
self.childrenList.append(slotImage)
|
|
|
|
if app.IsRTL():
|
|
slotImage.SetPosition(self.toolTipWidth - slotImage.GetWidth() - 9, self.toolTipHeight-1)
|
|
nameTextLine.SetPosition(self.toolTipWidth - 50, self.toolTipHeight + 2)
|
|
else:
|
|
slotImage.SetPosition(9, self.toolTipHeight-1)
|
|
nameTextLine.SetPosition(50, self.toolTipHeight + 2)
|
|
|
|
metinImage = ui.ImageBox()
|
|
metinImage.SetParent(self)
|
|
metinImage.Show()
|
|
self.childrenList.append(metinImage)
|
|
|
|
if itemIndex:
|
|
|
|
item.SelectItem(itemIndex)
|
|
|
|
## Image
|
|
try:
|
|
metinImage.LoadImage(item.GetIconImageFileName())
|
|
except:
|
|
dbg.TraceError("ItemToolTip.__AppendMetinSocketData() - Failed to find image file %d:%s" %
|
|
(itemIndex, item.GetIconImageFileName())
|
|
)
|
|
|
|
nameTextLine.SetText(item.GetItemName())
|
|
|
|
## Affect
|
|
affectTextLine = ui.TextLine()
|
|
affectTextLine.SetParent(self)
|
|
affectTextLine.SetFontName(self.defFontName)
|
|
affectTextLine.SetPackedFontColor(self.POSITIVE_COLOR)
|
|
affectTextLine.SetOutline()
|
|
affectTextLine.SetFeather()
|
|
affectTextLine.Show()
|
|
|
|
if app.IsRTL():
|
|
metinImage.SetPosition(self.toolTipWidth - metinImage.GetWidth() - 10, self.toolTipHeight)
|
|
affectTextLine.SetPosition(self.toolTipWidth - 50, self.toolTipHeight + 16 + 2)
|
|
else:
|
|
metinImage.SetPosition(10, self.toolTipHeight)
|
|
affectTextLine.SetPosition(50, self.toolTipHeight + 16 + 2)
|
|
|
|
if custumAffectString:
|
|
affectTextLine.SetText(custumAffectString)
|
|
elif itemIndex!=constInfo.ERROR_METIN_STONE:
|
|
affectType, affectValue = item.GetAffect(0)
|
|
affectString = self.__GetAffectString(affectType, affectValue)
|
|
if affectString:
|
|
affectTextLine.SetText(affectString)
|
|
else:
|
|
affectTextLine.SetText(localeInfo.TOOLTIP_APPLY_NOAFFECT)
|
|
|
|
self.childrenList.append(affectTextLine)
|
|
|
|
if custumAffectString2:
|
|
affectTextLine = ui.TextLine()
|
|
affectTextLine.SetParent(self)
|
|
affectTextLine.SetFontName(self.defFontName)
|
|
affectTextLine.SetPackedFontColor(self.POSITIVE_COLOR)
|
|
affectTextLine.SetPosition(50, self.toolTipHeight + 16 + 2 + 16 + 2)
|
|
affectTextLine.SetOutline()
|
|
affectTextLine.SetFeather()
|
|
affectTextLine.Show()
|
|
affectTextLine.SetText(custumAffectString2)
|
|
self.childrenList.append(affectTextLine)
|
|
self.toolTipHeight += 16 + 2
|
|
|
|
# MR-10: Add real-time remaining time display for accessory sockets.
|
|
if 0 != leftTime:
|
|
isEquipped = False
|
|
|
|
if self.itemWindowType == player.INVENTORY and self.itemSlotIndex >= 0:
|
|
isEquipped = player.IsEquipmentSlot(self.itemSlotIndex)
|
|
|
|
if isEquipped:
|
|
endTime = self.__GetAccessorySocketEndTime(leftTime, index)
|
|
leftSec = max(0, endTime - app.GetGlobalTimeStamp())
|
|
timeText = localeInfo.LEFT_TIME + " : " + localeInfo.RTSecondToDHMS(leftSec)
|
|
else:
|
|
endTime = None
|
|
timeText = localeInfo.LEFT_TIME + " : " + localeInfo.RTSecondToDHMS(leftTime)
|
|
# MR-10: -- END OF -- Add real-time remaining time display for accessory sockets.
|
|
|
|
timeTextLine = ui.TextLine()
|
|
timeTextLine.SetParent(self)
|
|
timeTextLine.SetFontName(self.defFontName)
|
|
timeTextLine.SetPackedFontColor(self.POSITIVE_COLOR)
|
|
timeTextLine.SetPosition(50, self.toolTipHeight + 16 + 2 + 16 + 2)
|
|
timeTextLine.SetOutline()
|
|
timeTextLine.SetFeather()
|
|
timeTextLine.Show()
|
|
timeTextLine.SetText(timeText)
|
|
self.childrenList.append(timeTextLine)
|
|
|
|
# MR-10: Add real-time remaining time display for accessory sockets.
|
|
if isEquipped and endTime is not None:
|
|
self.timeInfoList.append({"line": timeTextLine, "value": endTime, "limit": None})
|
|
# MR-10: -- END OF -- Add real-time remaining time display for accessory sockets.
|
|
|
|
self.toolTipHeight += 16 + 2
|
|
|
|
else:
|
|
nameTextLine.SetText(localeInfo.TOOLTIP_SOCKET_EMPTY)
|
|
|
|
self.toolTipHeight += 35
|
|
self.ResizeToolTip()
|
|
|
|
def __AppendFishInfo(self, size):
|
|
if size > 0:
|
|
self.AppendSpace(5)
|
|
self.AppendTextLine(localeInfo.TOOLTIP_FISH_LEN % (float(size) / 100.0), self.NORMAL_COLOR)
|
|
|
|
def AppendUniqueItemLastTime(self, restMin):
|
|
if restMin > 0:
|
|
restSecond = restMin * 60
|
|
|
|
self.AppendSpace(5)
|
|
self.AppendTextLine(localeInfo.LEFT_TIME + " : " + localeInfo.RTSecondToDHMS(restSecond), self.NORMAL_COLOR)
|
|
|
|
def AppendMallItemLastTime(self, endTime, getLimit):
|
|
if endTime > 0:
|
|
self.AppendSpace(5)
|
|
self.AppendTextLineTime(endTime, getLimit)
|
|
|
|
def AppendTextLineTime(self, endTime, getLimit, color = FONT_COLOR):
|
|
leftSec = max(0, endTime - app.GetGlobalTimeStamp())
|
|
|
|
timeTextLine = ui.TextLine()
|
|
timeTextLine.SetParent(self)
|
|
timeTextLine.SetFontName(self.defFontName)
|
|
timeTextLine.SetPackedFontColor(color)
|
|
|
|
if not self.isShopItem:
|
|
timeTextLine.SetText(localeInfo.LEFT_TIME + ": " + localeInfo.RTSecondToDHMS(leftSec))
|
|
|
|
timeTextLine.SetOutline()
|
|
timeTextLine.SetFeather(False)
|
|
timeTextLine.SetPosition(self.toolTipWidth // 2, self.toolTipHeight)
|
|
timeTextLine.SetHorizontalAlignCenter()
|
|
timeTextLine.Show()
|
|
|
|
self.timeInfoList.append({"line": timeTextLine, "value": endTime, "limit": getLimit})
|
|
|
|
self.toolTipHeight += self.TEXT_LINE_HEIGHT
|
|
self.ResizeToolTip()
|
|
|
|
return timeTextLine
|
|
|
|
def AppendTimerBasedOnWearLastTime(self, metinSlot, getLimit):
|
|
remainSec = metinSlot[0]
|
|
|
|
if remainSec <= 0:
|
|
self.AppendSpace(5)
|
|
self.AppendTextLine(localeInfo.CANNOT_USE, self.DISABLE_COLOR)
|
|
|
|
return
|
|
|
|
isTimerActive = self.__IsTimerBasedOnWearActive()
|
|
|
|
if not isTimerActive:
|
|
self.AppendSpace(5)
|
|
self.AppendTextLine(localeInfo.LEFT_TIME + ": " + localeInfo.RTSecondToDHMS(remainSec), self.NORMAL_COLOR)
|
|
|
|
return
|
|
|
|
endTime = self.__GetOrCreateCachedEndTime(remainSec)
|
|
|
|
self.AppendMallItemLastTime(endTime, getLimit)
|
|
|
|
def __IsTimerBasedOnWearActive(self):
|
|
item.SelectItem(self.itemVnum)
|
|
|
|
if item.GetItemType() == item.ITEM_TYPE_DS:
|
|
isEquippedOnDeck = (self.itemWindowType == player.INVENTORY)
|
|
isDeckActivated = self.wndDragonSoul and self.wndDragonSoul.isActivated
|
|
return isEquippedOnDeck and isDeckActivated
|
|
|
|
return True
|
|
|
|
def __GetOrCreateCachedEndTime(self, remainSec):
|
|
key = (self.itemVnum, self.itemSlotIndex)
|
|
cache = self.dsActivatedTimeCache.get(key)
|
|
|
|
if cache and cache["remainSec"] == remainSec:
|
|
return cache["endTime"]
|
|
|
|
now = app.GetGlobalTimeStamp()
|
|
endTime = now + remainSec
|
|
self.dsActivatedTimeCache[key] = {"remainSec": remainSec, "endTime": endTime}
|
|
return endTime
|
|
|
|
# MR-10: Add real-time remaining time display for accessory sockets.
|
|
def __GetAccessorySocketEndTime(self, remainSec, socketIndex):
|
|
key = (self.itemWindowType, self.itemSlotIndex, socketIndex, self.itemVnum)
|
|
cache = self.accessorySocketTimeCache.get(key)
|
|
|
|
now = app.GetGlobalTimeStamp()
|
|
|
|
if cache:
|
|
cachedEnd = cache.get("endTime", 0)
|
|
cachedRemain = cache.get("remainSec", remainSec)
|
|
|
|
if cachedEnd > now and remainSec >= cachedRemain:
|
|
return cachedEnd
|
|
|
|
endTime = now + remainSec
|
|
self.accessorySocketTimeCache[key] = {"remainSec": remainSec, "endTime": endTime}
|
|
|
|
return endTime
|
|
# MR-10: -- END OF -- Add real-time remaining time display for accessory sockets.
|
|
|
|
def AppendRealTimeStartFirstUseLastTime(self, item, metinSlot, limitIndex, getLimit):
|
|
useCount = metinSlot[1]
|
|
endTime = metinSlot[0]
|
|
|
|
# If it has been used even once, Socket0 will have an end time (such as 13:01 on March 1, 2012).
|
|
# If it has not been used, Socket0 may have an available time (such as 600, in seconds). If it is 0, the available time in the Limit Value is used.
|
|
if 0 == useCount:
|
|
if 0 == endTime:
|
|
(limitType, limitValue) = item.GetLimit(limitIndex)
|
|
endTime = limitValue
|
|
|
|
self.AppendUniqueItemLastTime(endTime // 60)
|
|
|
|
return
|
|
|
|
endTime += app.GetGlobalTimeStamp()
|
|
|
|
self.AppendMallItemLastTime(endTime, getLimit)
|
|
|
|
class HyperlinkItemToolTip(ItemToolTip):
|
|
def __init__(self):
|
|
ItemToolTip.__init__(self, isPickable=True)
|
|
|
|
def SetHyperlinkItem(self, tokens):
|
|
minTokenCount = 3 + player.METIN_SOCKET_MAX_NUM
|
|
maxTokenCount = minTokenCount + 2 * player.ATTRIBUTE_SLOT_MAX_NUM
|
|
if tokens and len(tokens) >= minTokenCount and len(tokens) <= maxTokenCount:
|
|
head, vnum, flag = tokens[:3]
|
|
itemVnum = int(vnum, 16)
|
|
metinSlot = [int(metin, 16) for metin in tokens[3:6]]
|
|
|
|
rests = tokens[6:]
|
|
if rests:
|
|
attrSlot = []
|
|
|
|
rests.reverse()
|
|
while rests:
|
|
key = int(rests.pop(), 16)
|
|
if rests:
|
|
val = int(rests.pop())
|
|
attrSlot.append((key, val))
|
|
|
|
attrSlot += [(0, 0)] * (player.ATTRIBUTE_SLOT_MAX_NUM - len(attrSlot))
|
|
else:
|
|
attrSlot = [(0, 0)] * player.ATTRIBUTE_SLOT_MAX_NUM
|
|
|
|
self.ClearToolTip()
|
|
self.AddItemData(itemVnum, metinSlot, attrSlot)
|
|
|
|
ItemToolTip.OnUpdate(self)
|
|
|
|
def OnUpdate(self):
|
|
pass
|
|
|
|
def OnMouseLeftButtonDown(self):
|
|
self.Hide()
|
|
|
|
class SkillToolTip(ToolTip):
|
|
|
|
POINT_NAME_DICT = {
|
|
player.LEVEL : localeInfo.SKILL_TOOLTIP_LEVEL,
|
|
player.IQ : localeInfo.SKILL_TOOLTIP_INT,
|
|
}
|
|
|
|
SKILL_TOOL_TIP_WIDTH = 200
|
|
PARTY_SKILL_TOOL_TIP_WIDTH = 340
|
|
|
|
PARTY_SKILL_EXPERIENCE_AFFECT_LIST = ( ( 2, 2, 10,),
|
|
( 8, 3, 20,),
|
|
(14, 4, 30,),
|
|
(22, 5, 45,),
|
|
(28, 6, 60,),
|
|
(34, 7, 80,),
|
|
(38, 8, 100,), )
|
|
|
|
PARTY_SKILL_PLUS_GRADE_AFFECT_LIST = ( ( 4, 2, 1, 0,),
|
|
(10, 3, 2, 0,),
|
|
(16, 4, 2, 1,),
|
|
(24, 5, 2, 2,), )
|
|
|
|
PARTY_SKILL_ATTACKER_AFFECT_LIST = ( ( 36, 3, ),
|
|
( 26, 1, ),
|
|
( 32, 2, ), )
|
|
|
|
SKILL_GRADE_NAME = { player.SKILL_GRADE_MASTER : localeInfo.SKILL_GRADE_NAME_MASTER,
|
|
player.SKILL_GRADE_GRAND_MASTER : localeInfo.SKILL_GRADE_NAME_GRAND_MASTER,
|
|
player.SKILL_GRADE_PERFECT_MASTER : localeInfo.SKILL_GRADE_NAME_PERFECT_MASTER, }
|
|
|
|
AFFECT_NAME_DICT = {
|
|
"HP" : localeInfo.TOOLTIP_SKILL_AFFECT_ATT_POWER,
|
|
"ATT_GRADE" : localeInfo.TOOLTIP_SKILL_AFFECT_ATT_GRADE,
|
|
"DEF_GRADE" : localeInfo.TOOLTIP_SKILL_AFFECT_DEF_GRADE,
|
|
"ATT_SPEED" : localeInfo.TOOLTIP_SKILL_AFFECT_ATT_SPEED,
|
|
"MOV_SPEED" : localeInfo.TOOLTIP_SKILL_AFFECT_MOV_SPEED,
|
|
"DODGE" : localeInfo.TOOLTIP_SKILL_AFFECT_DODGE,
|
|
"RESIST_NORMAL" : localeInfo.TOOLTIP_SKILL_AFFECT_RESIST_NORMAL,
|
|
"REFLECT_MELEE" : localeInfo.TOOLTIP_SKILL_AFFECT_REFLECT_MELEE,
|
|
}
|
|
AFFECT_APPEND_TEXT_DICT = {
|
|
"DODGE" : "%",
|
|
"RESIST_NORMAL" : "%",
|
|
"REFLECT_MELEE" : "%",
|
|
}
|
|
|
|
def __init__(self):
|
|
ToolTip.__init__(self, self.SKILL_TOOL_TIP_WIDTH)
|
|
def __del__(self):
|
|
ToolTip.__del__(self)
|
|
|
|
def SetSkill(self, skillIndex, skillLevel = -1):
|
|
|
|
if 0 == skillIndex:
|
|
return
|
|
|
|
if skill.SKILL_TYPE_GUILD == skill.GetSkillType(skillIndex):
|
|
|
|
if self.SKILL_TOOL_TIP_WIDTH != self.toolTipWidth:
|
|
self.toolTipWidth = self.SKILL_TOOL_TIP_WIDTH
|
|
self.ResizeToolTip()
|
|
|
|
self.AppendDefaultData(skillIndex)
|
|
self.AppendSkillConditionData(skillIndex)
|
|
self.AppendGuildSkillData(skillIndex, skillLevel)
|
|
|
|
else:
|
|
|
|
if self.SKILL_TOOL_TIP_WIDTH != self.toolTipWidth:
|
|
self.toolTipWidth = self.SKILL_TOOL_TIP_WIDTH
|
|
self.ResizeToolTip()
|
|
|
|
slotIndex = player.GetSkillSlotIndex(skillIndex)
|
|
skillGrade = player.GetSkillGrade(slotIndex)
|
|
skillLevel = player.GetSkillLevel(slotIndex)
|
|
skillCurrentPercentage = player.GetSkillCurrentEfficientPercentage(slotIndex)
|
|
skillNextPercentage = player.GetSkillNextEfficientPercentage(slotIndex)
|
|
|
|
self.AppendDefaultData(skillIndex)
|
|
self.AppendSkillConditionData(skillIndex)
|
|
self.AppendSkillDataNew(slotIndex, skillIndex, skillGrade, skillLevel, skillCurrentPercentage, skillNextPercentage)
|
|
self.AppendSkillRequirement(skillIndex, skillLevel)
|
|
|
|
self.ShowToolTip()
|
|
|
|
def SetSkillNew(self, slotIndex, skillIndex, skillGrade, skillLevel):
|
|
|
|
if 0 == skillIndex:
|
|
return
|
|
|
|
if player.SKILL_INDEX_TONGSOL == skillIndex:
|
|
|
|
slotIndex = player.GetSkillSlotIndex(skillIndex)
|
|
skillLevel = player.GetSkillLevel(slotIndex)
|
|
|
|
self.AppendDefaultData(skillIndex)
|
|
self.AppendPartySkillData(skillGrade, skillLevel)
|
|
|
|
elif player.SKILL_INDEX_RIDING == skillIndex:
|
|
|
|
slotIndex = player.GetSkillSlotIndex(skillIndex)
|
|
self.AppendSupportSkillDefaultData(skillIndex, skillGrade, skillLevel, 30)
|
|
|
|
elif player.SKILL_INDEX_SUMMON == skillIndex:
|
|
|
|
maxLevel = 10
|
|
|
|
self.ClearToolTip()
|
|
self.__SetSkillTitle(skillIndex, skillGrade)
|
|
|
|
## Description
|
|
description = skill.GetSkillDescription(skillIndex)
|
|
self.AppendDescription(description)
|
|
|
|
if skillLevel == 10:
|
|
self.AppendSpace(5)
|
|
self.AppendTextLine(localeInfo.TOOLTIP_SKILL_LEVEL_MASTER % (skillLevel), self.NORMAL_COLOR)
|
|
self.AppendTextLine(localeInfo.SKILL_SUMMON_DESCRIPTION % (skillLevel*10), self.NORMAL_COLOR)
|
|
|
|
else:
|
|
self.AppendSpace(5)
|
|
self.AppendTextLine(localeInfo.TOOLTIP_SKILL_LEVEL % (skillLevel), self.NORMAL_COLOR)
|
|
self.__AppendSummonDescription(skillLevel, self.NORMAL_COLOR)
|
|
|
|
self.AppendSpace(5)
|
|
self.AppendTextLine(localeInfo.TOOLTIP_SKILL_LEVEL % (skillLevel+1), self.NEGATIVE_COLOR)
|
|
self.__AppendSummonDescription(skillLevel+1, self.NEGATIVE_COLOR)
|
|
|
|
elif skill.SKILL_TYPE_GUILD == skill.GetSkillType(skillIndex):
|
|
|
|
if self.SKILL_TOOL_TIP_WIDTH != self.toolTipWidth:
|
|
self.toolTipWidth = self.SKILL_TOOL_TIP_WIDTH
|
|
self.ResizeToolTip()
|
|
|
|
self.AppendDefaultData(skillIndex)
|
|
self.AppendSkillConditionData(skillIndex)
|
|
self.AppendGuildSkillData(skillIndex, skillLevel)
|
|
|
|
else:
|
|
|
|
if self.SKILL_TOOL_TIP_WIDTH != self.toolTipWidth:
|
|
self.toolTipWidth = self.SKILL_TOOL_TIP_WIDTH
|
|
self.ResizeToolTip()
|
|
|
|
slotIndex = player.GetSkillSlotIndex(skillIndex)
|
|
|
|
skillCurrentPercentage = player.GetSkillCurrentEfficientPercentage(slotIndex)
|
|
skillNextPercentage = player.GetSkillNextEfficientPercentage(slotIndex)
|
|
|
|
self.AppendDefaultData(skillIndex, skillGrade)
|
|
self.AppendSkillConditionData(skillIndex)
|
|
self.AppendSkillDataNew(slotIndex, skillIndex, skillGrade, skillLevel, skillCurrentPercentage, skillNextPercentage)
|
|
self.AppendSkillRequirement(skillIndex, skillLevel)
|
|
|
|
self.ShowToolTip()
|
|
|
|
def __SetSkillTitle(self, skillIndex, skillGrade):
|
|
self.SetTitle(skill.GetSkillName(skillIndex, skillGrade))
|
|
self.__AppendSkillGradeName(skillIndex, skillGrade)
|
|
|
|
def __AppendSkillGradeName(self, skillIndex, skillGrade):
|
|
if skillGrade in self.SKILL_GRADE_NAME:
|
|
self.AppendSpace(5)
|
|
self.AppendTextLine(self.SKILL_GRADE_NAME[skillGrade] % (skill.GetSkillName(skillIndex, 0)), self.CAN_LEVEL_UP_COLOR)
|
|
|
|
def SetSkillOnlyName(self, slotIndex, skillIndex, skillGrade):
|
|
if 0 == skillIndex:
|
|
return
|
|
|
|
slotIndex = player.GetSkillSlotIndex(skillIndex)
|
|
|
|
self.toolTipWidth = self.SKILL_TOOL_TIP_WIDTH
|
|
self.ResizeToolTip()
|
|
|
|
self.ClearToolTip()
|
|
self.__SetSkillTitle(skillIndex, skillGrade)
|
|
self.AppendDefaultData(skillIndex, skillGrade)
|
|
self.AppendSkillConditionData(skillIndex)
|
|
self.ShowToolTip()
|
|
|
|
def AppendDefaultData(self, skillIndex, skillGrade = 0):
|
|
self.ClearToolTip()
|
|
self.__SetSkillTitle(skillIndex, skillGrade)
|
|
|
|
## Level Limit
|
|
levelLimit = skill.GetSkillLevelLimit(skillIndex)
|
|
if levelLimit > 0:
|
|
|
|
color = self.NORMAL_COLOR
|
|
if player.GetStatus(player.LEVEL) < levelLimit:
|
|
color = self.NEGATIVE_COLOR
|
|
|
|
self.AppendSpace(5)
|
|
self.AppendTextLine(localeInfo.TOOLTIP_ITEM_LIMIT_LEVEL % (levelLimit), color)
|
|
|
|
## Description
|
|
description = skill.GetSkillDescription(skillIndex)
|
|
self.AppendDescription(description)
|
|
|
|
def AppendSupportSkillDefaultData(self, skillIndex, skillGrade, skillLevel, maxLevel):
|
|
self.ClearToolTip()
|
|
self.__SetSkillTitle(skillIndex, skillGrade)
|
|
|
|
## Description
|
|
description = skill.GetSkillDescription(skillIndex)
|
|
self.AppendDescription(description)
|
|
|
|
if 1 == skillGrade:
|
|
skillLevel += 19
|
|
elif 2 == skillGrade:
|
|
skillLevel += 29
|
|
elif 3 == skillGrade:
|
|
skillLevel = 40
|
|
|
|
self.AppendSpace(5)
|
|
self.AppendTextLine(localeInfo.TOOLTIP_SKILL_LEVEL_WITH_MAX % (skillLevel, maxLevel), self.NORMAL_COLOR)
|
|
|
|
def AppendSkillConditionData(self, skillIndex):
|
|
conditionDataCount = skill.GetSkillConditionDescriptionCount(skillIndex)
|
|
if conditionDataCount > 0:
|
|
self.AppendSpace(5)
|
|
|
|
for i in range(conditionDataCount):
|
|
self.AppendTextLine(skill.GetSkillConditionDescription(skillIndex, i), self.CONDITION_COLOR)
|
|
|
|
def AppendGuildSkillData(self, skillIndex, skillLevel):
|
|
skillMaxLevel = 7
|
|
skillCurrentPercentage = float(skillLevel) / float(skillMaxLevel)
|
|
skillNextPercentage = float(skillLevel + 1) / float(skillMaxLevel)
|
|
|
|
## Current Level
|
|
if skillLevel > 0:
|
|
if self.HasSkillLevelDescription(skillIndex, skillLevel):
|
|
self.AppendSpace(5)
|
|
|
|
if skillLevel == skillMaxLevel:
|
|
self.AppendTextLine(localeInfo.TOOLTIP_SKILL_LEVEL_MASTER % (skillLevel), self.NORMAL_COLOR)
|
|
else:
|
|
self.AppendTextLine(localeInfo.TOOLTIP_SKILL_LEVEL % (skillLevel), self.NORMAL_COLOR)
|
|
|
|
#####
|
|
|
|
for i in range(skill.GetSkillAffectDescriptionCount(skillIndex)):
|
|
self.AppendTextLine(skill.GetSkillAffectDescription(skillIndex, i, skillCurrentPercentage), self.ENABLE_COLOR)
|
|
|
|
## Cooltime
|
|
coolTime = skill.GetSkillCoolTime(skillIndex, skillCurrentPercentage)
|
|
|
|
if coolTime > 0:
|
|
self.AppendTextLine(localeInfo.TOOLTIP_SKILL_COOL_TIME + str(coolTime), self.ENABLE_COLOR)
|
|
|
|
## SP
|
|
needGSP = skill.GetSkillNeedSP(skillIndex, skillCurrentPercentage)
|
|
if needGSP > 0:
|
|
self.AppendTextLine(localeInfo.TOOLTIP_NEED_GSP % (needGSP), self.ENABLE_COLOR)
|
|
|
|
## Next Level
|
|
if skillLevel < skillMaxLevel:
|
|
if self.HasSkillLevelDescription(skillIndex, skillLevel+1):
|
|
self.AppendSpace(5)
|
|
self.AppendTextLine(localeInfo.TOOLTIP_NEXT_SKILL_LEVEL_1 % (skillLevel+1, skillMaxLevel), self.DISABLE_COLOR)
|
|
|
|
#####
|
|
|
|
for i in range(skill.GetSkillAffectDescriptionCount(skillIndex)):
|
|
self.AppendTextLine(skill.GetSkillAffectDescription(skillIndex, i, skillNextPercentage), self.DISABLE_COLOR)
|
|
|
|
## Cooltime
|
|
coolTime = skill.GetSkillCoolTime(skillIndex, skillNextPercentage)
|
|
if coolTime > 0:
|
|
self.AppendTextLine(localeInfo.TOOLTIP_SKILL_COOL_TIME + str(coolTime), self.DISABLE_COLOR)
|
|
|
|
## SP
|
|
needGSP = skill.GetSkillNeedSP(skillIndex, skillNextPercentage)
|
|
if needGSP > 0:
|
|
self.AppendTextLine(localeInfo.TOOLTIP_NEED_GSP % (needGSP), self.DISABLE_COLOR)
|
|
|
|
def AppendSkillDataNew(self, slotIndex, skillIndex, skillGrade, skillLevel, skillCurrentPercentage, skillNextPercentage):
|
|
|
|
self.skillMaxLevelStartDict = { 0 : 17, 1 : 7, 2 : 10, }
|
|
self.skillMaxLevelEndDict = { 0 : 20, 1 : 10, 2 : 10, }
|
|
|
|
skillLevelUpPoint = 1
|
|
realSkillGrade = player.GetSkillGrade(slotIndex)
|
|
skillMaxLevelStart = self.skillMaxLevelStartDict.get(realSkillGrade, 15)
|
|
skillMaxLevelEnd = self.skillMaxLevelEndDict.get(realSkillGrade, 20)
|
|
|
|
## Current Level
|
|
if skillLevel > 0:
|
|
if self.HasSkillLevelDescription(skillIndex, skillLevel):
|
|
self.AppendSpace(5)
|
|
if skillGrade == skill.SKILL_GRADE_COUNT:
|
|
pass
|
|
elif skillLevel == skillMaxLevelEnd:
|
|
self.AppendTextLine(localeInfo.TOOLTIP_SKILL_LEVEL_MASTER % (skillLevel), self.NORMAL_COLOR)
|
|
else:
|
|
self.AppendTextLine(localeInfo.TOOLTIP_SKILL_LEVEL % (skillLevel), self.NORMAL_COLOR)
|
|
self.AppendSkillLevelDescriptionNew(skillIndex, skillCurrentPercentage, self.ENABLE_COLOR)
|
|
|
|
## Next Level
|
|
if skillGrade != skill.SKILL_GRADE_COUNT:
|
|
if skillLevel < skillMaxLevelEnd:
|
|
if self.HasSkillLevelDescription(skillIndex, skillLevel+skillLevelUpPoint):
|
|
self.AppendSpace(5)
|
|
## In case of HP reinforcement, penetration evasion auxiliary skills
|
|
if skillIndex == 141 or skillIndex == 142:
|
|
self.AppendTextLine(localeInfo.TOOLTIP_NEXT_SKILL_LEVEL_3 % (skillLevel+1), self.DISABLE_COLOR)
|
|
else:
|
|
self.AppendTextLine(localeInfo.TOOLTIP_NEXT_SKILL_LEVEL_1 % (skillLevel+1, skillMaxLevelEnd), self.DISABLE_COLOR)
|
|
self.AppendSkillLevelDescriptionNew(skillIndex, skillNextPercentage, self.DISABLE_COLOR)
|
|
|
|
def AppendSkillLevelDescriptionNew(self, skillIndex, skillPercentage, color):
|
|
|
|
affectDataCount = skill.GetNewAffectDataCount(skillIndex)
|
|
if affectDataCount > 0:
|
|
for i in range(affectDataCount):
|
|
type, minValue, maxValue = skill.GetNewAffectData(skillIndex, i, skillPercentage)
|
|
|
|
if type not in self.AFFECT_NAME_DICT:
|
|
continue
|
|
|
|
minValue = int(minValue)
|
|
maxValue = int(maxValue)
|
|
affectText = self.AFFECT_NAME_DICT[type]
|
|
|
|
if "HP" == type:
|
|
if minValue < 0 and maxValue < 0:
|
|
minValue *= -1
|
|
maxValue *= -1
|
|
|
|
else:
|
|
affectText = localeInfo.TOOLTIP_SKILL_AFFECT_HEAL
|
|
|
|
affectText += str(minValue)
|
|
if minValue != maxValue:
|
|
affectText += " - " + str(maxValue)
|
|
affectText += self.AFFECT_APPEND_TEXT_DICT.get(type, "")
|
|
|
|
#import debugInfo
|
|
#if debugInfo.IsDebugMode():
|
|
# affectText = "!!" + affectText
|
|
|
|
self.AppendTextLine(affectText, color)
|
|
|
|
else:
|
|
for i in range(skill.GetSkillAffectDescriptionCount(skillIndex)):
|
|
self.AppendTextLine(skill.GetSkillAffectDescription(skillIndex, i, skillPercentage), color)
|
|
|
|
|
|
## Duration
|
|
duration = skill.GetDuration(skillIndex, skillPercentage)
|
|
if duration > 0:
|
|
self.AppendTextLine(localeInfo.TOOLTIP_SKILL_DURATION % (duration), color)
|
|
|
|
## Cooltime
|
|
coolTime = skill.GetSkillCoolTime(skillIndex, skillPercentage)
|
|
if coolTime > 0:
|
|
self.AppendTextLine(localeInfo.TOOLTIP_SKILL_COOL_TIME + str(coolTime), color)
|
|
|
|
## SP
|
|
needSP = skill.GetSkillNeedSP(skillIndex, skillPercentage)
|
|
if needSP != 0:
|
|
continuationSP = skill.GetSkillContinuationSP(skillIndex, skillPercentage)
|
|
|
|
if skill.IsUseHPSkill(skillIndex):
|
|
self.AppendNeedHP(needSP, continuationSP, color)
|
|
else:
|
|
self.AppendNeedSP(needSP, continuationSP, color)
|
|
|
|
def AppendSkillRequirement(self, skillIndex, skillLevel):
|
|
|
|
skillMaxLevel = skill.GetSkillMaxLevel(skillIndex)
|
|
|
|
if skillLevel >= skillMaxLevel:
|
|
return
|
|
|
|
isAppendHorizontalLine = False
|
|
|
|
## Requirement
|
|
if skill.IsSkillRequirement(skillIndex):
|
|
|
|
if not isAppendHorizontalLine:
|
|
isAppendHorizontalLine = True
|
|
self.AppendHorizontalLine()
|
|
|
|
requireSkillName, requireSkillLevel = skill.GetSkillRequirementData(skillIndex)
|
|
|
|
color = self.CANNOT_LEVEL_UP_COLOR
|
|
if skill.CheckRequirementSueccess(skillIndex):
|
|
color = self.CAN_LEVEL_UP_COLOR
|
|
self.AppendTextLine(localeInfo.TOOLTIP_REQUIREMENT_SKILL_LEVEL % (requireSkillName, requireSkillLevel), color)
|
|
|
|
## Require Stat
|
|
requireStatCount = skill.GetSkillRequireStatCount(skillIndex)
|
|
if requireStatCount > 0:
|
|
|
|
for i in range(requireStatCount):
|
|
type, level = skill.GetSkillRequireStatData(skillIndex, i)
|
|
if type in self.POINT_NAME_DICT:
|
|
|
|
if not isAppendHorizontalLine:
|
|
isAppendHorizontalLine = True
|
|
self.AppendHorizontalLine()
|
|
|
|
name = self.POINT_NAME_DICT[type]
|
|
color = self.CANNOT_LEVEL_UP_COLOR
|
|
if player.GetStatus(type) >= level:
|
|
color = self.CAN_LEVEL_UP_COLOR
|
|
self.AppendTextLine(localeInfo.TOOLTIP_REQUIREMENT_STAT_LEVEL % (name, level), color)
|
|
|
|
def HasSkillLevelDescription(self, skillIndex, skillLevel):
|
|
if skill.GetSkillAffectDescriptionCount(skillIndex) > 0:
|
|
return True
|
|
if skill.GetSkillCoolTime(skillIndex, skillLevel) > 0:
|
|
return True
|
|
if skill.GetSkillNeedSP(skillIndex, skillLevel) > 0:
|
|
return True
|
|
|
|
return False
|
|
|
|
def AppendMasterAffectDescription(self, index, desc, color):
|
|
self.AppendTextLine(desc, color)
|
|
|
|
def AppendNextAffectDescription(self, index, desc):
|
|
self.AppendTextLine(desc, self.DISABLE_COLOR)
|
|
|
|
def AppendNeedHP(self, needSP, continuationSP, color):
|
|
|
|
self.AppendTextLine(localeInfo.TOOLTIP_NEED_HP % (needSP), color)
|
|
|
|
if continuationSP > 0:
|
|
self.AppendTextLine(localeInfo.TOOLTIP_NEED_HP_PER_SEC % (continuationSP), color)
|
|
|
|
def AppendNeedSP(self, needSP, continuationSP, color):
|
|
|
|
if -1 == needSP:
|
|
self.AppendTextLine(localeInfo.TOOLTIP_NEED_ALL_SP, color)
|
|
|
|
else:
|
|
self.AppendTextLine(localeInfo.TOOLTIP_NEED_SP % (needSP), color)
|
|
|
|
if continuationSP > 0:
|
|
self.AppendTextLine(localeInfo.TOOLTIP_NEED_SP_PER_SEC % (continuationSP), color)
|
|
|
|
def AppendPartySkillData(self, skillGrade, skillLevel):
|
|
|
|
if 1 == skillGrade:
|
|
skillLevel += 19
|
|
elif 2 == skillGrade:
|
|
skillLevel += 29
|
|
elif 3 == skillGrade:
|
|
skillLevel = 40
|
|
|
|
if skillLevel <= 0:
|
|
return
|
|
|
|
skillIndex = player.SKILL_INDEX_TONGSOL
|
|
slotIndex = player.GetSkillSlotIndex(skillIndex)
|
|
skillPower = player.GetSkillCurrentEfficientPercentage(slotIndex)
|
|
k = player.GetSkillLevel(skillIndex) / 100.0
|
|
|
|
self.AppendSpace(5)
|
|
self.AutoAppendTextLine(localeInfo.TOOLTIP_PARTY_SKILL_LEVEL % skillLevel, self.NORMAL_COLOR)
|
|
|
|
if skillLevel >= 10:
|
|
self.AutoAppendTextLine(localeInfo.PARTY_SKILL_ATTACKER % chop( 10 + 60 * k ))
|
|
|
|
if skillLevel >= 20:
|
|
self.AutoAppendTextLine(localeInfo.PARTY_SKILL_BERSERKER % chop(1 + 5 * k))
|
|
self.AutoAppendTextLine(localeInfo.PARTY_SKILL_TANKER % chop(50 + 1450 * k))
|
|
|
|
if skillLevel >= 25:
|
|
self.AutoAppendTextLine(localeInfo.PARTY_SKILL_BUFFER % chop(5 + 45 * k ))
|
|
|
|
if skillLevel >= 35:
|
|
self.AutoAppendTextLine(localeInfo.PARTY_SKILL_SKILL_MASTER % chop(25 + 600 * k ))
|
|
|
|
if skillLevel >= 40:
|
|
self.AutoAppendTextLine(localeInfo.PARTY_SKILL_DEFENDER % chop( 5 + 30 * k ))
|
|
|
|
self.AlignHorizonalCenter()
|
|
|
|
def __AppendSummonDescription(self, skillLevel, color):
|
|
if skillLevel > 1:
|
|
self.AppendTextLine(localeInfo.SKILL_SUMMON_DESCRIPTION % (skillLevel * 10), color)
|
|
elif 1 == skillLevel:
|
|
self.AppendTextLine(localeInfo.SKILL_SUMMON_DESCRIPTION % (15), color)
|
|
elif 0 == skillLevel:
|
|
self.AppendTextLine(localeInfo.SKILL_SUMMON_DESCRIPTION % (10), color)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
import app
|
|
import wndMgr
|
|
import systemSetting
|
|
import mouseModule
|
|
import grp
|
|
import ui
|
|
|
|
#wndMgr.SetOutlineFlag(True)
|
|
|
|
app.SetMouseHandler(mouseModule.mouseController)
|
|
app.SetHairColorEnable(True)
|
|
wndMgr.SetMouseHandler(mouseModule.mouseController)
|
|
wndMgr.SetScreenSize(systemSetting.GetWidth(), systemSetting.GetHeight())
|
|
app.Create("METIN2 CLOSED BETA", systemSetting.GetWidth(), systemSetting.GetHeight(), 1)
|
|
mouseModule.mouseController.Create()
|
|
|
|
toolTip = ItemToolTip()
|
|
toolTip.ClearToolTip()
|
|
#toolTip.AppendTextLine("Test")
|
|
desc = "Item descriptions:|increase of width of display to 35 digits per row AND installation of function that the displayed words are not broken up in two parts, but instead if one word is too long to be displayed in this row, this word will start in the next row."
|
|
summ = ""
|
|
|
|
toolTip.AddItemData_Offline(10, desc, summ, 0, 0)
|
|
toolTip.Show()
|
|
|
|
app.Loop()
|