-
Posts
14 -
Joined
-
Last visited
-
Feedback
0%
Grzyb's Achievements
-
Grzyb changed their profile photo
-
New Video V0.1 & V0.2 [previous videos deleted] New Version *[V0.3]* Fixed various new and annoying bugs related to objects, including their height, rotation, and other parameters. Added the ability to replace a selected terrain texture with a single click. Implemented undo/redo for terrain painting using Ctrl + Z / Y. Fixed the issue of “floating” objects (such as grass) on uneven terrain objects now automatically adjust to the surface. Fixed the jumping slider that was making work difficult. Removed the bug that caused setting.txt to be overwritten, so saving the map no longer modifies your custom values. Added the ability to edit the height of all selected objects at once. Improved mass object rotation rotating multiple objects on the Z axis no longer disrupts their arrangement. Added a dedicated rotation function for groups to keep their original layout. Fixed the texture selection offset in the Texture Name field the highlighted texture now always matches the correct name. Improved editing of the Height Bias field, allowing stable input without automatic value resets. Added a preview of all property objects, making it easier to quickly find suitable items for the map. Fixed the property object search function. Added a new "Keep Original Height" feature. Introduced a completely new Property Viewer window, allowing quick browsing of objects, trees, and other items, fast scrolling, and easy placement on the map. Improved map loading. I dont want to spam the thread with more posts, and editing existing ones isn’t possible. I’ve completed most of the planned changes, so version 0.4 may not be released for another six months. For now, I’m pausing development due to lack of time. All videos show World Editor are available on YouTube (2 videos).
-
[Version 0.2 BETA] Temporarily removed the black color which was causing strange problems with the application Fixed loading of large files Fixed water drawing and undoing water with ctrl + z Added new water drawing function as a circle instead of a square Removed annoying messages Moving placed objects no longer changes the object's height Added the ability to manually enter values at the slider When you select an object and press the "M" key, a new window pops up where you can replace all object properties with others or remove them all at once from the entire map Fixed a specific problem with moving objects Fixed copying CRC in "Object Info" Removed the annoying "Create Property" window Added a new window enabling adding objects to a favorites list. The list is saved locally (e.g., in a .txt file), so favorite objects remain available after restarting the application. Introduced recently used objects history - the application remembers up to 30 recent items that can be quickly reopened from the new history window. Fixed Map Sorter and folders like "daimao, realis" - the application now automatically detects folders or other file names from different creators Removed some unused code and functions that nobody needed Fixed several other minor issues reported by testers (Less important)
-
project is in the process of being created and every now and then something new is added, for example now there is copying objects via ctrl + c and ctrl + v ok, I understand, it makes sense I have 2/3 discord accounts, I tried but always no response, I even offered money ;D but chill, no problem. Wooow, this looks better than my project, amazing not at the moment, its during testing. I mainly want the application to be as automated as possible so that it takes as little time as possible when creating a new map, everything that makes the work easier, even by 1 second, will be added
-
I was always annoyed that it was Martysama who fixed the project, but he never shared the source code. Because of that, people creating maps have had a harder time, as everything is stuck, buggy, difficult to use, and hasn’t been fixed for many years (Marty himself probably stopped doing anything at all). That’s why I decided to create my own map editor – to eliminate bugs and make mappers’ work easier. **[V0.1]** - Fixed all the annoying object-related bugs. - Fixed bugs related to camera control. - Added visibility for gr2 animations (objects). - Objects now automatically adjust their height to the terrain. - Improved selecting and moving trees. - Fixed the issue with disappearing open folders in the property panel. - Ability to move multiple objects at once (e.g., a flag made of several parts, the fountain in M1) without breaking the original objects. - Ability to move multiple objects up and down at once. - Added a search function in the property panel. - Added autobackup with a customizable timer – backups are created as timestamped folders, so you can go back even an hour of work; every 1/5/15 minutes a new folder is created with the current state. - Fixed the overly fast slider speed. - Changed the GUI look to dark (black). - Introduced a completely new and stable Map Sorter (works better than all other versions, doesn’t lose files, captures .dds/.tga/.png/custom folders – basically everything map-related without any issues or bugs). - The entire map now loads instantly with “Load” = no lag when moving around since everything is already loaded. - Added the “B” and “N” keys to add objects to a blacklist, making it easier to select elements located under others. - Improved logs when selecting multiple objects – now when selecting e.g. 100 elements, detailed information about each one is displayed. - Removed unnecessary functions that nobody used. - Rewritten map coordinate handling and fixed the “Go” button – now it finally works like in the original Metin2. - Updated DirectX8 to DirectX9. - Updated the code to C++23. - The application now opens centered on the screen at 1920x1080 resolution. - Added Ctrl+Z / Ctrl+Y shortcuts for “Water Brush (Add/Remove)”. - Fixed Water Brush functionality and all related bugs. - Environment is now automatically detected from folders, and changing it takes a second – “just scroll”. **(Coming soon)** - Support for Jettyx shaders. - All other bugs or crashes reported by testers. The current version is being tested by the first mappers from Poland, and how the future of the project unfolds will be revealed in time. I have a question for you – do you want the application to be paid or completely free? And what features would be most useful for you? Let me know in the comments!
- 20 replies
-
- 78
-
-
-
-
-
-
-
-
I did a job for someone once, and when I saw Mali's code from 2020, I was stunned by how many unnecessary packets and lines of code it sends. locale_game.txt NEW_KOMUNIKAT1 Testowy Komunikat Jeden NEW_KOMUNIKAT2 Testowy Komunikat Dwa NEW_KOMUNIKAT3 Testowy Komunikat Trzy NEW_KOMUNIKAT4 Testowy Komunikat Cztery NEW_KOMUNIKAT5 Testowy Komunikat Piec NEW_KOMUNIKAT6 Testowy Komunikat Szesc ui.py class MiddleBoard(Window): CORNER_WIDTH = 16 CORNER_HEIGHT = 16 LINE_WIDTH = 16 LINE_HEIGHT = 16 LT = 0 LB = 1 RT = 2 RB = 3 L = 0 R = 1 T = 2 B = 3 def __init__(self, layer = "UI"): Window.__init__(self, layer) CornerFileNames = [ "d:/ymir work/ui/pattern/ThinBoard_Corner_"+dir+".tga" for dir in ["LeftTop","LeftBottom","RightTop","RightBottom"] ] LineFileNames = [ "d:/ymir work/ui/pattern/ThinBoard_Line_"+dir+".tga" for dir in ["Left","Right","Top","Bottom"] ] Base = ExpandedImageBox() Base.AddFlag("not_pick") Base.LoadImage("d:/ymir work/ui/cien.png") Base.SetParent(self) Base.SetPosition(self.CORNER_WIDTH, self.CORNER_HEIGHT) Base.Show() self.Base = Base self.Corners = [] for fileName in CornerFileNames: Corner = ExpandedImageBox() Corner.AddFlag("attach") Corner.AddFlag("not_pick") Corner.LoadImage(fileName) Corner.SetParent(self) Corner.SetPosition(0, 0) Corner.Show() self.Corners.append(Corner) self.Lines = [] for fileName in LineFileNames: Line = ExpandedImageBox() Line.AddFlag("attach") Line.AddFlag("not_pick") Line.LoadImage(fileName) Line.SetParent(self) Line.SetPosition(0, 0) Line.Show() self.Lines.append(Line) self.Lines[self.L].SetPosition(0, self.CORNER_HEIGHT) self.Lines[self.T].SetPosition(self.CORNER_WIDTH, 0) def __del__(self): Window.__del__(self) def SetSize(self, width, height): width = max(self.CORNER_WIDTH*2, width) height = max(self.CORNER_HEIGHT*2, height) Window.SetSize(self, width, height) self.Corners[self.LB].SetPosition(0, height - self.CORNER_HEIGHT) self.Corners[self.RT].SetPosition(width - self.CORNER_WIDTH, 0) self.Corners[self.RB].SetPosition(width - self.CORNER_WIDTH, height - self.CORNER_HEIGHT) self.Lines[self.R].SetPosition(width - self.CORNER_WIDTH, self.CORNER_HEIGHT) self.Lines[self.B].SetPosition(self.CORNER_HEIGHT, height - self.CORNER_HEIGHT) verticalShowingPercentage = float((height - self.CORNER_HEIGHT*2) - self.LINE_HEIGHT) / self.LINE_HEIGHT horizontalShowingPercentage = float((width - self.CORNER_WIDTH*2) - self.LINE_WIDTH) / self.LINE_WIDTH self.Lines[self.L].SetRenderingRect(0, 0, 0, verticalShowingPercentage) self.Lines[self.R].SetRenderingRect(0, 0, 0, verticalShowingPercentage) self.Lines[self.T].SetRenderingRect(0, 0, horizontalShowingPercentage, 0) self.Lines[self.B].SetRenderingRect(0, 0, horizontalShowingPercentage, 0) if self.Base: self.Base.SetRenderingRect(0, 0, (float(width)-32)/float(self.Base.GetWidth()) - 1.0, (float(height)-32)/float(self.Base.GetHeight()) - 1.0) def ShowInternal(self): self.Base.Show() for wnd in self.Lines: wnd.Show() for wnd in self.Corners: wnd.Show() def HideInternal(self): self.Base.Hide() for wnd in self.Lines: wnd.Hide() for wnd in self.Corners: wnd.Hide() and elif Type == "middleboard": parent.Children[Index] = MiddleBoard() parent.Children[Index].SetParent(parent) self.LoadElementThinBoard(parent.Children[Index], ElementValue, parent) introloading.py add import: import background import random Find: self.loadingGage=self.GetChild("FullGage") add after: self.loadingTip2=self.GetChild("LoadingTip") Find: def LoadData(self, playerX, playerY): and add: def LoadData(self, playerX, playerY): grzybovh = [ localeInfo.NEW_KOMUNIKAT1, localeInfo.NEW_KOMUNIKAT2, ] grzybovh2 = [ localeInfo.NEW_KOMUNIKAT3, localeInfo.NEW_KOMUNIKAT4, ] grzybovh3 = [ localeInfo.NEW_KOMUNIKAT5, localeInfo.NEW_KOMUNIKAT6, ] #Here you can add any maps, names from atlasinfo if background.GetCurrentMapName() == "metin2_map_a1": self.loadingTip2.SetText(random.choice(grzybovh)) elif background.GetCurrentMapName() == "metin2_map_c1": self.loadingTip2.SetText(random.choice(grzybovh2)) else: self.loadingTip2.SetText(random.choice(grzybovh3)) uiscript/introloading.py { "name": "TipBackground", "type": "middleboard", "x": float(SCREEN_WIDTH) / 2 - (SCREEN_WIDTH / 4), "y": float(SCREEN_HEIGHT) * 500 / 600.0 - 50, "width": SCREEN_WIDTH / 2, "height": 50, "children": [ { "name": "LoadingTip", "type": "text", "x": float(SCREEN_WIDTH) / 4, "y": 16, "text": " ", "text_horizontal_align": "center", "fontsize": "LARGE", }, ], },
-
@MT2Dev@ martysama0134@ masodikbela Very strange solutions, the main problem is void ITEM_MANAGER::Update() function in item_manager.cpp when you fix this function, you fix this problem exploit without MoveItem
-
Block 2 items with type 33
Grzyb replied to JarajTo's topic in Community Support - Questions & Answers
My new fix 100% work: if (item->GetType() == ITEM_RING) { std::vector<LPITEM> FixByMuchomor = { GetWear(WEAR_RING1), GetWear(WEAR_RING2) }; const int FixByMuchomorSize = FixByMuchomor.size(); for (int i = 0; i < FixByMuchomorSize; i++) { if (FixByMuchomor[i]) { if (FixByMuchomor[i]->GetVnum() == item->GetVnum() || FixByMuchomor[i]->GetSubType() == item->GetSubType()) { ChatPacket(CHAT_TYPE_INFO, "Nie możesz założyć tego przedmiotu dwa razy!"); return false; } } } } -
Block 2 "Ring" types with the same Vnum
Grzyb replied to Veneno's topic in Community Support - Questions & Answers
My new fix 100% work: if (item->GetType() == ITEM_RING) { std::vector<LPITEM> FixByMuchomor = { GetWear(WEAR_RING1), GetWear(WEAR_RING2) }; const int FixByMuchomorSize = FixByMuchomor.size(); for (int i = 0; i < FixByMuchomorSize; i++) { if (FixByMuchomor[i]) { if (FixByMuchomor[i]->GetVnum() == item->GetVnum() || FixByMuchomor[i]->GetSubType() == item->GetSubType()) { ChatPacket(CHAT_TYPE_INFO, "Nie możesz założyć tego przedmiotu dwa razy!"); return false; } } } } -
Video: Code: # The script automatically translates the drop from mob_drop_item.txt and special_item_group.txt files, utilizing the information in the locale_name.txt file import chardet import codecs def detect_encoding(filename): with open(filename, 'rb') as f: result = chardet.detect(f.read()) return result['encoding'] with codecs.open('item_names.txt', 'r', encoding='cp1250') as source_file: contents = source_file.read() with codecs.open('item_names_utf8.txt', 'w', encoding='utf-8') as target_file: target_file.write(contents) with open('item_names_utf8.txt', 'r', encoding='utf-8') as f: item_names = {} for line in f: if 'VNUM' in line or 'LOCALE_NAME' in line: continue vnum, name = line.strip().split('\t') item_names[vnum] = name drop_cpp_encoding = detect_encoding('drop.txt') with open('drop.txt', 'r', encoding=drop_cpp_encoding) as f: lines = f.readlines() new_lines = [] for line in lines: if line.startswith('Group') or 'exp' in line: new_lines.append(line) else: parts = line.split('\t') if len(parts) > 2 and parts[2] in item_names: line = line.rstrip() + ' // ' + item_names[parts[2]] + '\n' new_lines.append(line) with open('drop2.txt', 'w', encoding='utf-8') as f: f.writelines(new_lines)
-
Video: Code: def convert_to_quest(input_text, quest_name, state_name, npc_id, chat_option): quest_code = f"quest {quest_name} begin\n\tstate {state_name} begin\n\t\twhen {npc_id}.chat.\"{chat_option}\" begin\n" lines = input_text.split('\n') indentation_level = 0 for line in lines: stripped_line = line.strip() if stripped_line.startswith("end"): indentation_level -= 1 stripped_line = stripped_line.replace(" (", "(").replace(" )", ")") stripped_line = stripped_line.replace(" . ", ".") stripped_line = stripped_line.replace(' "', '"') indent = '\t' * (3 + indentation_level) quest_code += f"{indent}{stripped_line}\n" if stripped_line.startswith(("if", "while", "for")) and "end" not in stripped_line: indentation_level += 1 quest_code += "\t\tend\n\tend\nend" return quest_code def process_script_file(script_file_name, quest_name, state_name, npc_id, chat_option): with open(script_file_name, 'r', encoding='latin1') as f: input_text = f.read() quest_code = convert_to_quest(input_text, quest_name, state_name, npc_id, chat_option) quest_file_name = script_file_name.replace('.script', '.quest') with open(quest_file_name, 'w', encoding='latin1') as f: f.write(quest_code) process_script_file('marriage_manage.start.0.script', 'weeding', 'start', 20358, 'Oldwoman')
-
Video: Code: import os import shutil source_folder = '/txt/src' target_folder = '/txt/src2' if not os.path.exists(target_folder): os.makedirs(target_folder) ifdef = '#ifdef ' ifndef = '#ifndef ' define = 'ENABLE_SWITCHBOT' def process_files(source_folder, target_folder): for entry in os.scandir(source_folder): if entry.is_file() and entry.name.endswith(('.cpp', '.h')): with open(entry.path, 'r', encoding='latin1') as file: new_file = None copy = False lines = file.readlines() line_num = 0 for line in lines: if ifdef + define in line or ifndef + define in line: copy = True if not new_file: new_file = open(os.path.join(target_folder, entry.name), 'w', encoding='latin1') for i in range(max(0, line_num - 30), line_num): new_file.write(lines[i]) if copy: new_file.write(line) if '#endif' in line: if copy: new_file.write("\n // =================== INNA FUNKCJA ================= \n \n") new_file.write("// ====== WYSZUKAJ: ") new_file.write(define) new_file.write("\n// Tutorial wygenerowany automatycznie przez Grzyb.ovh \n") new_file.write("\n \n") copy = False line_num += 1 if new_file: new_file.close() elif entry.is_dir(): new_target_folder = os.path.join(target_folder, entry.name) if not os.path.exists(new_target_folder): os.makedirs(new_target_folder) process_files(entry.path, new_target_folder) process_files(source_folder, target_folder)
-
Script for scanning and automatically removing definitions Remove.cpp import os folder_path = '/txt/src' encoding = 'latin1' definition_to_remove = '#ifdef __ENABLE_OFFLINE_SHOP__' for root, dirs, files in os.walk(folder_path): for file in files: if file.endswith('.cpp') or file.endswith('.h'): file_path = os.path.join(root, file) with open(file_path, 'r', encoding=encoding) as f: lines = f.readlines() with open(file_path, 'w', encoding=encoding) as f: remove_lines = False for line in lines: if definition_to_remove in line: remove_lines = True if remove_lines: if '#endif' in line: remove_lines = False continue f.write(line) Remove if app. import os directory = '/txt/src' encoding = 'latin1' target_if = 'if app.ENABLE_OFFLINE_SHOP:' for filename in os.listdir(directory): if filename.endswith('.py'): filepath = os.path.join(directory, filename) with open(filepath, 'r', encoding=encoding) as f: lines = f.readlines() with open(filepath, 'w', encoding=encoding) as f: in_target_block = False target_indent = 0 for line in lines: indent = len(line) - len(line.lstrip()) if target_if in line: in_target_block = True target_indent = indent elif in_target_block and indent > target_indent: continue else: in_target_block = False f.write(line)

