feat: add MeshPort overlay networking, item actions window, and AVA2 client enhancements
- add MeshPort peer-to-peer overlay networking SDK, C++ integration, and Python bindings - add item actions quick use/split/delete/lock overlay window (mt_item_actions) - add shop name range and NPC name visibility settings to system display options - support battlepass ticket activation and month validation in mt_battlepass - support boss tracking teleport destination button in mt_bosses - support asynchronous account registration cancellation and pending login cancellation - update AVA2 item conversion for attr lock scrolls and battlepass tickets - update .gitignore for local build outputs and caches
This commit is contained in:
@@ -11,6 +11,7 @@ import grp
|
||||
import item
|
||||
import net
|
||||
import nonplayer
|
||||
import player
|
||||
import ui
|
||||
import weakref
|
||||
from mt_biolog import Action, Text, L
|
||||
@@ -29,7 +30,8 @@ TYPES={1:('击杀怪物','击杀 ','mob'),2:('击杀 Boss','击杀 Boss ','mob')
|
||||
9:(None,'向 NPC 出售 ','item')}
|
||||
ERRORS={'loading':'数据加载中,请稍后再试','slot':'没有这个任务','claimed':'奖励已经领取过了','incomplete':'任务尚未完成',
|
||||
'space':'背包空间不足,请整理后再领取','config':'奖励配置有误,请联系管理员','db':'服务器繁忙,请稍后再试',
|
||||
'rate':'操作过快,请稍后再试','invalid':'参数无效'}
|
||||
'rate':'操作过快,请稍后再试','invalid':'参数无效','ticket':'请使用当月战令票激活','month':'这张战令票不属于当前月份',
|
||||
'activated':'本月战令已经激活过了','busy':'请先结束交易、商店、仓库或传送'}
|
||||
|
||||
|
||||
def Number(text,low=0,high=10**12):
|
||||
@@ -86,7 +88,7 @@ class Pass(object):
|
||||
self.Clear()
|
||||
|
||||
def Clear(self):
|
||||
self.season=None;self.missions={};self.final=None;self.reading=None;self.none=False;self.error=None;self.claiming=None
|
||||
self.season=None;self.missions={};self.final=None;self.reading=None;self.none=False;self.error=None;self.claiming=None;self.access=None;self.month=None
|
||||
|
||||
def Ready(self):
|
||||
return self.waiting is None or self.now()>=self.waiting
|
||||
@@ -104,10 +106,15 @@ class Pass(object):
|
||||
return self.Post('/mt_bp 1 info')
|
||||
|
||||
def Claim(self,slot):
|
||||
if self.claiming is not None or not self.season:return False
|
||||
if self.claiming is not None or not self.season or self.access not in (None,1):return False
|
||||
if self.Post('/mt_bp 1 claim %d'%slot):self.claiming=slot;self.error=None;return True
|
||||
return False
|
||||
|
||||
def Activate(self,cell,vnum):
|
||||
if self.access!=0 or self.waiting is not None or not 25150<=vnum<=25161:return False
|
||||
if player.GetItemIndex(cell)!=vnum:return False
|
||||
return self.Post('/mt_bp 1 activate %d %d'%(cell,vnum))
|
||||
|
||||
def Close(self):
|
||||
self.send('/mt_bp 1 close')
|
||||
|
||||
@@ -135,7 +142,10 @@ class Pass(object):
|
||||
def Parse(self,kind,args):
|
||||
if kind=='season' and len(args)==5:
|
||||
seasonId,start,end,now=[Number(w,0,2**32-1) for w in args[:4]];count=Number(args[4],1,MAX_SLOT)
|
||||
self.reading=dict(season=(seasonId,start,end,now,self.now()),count=count,missions={},final=None)
|
||||
self.reading=dict(season=(seasonId,start,end,now,self.now()),count=count,missions={},final=None,access=None,month=None)
|
||||
elif kind=='access' and len(args) in (1,2) and self.reading is not None:
|
||||
self.reading['access']=Number(args[0],0,2)
|
||||
if len(args)==2:self.reading['month']=Number(args[1],1,12)
|
||||
elif kind=='mission' and self.reading is not None and len(args)>=6:
|
||||
slot=Number(args[0],1,MAX_SLOT);kind=Number(args[1],1,9)
|
||||
self.reading['missions'][slot]=dict(slot=slot,type=kind,sub=Number(args[2],0,2**32-1),target=Number(args[3],1),
|
||||
@@ -145,7 +155,7 @@ class Pass(object):
|
||||
elif kind=='end' and not args and self.reading is not None:
|
||||
r=self.reading;self.reading=None
|
||||
if len(r['missions'])!=r['count'] or r['final'] is None:return
|
||||
self.season=r['season'];self.missions=r['missions'];self.final=r['final'];self.none=False
|
||||
self.season=r['season'];self.missions=r['missions'];self.final=r['final'];self.access=r['access'];self.month=r['month'];self.none=False
|
||||
self.Answered('info')
|
||||
elif kind=='none' and not args:
|
||||
self.Clear();self.none=True;self.Answered('none')
|
||||
@@ -214,6 +224,8 @@ class BattlePassWindow(ui.Window):
|
||||
self.finalState=Text(self,330,y+4,'')
|
||||
self.finalReward=Text(self,18,y+26,'',0xffb3aa98)
|
||||
self.finalButton=Action(self,WIDTH-118,y,100,'领取',lambda:self.state.Claim(0) and self.Refresh())
|
||||
self.activateButton=Action(self,WIDTH-218,y,200,'使用当月战令票激活',self.AskActivate)
|
||||
self.activateButton.Hide();self.confirm=None;self.pendingTicket=None
|
||||
y=self.GetHeight()-56
|
||||
self.prev=Action(self,18,y,80,'上一页',lambda:self.Turn(-1))
|
||||
self.pageText=Text(self,140,y+24,'');self.pageText.SetHorizontalAlignCenter()
|
||||
@@ -232,8 +244,43 @@ class BattlePassWindow(ui.Window):
|
||||
def Hide(self):
|
||||
state=self.__dict__.get('state') # ui.Window.__init__ hides the window before state is set
|
||||
if self.IsShow() and state and state.season:state.Close()
|
||||
self.pendingTicket=None
|
||||
self.CloseConfirm()
|
||||
ui.Window.Hide(self)
|
||||
|
||||
def CloseConfirm(self):
|
||||
confirm=self.__dict__.get('confirm')
|
||||
if confirm:
|
||||
confirm.Close();confirm.SetAcceptEvent(None);confirm.SetCancelEvent(None);self.confirm=None
|
||||
|
||||
def OfferTicket(self,cell,vnum):
|
||||
self.pendingTicket=(cell,vnum)
|
||||
self.Open()
|
||||
|
||||
def AskTicket(self,cell,vnum):
|
||||
if self.state.access!=0 or player.GetItemIndex(cell)!=vnum:return
|
||||
item.SelectItem(vnum)
|
||||
if item.GetValue(0)!=self.state.month:self.state.error='month';self.Refresh();return
|
||||
import uiCommon
|
||||
self.CloseConfirm();self.confirm=uiCommon.QuestionDialog()
|
||||
self.confirm.SetText(L('消耗战令票并激活本月战令?'))
|
||||
self.confirm.SetAcceptEvent(lambda:self.ConfirmActivate(cell,vnum))
|
||||
self.confirm.SetCancelEvent(self.CloseConfirm);self.confirm.Open()
|
||||
|
||||
def AskActivate(self):
|
||||
if self.state.access!=0:return
|
||||
for cell in range(player.INVENTORY_PAGE_SIZE*player.INVENTORY_PAGE_COUNT):
|
||||
vnum=player.GetItemIndex(cell)
|
||||
if not 25150<=vnum<=25161:continue
|
||||
item.SelectItem(vnum)
|
||||
# Display uses server time, not the phone's local month/time zone.
|
||||
if item.GetValue(0)!=self.state.month:continue
|
||||
self.AskTicket(cell,vnum);return
|
||||
self.state.error='ticket';self.Refresh()
|
||||
|
||||
def ConfirmActivate(self,cell,vnum):
|
||||
self.CloseConfirm();self.state.Activate(cell,vnum);self.Refresh()
|
||||
|
||||
def Slots(self):
|
||||
return sorted(self.state.missions)
|
||||
|
||||
@@ -264,7 +311,7 @@ class BattlePassWindow(ui.Window):
|
||||
if m['claimed']:row['button'].SetText('已领取')
|
||||
elif s.claiming==m['slot']:row['button'].SetText('领取中')
|
||||
else:row['button'].SetText('领取' if done else '未完成')
|
||||
row['button'].SetEnabled(done and not m['claimed'] and bool(m['rewards']) and s.claiming is None)
|
||||
row['button'].SetEnabled(s.access in (None,1) and done and not m['claimed'] and bool(m['rewards']) and s.claiming is None)
|
||||
f=s.final
|
||||
for w in (self.finalName,self.finalState,self.finalReward,self.finalButton):
|
||||
if f:w.Show()
|
||||
@@ -274,7 +321,11 @@ class BattlePassWindow(ui.Window):
|
||||
self.finalState.SetText(L('已领取' if f['claimed'] else '全部任务完成' if ready else '完成全部任务后可领取'))
|
||||
self.finalReward.SetText(L('奖励:')+RewardText(f['rewards']))
|
||||
self.finalButton.SetText('已领取' if f['claimed'] else '领取中' if s.claiming==0 else '领取')
|
||||
self.finalButton.SetEnabled(ready and not f['claimed'] and s.claiming is None)
|
||||
self.finalButton.SetEnabled(s.access in (None,1) and ready and not f['claimed'] and s.claiming is None)
|
||||
if s.access==0:
|
||||
self.finalButton.Hide();self.finalState.Hide();self.finalReward.Hide();self.activateButton.Show()
|
||||
self.activateButton.SetEnabled(s.waiting is None)
|
||||
else:self.activateButton.Hide()
|
||||
many=self.Pages()>1
|
||||
for w in (self.prev,self.next,self.pageText):
|
||||
if many and s.season:w.Show()
|
||||
@@ -288,6 +339,8 @@ class BattlePassWindow(ui.Window):
|
||||
elif s.none:note='当前没有进行中的战令赛季'
|
||||
elif not s.season:note='正在查询……'
|
||||
elif s.claiming is not None:note='正在领取……'
|
||||
elif s.access==0:note='激活后才开始累计进度'
|
||||
elif s.access==2:note='本月战令已完成'
|
||||
else:note='击杀、钓鱼、强化等都会自动计入进度'
|
||||
self.note.SetText(L(note))
|
||||
|
||||
@@ -305,7 +358,7 @@ class BattlePassWindow(ui.Window):
|
||||
def OnPressEscapeKey(self):self.Hide();return True
|
||||
|
||||
def Destroy(self):
|
||||
self.Hide();self.closeButton.event=self.finalButton.event=self.prev.event=self.next.event=None
|
||||
self.Hide();self.closeButton.event=self.finalButton.event=self.activateButton.event=self.prev.event=self.next.event=None
|
||||
for row in self.rows:row['button'].event=None
|
||||
self.state=None
|
||||
|
||||
@@ -327,7 +380,10 @@ def OnPass(kind,value):
|
||||
chat.AppendChat(chat.CHAT_TYPE_INFO,L('战令任务完成:')+name+L(',按 F6 领取奖励'))
|
||||
elif kind=='claimed':chat.AppendChat(chat.CHAT_TYPE_INFO,L('战令奖励已放入背包' if value else '战令最终奖励已放入背包'))
|
||||
elif kind=='error':chat.AppendChat(chat.CHAT_TYPE_INFO,L(ERRORS[s.error]))
|
||||
if g_window and g_window.IsShow():g_window.Refresh()
|
||||
if g_window and g_window.IsShow():
|
||||
if kind=='info' and g_window.pendingTicket:
|
||||
ticket=g_window.pendingTicket;g_window.pendingTicket=None;g_window.AskTicket(*ticket)
|
||||
g_window.Refresh()
|
||||
|
||||
|
||||
g_pass=Pass(net.SendChatPacket,app.GetTime,OnPass)
|
||||
|
||||
Reference in New Issue
Block a user