// PORT: AVA2-inspired encyclopedia, adapted to current server templates and touch controls. // Static templates plus negotiated read-only server views; no gameplay mutation or loot RNG here. static const char c_szWikiScript[] = R"PY(# -*- coding: utf-8 -*- import app import game import grp import item import pack import player import ui import wndMgr import weakref import mt_feature_service from mt_biolog import Action, Text, L from mt_wiki_data import Catalogue PATH='wiki/catalogue.txt' g_window=None g_entry=None def ServerCapabilities(): mask=mt_feature_service.g_service.mask if mt_feature_service.g_service else None return {'schema':1,'static_catalogue':True,'model_preview':False, 'live_drops':None if mask is None else bool(mask&1), 'chest_preview':None if mask is None else bool(mask&2), 'attributes':None if mask is None else bool(mask&4), 'sources':None if mask is None else bool(mask&8), 'dungeons':None if mask is None else bool(mask&16), 'calendar':None if mask is None else bool(mask&32)} def U(text): return text if isinstance(text,unicode) else text.decode('utf-8') def B(text, limit=0): text=U(text) if limit and len(text)>limit:text=text[:limit-1]+u'…' return text.encode('utf-8') KINDS=(('', '全部物品'),('ITEM_WEAPON','武器'),('ITEM_ARMOR','防具首饰'),('ITEM_MATERIAL','材料'), ('ITEM_QUEST','任务物品'),('ITEM_USE','消耗品'),('ITEM_GIFTBOX','宝箱'),('ITEM_METIN','宝石')) MOBKINDS=(('', '全部怪物'),('MONSTER','怪物'),('STONE','矿石')) TYPE_NAMES=dict(KINDS) TYPE_NAMES.update({'ITEM_NONE':'特殊道具','ITEM_UNIQUE':'特殊装备','ITEM_TOOL':'工具','ITEM_FISH':'鱼类','ITEM_ROD':'鱼竿','ITEM_PICK':'采矿镐','ITEM_RESOURCE':'资源','ITEM_SKILLBOOK':'技能书','ITEM_SKILLFORGET':'技能忘却书','ITEM_COSTUME':'时装','ITEM_SPECIAL':'特殊道具'}) RANK_NAMES={'PAWN':'普通','S_PAWN':'弱小','KNIGHT':'精英','S_KNIGHT':'强力','BOSS':'首领','KING':'王者'} class WikiWindow(ui.Window): def __init__(self): ui.Window.__init__(self) self.SetWindowName('WikiWindow') self.AddFlag('float') self.AddFlag('movable') self.mode='items';self.category=0;self.page=0;self.detailPage=0 self.catalogue=None;self.error='';self.selected=None;self.results=[];self.links=[] self.dimensions=None;self.lastQuery=None;self.history=[] self.remote=None;self.remoteData=None;self.remoteError=None;self.remoteSerial=0 self.heading=Text(self,18,18,'游戏百科',0xffffd68b) self.detailsButton=Action(self,130,6,120,'详细属性',self.OpenDetails) self.dungeonButton=Action(self,258,6,96,'副本信息',self.OpenDungeons) self.calendarButton=Action(self,362,6,80,'活动日历',self.OpenCalendar) self.closeButton=Action(self,0,6,52,'关闭',self.Hide) self.backButton=Action(self,0,6,72,'返回',self.Back) self.searchBox=ui.SlotBar();self.searchBox.SetParent(self);self.searchBox.SetPosition(18,54) self.searchBox.SetSize(320,28);self.searchBox.Show() self.search=ui.EditLine();self.search.SetParent(self.searchBox);self.search.SetPosition(8,6) self.search.SetSize(302,20);self.search.SetMax(80);self.search.SetReturnEvent(self.Search) self.search.SetEscapeEvent(self.Hide);self.search.Show() self.searchButton=Action(self,346,50,72,'搜索',self.Search) self.itemTab=Action(self,18,100,96,'物品',lambda:self.SetMode('items')) self.mobTab=Action(self,122,100,96,'怪物',lambda:self.SetMode('mobs')) self.categoryButton=Action(self,226,100,164,'全部物品',self.NextCategory) self.status=Text(self,18,85,'输入名称或 ID 搜索',0xffc3b7a1) self.title=Text(self,0,112,'选择左侧条目',0xffffd68b) self.icon=ui.ExpandedImageBox();self.icon.SetParent(self);self.icon.AddFlag('not_pick') self.listButtons=[Action(self,0,0,100,'',lambda i=i:self.SelectResult(i)) for i in range(8)] self.detailButtons=[Action(self,0,0,100,'',lambda i=i:self.Follow(i)) for i in range(8)] self.prev=Action(self,18,0,72,'上一页',lambda:self.Page(-1)) self.next=Action(self,0,0,72,'下一页',lambda:self.Page(1)) self.pageText=Text(self,110,0) self.dprev=Action(self,0,0,72,'详情上页',lambda:self.DetailPage(-1)) self.dnext=Action(self,0,0,72,'详情下页',lambda:self.DetailPage(1)) self.revision=Text(self,430,66,'未加载资料',0xffaaa08b) self.Reflow() self.Hide() def OpenCalendar(self): import mt_calendar mt_calendar.Toggle() def OpenDungeons(self): import mt_dungeons mt_dungeons.Toggle() def OpenDetails(self): import mt_details mt_details.Toggle() def Load(self): if self.catalogue:return True try: if not pack.Exist(PATH):raise ValueError('missing catalogue') self.catalogue=Catalogue(pack.Get(PATH)) self.revision.SetText(L(B(u'资料版本 '+self.catalogue.version[:12]))) self.error='' return True except (ValueError,TypeError,UnicodeError,RuntimeError,IOError): self.error='百科资料缺失或版本不支持,请更新资源包。' self.status.SetText(L(B(self.error,24))) return False def Open(self,vnum=0): self.Reflow();self.SetCenterPosition();self.Show();self.SetTop() if not self.Load():return self.Search() if vnum: row=self.catalogue.FindItem(int(vnum)) if row:self.Select('items',row) else:self.status.SetText(L(B('当前资料未收录此物品。'))) def Query(self): value=self.search.GetText() return player.FeatureLocaleToUTF8(value).decode('utf-8').strip() def Search(self): self.page=0;self.lastQuery=self.Query();self.Refresh() def SetMode(self,mode): self.mode=mode;self.category=0;self.page=0;self.Refresh() def NextCategory(self): choices=KINDS if self.mode=='items' else MOBKINDS self.category=(self.category+1)%len(choices);self.page=0;self.Refresh() def Page(self,step): self.page+=step;self.Refresh() def DetailPage(self,step): if self.remote and self.remoteData: pages=max(1,(len(self.links)+self.rowCount-1)//self.rowCount) kind,subject,offset=self.remote if step>0 and self.detailPage+1>=pages and offset+len(self.remoteData['rows'])0: self.QueryRemote(kind,subject,max(0,offset-8));return self.detailPage+=step;self.RefreshDetail() def Refresh(self): for button in self.listButtons:button.Hide() if not self.catalogue:return choices=KINDS if self.mode=='items' else MOBKINDS kind,label=choices[self.category] self.categoryButton.SetText(label) self.results,count,self.page,pages=self.catalogue.Search(self.mode,self.Query(),kind,self.page,self.rowCount) for i,row in enumerate(self.results): self.listButtons[i].SetText(B(row['name'],max(9,(self.split-130)//12))+' #%d'%row['id']);self.listButtons[i].Show() self.status.SetText(L(B('%d 项;模板资料不保证可获取。'%count))) self.pageText.SetText(L(B('%d / %d'%(self.page+1,pages)))) self.prev.SetEnabled(self.page>0);self.next.SetEnabled(self.page+10) after=bool(self.remoteData and self.remote and self.remote[2]+len(self.remoteData['rows'])0 or before);self.dnext.SetEnabled(self.detailPage+1=20:detail=U('宝箱来源;点击可继续查看预览') elif rule==0:detail=u'通用掉落;角色等级 %d—%d'%(low,high) elif rule==2:detail=u'击杀组候选权重 %d/%d'%(weight,total) elif rule==3:detail=u'等级组;角色至少 %d 级'%low elif rule==4:detail=U('需掉宝手套或对应增益资格') elif rule==5:detail=U('怪物模板附加掉落') else:detail=U('怪物独立掉落组') lines.append((detail,0)) if not data['rows']:lines.append((U('当前查询范围内无配置;不代表所有途径均不存在'),0)) lines.append((U('第 %d—%d 条,共 %d 条')%(offset+1 if data['total'] else 0,offset+len(data['rows']),data['total']),0)) return lines def Reflow(self): dims=(wndMgr.GetScreenWidth(),wndMgr.GetScreenHeight()) if dims==self.dimensions:return self.dimensions=dims width=min(760,max(600,dims[0]-16));height=min(480,max(300,dims[1]-16)) self.SetSize(width,height);self.split=width//2 self.categoryButton.SetSize(self.split-234,48);self.categoryButton.label.SetPosition((self.split-234)//2,24) self.rowCount=min(8,max(2,(height-216)//48)) self.closeButton.SetPosition(width-70,6);self.backButton.SetPosition(width-150,6) self.title.SetPosition(self.split+48,122);self.icon.SetPosition(self.split+8,112) for i,b in enumerate(self.listButtons): b.SetPosition(18,154+i*48);b.SetSize(self.split-30,44);b.label.SetPosition((self.split-30)//2,22) for i,b in enumerate(self.detailButtons): b.SetPosition(self.split+8,154+i*48);b.SetSize(self.split-26,44);b.label.SetPosition((self.split-26)//2,22) self.prev.SetPosition(18,height-54);self.next.SetPosition(self.split-90,height-54);self.pageText.SetPosition(112,height-30) self.dprev.SetPosition(self.split+8,height-54);self.dnext.SetPosition(width-90,height-54) self.SetCenterPosition();self.Refresh();self.RefreshDetail() def OnUpdate(self): if self.IsShow():self.Reflow() def OnRender(self): x,y=self.GetGlobalPosition();grp.SetColor(0xf51b1916);grp.RenderBar(x,y,self.GetWidth(),self.GetHeight()) grp.SetColor(0xff9b7b48);grp.RenderBox(x,y,self.GetWidth(),self.GetHeight()) grp.RenderLine(x+self.split,y+108,0,self.GetHeight()-170) def OnMouseWheel(self,delta): x,y=self.GetGlobalPosition();mx,my=wndMgr.GetMousePosition() if mx>=x+self.split:self.DetailPage(-1 if delta>0 else 1) else:self.Page(-1 if delta>0 else 1) return True def Hide(self): if hasattr(self,'search'):self.search.KillFocus() ui.Window.Hide(self) def OnPressEscapeKey(self): self.Hide();return True def Destroy(self): self.Hide();self.search.SetReturnEvent(None);self.search.SetEscapeEvent(None) for b in self.listButtons+self.detailButtons+[self.detailsButton,self.dungeonButton,self.calendarButton,self.closeButton,self.backButton,self.searchButton,self.itemTab,self.mobTab,self.categoryButton,self.prev,self.next,self.dprev,self.dnext]:b.event=None self.remoteSerial+=1;self.catalogue=None class Entry(Action): def __init__(self,window): Action.__init__(self,None,0,0,64,'百科',Toggle) self.minimap=weakref.proxy(window.interface.wndMiniMap);self.SetWindowName('WikiEntry');self.OnUpdate() def OnUpdate(self): x,y=self.minimap.GetGlobalPosition();self.SetPosition(max(4,x-68),y+96) def Toggle(): if g_window: if g_window.IsShow():g_window.Hide() else:g_window.Open() def OpenItem(vnum): if g_window:g_window.Open(vnum) _open=game.GameWindow.Open _close=game.GameWindow.Close def Open(self): global g_window,g_entry _open(self);g_window=WikiWindow();g_entry=Entry(self) def Close(self): global g_window,g_entry if g_entry:g_entry.Hide();g_entry.event=None;g_entry=None if g_window:g_window.Destroy();g_window=None _close(self) game.GameWindow.Open=Open game.GameWindow.Close=Close )PY";