Jump to content

Intel

Premium
  • Posts

    200
  • Joined

  • Last visited

  • Days Won

    4
  • Feedback

    0%

Everything posted by Intel

  1. cryptopp 8.7.0 from github, gcc12 FreeBSD 13.0/13.1 (32 bit of course)
  2. This still won't fix the problem when left clicking on the bar (and keeping the left click down, same with the right click). When moving, the player will keep moving in background and the window will also unfreeze, but not when auto attacking and pressing the spacebar, or moving pressing W (basically pressing any button while keeping the menubar clicked fucks it up. I still haven't found a solution for that but I also don't know if it causes to fly bug an enemy character).
  3. About cryptopp, I've just tested 8.7.0 and it does work as well, if anyone wants to upgrade.
  4. Please post screenshots, not the entire error text. Anyway, install makedepend pkg install makedepend and do: gmake clean gmake dep then rebuild it
  5. pkg info shows you the list of packages installed
  6. Funnily enough, compiling it gave me the shared libs, the package the static libs (linux AND FreeBSD as well when I tried on 64bit) FreeBSD though gives you the 1.8.0 version if I am not mistaken.
  7. Oh yeah, for sure, but (at least from original sources and package) I guess cmake kept detecting libtiff (and the others) in the system. If marty's version only goes for targa then it's great. I should definitely retry removing all the useless dependencies EDIT: Ok, I should nuke the useless stuff I guess before compiling DevIL or maybe it's just a Linux thing:
  8. Mh, I don't know on FreeBSD (I am not interesting on upgrading DevIL on there unless I want to build a native 64bit file game), but I was trying to build a Linux version and it asks for lzma. It's from libtiff: needed for il_tiff:
  9. or that, yeah lol so: //somewhere maybe a header in common/target_info.h struct drop_info { uint32_t vnum; uint16_t count; uint8_t rarity; } //and in input_main include the new header and the vector becomes: static std::vector<drop_info> s_vec_item; //and to read its info: for(const auto& x : s_vec_item) { pInfo.dwVID = m_pkChrTarget->GetVID(); pInfo.race = m_pkChrTarget->GetRaceNum(); pInfo.dwVnum = x.vnum; pInfo.count = x.count; pInfo.rarity = x.rarity; //.... //and to fill the vector (include the header again): // Drop Item Group { auto it = m_map_pkDropItemGroup.find(pkChr->GetRaceNum()); if(it != m_map_pkDropItemGroup.end()) { auto v = it->second->GetVector(); for (DWORD i = 0; i < v.size(); ++i) { if( iLevel >= (iMobLevel - 15) && iLevel <= (iMobLevel + 15) ) { drop_info info{}; info.vnum = v[i].dwVnum; info.count = v[i].iCount; info.rarity = CalculateDropRarityDropItemGroup(v[i].dwPct, bType); vec_item.emplace_back(info); } } } }
  10. Oh hell no, I also use c++2a. That's odd. AH NO WAIT hold up lmao. You need to add: #include <tuple> in input_main.cpp and item_manager.cpp
  11. You need c++11 (-std=c++11 on your makefile in the CXXFLAGS) I think.. I say I think because generally I'd understand this if you were trying to put some objects of a class with no default constructor (but they are integers...)
  12. Example for drop item group, replace: vec_item.push_back(std::make_pair(std::make_pair(v[i].dwVnum, v[i].iCount),v[i].rarity)); with: vec_item.emplace_back(std::make_tuple(v[i].dwVnum, v[i].iCount, rarity)); (so make_pair with make_tuple and add rarity as the third parameter) Rarities functions I've made: int CalculateDropRarityCommonDropItem(int x) { int pct = x; int rarity = 0; if(pct >= 4000000) rarity = 1; else if(pct < 40000000 && pct >= 200000 ) rarity = 2; else if(pct < 200000 && pct >= 10000 ) rarity = 3; else if(pct < 10000 && pct >= 5000 ) rarity = 4; else if(pct < 5000 && pct >= 1000 ) rarity = 5; else if(pct < 1000 && pct >= 0 ) rarity = 6; return rarity; } int CalculateDropRarityKillDrop(int x, BYTE bType) { int pct = x; int rarity = 0; if(pct == 1) rarity = 1; else if(pct > 1 && pct <= 300 ) rarity = 2; else if(pct > 300 && pct <= 500 ) rarity = 3; else if(pct > 500 && pct <= 2000 ) rarity = 4; else if(pct > 2000 && pct <= 5000 ) rarity = 5; else if(pct > 5000 ) rarity = 6; return rarity; } int CalculateDropRarityDropItemGroup(int x, BYTE bType) { int pct = x; int rarity = 0; switch(bType) { case CHAR_TYPE_BOSS: { if(pct >= 4000000) rarity = 1; else if(pct < 4000000 && pct >= 2600000 ) //100~65 rarity = 2; else if(pct < 2600000 && pct >= 1600000 ) //65~40 rarity = 3; else if(pct < 1600000 && pct >= 1000000 ) //40~25 rarity = 4; else if(pct < 1000000 && pct >= 600000 ) //25~15 rarity = 5; else if(pct < 600000 ) rarity = 6; } break; case CHAR_TYPE_MONSTER: { if(pct >= 4000000) rarity = 1; else if(pct < 4000000 && pct >= 1600000 ) //100~40 rarity = 2; else if(pct < 1600000 && pct >= 800000 ) //40~20 rarity = 3; else if(pct < 800000 && pct >= 200000 ) //20~5 rarity = 4; else if(pct < 200000 && pct >= 20000 ) //5~0.5 rarity = 5; else if(pct < 20000 ) rarity = 6; } break; case CHAR_TYPE_STONE: { if(pct >= 4000000) rarity = 1; else if(pct < 4000000 && pct >= 2000000 ) //100~50 rarity = 2; else if(pct < 2000000 && pct >= 1000000 ) //50~25 rarity = 3; else if(pct < 1000000 && pct >= 600000 ) //25~15 rarity = 4; else if(pct < 600000 && pct >= 200000 ) //15~5 rarity = 5; else if(pct < 200000 ) rarity = 6; } break; default: { if(pct >= 4000000) rarity = 1; else if(pct < 4000000 && pct >= 2000000 ) //100~50 rarity = 2; else if(pct < 2000000 && pct >= 1000000 ) //50~25 rarity = 3; else if(pct < 1000000 && pct >= 600000 ) //25~15 rarity = 4; else if(pct < 600000 && pct >= 200000 ) //15~5 rarity = 5; else if(pct < 200000 ) rarity = 6; } break; } return rarity; } int CalculateDropRarityLevelItemGroup(float x, BYTE bType) { float pct = x / 10000.0000; int rarity = 0; switch(bType) { case CHAR_TYPE_BOSS: { if(pct >= 100.0000) rarity = 1; else if(pct < 100.0000 && pct >= 65.0000 ) rarity = 2; else if(pct < 65.0000 && pct >= 40.0000 ) rarity = 3; else if(pct < 40.0000 && pct >= 25.0000 ) rarity = 4; else if(pct < 25.0000 && pct >= 15.0000 ) rarity = 5; else if(pct < 15.0000 ) rarity = 6; } break; case CHAR_TYPE_STONE: { if(pct >= 100.0000) rarity = 1; else if(pct < 100.0000 && pct >= 50.0000 ) rarity = 2; else if(pct < 50.0000 && pct >= 25.0000 ) rarity = 3; else if(pct < 25.0000 && pct >= 15.0000 ) rarity = 4; else if(pct < 15.0000 && pct >= 5.0000 ) rarity = 5; else if(pct < 5.0000 ) rarity = 6; } break; case CHAR_TYPE_MONSTER: { if(pct >= 100.0000) rarity = 1; else if(pct < 100.0000 && pct >= 30.0000 ) rarity = 2; else if(pct < 30.0000 && pct >= 15.0000 ) rarity = 3; else if(pct < 15.0000 && pct >= 1.0000 ) rarity = 4; else if(pct < 1.0000 && pct >= 0.1000 ) rarity = 5; else if(pct < 0.1000 ) rarity = 6; } break; default: { if(pct >= 100.0000) rarity = 1; else if(pct < 100.0000 && pct >= 65.0000 ) rarity = 2; else if(pct < 65.0000 && pct >= 40.0000 ) rarity = 3; else if(pct < 40.0000 && pct >= 25.0000 ) rarity = 4; else if(pct < 25.0000 && pct >= 15.0000 ) rarity = 5; else if(pct < 15.0000 ) rarity = 6; } } return rarity; } int CalculateDropRarityTimeDrop(int x, BYTE bType) { int pct = x; int rarity = 0; switch(bType) { case CHAR_TYPE_BOSS: { if(pct == 1000000) rarity = 1; else if(pct < 1000000 && pct >= 650000 ) rarity = 2; else if(pct < 650000 && pct >= 400000 ) rarity = 3; else if(pct < 400000 && pct >= 250000 ) rarity = 4; else if(pct < 250000 && pct >= 150000 ) rarity = 5; else if(pct < 150000 ) rarity = 6; } break; case CHAR_TYPE_MONSTER: { if(pct == 1000000) rarity = 1; else if(pct < 1000000 && pct >= 400000 ) rarity = 2; else if(pct < 400000 && pct >= 200000 ) rarity = 3; else if(pct < 200000 && pct >= 100000 ) rarity = 4; else if(pct < 100000 && pct >= 5000 ) rarity = 5; else if(pct < 5000 ) rarity = 6; } break; case CHAR_TYPE_STONE: { if(pct == 1000000) rarity = 1; else if(pct < 1000000 && pct >= 500000 ) rarity = 2; else if(pct < 500000 && pct >= 250000 ) rarity = 3; else if(pct < 250000 && pct >= 150000 ) rarity = 4; else if(pct < 150000 && pct >= 50000 ) rarity = 5; else if(pct < 50000 ) rarity = 6; } default: { if(pct == 1000000) rarity = 1; else if(pct < 1000000 && pct >= 500000 ) rarity = 2; else if(pct < 500000 && pct >= 250000 ) rarity = 3; else if(pct < 250000 && pct >= 150000 ) rarity = 4; else if(pct < 150000 && pct >= 50000 ) rarity = 5; else if(pct < 50000 ) rarity = 6; } break; } return rarity; } Hint: instead of the char type, since the BOSS type is not by default in the sources, you could pass the rank as well, then put the rank on the switch case and, if the rank is 5, check if it's a metin or not. Therefore in the drop item group example would be like this: // Drop Item Group { auto it = m_map_pkDropItemGroup.find(pkChr->GetRaceNum()); if(it != m_map_pkDropItemGroup.end()) { auto v = it->second->GetVector(); for (DWORD i = 0; i < v.size(); ++i) { if( iLevel >= (iMobLevel - 15) && iLevel <= (iMobLevel + 15) ) //don't show outside level limits { uint8_t rarity = CalculateDropRarityDropItemGroup(v[i].dwPct, bType); vec_item.emplace_back(std::make_tuple(v[i].dwVnum, v[i].iCount, rarity)); //vec_item.push_back(std::make_pair(std::make_pair(v[i].dwVnum, v[i].iCount),v[i].rarity)); } } } } You can sort them by rarity like this: std::sort(vec_item.begin(),vec_item.end(), sortbyrarity); //then sort by rarity sortbyrarity function: bool sortbyrarity(std::tuple<int, int, int>& a, std::tuple<int, int, int>& b) { return (std::get<2>(a) > std::get<2>(b)); } and in input_main.cpp: pInfo.dwVID = m_pkChrTarget->GetVID(); pInfo.race = m_pkChrTarget->GetRaceNum(); pInfo.dwVnum = std::get<0>(x); pInfo.count = std::get<1>(x); pInfo.rarity = std::get<2>(x); this is how you get the data from the tuple and s_vec_item declaration changes to: static std::vector<std::tuple<int,int,int>> s_vec_item; Obviously you should change the packet accordingly and in bool CPythonNetworkStream::RecvTargetInfoPacket() change: Py_BuildValue("(iii)", pInfoTargetPacket.race, pInfoTargetPacket.dwVnum, pInfoTargetPacket.count)); into: Py_BuildValue("(iiii)", pInfoTargetPacket.race, pInfoTargetPacket.dwVnum, pInfoTargetPacket.count, pInfoTargetPacket.rarity)); game.py change of BINARY_AddTargetMonsterDropInfo: if app.ENABLE_SEND_TARGET_INFO: def BINARY_AddTargetMonsterDropInfo(self, raceNum, itemVnum, itemCount, rarity): if not raceNum in uiTarget.MONSTER_INFO_DATA: uiTarget.MONSTER_INFO_DATA.update({raceNum : {}}) uiTarget.MONSTER_INFO_DATA[raceNum].update({"items" : []}) curList = uiTarget.MONSTER_INFO_DATA[raceNum]["items"] isUpgradeable = False isMetin = False item.SelectItem(itemVnum) if item.GetItemType() == item.ITEM_TYPE_WEAPON or item.GetItemType() == item.ITEM_TYPE_ARMOR: isUpgradeable = True elif item.GetItemType() == item.ITEM_TYPE_METIN: isMetin = True for curItem in curList: if isUpgradeable: if curItem.has_key("vnum_list") and curItem["vnum_list"][0] / 10 * 10 == itemVnum / 10 * 10: if not (itemVnum in curItem["vnum_list"]): curItem["vnum_list"].append(itemVnum) return elif isMetin: if curItem.has_key("vnum_list"): baseVnum = curItem["vnum_list"][0] if curItem.has_key("vnum_list") and (baseVnum - baseVnum%1000) == (itemVnum - itemVnum%1000): if not (itemVnum in curItem["vnum_list"]): curItem["vnum_list"].append(itemVnum) return else: if curItem.has_key("vnum") and curItem["vnum"] == itemVnum and curItem["count"] == itemCount and curItem["rarity"] == rarity: return if isUpgradeable or isMetin: curList.append({"vnum_list":[itemVnum], "count":itemCount, "rarity":rarity}) else: curList.append({"vnum":itemVnum, "count":itemCount, "rarity":rarity}) and in uitarget.py, the class ItemListBoxItem: class ItemListBoxItem(ui.Window): def __init__(self, width): ui.Window.__init__(self) image = ui.ExpandedImageBox() image.SetParent(self) image.Show() self.image = image nameLine = ui.TextLine() nameLine.SetParent(self) nameLine.SetPosition(32 + 5, 0) nameLine.Show() self.nameLine = nameLine rarity = ui.TextLine() rarity.SetParent(self) rarity.SetPosition(32 + 5, 13) rarity.Show() self.rarity = rarity self.SetSize(width, 32 + 5) def LoadImage(self, image, name = None): self.image.LoadImage(image) self.SetSize(self.GetWidth(), self.image.GetHeight() + 5) if name != None: self.SetText(name) def SetText(self, text): self.nameLine.SetText(text) def SetRarityText(self, text, rarity): TEXT_COLORS = [ grp.GenerateColor(1.0, 0.0, 0.0, 1.0), grp.GenerateColor(1.0, 1.0, 1.0, 1.0), grp.GenerateColor(0.33, 1.0, 0.12, 1.0), grp.GenerateColor(0.42, 0.93, 0.76, 1.0), grp.GenerateColor(0.0, 0.89, 1.0, 1.0), grp.GenerateColor(0.41, 0.0, 1.0, 1.0), grp.GenerateColor(1.0, 0.86, 0.0, 1.0) ] if rarity != 1: self.rarity.SetPackedFontColor(TEXT_COLORS[rarity]) self.rarity.SetText(text) __LoadInformation_Drops: def __LoadInformation_Drops(self, race): self.AppendSeperator() if race in MONSTER_INFO_DATA: if len(MONSTER_INFO_DATA[race]["items"]) == 0: self.AppendTextLine(localeInfo.TARGET_INFO_NO_ITEM_TEXT) else: itemListBox = ui.ListBoxExNew(32 + 5, self.MAX_ITEM_COUNT) itemListBox.SetSize(self.GetWidth() - 15 * 2 - ui.ScrollBar.SCROLLBAR_WIDTH, (32 + 5) * self.MAX_ITEM_COUNT) height = 0 for curItem in MONSTER_INFO_DATA[race]["items"]: if curItem.has_key("vnum_list"): height += self.AppendItem(itemListBox, curItem["vnum_list"], curItem["count"], curItem["rarity"], race) else: height += self.AppendItem(itemListBox, curItem["vnum"], curItem["count"], curItem["rarity"], race) if height < itemListBox.GetHeight(): itemListBox.SetSize(itemListBox.GetWidth(), height) self.AppendWindow(itemListBox, 15) itemListBox.SetBasePos(0) if len(MONSTER_INFO_DATA[race]["items"]) > itemListBox.GetViewItemCountFixed(): itemScrollBar = ui.ScrollBar() itemScrollBar.SetParent(self) itemScrollBar.SetPosition(itemListBox.GetRight(), itemListBox.GetTop()) itemScrollBar.SetScrollBarSize(32 * self.MAX_ITEM_COUNT + 5 * (self.MAX_ITEM_COUNT - 1)) itemScrollBar.SetMiddleBarSize(float(self.MAX_ITEM_COUNT) / float(height / (32 + 5))) itemScrollBar.Show() itemListBox.SetScrollBar(itemScrollBar) self.scrollBar = itemListBox.GetScrollBar() else: self.AppendTextLine(localeInfo.TARGET_INFO_NO_ITEM_TEXT) AppendItem: def AppendItem(self, listBox, vnums, count, rarity, race): if type(vnums) == int: vnum = vnums else: vnum = vnums[0] item.SelectItem(vnum) itemName = item.GetItemName() if type(vnums) != int and len(vnums) > 1: #vnums = sorted(vnums) realName = itemName[:itemName.find("+")] if item.GetItemType() == item.ITEM_TYPE_METIN: realName = localeInfo.TARGET_INFO_STONE_NAME itemName = realName + "+0 - +4" else: itemName = realName + "+" + str(vnums[0] % 10) + " - +" + str(vnums[len(vnums) - 1] % 10) vnum = vnums[len(vnums) - 1] myItem = self.ItemListBoxItem(listBox.GetWidth()) myItem.LoadImage(item.GetIconImageFileName()) if count <= 1: myItem.SetText(itemName) else: myItem.SetText("%dx %s" % (count, itemName)) RARITY_NAMES_LIST = [localeInfo.DROP_RARITY_ERROR, localeInfo.DROP_GUARANTEED, localeInfo.DROP_COMMON, localeInfo.DROP_UNCOMMON, localeInfo.DROP_RARE, localeInfo.DROP_MYTHIC, localeInfo.DROP_LEGENDARY] myItem.SetRarityText("%s" % RARITY_NAMES_LIST[rarity], rarity) myItem.SAFE_SetOverInEvent(self.OnShowItemTooltip,vnum) myItem.SAFE_SetOverOutEvent(self.OnHideItemTooltip) listBox.AppendItem(myItem) if item.GetItemType() == item.ITEM_TYPE_METIN: self.stoneImg = myItem self.stoneVnum = vnums self.lastStoneVnum = self.STONE_LAST_VNUM + vnums[len(vnums) - 1] % 1000 / 100 * 100 return myItem.GetHeight()
  13. We do realize that some of the prices can be pretty high and they are not meant for a need to protect our code. It's priced at the value we believe they are worth.
  14. Mh, I see different drops. This is my python part: if app.ENABLE_SEND_TARGET_INFO: def BINARY_AddTargetMonsterDropInfo(self, raceNum, itemVnum, itemCount, rarity): if not raceNum in uiTarget.MONSTER_INFO_DATA: uiTarget.MONSTER_INFO_DATA.update({raceNum : {}}) uiTarget.MONSTER_INFO_DATA[raceNum].update({"items" : []}) curList = uiTarget.MONSTER_INFO_DATA[raceNum]["items"] isUpgradeable = False isMetin = False item.SelectItem(itemVnum) if item.GetItemType() == item.ITEM_TYPE_WEAPON or item.GetItemType() == item.ITEM_TYPE_ARMOR: isUpgradeable = True elif item.GetItemType() == item.ITEM_TYPE_METIN: isMetin = True for curItem in curList: if isUpgradeable: if curItem.has_key("vnum_list") and curItem["vnum_list"][0] / 10 * 10 == itemVnum / 10 * 10: if not (itemVnum in curItem["vnum_list"]): curItem["vnum_list"].append(itemVnum) return elif isMetin: if curItem.has_key("vnum_list"): baseVnum = curItem["vnum_list"][0] if curItem.has_key("vnum_list") and (baseVnum - baseVnum%1000) == (itemVnum - itemVnum%1000): if not (itemVnum in curItem["vnum_list"]): curItem["vnum_list"].append(itemVnum) return else: if curItem.has_key("vnum") and curItem["vnum"] == itemVnum and curItem["count"] == itemCount and curItem["rarity"] == rarity: return if isUpgradeable or isMetin: curList.append({"vnum_list":[itemVnum], "count":itemCount, "rarity":rarity}) else: curList.append({"vnum":itemVnum, "count":itemCount, "rarity":rarity})
  15. Added new system -> Persistent Settings: This system replaces the old "in game settings" code (and others, if available, like the shining system) Every option is encapsulated in a json structure (both on the server, as a master, and in the launcher). Ex: { "general": { "name_color": "normal", "target_menu": "show", "chat_lines": "show", "char_names": "always", "monster_level": "show", "damage": "show", "day_light": true, "aestethic_effects": true, "models_visibility": { "pet": true, "mount": true, "shops": true } } } The utility of the system, aside of easier management of all this stuff, is that the players will keep all their settings saved, even when using a totally different computer. The system uses nlohman json library. If you use Marty's [legit] files and you are already using RapidJSON I can work with that as well. C++11 minimum required. The system also requires the boost library on the server and the client (boost::variant/boost::static_visitor/boost::alghoritm) if for some reason you removed it.
  16. as I said: uiscript I thought it could be made from the video, and something has to be edited from mine (same reasons, different sources, different stuff): import uiScriptLocale import colorInfo TASKBAR = "d:/ymir work/ui/taskbar/" window = { "name" : "ResearchWindow", "x" : 100, "y" : 20, "style" : ("movable", "float","limit",), "width" : 330, "height" : 330, "children" : ( { "name" : "board", "type" : "board_with_titlebar", "x" : 0, "y" : 0, "width" : 330, "height" : 330, "title": uiScriptLocale.RESEARCH_TITLE, "children" : ( { "name" : "thinboardAllContainer", "type" : "thinboard", "x" : 7, "y" : 27, "width" : 316, "height" : 296, "style" : ["not_pick"], "children" : ( { "name" : "thinboardDeliverContainer", "type" : "thinboard", "x" : 5, "y" : 5, "width" : 306, "height" : 116, "style" : ["not_pick"], "children" : ( { "name" : "current_item", "type" : "grid_table", "x" : 31, "y" : 34, "start_index" : 0, "x_count" : 1, "y_count" : 1, "x_step" : 32, "y_step" : 32, "image" : "d:/ymir work/ui/public/Slot_Base.sub", }, { "name" : "UpButton0", "type" : "button", "tooltip_text" : uiScriptLocale.RESEARCH_UP, "x" : 31-4, "y" : 34+32+2, "default_image" : TASKBAR + "pageup.sub", "over_image" : TASKBAR + "pageup_over.sub", "down_image" : TASKBAR + "pageup_click.sub", }, { "name" : "DownButton0", "type" : "button", "tooltip_text" : uiScriptLocale.RESEARCH_DOWN, "x" : 31-4, "y" : 34+32+12, "default_image" : TASKBAR + "pagedown.sub", "over_image" : TASKBAR + "pagedown_over.sub", "down_image" : TASKBAR + "pagedown_click.sub", }, { "name":"ItemSlotbar0", "type":"slotbar", "x":40, "y":34+36, "preset":"parameter_slot_09", "children" : ( { "name":"ItemSlotbar0Text", "type":"text", "x":1, "y":2, "text":"1", "r":1.0, "g":1.0, "b":1.0, "a":1.0, "text_horizontal_align":"center", "horizontal_align":"center"}, ), }, { "name" : "textItemName", "type" : "text", "x" : 111 - 27, "y" : 18, "color" : colorInfo.FONT_COLOR, "fontsize":"middle", "text" : uiScriptLocale.RESEARCH_OBJECT, "style" : ["not_pick"], }, { "name" : "ItemNametext", "type" : "text", "x" : 111 - 27 + 84, "y" : 18, "color" : colorInfo.GOLD_COLOR, "fontsize":"middle", "text" : uiScriptLocale.RESEARCH_OBJECT, "style" : ["not_pick"], }, { "name" : "textItemDeliverd", "type" : "text", "x" : 111 - 27, "y" : 18 + 16, "color" : colorInfo.FONT_COLOR, "fontsize":"middle", "text" : uiScriptLocale.RESEARCH_DELIVERED, "style" : ["not_pick"], }, { "name" : "textItemDeliverdQty", "type" : "text", "x" : 111 - 27 + 55, "y" : 18 + 16, "color" : colorInfo.GOLD_COLOR, "fontsize":"middle", "text" : "0/0", "style" : ["not_pick"], }, { "name" : "textItemPct", "type" : "text", "x" : 111 - 27, "y" : 18 + 16 * 2, "color" : colorInfo.FONT_COLOR, "fontsize":"middle", "text" : uiScriptLocale.RESEARCH_PCT, "style" : ["not_pick"], }, { "name" : "ItemPctText", "type" : "text", "x" : 111 - 27 + 104, "y" : 18 + 16 * 2, "color" : colorInfo.GOLD_COLOR, "fontsize":"middle", "text" : "", "style" : ["not_pick"], }, { "name" : "textItemCD", "type" : "text", "x" : 111 - 27, "y" : 18 + 16 * 3, "color" : colorInfo.FONT_COLOR, "fontsize":"middle", "text" : uiScriptLocale.RESEARCH_TIMER, "style" : ["not_pick"], }, { "name" : "ItemCDText", "type" : "text", "x" : 111 - 27 + 77, "y" : 18 + 16 * 3, "color" : colorInfo.RED, "fontsize":"middle", "text" : "", "style" : ["not_pick"], }, { "name" : "exam_button", "type" : "dynamic_button", "x" : 0, "y" : 86, "text" : uiScriptLocale.RESEARCH_BUTTON, "horizontal_align" : "center", "preset" : "not_so_largerer_button", }, { "name" : "CD_Image", "type" : "image", "x" : 246, "y" : 46+13, "image" : "d:/ymir work/ui/game/mailbox/mailbox_icon_cd.sub", }, { "name" : "CD_checkbox", "type" : "checkbox_new", "x" : 272, "y" : 51+14, }, ), }, { "name" : "thinboardIconContainer", "type" : "thinboard", "x" : 51-15, "y" : 136, "width" : 214+30, "height" : 40, "style" : ["not_pick"], "children" : ( { "name" : "time_deleter_slot", "type" : "grid_table", "x" : 46, "y" : 3, "start_index" : 0, "x_count" : 1, "y_count" : 1, "x_step" : 32, "y_step" : 32, #"image" : "d:/ymir work/ui/public/Slot_Base.sub", }, #{ # "name" : "cd_reset_icon", # "type" : "image", # # "x" : 46, # "y" : 3, # # "image" : "d:/icon/item/102517.tga", #}, { "name" : "UpButton1", "type" : "button", "tooltip_text" : uiScriptLocale.RESEARCH_UP, "x" : 9, "y" : 9, "default_image" : TASKBAR + "pageup.sub", "over_image" : TASKBAR + "pageup_over.sub", "down_image" : TASKBAR + "pageup_click.sub", }, { "name" : "DownButton1", "type" : "button", "tooltip_text" : uiScriptLocale.RESEARCH_DOWN, "x" : 9, "y" : 19, "default_image" : TASKBAR + "pagedown.sub", "over_image" : TASKBAR + "pagedown_over.sub", "down_image" : TASKBAR + "pagedown_click.sub", }, { "name":"ItemSlotbar1", "type":"slotbar", "x":22, "y":11, "preset":"parameter_slot_09", "children" : ( { "name":"ItemSlotbar1Text", "type":"text", "x":1, "y":2, "text":"0", "r":1.0, "g":1.0, "b":1.0, "a":1.0, "text_horizontal_align":"center", "horizontal_align":"center"}, ), }, { "name" : "elisir_10_slot", "type" : "grid_table", "x" : 126, "y" : 3, "start_index" : 0, "x_count" : 1, "y_count" : 1, "x_step" : 32, "y_step" : 32, #"image" : "d:/ymir work/ui/public/Slot_Base.sub", }, #{ # "name" : "elisir_10_icon", # "type" : "image", # "x" : 126, # "y" : 3, # "image" : "d:/icon/item/102529.tga", #}, { "name" : "UpButton2", "type" : "button", "tooltip_text" : uiScriptLocale.RESEARCH_UP, "x" : 92, "y" : 9, "default_image" : TASKBAR + "pageup.sub", "over_image" : TASKBAR + "pageup_over.sub", "down_image" : TASKBAR + "pageup_click.sub", }, { "name" : "DownButton2", "type" : "button", "tooltip_text" : uiScriptLocale.RESEARCH_DOWN, "x" : 92, "y" : 19, "default_image" : TASKBAR + "pagedown.sub", "over_image" : TASKBAR + "pagedown_over.sub", "down_image" : TASKBAR + "pagedown_click.sub", }, { "name":"ItemSlotbar2", "type":"slotbar", "x":104, "y":11, "preset":"parameter_slot_09", "children" : ( { "name":"ItemSlotbar2Text", "type":"text", "x":1, "y":2, "text":"0", "r":1.0, "g":1.0, "b":1.0, "a":1.0, "text_horizontal_align":"center", "horizontal_align":"center"}, ), }, { "name" : "elisir_30_slot", "type" : "grid_table", "x" : 206, "y" : 3, "start_index" : 0, "x_count" : 1, "y_count" : 1, "x_step" : 32, "y_step" : 32, #"image" : "d:/ymir work/ui/public/Slot_Base.sub", }, #{ # "name" : "elisir_30_icon", # "type" : "image", # # "x" : 206, # "y" : 3, # "image" : "d:/icon/item/102616.tga", #}, { "name" : "UpButton3", "type" : "button", "tooltip_text" : uiScriptLocale.RESEARCH_UP, "x" : 172, "y" : 9, "default_image" : TASKBAR + "pageup.sub", "over_image" : TASKBAR + "pageup_over.sub", "down_image" : TASKBAR + "pageup_click.sub", }, { "name" : "DownButton3", "type" : "button", "tooltip_text" : uiScriptLocale.RESEARCH_DOWN, "x" : 172, "y" : 19, "default_image" : TASKBAR + "pagedown.sub", "over_image" : TASKBAR + "pagedown_over.sub", "down_image" : TASKBAR + "pagedown_click.sub", }, { "name":"ItemSlotbar3", "type":"slotbar", "x":184, "y":11, "preset":"parameter_slot_09", "children" : ( { "name":"ItemSlotbar3Text", "type":"text", "x":1, "y":2, "text":"0", "r":1.0, "g":1.0, "b":1.0, "a":1.0, "text_horizontal_align":"center", "horizontal_align":"center"}, ), }, ), }, { "name" : "MessagesName", "type" : "text", "x" : 115, "y" : 169+16, "text" : uiScriptLocale.SYSTEM_MESSAGES, "color" : colorInfo.GOLD, "fontsize":"middle", "children" : ( { "name" : "NotifySlot", "type" : "slotbar", "x" : -110, "y" : 18 * 1, "width" : 305, "height" : 16*5, "children" : ( { "name" : "NotifyValue1", "type" : "text", "x" : 0, "y" : 0, "text" : " ", "horizontal_align" : "center", "text_horizontal_align" : "center", }, ), }, ), }, ), }, ), }, ), }
  17. I saw, and I thought to have replied to the DM, but oh well Anyway, you worry about the container's copy but as I explained, your line is the same as the line in the original function (which is optimized anyway by the compiler, unless you ship a debug version for the live server). Therefore I don't see the need for the new snapshot class created.
  18. Mh, this is my update function (yes I removed the GNUC define). I also use GCC (v10 with std=c++2a) : void CHARACTER_MANAGER::Update(int iPulse) { BeginPendingDestroy(); // PC character updates { if(!m_map_pkPCChr.empty()) { // Copy container CHARACTER_VECTOR v; v.reserve(m_map_pkPCChr.size()); transform(m_map_pkPCChr.begin(), m_map_pkPCChr.end(), back_inserter(v), boost::bind(&NAME_MAP::value_type::second, boost::placeholders::_1)); if(0 == (iPulse % PASSES_PER_SEC(5))) { FuncUpdateAndResetChatCounter f; std::for_each(v.begin(), v.end(), f); } else { std::for_each(v.begin(), v.end(), [iPulse](auto&& arg) -> decltype(arg->UpdateCharacter(iPulse)) { return arg->UpdateCharacter(iPulse); }); } } } // Monster Updates { if(!m_set_pkChrState.empty()) { CHARACTER_VECTOR v; v.reserve(m_set_pkChrState.size()); v.insert(v.end(), m_set_pkChrState.begin(), m_set_pkChrState.end()); std::for_each(v.begin(), v.end(), [iPulse](auto&& arg) -> decltype(arg->UpdateStateMachine(iPulse)) { return arg->UpdateStateMachine(iPulse); }); } } // Update separately Santa { CharacterVectorInteractor i; if(CHARACTER_MANAGER::instance().GetCharactersByRaceNum(xmas::MOB_SANTA_VNUM, i)) { std::for_each(i.begin(), i.end(), [iPulse](auto&& arg) -> decltype(arg->UpdateStateMachine(iPulse)) { return arg->UpdateStateMachine(iPulse); }); } } // Number of records once an hour hunt monsters if(0 == (iPulse % PASSES_PER_SEC(3600))) { for (auto it = m_map_dwMobKillCount.begin(); it != m_map_dwMobKillCount.end(); ++it) DBManager::instance().SendMoneyLog(MONEY_LOG_MONSTER_KILL, it->first, it->second); m_map_dwMobKillCount.clear(); } // The test server every 60 seconds to count the number of characters if(g_bIsTestServer && 0 == (iPulse % PASSES_PER_SEC(60))) sys_log(0, "CHARACTER COUNT vid %zu pid %zu", m_map_pkChrByVID.size(), m_map_pkChrByPID.size()); // Delayed DestroyCharacter to FlushPendingDestroy(); }
  19. You and your quests solutions, smh /s Btw it's possible, except this drop should take in consideration a different range table than the original one (you know, the +15/-15).
  20. That random thing is very interesting, I didn't know about such speed improvement (I replaced the number() function with STL implementations. Obviously in a test server environment it doesn't feel slow, but this is a big jump on speed nonetheless. Love it.)
  21. If the problem is in: const TItemAttrTable& r = g_map_itemRare[avail[number(0, avail.size() - 1)]]; that means avail.size() - 1 is less than 0 From my sources (check the fix lines): bool CItem::AddRareAttribute() { int count = GetRareAttrCount(); if(count >= 2) return false; int pos = count + 5; TPlayerItemAttribute & attr = m_aAttr[pos]; int nAttrSet = GetAttributeSetIndex(); std::vector<int> avail; for (int i = 0; i < MAX_APPLY_NUM; ++i) { const TItemAttrTable & r = g_map_itemRare[i]; if(r.dwApplyIndex != 0 && r.bMaxLevelBySet[nAttrSet] > 0 && HasRareAttr(i) != true) { avail.push_back(i); } } //FIX_START if(avail.size() <= 0) return false; //FIX_END const TItemAttrTable& r = g_map_itemRare[avail[number(0, avail.size() - 1)]]; int nAttrLevel = 5; if(nAttrLevel > r.bMaxLevelBySet[nAttrSet]) nAttrLevel = r.bMaxLevelBySet[nAttrSet]; attr.bType = r.dwApplyIndex; attr.sValue = r.lValues[nAttrLevel - 1]; UpdatePacket(); Save(); #ifdef SET_RARE_LOG const char * pszIP = NULL; if(GetOwner() && GetOwner()->GetDesc()) pszIP = GetOwner()->GetDesc()->GetHostName(); LogManager::instance().ItemLog(pos, attr.bType, attr.sValue, GetID(), "SET_RARE", "", pszIP ? pszIP : "", GetOriginalVnum()); #endif return true; }
  22. Download Metin2 Download The files contain the server side and quests example. Video: [Hidden Content] (yes, at the end the Biologist doesn't give me the rewards because I forgot to change a condition in the quest and I didn't wanna try to record it, again) So where is the interface file? I am sorry but I don't have any way to set up an interface for the original sources of the Client. I can share the logic I used: import ui import app import localeInfo import item import colorInfo import net import uiCommon import player import chat class uiResearchWindow(ui.ScriptWindow): BIOLOGIST_QUEST_DICT = { 0 : { 'item_wanted': 30006, 'pct' : 90, 'required': 20 }, 1 : { 'item_wanted': 30055, 'pct' : 90, 'required': 20 }, 2 : { 'item_wanted': 30047, 'pct' : 90, 'required': 20 }, 3 : { 'item_wanted': 30324, 'pct' : 90, 'required': 25 }, 4 : { 'item_wanted': 30015, 'pct' : 90, 'required': 20 }, 5 : { 'item_wanted': 30050, 'pct' : 90, 'required': 25 }, 6 : { 'item_wanted': 30198, 'pct' : 44, 'required': 30 }, 7 : { 'item_wanted': 30166, 'pct' : 42, 'required': 35 }, 8 : { 'item_wanted': 30495, 'pct' : 30, 'required': 15 }, 9 : { 'item_wanted': 100029, 'pct' : 38, 'required': 40 }, 10 : { 'item_wanted': 30329, 'pct' : 36, 'required': 45 }, 11 : { 'item_wanted': 100039, 'pct' : 34, 'required': 50 }, } MAX_ITEM_QUANTITY = 5 PCT_BONUS = 10 PCT_BONUS_PLUS = 30 BIOLOGIST_PCT_ADDER_VNUM = 102529 BIOLOGIST_PCT_ADDER_PLUS_VNUM = 102616 BIOLOGIST_TIME_DELETER_VNUM = 102517 def __init__(self): ui.ScriptWindow.__init__(self) self.remainTime = 0 self.receivedTime = app.GetTime() self.remainTimeText = None self.questID = 0 self.itemRequestedText = None self.pctSuccessText = None self.lastCountDownRefresh = 0 self.itemToDeliverCount = 1 self.itemToDeliverVnum = 0 self.questionDialog = None self.popupDialog = None self.deliveredItemsQty = 0 self.isOpened = False self.LoadWindow() def __del__(self): self.remainTime = 0 self.questID = 0 self.itemRequestedText = None self.pctSuccessText = None self.lastCountDownRefresh = 0 self.itemToDeliverVnum = 0 self.questionDialog = None self.popupDialog = None self.isOpened = False self.tooltipItem = 0 ui.ScriptWindow.__del__(self) def LoadWindow(self): try: PythonScriptLoader = ui.PythonScriptLoader() PythonScriptLoader.LoadScriptFile(self, "UIScript/researchwindow.py") except: import exception exception.Abort("ResearchWindow.LoadWindow.LoadUIScriptFiles") try: self.board = self.GetChild("board") self.remainTimeText = self.GetChild("ItemCDText") self.itemRequestedText = self.GetChild("ItemNametext") self.pctSuccessText = self.GetChild("ItemPctText") self.buttonTimeDeleterUP = self.GetChild("UpButton1") self.itemTimeDeleterTextqty = self.GetChild("ItemSlotbar1Text") self.buttonTimeDeleterDown = self.GetChild("DownButton1") self.buttonElixirUP = self.GetChild("UpButton2") self.buttonElixirTextQty = self.GetChild("ItemSlotbar2Text") self.buttonElixirDown = self.GetChild("DownButton2") self.buttonElixirPlusUP = self.GetChild("UpButton3") self.buttonElixirPlusTextQty = self.GetChild("ItemSlotbar3Text") self.buttonElixirPlusDown = self.GetChild("DownButton3") self.itemWanted = self.GetChild("current_item") self.itemWantedButtonUP = self.GetChild("UpButton0") self.itemWantedButtonText = self.GetChild("ItemSlotbar0Text") self.itemWantedButtonDown = self.GetChild("DownButton0") self.deliverItemButton = self.GetChild("exam_button") self.deliveredItemsText = self.GetChild("textItemDeliverdQty") self.notifySlot = self.GetChild("NotifySlot") self.elixirSlot = self.GetChild("elisir_10_slot") self.elixirPlusSlot = self.GetChild("elisir_30_slot") self.timeDeleterSlot = self.GetChild("time_deleter_slot") except: import exception exception.Abort("ResearchWindow.LoadWindow.BindObject") self.board.SetCloseEvent(ui.__mem_func__(self.Close)) self.buttonTimeDeleterUP.SAFE_SetEvent(self.__OnClickButtonTimeDeleterUP) self.buttonTimeDeleterDown.SAFE_SetEvent(self.__OnClickButtonTimeDeleterDown) self.buttonElixirUP.SAFE_SetEvent(self.__OnClickbuttonElixirUP) self.buttonElixirDown.SAFE_SetEvent(self.__OnClickbuttonElixirDown) self.buttonElixirPlusUP.SAFE_SetEvent(self.__OnClickbuttonElixirPlusUP) self.buttonElixirPlusDown.SAFE_SetEvent(self.__OnClickbuttonElixirPlusDown) self.itemWantedButtonUP.SAFE_SetEvent(self.__OnClickButtonItemWantedUP) self.itemWantedButtonDown.SAFE_SetEvent(self.__OnClickButtonItemWantedDown) self.deliverItemButton.SAFE_SetEvent(self.__OnClickDeliverButton) item.SelectItem(self.BIOLOGIST_PCT_ADDER_VNUM) itemName = item.GetItemName() self.pctAdderName = itemName item.SelectItem(self.BIOLOGIST_PCT_ADDER_PLUS_VNUM) itemName = item.GetItemName() self.pctAdderPlusName = itemName item.SelectItem(self.BIOLOGIST_TIME_DELETER_VNUM) itemName = item.GetItemName() self.timeDeleterName = itemName def SendDeliverPacket(self): net.SendBiologistManagerDeliverCommand(self.questID, self.itemToDeliverCount,\ int(self.buttonElixirTextQty.GetText()), int(self.buttonElixirPlusTextQty.GetText()),\ int(self.itemTimeDeleterTextqty.GetText())) def CanSendRequest(self): elixirPlayerCount = player.GetItemCountByVnum(self.BIOLOGIST_PCT_ADDER_VNUM) elixirPlusPlayerCount = player.GetItemCountByVnum(self.BIOLOGIST_PCT_ADDER_PLUS_VNUM) timeDeleterPlayerCount = player.GetItemCountByVnum(self.BIOLOGIST_TIME_DELETER_VNUM) itemToDeliverPlayerCount = player.GetItemCountByVnum(self.itemToDeliverVnum) if self.itemToDeliverCount > itemToDeliverPlayerCount or \ int(self.buttonElixirTextQty.GetText()) > elixirPlayerCount or\ int(self.buttonElixirPlusTextQty.GetText()) > elixirPlusPlayerCount or\ int(self.itemTimeDeleterTextqty.GetText()) > timeDeleterPlayerCount: self.popupDialog = uiCommon.PopupDialog() self.popupDialog.SetText(localeInfo.BIOLOGIST_MANAGER_OVERFLOW_ERROR) self.popupDialog.SetAcceptEvent(self.__OnClosePopupDialog) self.popupDialog.Open() return False elif self.GetRemainTime() > 0 and int(self.itemTimeDeleterTextqty.GetText()) <= 0: self.popupDialog = uiCommon.PopupDialog() self.popupDialog.SetText(localeInfo.BIOLOGIST_MANAGER_TIME_ERROR) self.popupDialog.SetAcceptEvent(self.__OnClosePopupDialog) self.popupDialog.Open() else: return True def __OnClickDeliverButton(self): if self.pct > 100: self.questionDialog = uiCommon.QuestionDialog() self.questionDialog.Open() self.questionDialog.SetText(localeInfo.BIOLOGIST_MANAGER_CHECK_PCT) self.questionDialog.SetAcceptText(localeInfo.UI_ACCEPT) self.questionDialog.SetCancelText(localeInfo.UI_DENY) self.questionDialog.SetAcceptEvent(lambda arg = True: self.QuestionDialogAnswer(arg)) self.questionDialog.SetCancelEvent(lambda arg = False: self.QuestionDialogAnswer(arg)) self.questionDialog.SetTop() else: if self.CanSendRequest() == True: self.SendDeliverPacket() def __OnClosePopupDialog(self): self.popupDialog = None def QuestionDialogAnswer(self, answer): if not self.questionDialog: return if answer == True: if self.CanSendRequest() == True: self.SendDeliverPacket() self.questionDialog.Close() self.questionDialog = None def __OnClickButtonItemWantedUP(self): if self.itemToDeliverCount >= self.MAX_ITEM_QUANTITY: chat.AppendChat(chat.CHAT_TYPE_INFO, localeInfo.BIOLOGIST_MANAGER_ITEMS_OVERFLOW % (str(self.MAX_ITEM_QUANTITY), self.itemName)) return if self.itemToDeliverCount + 1 > player.GetItemCountByVnum(self.itemToDeliverVnum): chat.AppendChat(chat.CHAT_TYPE_INFO, localeInfo.BIOLOGIST_manager_NOT_ENOUGH_ITEMS % (str(self.MAX_ITEM_QUANTITY), self.itemName)) return self.itemToDeliverCount += 1 self.itemWantedButtonText.SetText(str(self.itemToDeliverCount)) def __OnClickButtonItemWantedDown(self): if self.itemToDeliverCount <= 1: return self.itemToDeliverCount -= 1 self.itemWantedButtonText.SetText(str(self.itemToDeliverCount)) def __OnClickButtonTimeDeleterUP(self): number = int(self.itemTimeDeleterTextqty.GetText()) if number >= self.MAX_ITEM_QUANTITY: chat.AppendChat(chat.CHAT_TYPE_INFO, localeInfo.BIOLOGIST_MANAGER_ITEMS_OVERFLOW % (str(self.MAX_ITEM_QUANTITY), self.timeDeleterName)) return if number + 1 > player.GetItemCountByVnum(self.BIOLOGIST_TIME_DELETER_VNUM): chat.AppendChat(chat.CHAT_TYPE_INFO, localeInfo.BIOLOGIST_manager_NOT_ENOUGH_ITEMS % (str(self.MAX_ITEM_QUANTITY), self.timeDeleterName)) return self.itemTimeDeleterTextqty.SetText(str(number+1)) self.UpdatePct() def __OnClickButtonTimeDeleterDown(self): number = int(self.itemTimeDeleterTextqty.GetText()) if number <= 0: return self.itemTimeDeleterTextqty.SetText(str(number-1)) self.UpdatePct() def __OnClickbuttonElixirUP(self): number = int(self.buttonElixirTextQty.GetText()) if number >= self.MAX_ITEM_QUANTITY: chat.AppendChat(chat.CHAT_TYPE_INFO, localeInfo.BIOLOGIST_MANAGER_ITEMS_OVERFLOW % (str(self.MAX_ITEM_QUANTITY), self.pctAdderName)) return if number + 1 > player.GetItemCountByVnum(self.BIOLOGIST_PCT_ADDER_VNUM): chat.AppendChat(chat.CHAT_TYPE_INFO, localeInfo.BIOLOGIST_manager_NOT_ENOUGH_ITEMS % (str(self.MAX_ITEM_QUANTITY), self.pctAdderName)) return self.buttonElixirTextQty.SetText(str(number+1)) self.UpdatePct() def __OnClickbuttonElixirDown(self): number = int(self.buttonElixirTextQty.GetText()) if number <= 0: return self.buttonElixirTextQty.SetText(str(number-1)) self.UpdatePct() def __OnClickbuttonElixirPlusUP(self): number = int(self.buttonElixirPlusTextQty.GetText()) if number >= self.MAX_ITEM_QUANTITY: chat.AppendChat(chat.CHAT_TYPE_INFO, localeInfo.BIOLOGIST_MANAGER_ITEMS_OVERFLOW % (str(self.MAX_ITEM_QUANTITY), self.pctAdderPlusName)) return if number + 1 > player.GetItemCountByVnum(self.BIOLOGIST_PCT_ADDER_PLUS_VNUM): chat.AppendChat(chat.CHAT_TYPE_INFO, localeInfo.BIOLOGIST_manager_NOT_ENOUGH_ITEMS % (str(self.MAX_ITEM_QUANTITY), self.pctAdderPlusName)) return self.buttonElixirPlusTextQty.SetText(str(number+1)) self.UpdatePct() def __OnClickbuttonElixirPlusDown(self): number = int(self.buttonElixirPlusTextQty.GetText()) if number <= 0: return self.buttonElixirPlusTextQty.SetText(str(number-1)) self.UpdatePct() def GetRemainTime(self): return self.remainTime - (app.GetTime() - self.receivedTime) def ResearchRequestInfo(self, deliversCounter, successDeliveries, failedDeliveries, timeDeleterUses, elixirUses, elixirPlusUses, remainingTime): self.remainTime = remainingTime self.deliveredItemsQty += successDeliveries self.deliveredItemsText.SetText(str(self.deliveredItemsQty) + "/" + str(self.BIOLOGIST_QUEST_DICT[self.questID]['required'])) self.itemWanted.SetItemSlot(0, self.itemToDeliverVnum, player.GetItemCountByVnum(self.itemToDeliverVnum)) text = "" if failedDeliveries == 1: text = localeInfo.BIOLOGIST_SYSTEM_MESSAGE_SINGLE_FAIL % (deliversCounter, self.itemName, successDeliveries, failedDeliveries, self.pctAdderName, elixirUses, self.pctAdderPlusName, elixirPlusUses, self.timeDeleterName, timeDeleterUses) else: text = localeInfo.BIOLOGIST_SYSTEM_MESSAGE_MULTIPLE_FAIL % (deliversCounter, self.itemName, successDeliveries, failedDeliveries, self.pctAdderName, elixirUses, self.pctAdderPlusName, elixirPlusUses, self.timeDeleterName, timeDeleterUses) self.multiHolder = ui.GenerateMultiLine(self.notifySlot, text, 300, colorInfo.GOLD) for i in self.multiHolder: totalH = self.multiHolder[0].GetTextSize()[1] * len(self.multiHolder) + 3 * (len(self.multiHolder) - 1) i.SetPosition(3, 80 / 2 - totalH / 2 + 3 * self.multiHolder.index(i) + i.GetTextSize()[1] * self.multiHolder.index(i)) self.UpdateSlots() def UpdateInfo(self, questID, remain_time, deliveredItems): self.remainTime = remain_time self.questID = questID self.itemToDeliverVnum = self.BIOLOGIST_QUEST_DICT[questID]['item_wanted'] self.deliveredItemsQty = deliveredItems self.deliveredItemsText.SetText(str(self.deliveredItemsQty) + "/" + str(self.BIOLOGIST_QUEST_DICT[self.questID]['required'])) item.SelectItem(self.itemToDeliverVnum) self.itemName = item.GetItemName() self.itemRequestedText.SetText(self.itemName) self.itemWanted.SetItemSlot(0, self.itemToDeliverVnum, player.GetItemCountByVnum(self.itemToDeliverVnum)) self.UpdatePct() self.UpdateTimer() def UpdatePct(self): elixir_qty = int(self.buttonElixirTextQty.GetText()) elixir_plus_qty = int(self.buttonElixirPlusTextQty.GetText()) if elixir_qty > 0 and elixir_plus_qty > 0: self.pct = self.BIOLOGIST_QUEST_DICT[self.questID]['pct'] + self.PCT_BONUS + self.PCT_BONUS_PLUS elif elixir_qty > 0: self.pct = self.BIOLOGIST_QUEST_DICT[self.questID]['pct'] + self.PCT_BONUS elif elixir_plus_qty > 0: self.pct = self.BIOLOGIST_QUEST_DICT[self.questID]['pct'] + self.PCT_BONUS_PLUS elif elixir_qty <= 0 and elixir_plus_qty <= 0: self.pct = self.BIOLOGIST_QUEST_DICT[self.questID]['pct'] elif elixir_qty <= 0: self.pct -= self.PCT_BONUS elif elixir_plus_qty <= 0: self.pct -= self.PCT_BONUS_PLUS self.pctSuccessText.SetText(str(self.pct) + "%") def OnUpdate(self): if app.GetTime() <= self.lastCountDownRefresh + 1.0: return self.lastCountDownRefresh = app.GetTime() self.UpdateTimer() def UpdateTimer(self): remain_time = self.GetRemainTime() if remain_time <= 0: self.remainTimeText.SetPackedFontColor(colorInfo.GREEN) self.remainTimeText.SetText(localeInfo.BIOLOGIST_MANAGER_CAN_DELIVER) else: self.remainTimeText.SetPackedFontColor(colorInfo.RED) self.remainTimeText.SetText("%s" % (str(localeInfo.SecondsToClock(remain_time)))) def SetItemToolTip(self, tooltipItem): self.tooltipItem = tooltipItem def OverInItem(self, itemVnum): if not self.tooltipItem: return self.tooltipItem.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, 0)) realValue = [] for i in range(player.REAL_VALUES_MAX_NUM): realValue.append(0) self.tooltipItem.AddItemData(itemVnum, metinSlot, attrSlot, realValue) def OverOutItem(self): if 0 != self.tooltipItem: self.tooltipItem.HideToolTip() def UpdateSlots(self): self.elixirSlot.SetItemSlot(0, self.BIOLOGIST_PCT_ADDER_VNUM, player.GetItemCountByVnum(self.BIOLOGIST_PCT_ADDER_VNUM)) self.elixirPlusSlot.SetItemSlot(0, self.BIOLOGIST_PCT_ADDER_PLUS_VNUM, player.GetItemCountByVnum(self.BIOLOGIST_PCT_ADDER_PLUS_VNUM)) self.timeDeleterSlot.SetItemSlot(0, self.BIOLOGIST_TIME_DELETER_VNUM, player.GetItemCountByVnum(self.BIOLOGIST_TIME_DELETER_VNUM)) self.itemWanted.SetItemSlot(0, self.itemToDeliverVnum, player.GetItemCountByVnum(self.itemToDeliverVnum)) def SetSlotsEvents(self): self.elixirSlot.SetEvent(ui.SLOT_OVER_IN_ITEM, self.OverInItem, self.BIOLOGIST_PCT_ADDER_VNUM) self.elixirPlusSlot.SetEvent(ui.SLOT_OVER_IN_ITEM, self.OverInItem, self.BIOLOGIST_PCT_ADDER_PLUS_VNUM) self.timeDeleterSlot.SetEvent(ui.SLOT_OVER_IN_ITEM, self.OverInItem, self.BIOLOGIST_TIME_DELETER_VNUM) self.elixirSlot.SetEvent(ui.SLOT_OVER_OUT_ITEM, self.OverOutItem) self.elixirPlusSlot.SetEvent(ui.SLOT_OVER_OUT_ITEM, self.OverOutItem) self.timeDeleterSlot.SetEvent(ui.SLOT_OVER_OUT_ITEM, self.OverOutItem) self.itemWanted.SetEvent(ui.SLOT_OVER_IN_ITEM, self.OverInItem, self.itemToDeliverVnum) self.itemWanted.SetEvent(ui.SLOT_OVER_OUT_ITEM, self.OverOutItem) def Open(self, questID, remainTime, deliveredItems): self.UpdateInfo(questID, remainTime, deliveredItems) self.UpdateSlots() self.SetSlotsEvents() self.Show() self.isOpened = True def IsOpened(self): return self.isOpened def Close(self, isOpened = True): if self.tooltipItem: self.tooltipItem.ClearToolTip() self.isOpened = isOpened self.Hide() def Destroy(self): self.ClearDictionary() if self.tooltipItem: self.tooltipItem.ClearToolTip() self.remainTime = 0 self.remainTimeText = None self.questID = 0 self.itemRequestedText = None self.pctSuccessText = None self.lastCountDownRefresh = 0 self.itemToDeliverVnum = 0 self.questionDialog = None self.tooltipItem = 0 self.popupDialog = None def OnPressEscapeKey(self): self.Close() return True Don't just copy and paste it, it won't work because of: realValue = [] for i in range(player.REAL_VALUES_MAX_NUM): realValue.append(0) self.tooltipItem.AddItemData(itemVnum, metinSlot, attrSlot, realValue) or the whole SetSlotsEvents function: def SetSlotsEvents(self): self.elixirSlot.SetEvent(ui.SLOT_OVER_IN_ITEM, self.OverInItem, self.BIOLOGIST_PCT_ADDER_VNUM) self.elixirPlusSlot.SetEvent(ui.SLOT_OVER_IN_ITEM, self.OverInItem, self.BIOLOGIST_PCT_ADDER_PLUS_VNUM) self.timeDeleterSlot.SetEvent(ui.SLOT_OVER_IN_ITEM, self.OverInItem, self.BIOLOGIST_TIME_DELETER_VNUM) self.elixirSlot.SetEvent(ui.SLOT_OVER_OUT_ITEM, self.OverOutItem) self.elixirPlusSlot.SetEvent(ui.SLOT_OVER_OUT_ITEM, self.OverOutItem) self.timeDeleterSlot.SetEvent(ui.SLOT_OVER_OUT_ITEM, self.OverOutItem) self.itemWanted.SetEvent(ui.SLOT_OVER_IN_ITEM, self.OverInItem, self.itemToDeliverVnum) self.itemWanted.SetEvent(ui.SLOT_OVER_OUT_ITEM, self.OverOutItem) If you make one, please feel free to share, I'll update the topic and give you credits. Why do you require to go back to the biologist instead of doing everything from the interface? Two reasons: it's based on my server where we want the player to go back to the biologist. there's already people selling that type of interface, if you so prefer The system requires c++20 (serverside) But I have C++17, what do I do then? Remove the constness from std::array(older version) and std::view_string, therefore even on the loop(older version): for(const auto& val : BiologistQuestNames) //here remove const { if(IsQuestStatusFindItem(ch, val) == true){ SendBiologistManagerOpenCommand(ch, iterVal); return true; } ++iterVal; } But I have C++14/C+11, what do I do then? Remove std::view_string and use either std::string or const char* and replace: utils::view_to_string(BiologistQuestStateCollect); with whatever is the way to convert a const char* to std::string (if you use const char*) [Hidden Content] Remove also the namespace on top: //TO REMOVE namespace utils{ std::string string_view_concat(std::string_view a, std::string_view b){ std::string rv(a.size() + b.size(), '\0'); std::copy(b.begin(), b.end(), std::copy(a.begin(), a.end(), rv.begin())); return rv; } std::string view_to_string(std::string_view a){ std::string st = {a.begin(), a.end()}; return st; } } the concat function can be replaced with the + operator (both have to be strings, not const* char): std::string new_string = old_string + string_to_concat; I still use C++98/03 Don't bother downloading these files. I want to set the cooldown even when some one fails, not only on success, how can I do that? Replace: else{ //set cooldown for success delivery pPC->SetFlag(timerFlag, get_global_time() + BiologistQuestCooldowns.at(questID)); ++successDeliveries; } } else{ //fail, but we don't set the cooldown for failing itemToDeliver->SetCount(itemToDeliver->GetCount() - 1); //remove the item to deliver pPC->SetFlag(timerFlag, 0); ++failedDeliveries; } with: else{ //set cooldown for success delivery pPC->SetFlag(timerFlag, get_global_time() + BiologistQuestCooldowns.at(questID)); ++successDeliveries; } } else{ //fail, but we don't set the cooldown for failing itemToDeliver->SetCount(itemToDeliver->GetCount() - 1); //remove the item to deliver pPC->SetFlag(timerFlag, get_global_time() + BiologistQuestCooldowns.at(questID)); ++failedDeliveries; } What if I don't wanna use elixirs, time deleter or something else? Try yourself first, if you encounter any error during your endeavour, just ask (don't be afraid to ask, people might help you). Why the double checks in the client AND the server????? I'll never forget: "what if they craft the packet?" "...fudge. Unlikely, but you are right." Is it bug free??? I'll never make such claims, if you find some, please report them
  23. Yeah, having someone who's worked on skills/effects/etc for years comes in handy, we've had this fix since ~2014
×
×
  • Create New...

Important Information

Terms of Use / Privacy Policy / Guidelines / We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.