Jump to content


Popular Content

Showing most liked content since 02/02/2014 in all areas

  1. 150 points
    Hello metin2dev, Vanilla project is a project where I'm going to modify the source code just to enhance the capabilities of the gamecore, add small new stuff, bugfixing and making it more comfortable to use. Some of the goals are more performance and lesser dependencies on dif-files. This project reached a level where it's easy to use and offers tons of new features. Many bugs and exploits are fixed. Additionally, this gamefile is the only one released for everyone that's having so much features and still allows you to customize them to your needs! There are a lot of CONFIG-options where you can enable/disable systems and even tune them to your needs. You won't need difs anymore, you can just configure the gamefile as you want! It's the only gamefile released that's compiled with newer libraries and gcc 4.9.1 with even more optimization to enhance the speed and lower the file size of the gamefile. Also this game has the package-system disabled by default and lets you run the dbcache from mysql tables by default instead of txt-files! That allows you to easily upgrade your current gamefile without the need to create new directories or convert your proto's to txt! You just have to download the package I provided, extract it and to read the install instructions! I promise you there isn't much to read! Since the source code is written by YMIR and I respect their work I won't release the source code or give any peeks into it. current version: 2.4.1 Developed version: 2.5 Download: See second post! *FEATURE LIST* + removed the license functions so the server won't connect to a license server nor check if your server is valid + removed the time limitation so it won't even check the time limit. This crash issue is completely fixed. + merged all the exp tables to the "exp_table_common" which will be used by ANY locale. You can change the needed exp for 200 levels there. + Max_level can be raised in the CONFIG file to a maximum of 255. + status points will be given at any level. It depends now on Max_level so if you set max_level to 120 you'll get status points until level 120! + fixed vampirism effects so you won't loose hp when you make an overkill (suras may embrace this change) + exp bonus now works comulutative instead of just making a chance to get double exp. If you have 20% exp bonus in your items you'll get 20% more exp at any time. + Rewrote the version check. You can now set your server version in your CONFIG-file and let it check with the client version. If serverversion != clientversion the server will print a message and kick the player out + Raised the gold limit up to 999.999.999.999 + membuf-errors fixed! Now you have a optimized buffer length so it won't consume much RAM but still have enough to not kick players out. + you can now give priv_empire (or other priv's) up to 2000% at any time. + a lot of new quest functions, when triggers and CONFIG-options + more stability and performance especially since it's compiled with a newer gcc version + Optimization flags and linker optimization enabled + ip's beginning with 5. and 25. are now allowed by the internal ip-check + Items can now be sold for 0 gold + 6/7 bonus are now working + name-change works with every locale + gold overflow: Now resets the gold to the maximum value to fight against gold overflow + horse-table has new entries for up to level 51. Raising the level extends the horse-stats. + New error handling for bonus overflow. Now the bonus will be set to the maximum generating a warning in your syserr + player movement speed will be observerd by the server now and set down to the maximum value if it's too high. + Skills can now apply new bonuses! You can e. g. raise your int-attribute + Dbcache can now start without txt-files + If you're warped into a non-existing map or non-existing coordinates your coordinates will be resetted to map1 of your village; You won't need unstuckers anymore + adminpage_ip set to localhost by default so it'll only listen to itself to prevent attackings from API tool. Additionally it's disabled by default and you can enable it with a CONFIG-option. Say good bye to the API tool! + Tons of bug fixes even YMIR had! + Completely rebuild of the source with gcc4.9, cryptopp 5.6.2 and boost 1.55; new optimizations flags and C++11 are enabled to make the core much more faster and more stable! + Advanced spam protection installed! + Unknown packet headers will no longer lead to a disconnect though they'll get dropped + Second binary compiled with 4 inventory pages! + Added the new skill flags so they can use FIRE, ICE, ELEC and DARK + Anti-Exp in the game source + reload q corrected. Note! Still not recommended. But if it's crashing, it'll now notice you. *Gameplay changes* + HP/MP overflow fixed + yang limit raised to unsigned long long int! + Fixed a huge load of format errors that'd actually crash the core! + Speedhack limit fixed so you won't get teleported back when riding + item.remove() won't remove stacks anymore! It'll just reduce the amount of the stack by 1. It there's only one left, the item will be removed. + Bypass to createa guild under level 40 fixed! + Guild wars won't crash the core anymore! + immune bug fixed (completely!!!) + Anti-Overflow mechanism prevents people from receiving too much gold + prisma glass system enabled and fixed + 6/7 bonuses work + polymorph bug fixed + invisibility bug fixed + empire exploit fixed + belt system and dragon soul system enabled + level size raised up to a normal int + You can put items for 0 gold in a shop + Exp can go higher than long int. It's now unsigned long long int (which makes higher exp requirements possible) *New CONFIG-options* MAX_LEVEL_STATUS: unsigned int Forces a maximum level. If you level up higher than this, you'll receive no status points anymore. MAX_STATUS: unsigned int Sets a maximum of distributed status points. If you e. g. set it to 20, you can only raise your stat's by 20 each status. SERVER_CHECK: 1/0 Checks if the client version and the server version are the same. If not, the server will send a message to the client and kick him out after a few seconds. SERVER_VERSION: unsigned int There you can set the version of your server for the SERVER_CHECK. MAX_HT: unsigned int It's the same option than MAX_STATUS but only for the con-attribute. MAX_IQ: unsigned int It's the same option than MAX_STATUS but only for the int-attribute. MAX_ST: unsigned int It's the same option than MAX_STATUS but only for the str-attribute. MAX_DX: unsigned int It's the same option than MAX_STATUS but only for the dex-attribute. ATTR_ALWAYS_ADD: 1/0 If enabled you'll get 100% chance to add new attributes to you equipment. ATTR_ALWAYS_5_ADD: 1/0 If enabled you'll get 100% chance to add new attributes to you equipment. Counts only for 5th Bonus (blessing marble). ATTR_CHANGE_LIMIT: int You can set a limit time to change your attributes again. It's changed to seconds (set it to 1 to let the users switch only once per second their attributes). GUILD_MAX_LEVEL: int Sets the maximum guild level. You can raise it up to 50 since the exp-table is extended to handle up to 50. ITEM_OWNERSHIP_TIME: int If you drop an item, this option sets how long the item will be flagged as yours. MIN_ADDON_FKS: int Sets the minimum ability bonus dmg you can have. MAX_ADDON_FKS: int Sets the maximum ability bonus dmg you can have. MIN_ADDON_DSS: int Sets the minimum normal hit bonus dmg you can have. MIN_ADDON_DSS: int Sets the maximum normal hit bonus dmg you can have. SKILLBOOK_DELAY: int Sets the time limit for reading a book (e. g. if you read skill books you'll have to wait x seconds until you can read the same skill book again). SKILLBOOK_NEED_EXP: int Sets the exp you need for reading a book. SKILLBOOK_ALWAYS_BOOK: 1/0 Sets if every book will be handled as you'd have used a skillbook chance amplifier. GOLD_DROP_TIME_INTERVAL: int Sets how long you have to wait until you can drop gold again. SEQUENCE_CHECK: 1/0 Enables a check if the sequence table is the same than the client's one. SKILLBOOK_STEP_LEVELING: 1/0 Enables the need of more books for raising a skill (e. g. you need 2 books from m2 to m3). RAISE_EMPIRE_PRICES: 1/0 Enables the raise of prices if you buy items in another empire. HORSE_MAX_LEVEL: int Sets the maximum level of your horse (you still need to write quests or something like that to allow players to achieve the higher horse-levels). MARRIAGE_MAX_PERCENT: int Sets the maximum allowed percent of love points. Warning! If love points > 100 it'd lead into bugs with breaking the marriage. PC_MAX_MOVEMENT_SPEED: int Sets the maximum movement speed for players. PC_MAX_ATTACK_SPEED: int Sets the maximum attack speed for players. MOB_MAX_MOVEMENT_SPEED: int Sets the maximum movement speed for mobs. MOB_MAX_ATTACK_SPEED: int Sets the maximum attack speed for mobs. TAXES: int From 0 to 100. Sets the % how much taxes you have to pay while shopping. DYE_LEVEL: int Sets how many levels you have to get after you can change your hair color again. YANG_MAX: long long Sets the maximum gold you can carry. You can change it up to 999.999.999.999 gold. package_enable: 0/1 1 = enabled. Disabled by default. Enable to use the package-feature. log_level: 0/1/2 Sets the logging level. 0 means to logs will be entered in your database. 1 means that the most important tables (hack-logs for example) will be used 2 means that all logging tables will be used new_test_server: 0/1 Protects your test-server so the gamecore will check if accounts are written into gmlist before granting them implementor-privileges. new_gm_host_check: 1/0 Checks the gmhost and gmlist for the right ip before granting privileges. Disabled by default. adminpage_enable: 1/0 Enables the adminpage-features. Disabled by default (say bye bye to API tools) adminpage_no_localhost: 1/0 Disables the security feature which inserts localhost into your adminpage_ip so it'll only listen to localhost. item_floor_time: int Set the time how long a dropped item will be lying on the ground (by monsters) max_rank_points: long int Set the maximum rank points movement_speed: int Set the initial movement speed for players. belt_all_allow_items: 0/1 Allow Players to store every item in their belt inventory attr_rare_enable: 0/1 Allow the using of rare attributes (6th and 7th attributes). Default: ON. GOLD_DROP_TIME: int Sets the time how long dropped gold will lay on the ground until it's purged. ITEM_DROP_TIME: int Sets how long dropped items will lay on the ground intil it's purged. BELT_FORCE_SLOTS: int Forces to open up the given amount of slots in your belt inventory. If this value is higher than the grade of your belt, it'll open the given amount of slots. If it's lower, the amount your belt provides will be used. For example: You set 10. You've got a belt that opens 5 slots. 10 will be opened. Now you set 4 and still have the same belt. This time 5 slots will be opened. This does also work when no belts are weared. But be careful: Since there's also a clientside part the slots may appear to be locked but you can still put items into them trade_effect: 1/0 Enables a effect that'll occur when people are traing stuff. Enabled by default. ban_force_reason: 1/0 This lets the ban-command only work when you're giving a reason. Disabled by default. start_gold: long int Let's players start with a custom amount of gold. Default: 0. view_equip_for_all: 1/0 Let's player view equip of others! Disabled by default. view_equip_sp_cost: int Sets the cost of using view_equip. This is in % so if you type in 30 then it'll cost 30% of the players maximum sp. Default: 0. glass_enable: 1/0 Enables the prisma glass-system to print your items in the chat. Disabled by default. glass_needed: 1/0 Sets if you need a glass for using the prisma glass-system or not. Enabled by default. trade_effect_exchange_threshold: int Sets the threshold to create another effect when making an exchange. Default: 500000. This means, that every 500000 gold traded away there'll be another fly effect created trade_effect_shop_threshold: int Same as trade_effect_exchange_threshold; This points to buying items in shops. Default: 100000000. VERSIONCHECK_KICK_DELAY: int Default is 10. Sets the time until the player is kicked when a version mismatch is occured. Takes only effect if the versioncheck is enabled. EMOTION_WITHOUT_MASK: 1/0 Default is 0. Lets you define if you won't need a mask to use emotions. EMOTION_SAME_GENDER: 1/0 Default is 0. Lets you define if people will be able to use emotions on the same gender. Notice: This'd possibly look awkward because the animations doesn't match CHECK_SPEEDHACK_ENABLE: 1/0 Default is 1. Lets you define if you want to use the speedhack/synchack check. Warning! Make sure you only use this for debugging purpose! You can fine-tune the variables for the speedhack in your CONFIG, so this should normally not be touched! QUEST_TRIGGER_ENABLE: 1/0 Default is 1. Lets you define if you want to use the new execute-trigger. EXP_NEED_THRESHOLD: unsigned long long int Allows you to set the exp needed if your level is higher than the maximum level of the exp table SKILL_MASTER_UPGRADE: int Sets the minimum level when your skill can jump to master. If it's set to 1 for example, then it'd happen that your skill jumps to m1 at any level. SKILL_FORCE_MASTER: 1/0 Lets you define if your skill will definitely raise to m1 if it hits the minimum level for jumping. So if you're enabling this, then your skill will definitely (unless you set SKILL_MASTER_UPGRADE) raise to m1 when hitting 17. BUGFIX_SURA_MANASHIELD: 1/0 Default is disabled. Fixes the sura manashield so it'll now scale with the proper value instead of always removing a third of the damage. Warning! When activating, you'd nerf the skill! Otherwise people with over 100 iq could prevent every incoming damage and even heal themselves or cause crashes! *New questfunctions* item.get_attr_type(int index) item.get_attr_value(int index) item.set_attr(int ApplyType, int ApplyValue[, int index]) npc.get_level() game.mysql_real_escape_string(string query) game.mysql_query(string query) game.mysql_update_query(string query) pc.delayed_disconnect(int zeit) pc.get_mount_vnum() pc.set_level(int level) pc.send_effect(int id) pc.block_exp() pc.unblock_exp() item.equip() npc.select() pet.is_mine() pc.get_id() *New conf.txt options* TXT_STARTUP = 0/1 1 = enabled. Disabled by default. Enable to boot with txt-files instead of sql *New quest trigger* OnBuy (triggers on buying a item from players or npc's) OnDie (triggers on dying) *commands* /ban playername reason /unban playername full list of all allowed bonuses for skills: MAX_HP MAX_SP HP_REGEN SP_REGEN BLOCK HP SP ATT_GRADE DEF_GRADE MAGIC_ATT_GRADE MAGIC_DEF_GRADE BOW_DISTANCE MOV_SPEED ATT_SPEED POISON_PCT RESIST_RANGE CASTING_SPEED REFLECT_MELEE ATT_BONUS DEF_BONUS RESIST_NORMAL DODGE KILL_HP_RECOVER KILL_SP_RECOVER HIT_HP_RECOVER HIT_SP_RECOVER CRITICAL MANASHIELD SKILL_DAMAGE_BONUS NORMAL_HIT_DAMAGE_BONUS HT IQ ST DX STUN_PCT SLOW_PCT PENETRATE_PCT ATTBONUS_HUMAN STEAL_HP STEAL_SP MANA_BURN_PCT DAMAGE_SP_RECOVER RESIST_SWORD RESIST_TWOHAND RESIST_DAGGER RESIST_BELL RESIST_FAN RESIST_BOW RESIST_FIRE RESIST_ELEC RESIST_MAGIC RESIST_WIND REFLECT_CURSE POISON_REDUCE EXP_DOUBLE_BONUS GOLD_DOUBLE_BONUS ITEM_DROP_BONUS POTION_BONUS IMMUNE_STUN IMMUNE_SLOW IMMUNE_FALL CURSE_PCT STA ATTBONUS_WARRIOR ATTBONUS_ASSASSIN ATTBONUS_SURA ATTBONUS_SHAMAN ATTBONUS_MONSTER MAX_HP_PCT MAX_SP_PCT SKILL_DEFEND_BONUS NORMAL_HIT_DEFEND_BONUS RESIST_WARRIOR RESIST_ASSASSIN RESIST_SURA RESIST_SHAMAN ENERGY RESIST_CRITICAL RESIST_PENETRATE Thanks to: xP3NG3Rx for some quest functions Sphinx² & lollo_9_1 for the mysql-functions Lefloyd for the 2 new quest triggers .InyaProduction for some new quest functions Tim for the suggestion to include libs from a special path MartPwnS for helping with the src code on gcc48/gcc49 And especially thanks to you!
  2. 77 points
    Hi, As requested by some users i have you a VM with FreeBSD 9.2 32bit, novaline source and pre installed Ports so you can compile the game. It was like 10 minutes of work to enter the commands so no thanks needed. Link: HerpDerp Login: root Pw: dev To compile the game: 1 2 3 cd /usr/src/novaline/Srcs/Server/game/src gmake clean gmake -j20 If there are any Problems or questsions you can add me in Skype(l337-5p34k) or Message me here i'll always give you support. Kind regards TheGame €: There are no Serverfiles on this VM because i dont have test serverfiles. If someone have Serverfiles for me i'll implement them and upload an updated version of this VM. €€: Updated Link: Thanks to Da'Real Pain
  3. 75 points
    This post is made for changelogs and for the download link! ### Changelog vanilla version 2.2 (without rev system) ### ~> See here ### Changelog vanilla revision rev52410 ### Also known as version 2.3 ~> See here ### Changelog vanilla revision 54180 ### Also known as version 2.4 ~> See here ### Changelog vanilla revision 54250 ### Also known as version 2.4.1 ~> See here ~> Hotfix see here ~> Second hotfix see here Download (v2.4.1): here password: vanilla note! Please always test newer versions of vanilla first in a test environment!! Only download the vanilla core from valid sources (this thread!!) If you want to donate then you can simply donate via paypal or other payment methods. Just write me a private message I appreciate every help I can get! Installation: Read readme.txt! You are allowed to freely distribute the vanilla core but be sure you mark the right authors! The main source code is from YMIR, the modifications are made by me (vanilla)! And if you release it somewhere else please make sure you create a reference to this thread and that it's allowed to be posted there.
  4. 60 points
    Today I'm gonna show you how to compile the mainline_released client binary. Tools we will need: VS2008,Visual Studio 2008 SP1 We will need to make two folders on our hard drive for example include_stuff and lib_stuff after that we go to srcnovalineSrcsToolsWorldEditorexterninclude and copy all that things into include_stuff next go to srcnovalineSrcsToolsWorldEditorexternlib and copy all that things into lib_stuff next open srcnovalineSrcsToolsRAD Game Toolsgrannycommongranny_common_2_9_12_0_release.zip go to lib then win32 and copy all that into lib_stuff next go to srcnovalineSrcsExternlib and copy all into lib_stuff after this go to srcnovalineSrcsExterninclude and copy all into include_stuff In VS 2008 go to Tools->Options->Project and Solutions->VC++ Directories=>Select Include files and include there your include_stuff folder then select Library files and include there your lib_stuff files. Finally we did it Select to release mode and press ctrl+shift+b Kind Regards, Denic
  5. 59 points
    Hi, In this thread I'm going to show you how to make a game-client or client-game communication with packets, instead of using the old quest-client, client-quest communication. Lets start with the game-client, in this example I will send 1 variable to the client. First start with the HEADER, open your binary source and navigate to UserInterface/Packet.h. Now you will see many headers, create a new one, but search for an empty number. I will use 57, because its not used. GC means it's used for Game -> Client packet, it's just a prefix. HEADER_GC_METIN2DEV Now add the structure for the packet, this is most important part. Structure is the "body" of the packet, it contains the HEADER as BYTE and the other optional variables. As I said I just want to send one int type to the client, so add it. typedef struct command_metin2dev_packet { BYTE bHeader; int M2int; } TPacketGCMetin2Dev; Now navigate to UserInterface/PythonNetworkStream.cpp and add your header to the CMainPacketHeaderMap class. The first parameter of the Set is the HEADER, second is the size of the structure. We will use just static size packets in this tutorial, but the third argument can be dynamic size too. Set(HEADER_GC_METIN2DEV, CNetworkPacketHeaderMap::TPacketType(sizeof(TPacketGCMetin2Dev), STATIC_SIZE_PACKET)); Now navigate to UserInterface/PythonNtworkStreamPhaseGame.cpp and add the function to the switch. case HEADER_GC_METIN2DEV: ret = RecvM2DevPacket(); break; The name of the function will be RecvM2DevPacket: Now declarate the function, navigate to UserInterface/PythonNetworkStream.h and add it as public: bool RecvM2DevPacket(); Now add the receiver part of the code. Recv "picks" out xy bytes from the buffer and the return type of it is false if there was no data in the buffer by that size otherwise true, which means it was successful. xy = size of the structure bool CPythonNetworkStream::RecvM2DevPacket() { TPacketGCMetin2Dev Metin2DevGC; if (!Recv(sizeof(TPacketGCMetin2Dev), &Metin2DevGC)) { Tracen("Recv Metin2DevGC Packet Error"); return false; } } Now we are calling the BINARY_M2DEV_Test function in game.py and passing the received data. PyCallClassMemberFunc(m_apoPhaseWnd[PHASE_WINDOW_GAME], "BINARY_M2DEV_Test", Py_BuildValue("(i)", Metin2DevGC.M2int)); This was the client-side of the game-client communication, lets start the server-side: First of all we need to add the header again, navigate to game/packet.h and add this: And the structure: typedef struct packet_metin2dev_packet { BYTE byHeader; int M2int; } TPacketGCMetin2Dev; Now navigate to game/char.cpp and create a function which sends the packet. void CHARACTER::SendMetin2DevPacket() { } Declare it in the game/char.h: void SendMetin2DevPacket(); Now lets add the content of the function. Create a new instance of the structure, set the values of it and send it to the client. void CHARACTER::SendMetin2DevPacket() { if (!GetDesc()) { return; } TPacketGCMetin2Dev Metin2DevGC; Metin2DevGC.byHeader = HEADER_GC_METIN2DEV; Metin2DevGC.M2int = GetPlayerID(); GetDesc()->Packet(&Metin2DevGC, sizeof(TPacketGCMetin2Dev)); } Now add the last function to game.py, this will be called by the binary: def BINARY_M2DEV_Test(self, M2int): import dbg dbg.LogBox(str(M2int)) Finally, lets check how it works: If you have any question or suggestion, please just reply to this topic. Kind Regards, Sanchez
  6. 46 points
    Hi guys Someone wondered how to make 4 inventory page with source. I will share how to make 4 inventory page today I hope you are like it First which you are use to source files open it. I will use to mainline_released(SG) log in mainline_released/mainline_sg/Srcs/Server/common after open length.h after search this INVENTORY_MAX_NUM = 90, Replace to INVENTORY_MAX_NUM = 180, Open char_item.cpp and search this BYTE bPage = bCell / (INVENTORY_MAX_NUM / 2); Replace to BYTE bPage = bCell / (INVENTORY_MAX_NUM / 4); search this if (p / (INVENTORY_MAX_NUM / 2) != bPage) Replace to if (p / (INVENTORY_MAX_NUM / 4) != bPage) open exchange.cpp. Search this after add under this. static CGrid s_grid2(5, INVENTORY_MAX_NUM/5 / 2); // inven page 2 will be like this. static CGrid s_grid1(5, INVENTORY_MAX_NUM/5 / 2); // inven page 1 static CGrid s_grid2(5, INVENTORY_MAX_NUM/5 / 2); // inven page 2 static CGrid s_grid3(5, INVENTORY_MAX_NUM/5 / 2); // inven page 3 static CGrid s_grid4(5, INVENTORY_MAX_NUM/5 / 2); // inven page 4 s_grid1.Clear(); s_grid2.Clear(); s_grid3.Clear(); s_grid4.Clear(); and replace to your self.. for (i = 0; i < INVENTORY_MAX_NUM / 4; ++i) { if (!(item = victim->GetInventoryItem(i))) continue; s_grid1.Put(i, 1, item->GetSize()); } for (i = INVENTORY_MAX_NUM / 4; i < INVENTORY_MAX_NUM; ++i) { if (!(item = victim->GetInventoryItem(i))) continue; s_grid2.Put(i - INVENTORY_MAX_NUM / 4, 1, item->GetSize()); } for (i = INVENTORY_MAX_NUM / 4; i < INVENTORY_MAX_NUM; ++i) { if (!(item = victim->GetInventoryItem(i))) continue; s_grid3.Put(i - INVENTORY_MAX_NUM / 4, 1, item->GetSize()); } for (i = INVENTORY_MAX_NUM / 4; i < INVENTORY_MAX_NUM; ++i) { if (!(item = victim->GetInventoryItem(i))) continue; s_grid4.Put(i - INVENTORY_MAX_NUM / 4, 1, item->GetSize()); } After client.. Log in mainline_released/mainline_sg/Srcs/Client/Userinterface after open GameType.h after search this const DWORD c_Inventory_Page_Count = 2; Replace to const DWORD c_Inventory_Page_Count = 4; open inventorywindow.py and search this EQUIPMENT_START_INDEX = 90 Replace to EQUIPMENT_START_INDEX = 180 open uiinventory.py and search this after add under this self.inventoryTab.append(self.GetChild("Inventory_Tab_02")) self.inventoryTab.append(self.GetChild("Inventory_Tab_03")) self.inventoryTab.append(self.GetChild("Inventory_Tab_04")) search this after add under this self.inventoryTab[1].SetEvent(lambda arg=1: self.SetInventoryPage(arg)) self.inventoryTab[2].SetEvent(lambda arg=2: self.SetInventoryPage(arg)) self.inventoryTab[3].SetEvent(lambda arg=3: self.SetInventoryPage(arg)) Search SetInventoryPage function and replace with this. def SetInventoryPage(self, page): self.inventoryTab[self.inventoryPageIndex].SetUp() self.inventoryPageIndex = page self.inventoryTab[self.inventoryPageIndex].Down() self.RefreshBagSlotWindow() Thanks for @Zardon,Deniec Cikiec comment. i will share my inventorywindow.py import uiScriptLocale import item EQUIPMENT_START_INDEX = 180 window = { "name" : "InventoryWindow", ## 600 - (width + 오른쪽으로 부터 띄우기 24 px) "x" : SCREEN_WIDTH - 176, "y" : SCREEN_HEIGHT - 37 - 565, "style" : ("movable", "float",), "width" : 176, "height" : 585, "children" : ( ## Inventory, Equipment Slots { "name" : "board", "type" : "board", "style" : ("attach",), "x" : 0, "y" : 0, "width" : 176, "height" : 585, "children" : ( ## Title { "name" : "TitleBar", "type" : "titlebar", "style" : ("attach",), "x" : 8, "y" : 7, "width" : 161, "color" : "yellow", "children" : ( { "name":"TitleName", "type":"text", "x":77, "y":3, "text":uiScriptLocale.INVENTORY_TITLE, "text_horizontal_align":"center" }, ), }, ## Equipment Slot { "name" : "Equipment_Base", "type" : "image", "x" : 10, "y" : 33, "image" : "d:/ymir work/ui/equipment_bg_without_ring.tga", "children" : ( { "name" : "EquipmentSlot", "type" : "slot", "x" : 3, "y" : 3, "width" : 150, "height" : 182, "slot" : ( {"index":EQUIPMENT_START_INDEX+0, "x":39, "y":37, "width":32, "height":64}, {"index":EQUIPMENT_START_INDEX+1, "x":39, "y":2, "width":32, "height":32}, {"index":EQUIPMENT_START_INDEX+2, "x":39, "y":145, "width":32, "height":32}, {"index":EQUIPMENT_START_INDEX+3, "x":75, "y":67, "width":32, "height":32}, {"index":EQUIPMENT_START_INDEX+4, "x":3, "y":3, "width":32, "height":96}, {"index":EQUIPMENT_START_INDEX+5, "x":114, "y":67, "width":32, "height":32}, {"index":EQUIPMENT_START_INDEX+6, "x":114, "y":35, "width":32, "height":32}, {"index":EQUIPMENT_START_INDEX+7, "x":2, "y":145, "width":32, "height":32}, {"index":EQUIPMENT_START_INDEX+8, "x":75, "y":145, "width":32, "height":32}, {"index":EQUIPMENT_START_INDEX+9, "x":114, "y":2, "width":32, "height":32}, {"index":EQUIPMENT_START_INDEX+10, "x":75, "y":35, "width":32, "height":32}, ## 새 반지1 ##{"index":item.EQUIPMENT_RING1, "x":2, "y":106, "width":32, "height":32}, ## 새 반지2 ##{"index":item.EQUIPMENT_RING2, "x":75, "y":106, "width":32, "height":32}, ## 새 벨트 {"index":item.EQUIPMENT_BELT, "x":39, "y":106, "width":32, "height":32}, ), }, ## Dragon Soul Button { "name" : "DSSButton", "type" : "button", "x" : 114, "y" : 107, "tooltip_text" : uiScriptLocale.TASKBAR_DRAGON_SOUL, "default_image" : "d:/ymir work/ui/dragonsoul/dss_inventory_button_01.tga", "over_image" : "d:/ymir work/ui/dragonsoul/dss_inventory_button_02.tga", "down_image" : "d:/ymir work/ui/dragonsoul/dss_inventory_button_03.tga", }, ## MallButton { "name" : "MallButton", "type" : "button", "x" : 118, "y" : 148, "tooltip_text" : uiScriptLocale.MALL_TITLE, "default_image" : "d:/ymir work/ui/game/TaskBar/Mall_Button_01.tga", "over_image" : "d:/ymir work/ui/game/TaskBar/Mall_Button_02.tga", "down_image" : "d:/ymir work/ui/game/TaskBar/Mall_Button_03.tga", }, ## CostumeButton { "name" : "CostumeButton", "type" : "button", "x" : 78, "y" : 5, "tooltip_text" : uiScriptLocale.COSTUME_TITLE, "default_image" : "d:/ymir work/ui/game/taskbar/costume_Button_01.tga", "over_image" : "d:/ymir work/ui/game/taskbar/costume_Button_02.tga", "down_image" : "d:/ymir work/ui/game/taskbar/costume_Button_03.tga", }, { "name" : "Equipment_Tab_01", "type" : "radio_button", "x" : 86, "y" : 161, "default_image" : "d:/ymir work/ui/game/windows/tab_button_small_01.sub", "over_image" : "d:/ymir work/ui/game/windows/tab_button_small_02.sub", "down_image" : "d:/ymir work/ui/game/windows/tab_button_small_03.sub", "children" : ( { "name" : "Equipment_Tab_01_Print", "type" : "text", "x" : 0, "y" : 0, "all_align" : "center", "text" : "I", }, ), }, { "name" : "Equipment_Tab_02", "type" : "radio_button", "x" : 86 + 32, "y" : 161, "default_image" : "d:/ymir work/ui/game/windows/tab_button_small_01.sub", "over_image" : "d:/ymir work/ui/game/windows/tab_button_small_02.sub", "down_image" : "d:/ymir work/ui/game/windows/tab_button_small_03.sub", "children" : ( { "name" : "Equipment_Tab_02_Print", "type" : "text", "x" : 0, "y" : 0, "all_align" : "center", "text" : "II", }, ), }, ), }, { "name" : "Inventory_Tab_01", "type" : "radio_button", "x" : 10, "y" : 33 + 189, "default_image" : "d:/ymir work/ui/game/windows/tab_button_large_01.sub", "over_image" : "d:/ymir work/ui/game/windows/tab_button_large_02.sub", "down_image" : "d:/ymir work/ui/game/windows/tab_button_large_03.sub", "tooltip_text" : uiScriptLocale.INVENTORY_PAGE_BUTTON_TOOLTIP_1, "children" : ( { "name" : "Inventory_Tab_01_Print", "type" : "text", "x" : 0, "y" : 0, "all_align" : "center", "text" : "I", }, ), }, { "name" : "Inventory_Tab_02", "type" : "radio_button", "x" : 10 + 78, "y" : 33 + 189, "default_image" : "d:/ymir work/ui/game/windows/tab_button_large_01.sub", "over_image" : "d:/ymir work/ui/game/windows/tab_button_large_02.sub", "down_image" : "d:/ymir work/ui/game/windows/tab_button_large_03.sub", "tooltip_text" : uiScriptLocale.INVENTORY_PAGE_BUTTON_TOOLTIP_2, "children" : ( { "name" : "Inventory_Tab_02_Print", "type" : "text", "x" : 0, "y" : 0, "all_align" : "center", "text" : "II", }, ), }, { "name" : "Inventory_Tab_03", "type" : "radio_button", "x" : 10, "y" : 33 + 210, "default_image" : "d:/ymir work/ui/game/windows/tab_button_large_01.sub", "over_image" : "d:/ymir work/ui/game/windows/tab_button_large_02.sub", "down_image" : "d:/ymir work/ui/game/windows/tab_button_large_03.sub", "tooltip_text" : uiScriptLocale.INVENTORY_PAGE_BUTTON_TOOLTIP_2, "children" : ( { "name" : "Inventory_Tab_03_Print", "type" : "text", "x" : 0, "y" : 0, "all_align" : "center", "text" : "III", }, ), }, { "name" : "Inventory_Tab_04", "type" : "radio_button", "x" : 10 + 78, "y" : 33 + 210, "default_image" : "d:/ymir work/ui/game/windows/tab_button_large_01.sub", "over_image" : "d:/ymir work/ui/game/windows/tab_button_large_02.sub", "down_image" : "d:/ymir work/ui/game/windows/tab_button_large_03.sub", "tooltip_text" : uiScriptLocale.INVENTORY_PAGE_BUTTON_TOOLTIP_2, "children" : ( { "name" : "Inventory_Tab_04_Print", "type" : "text", "x" : 0, "y" : 0, "all_align" : "center", "text" : "IV", }, ), }, ## Item Slot { "name" : "ItemSlot", "type" : "grid_table", "x" : 8, "y" : 264, "start_index" : 0, "x_count" : 5, "y_count" : 9, "x_step" : 32, "y_step" : 32, "image" : "d:/ymir work/ui/public/Slot_Base.sub" }, ## Print { "name":"Money_Slot", "type":"button", "x":8, "y":28, "horizontal_align":"center", "vertical_align":"bottom", "default_image" : "d:/ymir work/ui/public/parameter_slot_05.sub", "over_image" : "d:/ymir work/ui/public/parameter_slot_05.sub", "down_image" : "d:/ymir work/ui/public/parameter_slot_05.sub", "children" : ( { "name":"Money_Icon", "type":"image", "x":-18, "y":2, "image":"d:/ymir work/ui/game/windows/money_icon.sub", }, { "name" : "Money", "type" : "text", "x" : 3, "y" : 3, "horizontal_align" : "right", "text_horizontal_align" : "right", "text" : "123456789", }, ), }, ), }, ), } open beltinventorywindow.py after search this EQUIPMENT_START_INDEX = 90 replace to EQUIPMENT_START_INDEX = 180 I think someone don't make part of client-side. I share binary file (original file) with your. https://mega.co.nz/#!TxpUzL6Y!9vC4ip61k_El6Ew6POIF53_PApd29a4CFSqIMdzb4XQ Kind Regards HaveBeen
  7. 46 points
    Intro This release will explain how to "convert" your root .py files to .c ones. Actually, Cython only converts those files to pure CPython code. Download NOTE: ALL THE FILES HAVE BEEN MOVED TO HOW-TO-CYTHON-MT2. EDIT: As requested by many people, you can download the compatible and clean official cn root dated 20131228-0034 without further edits: rootCn_20131228-0034_edit.raruiscriptCn_20131228-0034.rarcN-serverinfo-edit.pyIs Cython really worth it?ProsAll the modules are compiled, and they can't be "extracted as .py" anymore.We can always disassemble the launcher with IDA, but the result will be pseudo-c code after waiting 6-8h of analyzing. Since we're not using .pyx files but directly .py ones, there's no "so much optimization".At least, 10% of performance increasing is guaranteed. ConsFor testing purposes, it's heavy to maintain. Everytime you try to re-compile your root files, you should wait 5-10 minutes.You can always use the uncythonized root (.py files) when you perform tests, and compile cython whenever you will make an update in your live server. The launcher's size will increase ~10mb. You can actually pack it to save space.If you directly use a .pyd (still 10mb), the launcher's size won't increase. VideoTutorial Credits Me (lollo_9_1/martysama0134)Night (OST suggestion)Random TestersWhat's New:v2.0The module's name check is now case-insensitive (colorInfo == colorinfo)Added a new function rootlib/uiscriptlib.getList() to retrieve a tuple of all the available cythonized modules.Now you can compile a uiscriptlib library from the uiscript*.py files! (implemented as __USE_EXTRA_CYTHON__)Added a sample ui.py containing the code to run uiscriptlib.
  8. 43 points
    Hi, In this thread I will show you how you can implement an advanced spam protection to your server. The player can write the same message just after 5 seconds. The player will receive 1 minute of chat ban if he is trying to send the same message more than 3 times in 5 seconds. You can specify a blockspamlist.lst file which contains words. If the user sending a message which contains a words from the list, the player will receive 5 minutes of chat ban. (You can specify the time of the chat ban) You can specify a bannspamlist.lst file which contains words. If the user sending a message which contains a words from the list, the player will receive a ban. (You can specify the time of the ban) Open game/input_main.cpp and search for this: if (ch->IncreaseChatCounter() >= 10) Add this over that: if (!strcmp(ch->LastPlayerMessage, buf) && (thecore_pulse() < (ch->LastMessageAt + SPAM_WAIT_SEC * 25)) && !ch->SpamAllowBuf(buf) && ch->GetGMLevel() < GM_LOW_WIZARD) { if (ch->BlockChatAfter < 2) { ch->ChatPacket(CHAT_TYPE_INFO, ("You must wait 5 seconds to repeat your message")); ch->BlockChatAfter++; return iExtraLen; } else { ch->BlockChatAfter = 0; ch->PlayerPunish(false, SPAM_CHAT_BAN_TIME); return iExtraLen; } } else { if (!ch->BannListCheck(buf) && ch->GetGMLevel() < GM_LOW_WIZARD) { ch->PlayerPunish(true, SPAM_BAN_TIME); return iExtraLen; } if (!ch->SpamListCheck(buf) && ch->GetGMLevel() < GM_LOW_WIZARD) { ch->ChatPacket(CHAT_TYPE_INFO, ("You wrote a not allowed words!")); ch->PlayerPunish(false, SPAM_CHAT_BAN_TIME); return iExtraLen; } } Still in input_main.cpp search for this: ch->GetMapIndex(), strlen(ch->GetName()))); Add this under that: strcpy(ch->LastPlayerMessage, buf); ch->LastMessageAt = thecore_pulse(); ch->BlockChatAfter = 0; Open game/char.h and search for this: BYTE GetChatCounter() const; Add this under that: int LastMessageAt; int BlockChatAfter; char LastPlayerMessage[CHAT_MAX_LEN + 1]; void PlayerPunish(bool PowerPunish, int Duration); bool SpamListCheck(const char *Message); bool BannListCheck(const char *Message); bool SpamAllowBuf(const char *Message); Open game/char.cpp and add these events: void CHARACTER::PlayerPunish(bool PowerPunish, int Duration) { if (!PowerPunish) { AddAffect(AFFECT_BLOCK_CHAT, POINT_NONE, 0, AFF_NONE, Duration, 0, true); sys_log(0, "%s[%d] has been chatbanned because of spamming/writing words which are in the spamlist.txt", GetName(), GetPlayerID()); } else { std::auto_ptr<SQLMsg> msg(DBManager::instance().DirectQuery("UPDATE account.account SET availDt = FROM_UNIXTIME(UNIX_TIMESTAMP(CURRENT_TIMESTAMP()) + %i) WHERE id = %d", Duration, GetAID())); sys_log(0, "%s[%d] has been banned because of saying blacklisted word", GetName(), GetPlayerID()); GetDesc()->DelayedDisconnect(5); } } bool CHARACTER::SpamAllowBuf(const char *Message) { if (!strcmp(Message, "(Ȳ´ç)") || !strcmp(Message, "(µ·)") || !strcmp(Message, "(±â»Ý)") || !strcmp(Message, "(ÁÁľĆ)") || !strcmp(Message, "(»ç¶ű)") || !strcmp(Message, "(şĐłë)") || !strcmp(Message, "(ľĆÇĎ)") || !strcmp(Message, "(żěżď)") || !strcmp(Message, "(ÁËĽŰ)")) { return true; } return false; } bool CHARACTER::SpamListCheck(const char *Message) { for (int i = 0; i < SpamBlockListArray.size(); i++) { if (!strcmp(Message, SpamBlockListArray[i].c_str())) { return false; } } return true; } bool CHARACTER::BannListCheck(const char *Message) { for (int i = 0; i < SpamBannListArray.size(); i++) { if (!strcmp(Message, SpamBannListArray[i].c_str())) { return false; } } return true; } Add 2 new files to your project: spamblock.cpp spamblock.h Add these to the spamblock.cpp #include "fstream" #include "string" #include "sstream" #include "stdafx.h" #include "../../common/length.h" std::vector<std::string> SpamBlockListArray; std::vector<std::string> SpamBannListArray; void LoadBlockSpamList() { std::string TempBlockList; std::ifstream File("chat/blockspamlist.lst"); if (!File.is_open()) { sys_log(0, "WARNING: cannot open chat/blockspamlist.lst"); return; } SpamBlockListArray.clear(); while (!File.eof()) { File >> TempBlockList; SpamBlockListArray.push_back(TempBlockList); } File.close(); } void LoadBannSpamList() { std::string TempBannList; std::ifstream File("chat/bannspamlist.lst"); if (!File.is_open()) { sys_log(0, "WARNING: cannot open chat/bannspamlist.lst"); return; } SpamBannListArray.clear(); while (!File.eof()) { File >> TempBannList; SpamBannListArray.push_back(TempBannList); } File.close(); } Add these to the spamblock.h #include "string" #include "../../common/length.h" extern void LoadBlockSpamList(); extern void LoadBannSpamList(); extern std::vector<std::string> SpamBlockListArray; extern std::vector<std::string> SpamBannListArray; Add this to game/char.cpp #include "spamblock.h" Add this to game/main.cpp #include "spamblock.h" Search for this in game/main.cpp: PanamaLoad(); Add these under that: LoadBlockSpamList(); LoadBannSpamList(); Open common/length.h and add these: SPAM_WAIT_SEC = 5, // The player can duplicate his message after 5 sec SPAM_CHAT_BAN_TIME = 60, // The player will receive 60 seconds chat ban, if he is saying a spamlist word SPAM_BAN_TIME = 3600, // The player will receive 1 hour ban, if he is saying a banlist word Open game/cmd_gm.cpp and search for this event: ACMD(do_reload) Add this to the switch function: case 'b': ch->ChatPacket(CHAT_TYPE_INFO, "Reloading bann/spam list infomations."); LoadBlockSpamList(); LoadBannSpamList(); sys_log(0, "Reloading bann/spam list infomations."); break; Add this to the top of the file: #include "spamblock.h" How to set up: Make sure you added everything to your game Create a new folder called chat in your channels Create 2 files, blockspamlist.lst and bannspamlist.lst Upload the words to these files Restart your server blockspamlist.lst example: obsceneword1 obsceneword2 obsceneword3 obsceneword4 bannspamlist.lst example: WWW.CHEAP-FARM-SERVICE.COM WWW.CHEAP-GOLD.COM WWW.EASY-HACKS.COM WWW.FREE-YANG.COM If you have any question or suggestion, please just reply to this topic. Kind Regards, Sanchez
  9. 42 points
    Hello everybody Today I will show my new system - I decided to release it...It's a very simple system and useful for PServers. What does it do? Well, it gives a random item to a player at every 12 hrs. He must enter the game and click on a gift to get the item. GM can set 5 items in DB and one of them will be gived to the players. You can change time for this system e.g.: Items ID are stored in a new table called "surprisebox". Server_side: FirstReq: If somebody wants to add new conditions to quest, first ask me in pm, then post here. Probably some people would think that it's my mistake...Thanks for understanding! Client_side: #####New: GS-Tool##### Updates: 13.iun.2014. - v1.2 - Added Gift box(17609 item) 3.july.2014 - v1.3 - Quest repaired. Added no-mysql_query version and shows box only when you can use it. Download the button: mega.co.nz - Add it in: (Etc.epk/eix)D:/ymir work/ui Download PHP-CPannel: mega.co.nz Kind regards, Zetsu I offer support, just ask me here or in PM! Soon I will add PHP_CPannel for beginners. I know this system it's very simple and contains some parts where i choose the hard way, but anyway.. i think this system keeps players online. Note: If you want to hide the Box press: LShift+P Sometimes it's annoying xD ...
  10. 42 points
    - Searching Glass, Allows the arrow mark appearing on the private shop where the item you select in the search results and guides for players to call the selling items easier access. You must be the same on the map with the seller. Default time limit; 1 Week - Trading Glass, Without going to the private shop on the same map that allows you can buy directly. Default time limit; 1 Week - Trading Glass+, Without going to the private shop you can buy directly works on any map. Default time limit; 2 Week - Common features, You can be viewed right from cheap to expensive price of items in the private shops, you can see the features of items When you move your mouse over the item you are looking for. Level, item name and bonuses you can search on the basis of price. HowTo tutorial exists in archive, Warning: It doesn't works with published shoulder sash system. You need upgrade attr type, value amounts. Download: http://puu.sh/oeibM/66130c335e.rar It doesn't looks like %100 official but it's works, My last shared and my last working in metin2.
  11. 42 points
    Hi m2dev, I release my modifications of game core. 0x01.) Here are "some" new questfunctions to you ^^ If either of them is already public I'm sorry :> but these works perfectly. A short list of them: * Item module: - get_flag | Return: Integer | Args: None - get_wearflag | Return: Integer | Args: None - get_antiflag | Return: Integer | Args: None - has_antiflag | Return: Boolean | Args: int Antiflag - get_refine_set | Return: Integer | Args: None - get_limit | Return: Table1 | Args: byte LimitIndex[0..1] - get_apply | Return: Table1 | Args: byte ApplyIndex[0..2] - get_applies | Return: Table2 | Args: None - get_refine_materials | Return: Table3 | Args: None - get_addon_type | Return: Integer | Args: None - dec | Return: Nil | Args: None or byte Count - inc | Return: Nil | Args: None or byte Count - add_attribute | Return: Boolean | Args: None - get_attribute | Return: Table1 | Args: byte AttrIndex[0..4] - set_attribute | Return: Boolean | Args: byte AttrIndex[0..4], byte AttrType[1..94], short AttrValue[-32768..32767] - change_attribute | Return: Boolean | Args: None - add_rare_attribute | Return: Boolean | Args: None - get_rare_attribute | Return: Table1 | Args: byte AttrIndex[0..1] - set_rare_attribute | Return: Boolean | Args: byte AttrIndex[0..1], byte AttrType[1..94], short AttrValue[-32768..32767] - change_rare_attribute | Return: Boolean | Args: None - equip | Return: Boolean | Args: byte EquipCell[0..32] - set_count | Return: Nil | Args: byte/short Count(short with increased item stack number) Returning item table-structures: Table1 = { -- Type, Value 1, 2000 } Table2 = { -- [idx] = {Type, Value} -- Triton sword+9: [0] = { 7, 30 }, [1] = { 22, 12 }, [2] = { 17, 12 } } Table3 = { -- Poison sword+8(refineSet:27): material_count = 2, materials = { -- { Vnum, Count } { 30091, 2 }, { 27994, 1 } }, cost = 150000, prob = 10, } * NPC module: - get_level | Return: Integer | Args: None - get_name | Return: String | Args: None - get_type | Return: Byte | Args: None - get_rank | Return: Byte | Args: None - is_metin | Return: Boolean | Args: None - is_boss | Return: Boolean | Args: None - show_effect_on_target | Return: Boolean | Args: string EffectRealPath - get_ip | Return: String | Args: None - get_client_version | Return: String | Args: None - get_job | Return: Byte | Args: None - get_pid | Return: Integer | Args: None - get_exp | Return: Long | Args: None * PC module: - get_mount_vnum | Return: Integer | Args: None - get_point | Return: Integer | Args: byte PointNumber - get_real_point | Return: Integer | Args: byte PointNumber - show_effect | Return: Boolean | Args: string EffectRealPath - disconnect_with_delay | Return: Nil | Args: int Delay - get_max_level | Return: Integer | Args: None - get_ip | Return: String | Args: None - get_client_version | Return: String | Args: None - kill | Return: Nil | Args: None * Game module: - drop_item_and_select | Return: Nil | Args: int Vnum, byte/short Count=1, bool HasOwnership=false, short OwnershipTime=180 Example call: game.drop_item_and_select(19, 1, true, 30); item.set_attribute(0, apply.CRITICAL_PCT, 10) * Pet module: - is_mine | Return: Boolean | Args: None * Global: - purge_vid | Return: Nil | Args: int Vid Here are the codes: questlua_item.cpp questlua_npc.cpp questlua_pc.cpp questlua_game.cpp questlua_pet.cpp questlua_global.cpp 0x02.) Two GM commands: - "/kill_all" -> Kill all players inside your view-range/horizon - "/drop_item" -> Drop an item from arg1, or drop all items from range(arg1, arg2) Commands: Clientside version of kill_all: 0x03.) refine_proto reloading without server restart. Extend your "/reload Proto" command with the refine_proto reloading with this code parts: - Open your db/src/ClientManager.cpp file and replace your "void CClientManager::QUERY_RELOAD_PROTO()" function to this: void CClientManager::QUERY_RELOAD_PROTO() { if (!InitializeTables()) { sys_err("QUERY_RELOAD_PROTO: cannot load tables"); return; } for (TPeerList::iterator i = m_peerList.begin(); i != m_peerList.end(); ++i) { CPeer * tmp = *i; if (!tmp->GetChannel()) continue; tmp->EncodeHeader(HEADER_DG_RELOAD_PROTO, 0, sizeof(WORD) + sizeof(TSkillTable) * m_vec_skillTable.size() + sizeof(WORD) + sizeof(TBanwordTable) * m_vec_banwordTable.size() + sizeof(WORD) + sizeof(TItemTable) * m_vec_itemTable.size() + sizeof(WORD) + sizeof(TMobTable) * m_vec_mobTable.size() + sizeof(WORD) + sizeof(TRefineTable) * m_iRefineTableSize); tmp->EncodeWORD(m_vec_skillTable.size()); tmp->Encode(&m_vec_skillTable[0], sizeof(TSkillTable) * m_vec_skillTable.size()); tmp->EncodeWORD(m_vec_banwordTable.size()); tmp->Encode(&m_vec_banwordTable[0], sizeof(TBanwordTable) * m_vec_banwordTable.size()); tmp->EncodeWORD(m_vec_itemTable.size()); tmp->Encode(&m_vec_itemTable[0], sizeof(TItemTable) * m_vec_itemTable.size()); tmp->EncodeWORD(m_vec_mobTable.size()); tmp->Encode(&m_vec_mobTable[0], sizeof(TMobTable) * m_vec_mobTable.size()); tmp->EncodeWORD(m_iRefineTableSize); tmp->Encode(m_pRefineTable, sizeof(TRefineTable) * m_iRefineTableSize); } } - Then open game/src/refine.cpp and replace this function: "bool CRefineManager::Initialize(TRefineTable * table, int size)" to this: bool CRefineManager::Initialize(TRefineTable * table, int size) { if (!m_map_RefineRecipe.empty()) m_map_RefineRecipe.clear(); for (int i = 0; i < size; ++i, ++table) { sys_log(0, "REFINE %d prob %d cost %d", table->id, table->prob, table->cost); m_map_RefineRecipe.insert(std::make_pair(table->id, *table)); } sys_log(0, "REFINE: COUNT %d", m_map_RefineRecipe.size()); return true; } - If you are done with these, open game/src/input_db.cpp and extend this event "void CInputDB::ReloadProto(const char * c_pData)" with this: /* * REFINE */ wSize = decode_2bytes(c_pData); c_pData += 2; sys_log(0, "RELOAD: REFINE: %d", wSize); if (wSize) { CRefineManager::instance().Initialize((TRefineTable *) c_pData, wSize); c_pData += wSize * sizeof(TRefineTable); } - Done. 0x04.) kill quest trigger fix (when kill / when race.kill) With this change you can use every kill methods with mobs and players and runs by once per kills. Examples: when 101.kill begin -> Works when you are killing Wild dogs. when kill begin -> Works with mobs and players too. when kill with npc.is_pc() begin -> Works with players only. when kill with npc.is_pc() == false begin -> Works with monsters only. when kill with npc.get_race() == 102 begin -> Works when you hunt Wolf. I tested with these codes: when kill begin if npc.is_pc() then chat("kill pc") end if npc.get_race() > 100 then chat("kill by race: "..tostring(npc.race)) end end when kill with npc.is_pc() begin chat("kill with npc.is_pc") end when kill with npc.get_race() == 102 begin chat("kill with npc.get_race 102") end when 101.kill begin chat("101.kill") end Follow these steps to fix it: - Open game/src/questmanager.h and search for this: "void Kill(unsigned int pc, unsigned int npc);" replace to: "void Kill(unsigned int pc, unsigned int npc, unsigned int pc2 = 0);" - Save&Close, open game/src/questmanager.cpp and search this function: "void CQuestManager::Kill(unsigned int pc, unsigned int npc)" - and replace to this: void CQuestManager::Kill(unsigned int pc, unsigned int npc, unsigned int pc2) { //m_CurrentNPCRace = npc; PC * pPC; sys_log(0, "CQuestManager::Kill QUEST_KILL_EVENT (pc=%d, npc=%d, pc2=%d)", pc, npc, pc2); if ((pPC = GetPC(pc))) { if (!CheckQuestLoaded(pPC)) return; /* [hyo] ¸÷ kill˝Ă Áßşą Ä«żîĆĂ ŔĚ˝´ °ü·ĂÇŃ ĽöÁ¤»çÇ× quest scriptżˇ when 171.kill begin ... µîŔÇ ÄÚµĺ·Î ŔÎÇĎż© ˝şĹ©¸łĆ®°ˇ Ăł¸®µÇľú´ő¶óµµ ąŮ·Î returnÇĎÁö ľĘ°í ´Ů¸Ą °Ë»çµµ ĽöÇŕÇϵµ·Ď şŻ°ćÇÔ. (2011/07/21) */ // call script if (npc > 0 && pc2 == 0) m_mapNPC[npc].OnKill(*pPC); LPCHARACTER ch = GetCurrentCharacterPtr(); LPPARTY pParty = ch->GetParty(); LPCHARACTER leader = pParty ? pParty->GetLeaderCharacter() : ch; if (leader) { m_pCurrentPartyMember = ch; if (m_mapNPC[npc].OnPartyKill(*GetPC(leader->GetPlayerID()))) return; pPC = GetPC(pc); } LPCHARACTER victim = CHARACTER_MANAGER::instance().FindByPID(pc2); if (victim && victim->IsPC() && m_mapNPC[QUEST_NO_NPC].OnKill(*pPC)) return; else if (m_mapNPC[QUEST_NO_NPC].OnKill(*pPC)) return; if (leader) { m_pCurrentPartyMember = ch; m_mapNPC[QUEST_NO_NPC].OnPartyKill(*GetPC(leader->GetPlayerID())); } } else sys_err("QUEST: no such pc id : %d", pc); } - Save&Close, open game/src/char_battle.cpp and search this call: "quest::CQuestManager::instance().Kill(pkKiller->GetPlayerID(), quest::QUEST_NO_NPC)" - and replace to this: "quest::CQuestManager::instance().Kill(pkKiller->GetPlayerID(), quest::QUEST_NO_NPC, GetPlayerID());" - Done. 0x05.) ImmuneBug fix. I know there are some fixes but this is a working solution.. Everything inside two functions into item.cpp file by names: "CItem::EquipTo" and "CItem::Unequip". Every two functions are containing this sh*!&t: DWORD dwImmuneFlag = 0; for (int i = 0; i < WEAR_MAX_NUM; ++i) if (m_pOwner->GetWear(i)) SET_BIT(dwImmuneFlag, m_pOwner->GetWear(i)->m_pProto->dwImmuneFlag); m_pOwner->SetImmuneFlag(dwImmuneFlag); Hm, you have to replace those to this: DWORD dwImmuneFlag = 0; LPITEM item = NULL; for (int i = 0; i < WEAR_MAX_NUM; ++i) { if (item=m_pOwner->GetWear(i)) { if (item->GetImmuneFlag() != 0) SET_BIT(dwImmuneFlag, item->GetImmuneFlag()); if (item->GetAttributeCount() > 0) { if (item->HasAttr(APPLY_IMMUNE_STUN)) SET_BIT(dwImmuneFlag, IMMUNE_STUN); if (item->HasAttr(APPLY_IMMUNE_SLOW)) SET_BIT(dwImmuneFlag, IMMUNE_SLOW); if (item->HasAttr(APPLY_IMMUNE_FALL)) SET_BIT(dwImmuneFlag, IMMUNE_FALL); } } } m_pOwner->SetImmuneFlag(dwImmuneFlag); - Done. 0x06.) Finished uiQuest.py selection by keyboard-usage with "Next" and "Prev" buttons. Test-example: when 9010.chat."TEST selection pages" begin local sTab = { "01","02","03","04","05","06","07","08","09","10", "11","12","13","14","15","16","17","18","19","20", "Exit"--to make exit by Escape key } local s=select_table(sTab) if s==table.getn(sTab) then return end chat("You'r choice: sTab["..tostring(s).."] -> "..sTab[s]) end Here you can download the full uiquest.py file from my client: Download 0x07.) Little SQL-Script: SELECT log.log.time AS "When", player.player.`name` AS Who, log.log.how AS WhatDid, log.log.what AS ItemID, log.log.vnum AS ItemVnum, player.item_proto.locale_name AS ItemName, player.item.count AS Count, player.item.Socket0, player.item.Socket1, player.item.Socket2, player.item.AttrType0, player.item.AttrValue0, player.item.AttrType1, player.item.AttrValue1, player.item.AttrType2, player.item.AttrValue2, player.item.AttrType3, player.item.AttrValue3, player.item.AttrType4, player.item.AttrValue4, player.item.AttrType5, player.item.AttrValue5, player.item.AttrType6, player.item.AttrValue6 FROM log.log INNER JOIN player.player ON log.log.who = player.player.id INNER JOIN player.item ON log.log.what = player.item.id INNER JOIN player.item_proto ON log.log.vnum = player.item_proto.vnum WHERE log.how in ("EXCHANGE_GIVE", "EXCHANGE_TAKE", "DROP", "SAFEBOX PUT", "SAFEBOX GET", "DEAD_DROP") AND player.`name` = "Xeriesey"; * You have to give a name where you can see Xeriesey ^-^ Result of query: I hope you like it. If you have any questions or find an error/mistake, just post a message into this thread and I will try to make answer when I'll be online. ps.: Sorry for my bad English. "(" + "c" + ")" == © -> F**k Changelog: - 2014.09.22. 16:29 / 04:29 PM ~ Added forgotten include to questlua_npc.cpp. - 2014.09.22. 16:48 / 04:48 PM ~ Added more forgotten things :S - 2014.09.27. 13:08 / 01:08 PM ~ SQL syntax fix With Regards, P3NG3R
  12. 41 points
    Hey all, Today I will explain to you how to use different designs for your quest scrolls like WoM. Setting up the system 1) Copy your scroll designs to ui/game/quest/questicon in the client. I have attached the WoM scrolls as example. 2) Open uiCharacter.py and insert the code that appears between comments: if questCount > quest.QUEST_MAX_NUM: self.questScrollBar.Show() else: self.questScrollBar.Hide() for i in questRange[:questCount]: (questName, questIcon, questCounterName, questCounterValue) = quest.GetQuestData(self.questShowingStartIndex+i) # start colored scrolls if questName[0] == '*': questName = questName[1:] elif questName[0] == '&': questName = questName[1:] elif questName[0] == '~': questName = questName[1:] elif questName[0] == '+': questName = questName[1:] # end colored scrolls self.questNameList[i].SetText(questName) self.questNameList[i].Show() self.questLastCountList[i].Show() self.questLastTimeList[i].Show()3) Open interfaceModule.py Replace this part: if locale.IsEUROPE(): btn.SetUpVisual(locale.GetLetterCloseImageName()) btn.SetOverVisual(locale.GetLetterOpenImageName()) btn.SetDownVisual(locale.GetLetterOpenImageName()) else: btn.SetUpVisual(buttonImageFileName) btn.SetOverVisual(buttonImageFileName) btn.SetDownVisual(buttonImageFileName) btn.Flash() # END_OF_QUEST_LETTER_IMAGE with this: if locale.IsSINGAPORE() or locale.IsEUROPE(): if name[0] == '*': btn.SetUpVisual("d:/ymir work/ui/game/quest/questicon/scroll_close_blue.tga") btn.SetOverVisual("d:/ymir work/ui/game/quest/questicon/scroll_open_blue.tga") btn.SetDownVisual("d:/ymir work/ui/game/quest/questicon/scroll_open_blue.tga") name = name[1:] elif name[0] == '~': btn.SetUpVisual("d:/ymir work/ui/game/quest/questicon/scroll_close_golden.tga") btn.SetOverVisual("d:/ymir work/ui/game/quest/questicon/scroll_open_golden.tga") btn.SetDownVisual("d:/ymir work/ui/game/quest/questicon/scroll_open_golden.tga") name = name[1:] elif name[0] == '&': btn.SetUpVisual("d:/ymir work/ui/game/quest/questicon/scroll_close_green.tga") btn.SetOverVisual("d:/ymir work/ui/game/quest/questicon/scroll_open_green.tga") btn.SetDownVisual("d:/ymir work/ui/game/quest/questicon/scroll_open_green.tga") name = name[1:] elif name[0] == '+': btn.SetUpVisual("d:/ymir work/ui/game/quest/questicon/scroll_close_purple.tga") btn.SetOverVisual("d:/ymir work/ui/game/quest/questicon/scroll_open_purple.tga") btn.SetDownVisual("d:/ymir work/ui/game/quest/questicon/scroll_open_purple.tga") name = name[1:] else: btn.SetUpVisual(locale.GetLetterCloseImageName()) btn.SetOverVisual(locale.GetLetterOpenImageName()) btn.SetDownVisual(locale.GetLetterOpenImageName()) else: btn.SetUpVisual(buttonImageFileName) btn.SetOverVisual(buttonImageFileName) btn.SetDownVisual(buttonImageFileName) btn.Flash() # END_OF_QUEST_LETTER_IMAGEUsage After you modified your client, there will be 4 color codes that you can use at the start of your quest's title to enable the colored scroll: Blue (*), Golden (~), Green (&) and Purple (+). You also have to add the q.set_icon function containing the filename of the scroll picture. Here is an example of how to make a quest scroll blue: when login with game.get_event_flag("worldbookday") == 1 begin send_letter("*World Book Day") q.set_icon("scroll_open_blue.tga") local v=find_npc_by_vnum(20023) if v!=0 then target.vid("__TARGET__", v, "Soon") end endAnd it looks like this: That's all you can also add new codes easily or use your own quest scroll designs. Enjoy! questicon.zip
  13. 41 points
    Hello guys today i'm gonna show u how to compile the source in freebsd. First of all you need and dns or a dedicated server because in hamachi server we can not use the fetch command We will install Gmake,Makedepend,Svn(subversion),Devil,G++ 1)gmake: cd /usr/ports/devel/gmake && make install clean 2)makedepend: cd /usr/ports/devel/makedepend && make install clean 3)svn: cd /usr/ports/devel/subversion && make install clean 4)devil: cd /usr/ports/graphics/devil && make install clean 5)G++: cd /usr/ports/lang/gcc48/ && make install clean NOTE: if you have already installed some of this step just skip the step and follow the other Then you do this: From libdevil/ copy all .a files into /usr/lib From libgame/From lib copy the From libgame.a file into /usr/lib From libhackshield/From lib copy the From libanticpxsvr.a file into /usr/lib From liblua/From lib copy the .a files into /usr/lib From libpoly/ copy the .o files into /usr/lib From libserverkey/ copy the .o files into /usr/lib From libthecore/From lib copy the From libthecore.a files into /usr/lib After copying the files into the /usr/lib do this: go to Extern folder of the novaline and open the include folder and copy everything into /usr/include go to Extern/Lib folder of the novaline branch and copy everything from there to /usr/lib go to Extern folder of the novaline branch and drag the cryptopp and openssl folders into /usr/include So we have installed everything then we have to upload the branch novaline into /usr/src then u give this command in freebsd: cd /usr/src/novaline/Server cd /usr/src/novaline/Server/ gmake To build db: cd /usr/src/novaline/Server/db/src gmake clean gmake -j20 To build game: cd /usr/src/novaline/Server/game/src gmake clean gmake -j20 Fixing the error: g++ directory": No such file or directory Solution: here
  14. 40 points
    In a few days / hours you will post the best source to client: D http://postimg.org/image/iwufapf2j/ -Binary Folder (The place is saved .exe after compilation.) -extern Folder (You realize only) -source Folder ( Contain source files .cpp and .h ) -vs_files Folder ( Containt files that's necesary for visual studio ) List of fix and definitions: Python >2.2 long overflow All mount can attack All toolset set to v120_xp (Windows xp compatibility) include source files of the client and library, all set to v120)xp toolset ENABLE_COSTUME_SYSTEM ENABLE_ENERGY_SYSTEM ENABLE_DRAGON_SOUL_SYSTEM ENABLE_BELT_SYSTEM Cryptopp 5.6.2 boost 1.55 I did not do updates because in my opinion are not required. http://prntscr.com/5yaf8b -library builder folder(This folder contains source to absolutely all the libraries it needs client. All can be built with Visual Studio 2013.) I solved all compilation errors, absolutely everything. There are only three errors that you will solve soon: D Currently working on the client, I want to pass it on OpenGL: D For linux. The link will appear in about a few hours / days, up to you if you are interested in the source ))) Soon windows server (Game & db) All projects in libraries (CWebBrowser, EffectLib etc. ..) are made by me with their own settings different from the Ymir. And if you are obedient to post a cythonized client source. If you are interested, I'll post it. So it is pointless: D DOWNLOAD LINK AVALIABLE Pleasw wait 24h , i make a special root files for this client src If you find bugs, leave message in topic so I can fix them, each update will be posted here.
  15. 39 points
    Hi, In this thread I will show you how to do an in-game ban for your GMs. First of all, you need to make a new column in the account.account. The name of the field should be reason and select varchar as type. Or just use this in your console to create the field: ALTER TABLE account ADD reason VARCHAR(256); Now open game/cmd.cpp and search for this: ACMD(do_block_chat); Add this under that: ACMD(do_ban); Search for this still in the game/cmd.cpp: { "block_chat_list",do_block_chat_list, 0, POS_DEAD, GM_PLAYER }, Make a new line and add this under that: { "ban", do_ban, 0, POS_DEAD, GM_IMPLEMENTOR }, At this point you can change the rights for the command: GM_PLAYER - do NOT choose this! GM_LOW_WIZARD GM_WIZARD GM_HIGH_WIZARD GM_GOD GM_IMPLEMENTOR Search for this event in game/cmd_gm.cpp: ACMD(do_block_chat) Add this under that: ACMD(do_ban) Now time to add the complete code to ACMD(do_ban): // Args char arg1[256], arg2[256], arg3[256]; // Local variables const char* szName; const char* szReason; int iDuration; one_argument(two_arguments(argument, arg1, sizeof(arg1), arg2, sizeof(arg2)), arg3, sizeof(arg3)); // Invalid syntax if (!*arg1 || !*arg2 || !*arg3) { ch->ChatPacket(CHAT_TYPE_INFO, "Invalid Syntax, usage: <player name> <time in hours> <reason> tip: don't use spaces in the reason, use _"); return; } szName = arg1; iDuration = atoi(arg2); szReason = arg3; if (iDuration <= 0) { ch->ChatPacket(CHAT_TYPE_INFO, "Duration can't be 0 or minus."); return; } LPCHARACTER tch = CHARACTER_MANAGER::instance().FindPC(szName); if (!tch) { ch->ChatPacket(CHAT_TYPE_INFO, "%s is not playing", szName); return; } if (!tch->GetDesc()) { ch->ChatPacket(CHAT_TYPE_INFO, "%s don't have desc", szName); return; } if (tch == ch) { ch->ChatPacket(CHAT_TYPE_INFO, "What's wrong with you? Don't ban yourself"); return; } if (tch->GetGMLevel() > GM_PLAYER) { ch->ChatPacket(CHAT_TYPE_INFO, "Do not ban GMs"); return; } std::auto_ptr<SQLMsg> msg(DBManager::instance().DirectQuery("UPDATE account.account SET availDt = FROM_UNIXTIME(UNIX_TIMESTAMP(CURRENT_TIMESTAMP()) + %i), reason = '%s' WHERE id = %d", iDuration * 3600, szReason, tch->GetDesc()->GetAccountTable().id)); tch->GetDesc()->DelayedDisconnect(5); sys_log(0, "%s[%d] banned %s for %i hours with reason: %s", ch->GetName(), ch->GetPlayerID(), szName, iDuration, szReason); ch->ChatPacket(CHAT_TYPE_INFO, "%s has been banned for %i hours with reason: %s", szName, iDuration, szReason); Check how it works: /ban <player name> <duration in hours> <reason> Example: /ban Doe 24 Hacking In-game: Database, account table: syslog: Feb 10 03:30:15.890000 :: Sanchez[57735] banned Doe for 24 hours with reason: Hacking If you have any question or suggestion, please just reply to this topic. Kind Regards, Sanchez
  16. 37 points
    Dear community, this is my first guide for you in which I will show you how you change the older Granny 2.4 version which is the client using to the newer Granny 2.9 version. For this tutorial I'm using the mainline_released client source (all client sources are the same as I heard). DO NOT FORGET TO CREATE BACKUPS! 1. Step: Navigate to novalineSrcsToolsRAD Game Toolsgrannycommon and unzip the file granny_common_2_9_12_0_release.zip. You will receive some folders. Now you navigate into the folder include and copy the granny.h file to the include folder of your client (for me it's mainline_releasedSrcsExterninclude). Then you go into the libwin32 folder and copy all the *.lib and *.pdb files into your lib folder of your client. 2. Step: Open your client source and navigate to the project EterGrnLib. Open Mesh.cpp. Search for this: int * boneIndices = GrannyGetMeshBindingToBoneIndices(pgrnMeshBinding); Replace with this: int * boneIndices = (int*)GrannyGetMeshBindingToBoneIndices(pgrnMeshBinding); Search for this: return GrannyGetMeshBindingToBoneIndices(m_pgrnMeshBindingTemp); Replace with this: return (int*)GrannyGetMeshBindingToBoneIndices(m_pgrnMeshBindingTemp); Search for this: m_pgrnMeshDeformer = GrannyNewMeshDeformer(pgrnInputType, pgrnOutputType, GrannyDeformPositionNormal); Replace with this: m_pgrnMeshDeformer = GrannyNewMeshDeformer(pgrnInputType, pgrnOutputType, GrannyDeformPositionNormal, GrannyAllowUncopiedTail); ----- Open ModelInstanceUpdate.cpp. Search for this: GrannyUpdateModelMatrix(m_pgrnModelInstance, fSecondsElapsed, (const float *) pMatrix, (float *) pMatrix); Replace with this: GrannyUpdateModelMatrix(m_pgrnModelInstance, fSecondsElapsed, (const float *) pMatrix, (float *) pMatrix, false); ----- Open Material.cpp. Search for this: granny_variant twoSideResult = GrannyFindMatchingMember(pgrnMaterial->ExtendedData.Type, pgrnMaterial->ExtendedData.Object, "Two-sided"); if (NULL != twoSideResult.Type) GrannyConvertSingleObject(twoSideResult.Type, twoSideResult.Object, TwoSidedFieldType, &twoSided); Replace with this: granny_variant twoSideResult; if (GrannyFindMatchingMember(pgrnMaterial->ExtendedData.Type, pgrnMaterial->ExtendedData.Object, "Two-sided", &twoSideResult) && NULL != twoSideResult.Type) GrannyConvertSingleObject(twoSideResult.Type, twoSideResult.Object, TwoSidedFieldType, &twoSided, NULL); ----- Open ModelInstanceModel.cpp Search for this: return GrannyGetMeshBindingToBoneIndices(m_vct_pgrnMeshBinding[iMeshBinding]); Replace with this: return (int*)GrannyGetMeshBindingToBoneIndices(m_vct_pgrnMeshBinding[iMeshBinding]); ----- Navigate to the UserInterface project. Open UserInterface.cpp. Search for this (it's at the end of the file): static void GrannyError(granny_log_message_type Type, granny_log_message_origin Origin, char const *Error, void *UserData) { TraceError("GRANNY: %s", Error); } Replace with this: static void GrannyError(granny_log_message_type Type, granny_log_message_origin Origin, char const* File, granny_int32x Line, char const *Error, void *UserData) { TraceError("GRANNY: %s", Error); } Now rebuild the whole project! 3. Step: Go to the folder where we unziped the things of the first step and go to the lib folder. Copy the granny2.dll into your main client directory. Now you're finished and you have Granny 2.9. I hope this guide helped you! Special Thanks to Cryfact! Regards
  17. 37 points
    This guide will walk you through each step of installing the necessary daemons for a Metin2 server on FreeBSD. Asking for help setting up Metin2 on the official FreeBSD forums is not permitted, I suggest if you have issues to ask in this forum only. You may not need to install cURL, it depends on whether or not you'll host your website on the same server and use things that require cURL (such as automatic paypal transactions). It's recommended to host your website on a separate web server and not share the IP with anyone then run it through CloudFlare. A guide will be posted soon in these forums on how to run your website through CloudFlare while preventing CloudFlare IP resolvers from functioning. However, if you do run your website on another server I would recommend hosting it in the same datacenter because you'll need to use Remote MYSQL to access your database. - For sake of simplicity I'll be using "ee editor" for this guide. Most new people don't like vi anyway. If you're already familiar with vi, feel free to use that to edit text inside files instead. - To transfer files to and from your server, use WinSCP. - To enter commands into your server, use PuTTy. Please note that when the system asks you for a password in PuTTy you won't see it as you type it on the screen, be precise! - Pressing the TAB key in PuTTy will auto-complete as much as possible in the directory you're in. Downloads Libs: https://mega.co.nz/#!rExCyBba!dho0EjPjjHLzARsaQ3XU2yY38mpRBrf0YpilLo3aC4c 1. Updating Ports portsnap fetch extract portsnap update 2. Installing Python 2.7 cd /usr/ports/lang/python27 make -DBATCH install clean pro tip: Use the "-DBATCH" flag for a default installation of the port. Skip all those annoying prompts during installation. 3. Standard C++ Libraries fetch ftp://ftp.freebsd.org/pub/FreeBSD/releases/amd64/amd64/9.1-RELEASE/lib32.txz tar Jxpvf lib32.txz -C / rm lib32.txz Unrar "Libs.rar" and put the files in the "/usr/lib32" directory. 4. Compat7x Because Metin2 was originally meant to be run on FreeBSD 7, we need this so that it's compatible with FreeBSD 9. cd /usr/ports/misc/compat7x && make -DBATCH install clean pkg_add -r compat7x-amd64 5. Install & Configure MySQL 5.6 server cd /usr/ports/databases/mysql56-server make BUILD_OPTIMIZED=yes BUILD_STATIC=yes make WITH_XCHARSET=all install clean Now we make it start on each startup of the system. ee /etc/rc.conf Add a new line: mysql_enable="YES" Press ESC then save and close the file. service mysql-server start /usr/local/bin/mysqladmin -uroot password 'enterpassword' pro tip: "enterpassword" should be the password you choose, don't use "enterpassword" as your password. A long string of lower case and capital letters and numbers is the safest bet. Don't use words that can be found in a dictionary. Don't use passwords which are the same as other passwords of yours. You may not need to do this, but when I got an OVH server it messed up the installation of mysql (on 9.2). If you get an error about the mysql user account with the step above, just do this: pwd_mkdb -p /etc/master.passwd chown -R mysql /var/db/mysql && chgrp -R mysql /var/db/mysql Then repeat the step. 6. Adding your server files and Metin2 Database Extract your game.tar.gz containing all the Metin2 server files somewhere in your server. This is all you have to do to extract a .tar.gz file: tar -zxvf filename.tar.gz You should have your metin2 database inside of a tarball (.tar.gz file). For structure, it doesn't really matter as long as once you extract your tarball on your server it follows this file hierarchy: Now you should change the group and ownership of some files for your database: service mysql-server stop chown -R mysql /var/db/mysql && chgrp -R mysql /var/db/mysql service mysql-server start Setup an account for you to login to the database via Navicat and an account for your game cores to interact with your database using. For this example I'll use the username "rumor" for my account and "metin2" for the game core's account. Every password in this example will be "password" but please DO NOT use this as your password! If you have a static IP address and wish to restrict access to the database only to your IP, change the "%" sign to your IP. The "%" sign indicates that any IP address is allowed to connect to the database using the specified credentials. mysql -p Now enter the password you set with mysqladmin earlier... and you will see this prompt: mysql> This is where we set the actual permissions for the accounts up. GRANT ALL PRIVILEGES ON *.* TO 'rumor'@'%' IDENTIFIED BY 'password' WITH GRANT OPTION; GRANT ALL PRIVILEGES ON *.* TO 'metin2'@'localhost' IDENTIFIED BY 'password' WITH GRANT OPTION; quit pro tip: remember (or write down) this information because you will need it later. Setup your CONFIG files under each channel folder and the "auth" folder. All of these are found inside the Metin2 server files. PLAYER_SQL: localhost metin2 password player COMMON_SQL: localhost metin2 password common LOG_SQL: localhost metin2 password log The conf.txt file looks a little bit different and it's found in the "db" folder of your Metin2 server files. SQL_ACCOUNT = "localhost account metin2 password 0" SQL_PLAYER = "localhost player metin2 password 0" SQL_COMMON = "localhost common metin2 password 0" SQL_HOTBACKUP = "localhost hotbackup metin2 password 0" ~~~~ STOP HERE IF YOU'RE RUNNING YOUR WEB SERVER SOMEWHERE ELSE ~~~~ 7. Setting up web server for website and/or patcher Install nginx: cd /usr/ports/www/nginx make install clean Make sure these are selected with space bar: [X] HTTP_MODULE Enable HTTP module [X] HTTP_ADDITION_MODULE Enable http_addition module [X] HTTP_CACHE_MODULE Enable http_cache module [X] HTTP_GEOIP_MODULE Enable http_geoip module [X] HTTP_GZIP_STATIC_MODULE Enable http_gzip_static module [X] HTTP_IMAGE_FILTER_MODULE Enable http_image_filter module [x] HTTP_PERL_MODULE Enable http_perl module [X] HTTP_REALIP_MODULE Enable http_realip module [X] HTTP_REWRITE_MODULE Enable http_rewrite module [X] HTTP_STATUS_MODULE Enable http_stub_status module Press "Enter" when ready to continue. Install libtool cd /usr/ports/devel/libtool make install clean Install php5 cd /usr/ports/lang/php5 make config Make sure the following is selected with space bar then press "Enter": [X] FPM Build FPM version (experimental) Leave everything else default. then do this: make install clean ~~~~ If you need cURL support then do this, if not then skip this step: cd /usr/ports/lang/php5-extensions make config Make sure that the "CURL Support" is selected then press "Enter". Then do the installation and clean the directory: make -DBATCH install clean ~~~~ Time to configure your php.ini file... cp /usr/local/etc/php.ini-production /usr/local/etc/php.ini Edit /usr/local/etc/php.ini in WinSCP using Notepad++. Firstly, set your "date.timezone" to the appropriate one. Choose from this list: http://php.net/manual/en/timezones.php Next, if you have something that needs to run large MYSQL queries you may run into some issues. Some website packages also can cause these problems. The issue is with memory usage. For security reasons there are limitations set on how much memory php is allowed to use. I suggest only modifying this IF you have problems loading memory-intensive pages. Just try to raise it a bit until it works, don't raise it to an excessively high number. I had to set mine to "512M" to make my queries work in my patcher. It can be set by just inputting numbers and they will be recognized as bytes, or you could use K, M, or G. memory_limit = 512M Installation of php-mysql5: cd /usr/ports/databases/php5-mysql make -DBATCH install clean If you've gotten this far, congratulations.. you're almost done! You need to create a folder for your website like this: mkdir /usr/local/www/nginx/domain.com Set the owner and permissions: chown www:www /usr/local/www/nginx/domain.com chmod 755 /usr/local/www/nginx/domain.com Customize this file to your needs and upload it to /usr/local/etc/nginx: If you're using cloudflare, uncomment the lines 38-57 by removing the "#". The reason for this is to ensure you get the real user IP in your logs rather than cloudflare's IP. If you want to allow directory listing.. ie: [url=http://domain.com/files]http://domain.com/files to present a visitor with a list of files they can access/download then uncomment lines 63 and 73. You MUST change the domain name to your own! Now you need to enable startup of php-fpm and nginx whenever your server is booted: ee /etc/rc.conf Add these lines: php_fpm_enable="YES" nginx_enable="YES" Start your services: service php-fpm start service nginx start Upload your website files to /usr/local/www/nginx/domain.com
  18. 37 points
    Good afternoon guys, As far as I know there is no available up to date client at the moment, so it's finally time to release one. Can I modify the root? It have .py files? Yes, you can modify it without any problems. Is it contains the updates from the last few weeks? Yes, everything till today. Can I unpack the patches or they are archived with type 4? Every patch has been repacked with type 0-1-2 without any modifications. What archiver should I use? It depends on you, but you can use the r3869/r2806 by Tim, which is available on this board. Is the client have any modifications? No, I just had to modify some lines in the root to get it work with the binary. Is there any way to use again the "pong"? Yes! The client contains 2 binary and the secondary one support it. (Please note: Without the modification of the (40250)game file the secondary binary will not work) metin2client_without_pong.exe metin2client_with_pong.exe Is the binary use Python 2.7? Sure, it's using 2.7. Is the the client have any known bug? I tested many time the client and I didn't found anything. Please let me know if you found an issue. I don't trust you. Can you prepare a VirusTotal? I can't. The size of the client is way too big for VT, but you can find the results of the binaries on pastebin. Download: PASTEBIN
  19. 35 points
    Greetings! The new beta is finished! I'm proud to present r71480. This time a few things have changed. And in this revision, we have a lot of new stuff. In the following I'll provide the download link along with the things I'd love you to test. *** DISCLAIMER *** The core is marked as stable. Anyway, I'll make it clear that I'm not responsible if you use this core since I can't give a warranty that I fixed every single security breach that potentially could happen - that's totally impossible. But we all together made the source great and secure so every public issue is fixed by now. You can use it in production environments now. So... What's new? boot-trigger for quests With this you can execute commands, timers, and all the stuff you'd like to have just on boot-time! revisioning of the 'unique class' (+ a ton of posibilities) added the functionality to create unique-groups temp-Variables for quests upgraded all libs moved completely to the newest clang version fixed some big security issues in the source code fixed the ingame ban and unban commands unified tables and gave them a new way: unify! file clean-up revisioned the makefiles gave the source a new, easier structure removed all external dependencies just install them by ports.. No external-folder necessary! removed 'boost' dependency (no boost lib needed yay) partial implementation of the wolfman (claws etc. are added, needs review) And basically everything that has been offered in the earlier versions of the vanilla core. Nothing should be missing. And if you miss something, just feel free to tell me! What needs testing? There are few things I'd love you to test out: Please check if the core is vulnerable to any security breaches you may know (also the public ones, don't know if I missed something) Please test out the new features! I'd really love to know if the new unique-functions and the boot-trigger does the job. Explanation to new features: Unique with container support Unique has evolved! This time you have a few new possibilities. Don't know what unique is? Here's a short explanation: With the unique-questfunctions you can spawn or set mobs, npcs and now even players to have a unique name. This name is stored into a unique-container. You can access this container and get all the vid's by their unique name (also called: the key) So for example you can spawn a boss with a key. Later on you can check if this specific mob has been killed or not. Or you can set his hp on-the-fly. There's basically no limits! And now with the revised system you'll have even more options. The new unique system works with containers. By default there are two containers reserved: __DEFAULT__ and __CHARACTER__. The first one is for all the basic stuff. And the second one is reserved for players. Now, as you may have noticed, there's a default one which means that the container-stuff is optional. If you just use the unique functions without specifying a container, it'll just use the default stuff. But you CAN use your own containers just as you want to. You can create, delete and list all the containers running. There is a list with all the quest-functions down below. boot-trigger This is pretty self-explanatory. With this release you can use "when boot begin" to specify a block of code that will be executed once the core has been booted. temp-variables With the new temp-variables you can set and remove player-specific variables. They are stored in the core and not written to disk or database. So be careful because they might get dropped once the core shutdowns. It's just a quick storage for people who want to have something like a cache for quick access. new quest functions nil unique.spawn_unique(string key, int vnum, string pos=unused, string container=optional) nil unique.set_unique(string key, int vid, string container=optional) nil unique.purge_unique(string key, string container=optional) nil unique.kill_unique(string key, string container=optional) bool unique.is_unique_dead(string key, string container=optional) int unique.get_hp_perc(string key, string container=optional) nil unique.set_def_grade(string key, int def, string container=optional) nil unique.set_hp(string key, int hp, string container=optional) nil unique.set_max_hp(string key, int maxhp, string container=optional) int unique.get_vid(string key, string container=optional) bool unique.exists(string key, string container=optional) table unique.get_container_list() this prints out all the unique containers table unique.get_container_list(string key) this prints out all the vids in the unique-container "key" nil unique.remove_container(string key) removes a whole container (flushes it when called on standard containers) nil pc.temp_var_set(string key, string value) string pc.temp_var_get(string key) nil pc.temp_var_delete(string key) Thanks a lot for participating! If there are any questions, this is the topic related to it. Further releases will be made public here too! If you'd like to contribute, just post code additions here. Changelog older changelogs Download Useful information: All necessary libs are included. If you're building your own vanilla binary you'll first have to move into every project of the Internal directory and rebuild the libs. The main makefile is not adapted yet, I was too lazy (ps: Still too lazy!) rev 71480 see this post: rev 70220 STABLE Core Sourcecode rev 70140 BETA Core Sourcecode Password for the archive is: vanilla Password for older source archives: vanillamt2 Best Regards Vanilla
  20. 35 points
    Hi everyone, Maybe just in my country, but it looks so many people started using this annoying PM flooder which cause a buffer overflow in the target client. It can be fixed easily on server-side, so let's do it: Add these functions as public to char.h: void ClearPMCounter(void) { m_iPMCounter = 0; } void IncreasePMCounter(void) { m_iPMCounter++; } void SetLastPMPulse(void); int GetPMCounter(void) const { return m_iPMCounter; } int GetLastPMPulse(void) const { return m_iLastPMPulse; } Add these to char.h too, but as protected: int m_iLastPMPulse; int m_iPMCounter; Add this function to char.cpp: void CHARACTER::SetLastPMPulse(void) { m_iLastPMPulse = thecore_pulse() + 25; } Still in char.cpp search for the Initialize and add these to the function: m_iLastPMPulse = 0; m_iPMCounter = 0; Now navigate to the Whisper function in input_main.cpp and add this after the iExtraLen variable checking at the top: if (ch->GetLastPMPulse() < thecore_pulse()) ch->ClearPMCounter(); if (ch->GetPMCounter() > 3 && ch->GetLastPMPulse() > thecore_pulse()) { ch->GetDesc()->SetPhase(PHASE_CLOSE); return -1; } Search for this still in the Whisper function: if (pkChr == ch) return (iExtraLen); Add these after that: ch->IncreasePMCounter(); ch->SetLastPMPulse();
  21. 35 points
    Hi guys, Since people are asking for a 34k client I have decided to release the World of Metin2 beta client from early last year. Many people have contributed to this release, namely the whole WoM team which as you may know is pretty big, but particularly Tim who created most of the scripts and the compiling stuff. Contents The package includes: bin folder: this is where you actually run the client. The client includes tim's granny 2.8 DLL and a .mix file that allows attacking on mounts made by Paylasici (DynamicPatcher.mix). Warning: metin2.bin may be identified by your antivirus as a threat. It's just packed with Themida. Why packed? because otherwise Tim's dll doesn't work. You will need to create the epk files first. A patch maker/uploader script is also included in this folder. data folder: the contents of the Eterpack archives, unpacked. Includes batch files to create the packs, an automatic XML generator (make_xml.py, configurable through make_xml.xml) and root/uiscript/locale pyc compiler. The data folders contain every official file (costumes pets etc) up to March 2013, and a few of our own. tools: includes FileArchiver, Tim's lz, and python22 (used by the compiling scripts). launcher: includes everything necessary to create your own official launcher Installation Unpack wherever you want Install Python2.7(if you don't have it already) and add your Python27 installation folder to the System Path Add the tools folder to the System Path Usage Edit the client to your liking and then run the appropiate make_*.bat file to compile the pack into the bin/pack folder. When done, make a copy of metin2.bin called metin2client.exe so you can test the client locally. Patch maker There is an official patch maker included under bin/make_patch.py configurable through Patch_config.txt, it will read an online crclist and a list of files / archives and create a zip file containing the updated archives (lz'ed) and the updated crclist. Syntax make_patch.py [-f filename] [-a packname] [-p patch (see PatchConfig.txt)] Example python make_patch.py -f pack/Index -a root -a uiscript -p patch_test Then you just need to upload this zip file to your patch root and unzip it. Regards World of Metin2 Client for metin2dev.org - Base.7z 95.9 MB https://mega.co.nz/#!WhpiVDBI!ipa7YoFKoo5Qnft7calTquWczM_WCScnyC3VQctUhNk World of Metin2 Client for metin2dev.org - Extra.7z 486.2 MB https://mega.co.nz/#!nhAV3RjY!e8ACrA-IwgwNk49vBAMBqa0ULf2tOZl5v8vcdLEpYZU
  22. 34 points
    June 17 2014 - I rewrote the whole the source. FAQ: How can I open the project, which version of Visual Studio do I need? I used Visual Studio 2013, but I'm sure you can open in 2012 too. What is CRC? You can learn more about Cyclic redundancy check here. How can I make a list for the patcher? You can use the lister tool, it's in the source. HOW TO MAKE IT WORKS: 1. Change the ServerURL variable in Globals.cs to your url 2. Build the project 3. Create a list with the lister tool (Example of the list) 4. Upload the files and the patchlist to your server (Example of the folder structure) Downloads: MEGA.CO.NZ If you have any question or suggestion please just reply to this topic. Kind Regards, Sanchez
  23. 33 points
    I go to release a simple system , to see the coins in the inventory. http://youtu.be/93aufcRE_4s REMEMBER: localeInfo is from binary r28k locale is from binary r36k First, go to uiinventory.py and now search: self.wndMoneySlot = self.GetChild("Money_Slot") And down put: self.wndMds = self.GetChild("Mds") self.wndMdsSlot = self.GetChild("Mds_Slot") Now, search def Destroy(self): self.ClearDictionary() .... .... self.wndMoney = 0 self.wndMoneySlot = 0 And down put: self.wndMds = 0 self.wndMdsSlot = 0 Now, Search: def RefreshStatus(self): And change to: def RefreshStatus(self): money = player.GetElk() self.wndMoney.SetText(localeInfo.NumberToMoneyString(money)) import constInfo self.wndMds.SetText(str(constInfo.mds) + " Md's") And down Put: def OnUpdate(self): import constInfo self.wndMds.SetText(str(constInfo.mds) + " Md's") The uiinventory is finished, save and close, now go to locale/xx/ui/inventorywindow.py. Search: ## Print { "name":"Money_Slot", "type":"button", "x":-68, "y":28, "horizontal_align":"center", "vertical_align":"bottom", "default_image" : "d:/ymir work/ui/public/parameter_slot_05.sub", "over_image" : "d:/ymir work/ui/public/parameter_slot_05.sub", "down_image" : "d:/ymir work/ui/public/parameter_slot_05.sub", "children" : ( { "name":"Money_Icon", "type":"image", "x":-21, "y":2, "image":"d:/ymir work/ui/game/windows/money_icon.sub", }, { "name" : "Money", "type" : "text", "x" : 5, "y" : 3, "horizontal_align" : "right", "text_horizontal_align" : "right", "text" : "123456789", }, ), }, And Down Put: { "name":"Mds_Slot", "type":"button", "x":-68, "y":48, "horizontal_align":"center", "vertical_align":"bottom", "default_image" : "d:/ymir work/ui/public/parameter_slot_05.sub", "over_image" : "d:/ymir work/ui/public/parameter_slot_05.sub", "down_image" : "d:/ymir work/ui/public/parameter_slot_05.sub", "children" : ( { "name":"Mds_Icon", "type":"image", "x":-21, "y":2, "image":"d:/ymir work/ui/game/windows/money_icon.sub", }, { "name" : "Mds", "type" : "text", "x" : 5, "y" : 3, "horizontal_align" : "right", "text_horizontal_align" : "right", "text" : "123456789 Md's", }, ), }, Remember change the "x" and "y". Now, go to game.py in root. Search: def __ServerCommand_Build(self): serverCommandList={ And down put: #Carga Mds Start "Mds" : self.__Mds, #Carga Mds End and now, go to the end and put: def __Mds(self, coins): import constInfo constInfo.mds = int(coins) Save and close. Now go to constinfo.py and put mds = 0 And Here the quest: quest mds begin state start begin when login begin loop_timer("carga_mds", 10) end when carga_mds.timer begin local coins = mysql_query("SELECT coins from account.account WHERE id="..pc.get_account_id().." LIMIT 1;")[1][1] cmdchat("Mds "..coins) end end end This is my release in this forum. Sorry my bad english.. I'm Spanish. If you don't know how put, upload my archives uiinventory and inventorywindow.py https://mega.co.nz/#!R9A3SD6Q!IFZ38BXrwGOt0Z8N3qT9g5vr5XAa4DdKdeAf2KRlPEY
  24. 33 points
    For years now we've relied on various file leaks which were usually in some Asian language, up until 2010 when someone (nico_w?) released the SG database. Even after this date, we continued to use our old file structures and methods, and old bash scripts to manage our servers. In 2013, some files were released which came from a private server that was based off the SG files. This isn't a thread to talk about who's right or wrong, or who did what work or anything like that... just a place to release files. The reason this release is beneficial is we've never really had a full release of "clean" and "untouched" files. Every time someone releases files they have some stupid backdoor added or are heavily modified from the original. The goal of this release is to get the files to be as close as possible to an official server, and remove things like Xtrap which none of us are using anyway. Official files is what all the pservers are based off of, so having the official structure just makes sense. There are several threads online with files that have been modified by some person but I never see threads with the files the way they originally came. These files in the game folder are from July, 2013 and the game/db cores are fully unmodified and straight from YMIR. That includes lack of modification to make them compatible with certain clients or anything like that. Garbage files like old logs are removed and ready to be generated when you launch your server. These are meant to be a "base server" for the one you want to create. For this reason, there are no customized quests or new items and stuff like that. It's only what SG had in 2013 of July. The database structure is the one from this thread: http://metin2dev.org/board/topic/174-complete-34k-db-structure/#entry950 The item_proto and mob_proto is the one from SG in July 2013. I've included a tool in the download as well used to dump the server proto to the client. Since the goal is purity of files, but some files had to be slightly modified for simplicity (and so they run at all) here's the list of things changed/removed: - Removed panama folder. - Removed old log files and pid files, etc.. - Removed Xcrap stuff - Removed all traces to the above (Symlinks) from install.sh. - Removed cshybridcrypt files. - Modified CONFIG file to guide you into configuration for your own usage. - The quests are from the leak of pserver files based off SG. Some of these may or may not work fully. - Timebomb fix applied (Updated: March 13th, 2014) Now in order to use these files: 1. Upload and untar the database and server files. "untouched_34083_db.tar.gz" goes in "/var/db". 2. Navigate with PuTTy to the game folder as a root user and run this command: "chown -R metin2 .". 3. Navigate to the game folder as the metin2 user and run install.sh. This will setup all the permissions and symlinks correctly. 4. Restart your database with the command "service mysql-server restart". The server can be started and stopped by executing "run.sh" and "shutdown.sh" and logs can be cleared by executing "clear.sh". All of these are found in the game folder. Make sure to "/shutdown" ingame before using "shutdown.sh" or you may have data loss. Don't be alarmed when running the shutdown script, it's normal for PuTTy to not give you a prompt for a while (you haven't disconnected from SSH). How to convert the database proto to a perfect client-side proto: 1. Grab the following files from the conf folder in the server files: mob_proto.txt mob_names.txt item_proto.txt item_names.txt 2. Put those files in a folder with the "dump_proto.exe" tool and run it. It will automatically generate the protos for your client assuming you have followed the correct structure of the txt files. Download: https://mega.co.nz/#!aNp3CJCa!UYpjfJvzWPDejhOTysXTqa-o0bQ_JsC5Q6emudCCQc4 (Updated: March 13th, 2014) - No password (I don't believe in putting passwords on archives released to the public).
  25. 32 points
    Description: Today's New Year's eve, and I felt that I should help the people who can't compile the gamecore/db on FreeBSD, because of the library mess that's usually going on - most people compile DevIL, mysqlclient etc from the ports collection, as this takes a lot of time, hardware resources, and even knowledge for some. Given this situation, I've decided to compile from the official sources of all the required libraries, and tidy a bit up the all lib-includes files, by putting them all into the Extern folder (link below). This allows to brush away some stuff from the Server folder: (Yay, it's so clean and shiny ) I've also changed the makefiles according to the needs (link also below). This pre-done stuff should easy the process of compilation a lot for others, not to mention that it should work on all branches (I'm gonna test this next year lol ) Usage: Decompress your Server folder from your favourite branch, and upload it to a FreeBSD machine, which has gmake, makedepend and python installed. Nothing more is needed (except for gcc/g++ ofc). Upload the Extern.tgz archive into the same folder where you put the Server folder, and extract it. Patch the Makefiles in the Server folder with the ones from Makefiles.zip. Compile using gmake / gmake all / gmake game / gmake db from within the Server folder. Video (da n00b prooph part): Note: my English pronounciation isn't that great; I'll be adding subtitles asap. Downloads: Extern.tgz: https://mega.co.nz/#!EZMzxD4R!w1HSgj5F14-K0nB2oLOMzvXZan-UOVKtYjNiGjc3Ioo Makefiles.zip: https://mega.co.nz/#!ZY1FGBzD!3tgmBRLfAfVTwC-qWo4oDAW2sq_jkGX7gADzkExn3_c Happy New Year!
  26. 32 points
    File Name: WorldEditor ReMIX File Submitter: martysama0134 File Submitted: 27 Aug 2014 File Category: Tools Intro: This WE is a version compiled directly by me which includes infinite fixes and features. It's certain that you won't longer use the worldeditor_en! To make it simple, I wrote all the details about this feature and the common WE inside the relative config file: (called WorldEditor.txt) // I recently built a new worldeditor version with new features, so: Be a guinea pig of mine and test it all! // Info: (v24) // -) 100% translated // -) granny2.9 // -) F6 as Insert alternative // -) many default features not present inside the worldeditor_en (probably, that binary was taken out from an SVN long time ago and resource hacked) such as Ins for all regions and skyboxes // -) WASD UPLEFTDOWNRIGHT to move around (+asynchronous diagonally movements) // -) UP-LEFT-DOWN-RIGHT to move around*10 (+asynchronous diagonally movements) // -) config file for few things // Output options by default // few others such as default WASD movement // whether or not Insert should let you go where you were before the press // no MAI dump when saving atlas // whether or not DevIL should compress and remove alpha from minimap.dds // whether or not loading .mdatr building heights // default textureset when creating maps // overlapped tabs // other stuff // -) few bugfixes // default title app name // attempting to write to an empty textureset name when creating new maps // ViewRadius doubled every load&save // shadowmap.dds creation // assert when saving atlas // crash when adjusting height // many buffer under/overflows // *.mdc collision data saving (for game_test) // not checking output options when loading maps // water brush waterid bug (the id was increased until 256 each time the function was called; now it's based on the water height just like it should be) // init texture map reload map crash and last 2px always blank // if pack/property exists, it'll be read! (note: if found, the local property/ directory will not be considered!) // square shape even for up/down height brushes // add textureset texture button (+multiselection) // remove textureset texture feature (just selecting a texture from the list and pressing DELETE) // creation of empty textureset with index -1 (changed to 0) // change baseposition button // misspelled stuff // skybox bottom image (nb: you also need a fixed launcher for this) // removed the boring CTRL requirement (to move the camera) when editing daylight/attr // fixed refresh texture imagebox when onKey-pressing the down/up keys (like when onClicking them) // fixed TextureSet file creation if not existing // fixed new wolfman motion event handling // -) created new TextureSet field when creating new maps // -) created new Change/Delete Texture buttons when double-clicking a texture // -) created Background Music playback and Shadow Recalculate buttons // -) created water height "set 0z", "+1z", "-1z" buttons // -) server_attr generator // Note: // 0) there are no regressions in this version! a bug here means it'd also be present in older WE versions too! // 1) the shadow output option is tricky: when UpdateUI is called, shadows are hidden although the check is pressed (i implemented the shadow recalculate function for that) #fixed since v11 // 2) the bgm player requires /miles and the fadein/out doesn't work until you load the map // 3) the adjusting height button works only if mdatr height is detected // 4) the Debug version is laggy when working on maps such as n_flame_dungeon and n_ice_dungeon (by default, because SphereRadius are intensively checked in SphereLib\spherepack.h) // 5) if you load a map, the script panels (where you load .msa et similia) will have the camera perspective a little fucked up (0z instead of -32767z or 0x 0y -163,94z) // 6) few tree objects are not movable and/or highlightable after placed on the ground and their selection is invisible (you can still delete 'em) // trick: draw a square selecting a normal building and 'em, then move the building and you'll see all of 'em will be moved! // 7) the server_attr generator will clean all the unused flags! attr[idx]&=~0xFFFFFFF8; // 8) you can read files from pack/Index 'n stuff but be aware that Property will not be considered! #fixed since v15 // 9) the MonsterAreaInfo features are laggy and buggy as fuck // 10) even though you can select many textures at once (using ctrl+click on textureset list; for brushing or initializing a base texture), you can't delete more than one at the same time // 11) the .mdatr height is tricky; if you move a building, the height will not be refreshed until you put a new building or whatever you want to trigger the update event // 12) by default, the worldeditor tries to render only the first 8 terrain textures of a 32x32px region (nb: a 1x1 map is a 256x256 px region) // 13) the minimap rendering cannot catch the buildings/trees inside the first 2x2 regions due a ymir cache fault and you need to set the camera to "see" them // 14) when the textureset, environment, etc load fails, the old filename still remains loaded // 15) the attr flag "3" (three) has no implementation, so don't use it! // TODO: // A) look at more than 8 textures for region -> DONE // B) create a shortcut to fix the #5 note -> DONE // C) disable the radius <= GetRadius()+0.0001f check to fix the #4 note -> REJECTED // the worldeditor_en calls this assert and, if ignored, the lag ceases to exist (this will not occur in source version) // at least, if the release version is not a problem for you, use that in those few cases when .mse are abused and try to kill the debug one // D) translation in more languages other than english -> REJECTED // english should be enough! // E) alternative path for d: -> REJECTED // you can mount d as a subpath of c like this: // subst d: "c:\mt2stuff" // ### WE CONFIG FILE VIEW_CHAR_OUTPUT_BY_DEFAULT = 1 VIEW_SHADOW_OUTPUT_BY_DEFAULT = 1 VIEW_WATER_OUTPUT_BY_DEFAULT = 1 // WINDOW_HEIGHT_SIZE = 1080 // WINDOW_WIDTH_SIZE = 1920 WINDOW_FOV_SIZE = 45 // #100 = 1px (minimal px movement when pressing WASD) WASD_MINIMAL_MOVE = 100 // came back from where you were before pressing Insert/F6 NO_GOTO_AFTER_INSERT = 1 // disable MAI dumps when saving atlas and/or pressing Insert/F6 NOMAI_ATLAS_DUMP = 1 // disable minimap.dds alpha saving and enable compression NOMINIMAP_RAWALPHA = 1 // enable .mdatr height collision loading when moving on buildings or adjusting terrain DETECT_MDATR_HEIGHT = 1 // disable fog when loading maps NOFOG_ONMAPLOAD = 1 // refresh all checkbox configurations when loading maps 'n stuff REFRESHALL_ONUPDATEUI = 0 // set a default mapname prefix when creating new maps ("" to disable) NEW_MAP_MAPNAME_PREFIX = "metin2_map_" // display a default textureset when creating new maps ("" to disable) // note: it loads the filepath if exists, otherwise it will create an empty textureset file NEWMAP_TEXTURESETLOADPATH = "textureset\metin2_a1.txt" // create a default textureset as "textureset/{mapname}.txt" // note: this option is not considered if NEWMAP_TEXTURESETLOADPATH is not empty. [before v24] // note: this option is not considered if the TextureSet path input is not empty when creating a new map [since v24] NEWMAP_TEXTURESETSAVEASMAPNAME = 1 // ## SHORT-CUTs // # ESC(ape) Clean cursor // # Canc(el|Delete) Delete stuff such as selected buildings // # Ctrl+S Save map // # Ins(ert) or F6 Save shadowmap|minimap.dds // # F3 BoundGrid Show/Hide // # F4 Render UI Show/Hide // # F11 WireFrame Show/Hide // # R Reload Texture // # Z and X Decrease/Increase Texture Splat by 0.1 // # CapsLock Show GaussianCubic effect if shadows are displayed // # L-Shift+1-6 Show TextureCountThreshold flags (&2-7) as colors on the ground // # L-Shift+8 Set Max Showable texture to 8 (de-fix note 12) // # L-Shift+0 Set Max Showable texture to 255 (fix note 12) // # H Refresh MDATR Heights (useful when you move an object) (fix note 11) // # Y Set Perspective as default (fix note 5) // # T Set the Camera to catch all the object on the screen (w/a note 13) then you'll be ready to press Insert/F6 // # DO NOT HAVE AN OBJECT SELECTED WHEN USING THOSE SHORTCUTS (MW1-7) // # MouseWheel+1 move cursor x rotation // # MouseWheel+2 move cursor y rotation // # MouseWheel+3 move cursor z rotation // # MouseWheel+4 move cursor height base (1x) // # MouseWheel+5 move cursor height base (0.5x) // # MouseWheel+6 move cursor height base (0.05x) // # MouseWheel+7 move cursor ambience scale (1x) // # MouseWheel+Q move selected object height base (1x) // # MouseWheel+9 move selected object x position (1x) (+asyncronous) // # MouseWheel+0 move selected object y position (1x) (+asyncronous) // # MW+RSHIFT+9|0 as above but *10x (+asyncronous) // # MW+RCONTROL+9|0 as above but *100x (+asyncronous) // # MouseLeft Insert Objects // # MouseRight Move camera (it could require CTRL too) // # SPACE Start move/selected animation in Object/Effect/Fly CB // # ESC Stop animation in Effect/Fly CB NB: A space is required for such things: //*space*stuff KEY*space*=*space*VALUE Download: http://www.mediafire.com/download/c4yhd41ruy97c88/we_remix_v23__20140801-1859.rar http://www.mediafire.com/download/jxmemazw50vmnmj/we_remix_v24__20150621-0154.rar​ How To Map: This release will not cover this part. Look at CryPrime`s tutorials to understand how to do it. About the ServerAttr Generator: (since v14) This is a beta function but it should work fine. I tested it on gm_guild_build (1x1), metin2_map_a1 (4x5), metin2_map_trent (2x2), metin2_n_snowm_01 (6x6) and the result was the same as the blackyuko map editor. (I use a different lzo version and I clean deprecated and useless flags, so the size is different from this last one but the "final image" will be the same; using game_test to fix his server_attr will let mine and his perfectly equal byte per byte) I also give you the source code of my server_attr generator function. CLICK A server_attr file is based on all the attr.atr files merged into a one raw RGBA image and each one scaled from 256x256 to 512x512. After that, the image will be splitted into sectors of 128x128 px and each one compressed using lzo compression. The server_attr header is composed by the size of the map*4. (e.g. a 4x4 will have a 16x16 size with 256 sectors inside) (gj ymir CLICK) An uncompressed server_attr sector is just like this: CLICK (the sub 4 byte header is the size returned by the LzoCompress which indicates how much the compressed sector data are large) Each attr.atr is just like this: CLICK (the header is composed of 6 byte in total: 3 WORDs respectively for version, width and height; they are always 2634, 1, 1 so don't bother about it) A single attr.atr scaled from 256x256 to 512x512 will be just like this: CLICK You can use the game_test (from source) to perform few tasks like:Create a server_attr from a .mcd file (I won't suggest it) a <collision data filename> <map directory>Regenerate an old server_attr to server_attr.new using the current lzo compression and cleaning useless flag CLICK c <filename>Other stuff such as b to create a character instance or q to quit About the SkyBox Bottom pic fix: (since v21) Both metin2launch.exe and worldeditor.exe should be edited to see the bottom pic of the skybox. Ymir messed up the code wrongly flipping the bottom image. Open .SrcsClientEterLibSkyBox.cpp and replace ////// Face 5: BOTTOM v3QuadPoints[0] = D3DXVECTOR3(1.0f, -1.0f, -1.0f); v3QuadPoints[1] = D3DXVECTOR3(1.0f, 1.0f, -1.0f); v3QuadPoints[2] = D3DXVECTOR3(-1.0f, -1.0f, -1.0f); v3QuadPoints[3] = D3DXVECTOR3(-1.0f, 1.0f, -1.0f);with ////// Face 5: BOTTOM v3QuadPoints[0] = D3DXVECTOR3(1.0f, 1.0f, -1.0f); v3QuadPoints[1] = D3DXVECTOR3(1.0f, -1.0f, -1.0f); v3QuadPoints[2] = D3DXVECTOR3(-1.0f, 1.0f, -1.0f); v3QuadPoints[3] = D3DXVECTOR3(-1.0f, -1.0f, -1.0f); then recompile. Credits: Click here to download this file
  27. 32 points
    Today I bring you another exclusive release from Tim. This time is the granny.dll compatible with Granny 2.8 models and new binaries. Included for completeness is the already public granny DLL for the old binaries, and the bulkconverter.exe tool. What can I do with this? You can use granny models from any Granny version up to 2.8 in your client. How do I use this? Just replace the original dll in your client. Please note, it only works on original, packed client binaries. A tool (bulkconverter.exe) is provided so you can easily convert your current models to 2.8 for best performance. Usage: bulkconverter foldername Will convert all the gr2 files found inside foldername to v2.8 Granny format. Regards granny28.zip
  28. 32 points
    I've been using this method since August 1st, 2013 and it's been working great. Most cheats are automatically blocked, just make sure you check sites that post metin2 cheats frequently to make sure there aren't any new ones that actually work. Those ones will need to be manually added. I'll begin by listing the features of using this method: - DLL files can normally be renamed to .mix, .dll, or .flt and inserted into the client before launching and they would inject the dll into the client. With this protection those files are deleted on client launch, there's no way around this. - MSS32.dll is an important file for protecting against cheats, and it's being checked by the client to ensure it's not tampered with. - There are exploits out there (and possibly more to be found or more which aren't yet released publicly) which this protection method can help detour. It hides the revision of the binary from the Details tab in Windows Properties for this reason. If they don't know which version you're using it's a good start already to protect against exploiting the binary. - This will prevent cheats from loading whether the player sets them up to automatically inject them on startup or while the game is already on. - This DOES block m2Pythonloader and Kernel Detective. - This DOES block the new ProDamage hack by lalaker1 with randomized window classes as well as switchbotv3. - I don't know of any cheats that actually work with this setup active... - Works even on lower end computers without a problem. - It restricts debugging the client. Caveats: - About 25% of Windows 8 users can't run the client. I'm not entirely sure what the problem is but it appears to be an issue from Windows 8 (thanks again Microshit). The user is warned upon running the client of a "FATAL ERROR" in which the Index file located in the pack folder is missing. It isn't missing. So far, the only workaround known for this issue is to run the game using Razer Game Booster. I feel that it's worth it because it stops cheaters from playing. It's up to you if you want to lose some of your Windows 8 users. UPDATE 2/11/2014: If you purchase the latest version of the software it WILL work with Windows 8! - Virtual Box: Bug fixed loading virtual dll files under Windows 8 x64 - Virtual Box: Bug fixed running some virtual exe files on Windows 8 - It may be detected by antivirus software as a virus because it's encrypted, it has no way of knowing what the file is really doing or really contains. Currently it's only detected by 2/50 scanners on Virustotal.com and it's not a definitive sign of a virus, only a warning that the virus scanner can't read the file. https://www.virustotal.com/en/file/f15ffd6c32d13ce7ac013c535f7abec22531093505609d082c9afa97db8f0009/analysis/1391644127/ - You can't run the command prompt while the game is open, nor can you have one open when attempting to launch the game. Setup Instructions: Open the file "prototype.py" in the root archive and find this: def RunApp(): musicInfo.LoadLastPlayFieldMusic() app.SetHairColorEnable(constInfo.HAIR_COLOR_ENABLE) app.SetArmorSpecularEnable(constInfo.ARMOR_SPECULAR_ENABLE) app.SetWeaponSpecularEnable(constInfo.WEAPON_SPECULAR_ENABLE) app.SetMouseHandler(mouseModule.mouseController) wndMgr.SetMouseHandler(mouseModule.mouseController) wndMgr.SetScreenSize(systemSetting.GetWidth(), systemSetting.GetHeight())On a new line enter this: injectionprotection = os.listdir('.') injectionprotection.sort() for Data in injectionprotection: if Data.find('.mix') != -1 or Data.find('.m3d') != -1 or Data.find('.flt') != -1 or Data.find('.asi') != -1: os.remove(Data)Add the following to the imports: import osSave and close the file. Now we'll block the introLogin.py bug allowing users to run client extractors or python cheats on client launch. Open "intrologin.py" from the same archive and find this: self.__LoadLoginInfo("loginInfo.py")Replace the entire line with this, edit the message to your liking: if not os.path.exists('logininfo.py') and not os.path.isfile('logininfo.py'): self.__LoadLoginInfo("loginInfo.py") else: dbg.LogBox('Ah so you want to try to extract the client?n' 'Or maybe you want to run your favorite cheat?n' 'Not gonna happen...n' 'It seems I have already thought of this.n' 'I am ATLEAST one step ahead of you...n' '------------------------------------------------n' 'n' "TRY HARDER BRO") exception.Abort("Unsupported file, please delete it. (TRY HARDER BRO)") # Syserr.txt returnAdd the following to the imports: import osSave and close the file. Now you need Enigma protector. You can purchase it here: http://www.enigmaprotector.com/en/order.html or download an older cracked version here: https://mega.co.nz/#!fBY1zRia!ib0eiy6Tq9FLFOphKJrceX2fMIlL_KiDjOlRCfuIhW4 You will also need a plugin created by my friend Anfidya: https://mega.co.nz/#!vVgxwI4Q!1GQ5GgfbvBHlkYc5O23IJ_Woy0OBJyIlh_bqNh0dDhM Place the .dll file in the "Plugins" directory of your installation of The Enigma Protector. Here's the Enigma settings file already ready-to-go minus some minor changes you need to make: https://mega.co.nz/#!LVJ1wIYa!cO9C2Vim_Gk8Lklh86mxK5FKTqOug8FltQOkPYYT-NE Now you will need to maintain two versions of your client, one for the public and one private one. Copy your client to another hard drive or directory on your computer. You should have two identical copies of the same game but you're going to do all your work on the private client from now on. You will keep your eix and epk archives in the pack folder of the private client and do your work there. You need to keep a client binary in your private client which isn't encrypted by Enigma so that you can create a new one whenever necessary. When you release a patch you will need to re-pack the binary even if you didn't change anything there or in Enigma. All it takes is a change of any of the archive files for the binary to need a re-encryption by Enigma. This is because the eIndex files are going to be hidden inside the binary. The miles folder can be used to inject cheats too, so we're going to hide that and all it's contents in the binary as well. The binary is protected from debuggers and people can't just unpack it with WinRAR or something to get files out of it. Despite Enigma offering messages displayed before client closing, I don't use them because they allow the client to stay open until the user clicks the OK button. This means they can just sit there with the cheat running and move the popup window. I've included my settings file for Enigma. You need to customize the Settings in the INPUT tab: - Modify the "file to protect" and "output protected file name" using the Browse buttons. - Modify the "Name" - Modify the "Version" (hint: don't put it the same as your binary version) You also have to edit the file name if you aren't going to call your client metin2.bin (note that on some newer binaries it has to begin with "metin2" or it doesn't work. I'm sure there's a way to edit this but it isn't so important. It's alright to show a message before termination, to assist the player with the reason why it won't work. This is only going to check during launch of the application and the file name can't be changed while the application is already running. You should go to "External Files" and delete my MSS32.dll file by clicking the red "X" and add your own MSS32.dll file to make sure it's the correct one. If you skip this step and your MSS32.dll doesn't match mine EXACTLY then the client will fail to run. Now you need to add some custom rules for cheat detection: You can see here I've already setup the miles folder for you. You need to click "pack" so that it's highlighted like in the image then click "Add" then "Add File(s)" and select all your .eix files as well as your Index file from the pack folder. An easy way to do this is set your Windows Explorer to detailed view and organize by File Type then use SHIFT + click to select a beginning and ending file. This next part is mostly preference, and to avoid letting anyone know which version you use for a binary. It adds customization to your client, it's a fancy thing that isn't too necessary but if you want to change this stuff go for it! An example of what that does: Now you just press "Protect". You need to copy your new protected bin to your Public Client and go delete the entire "miles" folder as well as the contents of the folder from your Public Client folder. Also go into the "pack" folder of your Public Client and delete "Index" and ALL of your ".eix" files (sort with detailed view again). In the end you should have a Public Client like this or very similar: Your Private Client should look something like this:
  29. 32 points
    Since I have no use for this anymore whatsoever, I changed the repo to be public. https://github.com/imermcmaps/libgame This included all the source code to it You can find a pre-compiled version here: https://github.com/imermcmaps/libgame/releases/tag/imer_final Porting it to the source code should be fairly easy as most of the functions and such are the same (yay for LibM2) It includes: SyncPos fix with automatic ban /war fix number_ex fix HorseVnum and Bonus on Mount via Questflag (horse_summon.horse_vnum, horse_summon.apply_type, horse_summon.apply_value) Damage bonuses (devil, undead) are each calculated seperately. CHARACTER::DropGold just returns GiveExp was rewritten to prevent xp boosts and glitches 6th and 7th bonus cant be put on costumes anymore More quest functions: item2.equip item2.get_attr item2.get_wearflag item2.is_wearflag item2.set_attr npc2.get_level npc2.get_pc_pid npc2.get_pc_vid npc2.select pc2.give_or_drop_item_and_select pc2.send_effect pc2.set_level You may still donate XP to guilds when the guild is max. level You'll always get status points max. priv_empire is modifiable via config change_attr time is in seconds and modifiable via config you can add new/modify existing bonuses via config And some other changes I cant think of right now, just snoop through the source. iMer PS: Check the license. If you use any of that source and publish it (even in binary form) you must credit me.
  30. 31 points
    Hi everyone, It's finally time to open a topic for the small tutorials, it's better than flooding the board with one sentence topics. 1. Binary name check: Sure, it's possible to do it on client-side, but if we can do it on server-side, theres no reason to do it on client-side. 1. Search for this function in game/input.cpp: void CInputProcessor::Version(LPCHARACTER ch, const char* c_pData) 2. Replace the entire function with this: if (!ch) { return; } TPacketCGClientVersion * p = (TPacketCGClientVersion *) c_pData; // If the file name is not metin2client.exe and the GM level is not equal with GM_IMPLEMENTOR kick the player if (strcmp(p->filename, "metin2client.exe") && ch->GetGMLevel() != GM_IMPLEMENTOR) { // immediately close the connection with the player sys_err("%s[%d] has been disconnected: %s", ch->GetName(), ch->GetPlayerID(), p->filename); ch->GetDesc()->SetPhase(PHASE_CLOSE); return; } sys_log(0, "VERSION: %s %s %s", ch->GetName(), p->timestamp, p->filename); ch->GetDesc()->SetClientVersion(p->timestamp); 2. Block the drop hacks: This issue is surely known by everybody, the server gets overloaded when dropping too many items in short time. 1. Open game/char_item.cpp and search for this: if (pkItemToDrop->AddToGround(GetMapIndex(), pxPos)) 2. Add this under that: // Clear the variable, it looks the player does not dropped any item in the past second. if (thecore_pulse() > LastDropTime + 25) CountDrops = 0; // It looks the player dropped min. 4 items in the past 1 second if (thecore_pulse() < LastDropTime + 25 && CountDrops >= 4) { // Set it to 0 CountDrops = 0; sys_err("%s[%d] has been disconnected because of drophack using", GetName(), GetPlayerID()); // Disconnect the player GetDesc()->SetPhase(PHASE_CLOSE); return false; } 3. Search for this still in game/char_item.cpp: LogManager::instance().ItemLog(this, pkItemToDrop, "DROP", szHint); 4. Add this under that: LastDropTime = thecore_pulse(); CountDrops++; 5. Open game/char.h and add these: int LastDropTime; int CountDrops; 6. Open game/char.cpp and search for this: void CHARACTER::Initialize() 7. Add these to the function: CountDrops = 0; LastDropTime = 0;
  31. 31 points
    Hey guy :3 Well... here you will find all my graphics i released till now, i really hope you like some of it ^-^ [#1] Download --------------------------------------------------------------------- [#2] Download --------------------------------------------------------------------- [#3] Download --------------------------------------------------------------------- [#4] Download --------------------------------------------------------------------- [#5] Download --------------------------------------------------------------------- [#6] Download --------------------------------------------------------------------- [#7] Download --------------------------------------------------------------------- [#8] Download --------------------------------------------------------------------- [#9] Download --------------------------------------------------------------------- [#10] Download --------------------------------------------------------------------- [#11] Download --------------------------------------------------------------------- [#12] Download --------------------------------------------------------------------- [#13] Download --------------------------------------------------------------------- [#14] Download --------------------------------------------------------------------- [#15] Download --------------------------------------------------------------------- [#16] Download --------------------------------------------------------------------- [#17] Download --------------------------------------------------------------------- [#18] Download --------------------------------------------------------------------- [#19] Download --------------------------------------------------------------------- [#20] Download --------------------------------------------------------------------- [#21] Download --------------------------------------------------------------------- [#22] Download --------------------------------------------------------------------- [#23] Download --------------------------------------------------------------------- [#24] Download ---------------------------------------------------------------------
  32. 31 points
    Since many people may need it, here's my complete official db structure for game 34k, including: - All Indexes and Options included - All auto increment values are set to 1 (except player that is set to 100 to avoid some issues) - Some non-fatal errors caused by original YMIR table structure are fixed 34k_official_db_structure.zip 69 KB https://mega.co.nz/#!SB1CzYyI!T8c_wILefEJBpYjNJXKW2BVaPzp2SRMjNuVDh2WEXkU Tables refine_proto (official, valid for all game revisions) object_proto (modified from official with smaller limits for buildings so they actually fit in your land) skill_proto (SG, has a couple of small differences in regards to GF) shop_item (SG)
  33. 31 points
    The World of Metin2 Monarch System is composed of two parts. For the system to work fully you need to use db core 33820 or a compiled db where this bug is solved (look dif part at the end. If anybody wants to create difs for other revisions, you are welcome to do so.) Monarch Election Authors: Musicinstructor and me (Shogun) Usage: the election has 3 stages: Candidacy, Election and Crowning. All the stages can be started sucessively from the Archer Guardian NPC in town. - During Candidacy phase, all players over level 65 can apply for election by paying some Yang. Up to 8 players can apply per kingdom. - During Election phase, players will drop an item called Certificate of Loyalty (60004) which allows them to cast a vote. - Finally, you can finish the election, which will announce the winners automatically. The new King / Queen will receive a new Hwang Armor on login and the Angel's Blessing item. For the quest to work you need the following preparation: 1) Create an empty file share/data/monarch_election in your server with the touch command. 2) Fill the table player.monarch with some random values (use the PID of your GM for example). You can also use this table: DROP TABLE IF EXISTS `monarch`; CREATE TABLE `monarch` ( `empire` int(10) unsigned NOT NULL DEFAULT '0', `pid` int(10) unsigned DEFAULT NULL, `windate` datetime DEFAULT NULL, `money` bigint(20) unsigned DEFAULT NULL, PRIMARY KEY (`empire`) ) ENGINE=MyISAM DEFAULT CHARSET=latin1; -- ---------------------------- -- Records of monarch -- ---------------------------- INSERT INTO `monarch` VALUES ('1', '266', '2014-02-04 04:36:55', '0'); INSERT INTO `monarch` VALUES ('2', '188', '2013-11-07 20:10:00', '0'); INSERT INTO `monarch` VALUES ('3', '170', '2013-09-16 22:12:06', '0');3) Make sure 60004 exists in item proto and has a suitable icon for it. The quest Add this to locale.lua Add this also to questlib.lua Items for item_list.txt 60004 ETC icon/item/60002.tgaitem_proto.txt entries for the certificate, blessing and armors 60004 loyalty_certificate ITEM_UNIQUE UNIQUE_NONE 1 ANTI_GET | ANTI_DROP | ANTI_SELL | ANTI_SAVE | ANTI_GIVE | ANTI_PKDROP | ANTI_STACK | ANTI_MYSHOP | ANTI_SAFEBOX LOG NONE NONE 0 0 0 0 0 LIMIT_NONE 0 LIMIT_NONE 0 APPLY_NONE 0 APPLY_NONE 0 APPLY_NONE 0 604800 0 1 0 0 0 0 0 0 70021 ±ºÁÖÀÇ ÁõÇ¥ ITEM_QUEST 0 1 ANTI_DROP | ANTI_SELL | ANTI_GIVE | ANTI_STACK | ANTI_MYSHOP | ANTI_SAFEBOX NONE NONE NONE 0 0 0 0 0 LIMIT_NONE 0 LIMIT_NONE 0 APPLY_NONE 0 APPLY_NONE 0 APPLY_NONE 0 0 0 0 0 0 0 0 0 0 11971 Ȳ»óÀü°© ITEM_ARMOR ARMOR_BODY 2 ANTI_ASSASSIN | ANTI_SURA | ANTI_MUDANG | ANTI_DROP | ANTI_SELL | ANTI_GIVE | ANTI_STACK | ANTI_MYSHOP ITEM_TUNABLE WEAR_BODY NONE 0 0 0 0 0 LEVEL 50 LIMIT_NONE 0 APPLY_MOV_SPEED 10 APPLY_RESIST_MAGIC 20 APPLY_ATTBONUS_HUMAN 15 0 350 0 24 0 100 100 3 0 11972 ȲÀÇ ITEM_ARMOR ARMOR_BODY 2 ANTI_MUSA | ANTI_SURA | ANTI_MUDANG | ANTI_DROP | ANTI_SELL | ANTI_GIVE | ANTI_STACK | ANTI_MYSHOP | ANTI_SAFEBOX ITEM_TUNABLE WEAR_BODY NONE 0 0 0 0 0 LEVEL 50 LIMIT_NONE 0 APPLY_MOV_SPEED 10 APPLY_RESIST_MAGIC 20 APPLY_ATTBONUS_HUMAN 15 0 350 0 24 0 100 100 3 0 11973 ÁøȲ»ó°© ITEM_ARMOR ARMOR_BODY 2 ANTI_MUSA | ANTI_ASSASSIN | ANTI_MUDANG | ANTI_DROP | ANTI_SELL | ANTI_GIVE | ANTI_STACK | ANTI_MYSHOP | ANTI_SAFEBOX ITEM_TUNABLE WEAR_BODY NONE 0 0 0 0 0 LEVEL 50 LIMIT_NONE 0 APPLY_MOV_SPEED 10 APPLY_RESIST_MAGIC 20 APPLY_ATTBONUS_HUMAN 15 0 350 0 24 0 100 100 3 0 11974 Ȳ»óÀÇ ITEM_ARMOR ARMOR_BODY 2 ANTI_MUSA | ANTI_ASSASSIN | ANTI_SURA | ANTI_DROP | ANTI_SELL | ANTI_GIVE | ANTI_STACK | ANTI_MYSHOP | ANTI_SAFEBOX ITEM_TUNABLE WEAR_BODY NONE 0 0 0 0 0 LEVEL 50 LIMIT_NONE 0 APPLY_MOV_SPEED 10 APPLY_RESIST_MAGIC 20 APPLY_ATTBONUS_HUMAN 15 0 350 0 24 0 100 100 3 0 Angel's Blessing Quest written by me and loosely based in the official quest used by Metin2 US. This is the item the Monarch can use to cast his powers, such as healing and attacking buffs which affect all the players from his kingdom in the same map; or summoning of different bosses and Guardians which only attack players from enemy kingdoms. It's an original YMIR item and the vnum is 70021. Instructions are included in the quest for the rookie kings/queens. Preparation: 1) Set MonarchHealGold event flag to an appropiate value (this is the cost of a monarch buff that heals everyone on the map) 2) Edit the list of bosses and their cost to your desires The quest: The function oh.takemonarchmoney() used in the angel's blessing quest is bugged on all official db cores. This is fixed in Vanilla Core 2.2+. For db 33820 here is a dif made by Paylasici: [UNSTRIPPED] db_r33820_32 000A30DD: 3B 20For db 40146 here's another dif made by PACIFICADOR db_r40146 000A5015: 3B 20 It is possible that something is missing in that case let me know here your answers are appreciated
  34. 30 points
    Hi there Devs, I would like to share my "little" system. If you aren't interested in the introduction/preview etc. and you just want to download it and put in to your server, just scroll down until the "[How-To] Set up" subtitle. The story Firstly let me tell this system's story. I've got an idea one year before, that it would be good if the players would be able to put their items into a "global" system where they could see the other player's items, and they could buy it for DC or gold (that time I worked with the latest vanilla core (not with the source)). Then in the following 8 days I made it (it took about 80-90 working hours). Originally the system was created for one of my friend's server. but this server has never started, and nobody used this system. After some mounts I've decided to publish it on the Hungarian forum, because it won't worth to work on it for long hours if nobody uses it and its just collecting dust on my computer. Then I've published it on the 2nd of December, 2014. After some time I've decided to translate it into English and I've got a new idea for a new feature. This feature was: the trade system (I will explain its working later). This idea inspired by one of the players (from a server where this system was able to use). He told me that it would be better if they could set the gold price via an item (what's value is very high). Then with more than 180 working hours (totally) behind my back I'm here. Overview [How-To] Set up Customizing the tradehouse Questions and Answers Notes changelog: 19th of August, 2015: I publicated the tradehouse here. my toDo list: add logging for the system (the released version don't log the actions in the tradehouse) Thanks for reading the topic, if you have any problem/remark feel free to ask it here or write me a PM. Have a good day!
  35. 30 points
    Put the content that the exe is in this path D:/ymir work/WorldEditor_en.exe Download
  36. 30 points
    Hello! I've created some Wallpapers for you! Original Logo by SquareEnix - Final Fantasy X These Wallpaper are full Vector Wallpapers, that means, you can scale it how you want, without quality loss! The standard Download mirror in this thread, just contains the non-vector Wallpaper in the resolution of 1920x1080. If you want a higher resolution, just write me a private message, with the reason, why you need one! I just want to mention, that the idea for these Wallpaper comes from "Plentakill", they are creating the same kind of Wallpaper, just for League of Legends! If you wanna see it, check their Channel on Youtube or use google! Wallpaper Preview (Version 1): http://i.epvpimg.com/wjYHh.jpg http://i.epvpimg.com/8aEic.png http://i.epvpimg.com/Bdi2b.jpg http://i.epvpimg.com/6dzkb.jpg Maybe there will come a version 2, with the male characters of Metin2! I just want to mention that one Wallpaper requires 8 hours of work and over 700 Shapes, and I am a lazy guy... so it will take its time for version 2. As a last resort, I ask you for your thought about the Wallpaper, please write feedback or critique, so i know what i have to change in version 2... And guys, please dont remove my copyright on the right-bottom corner! Download version 1 Best regards, Sora
  37. 29 points
    Animation Pipeline by PhiLL Hello guys... I don't know if someone of you knows me, I was working on InfinityMetin, 2 years ago... I left it for work and study on the 3D VFX field.. Now in my spare time I would like to work on the 3D stuffs for metin2 again but just for myself. The videos you are going to watch, are my pipeline for a new animation inside Metin2. Animation created by the user and not taken from other games like everyone does, where the skeleton has other positions and the character is going to be squashed and stretched in the wrong way... For now this pipeline is on alpha test, I've got to finish my rig setup in all the 8 characters. The skeletons are completely done and fixed (as you did see in my previous posts, I got some skeleton issues to resolve, and I did resolve 'em all). Information about the Pipeline: You can see everything from the video, is not difficult to understand. Software used: Maya 2016 Knowledge for this project: Rigging/Skinning/Animation on Autodesk Maya Video Animation System: Video in game: UPDATE 14/05/15 of the animation system: Request from you: Just want to know from you, what you think about this process and if it is usefull for metin2 developers or there are already "tools" like that one. And if you have ideas, just write 'em.
  38. 29 points
    Hi guys, Running a server for a year and a half while a bunch of guys gets paid to destroy it by any means ends up giving you a good insight in what the word security really means. So, after being the target of almost every type of attack possible over the Internet, I think I am ready today to write a quick checklist on how your Metin2 server should be secured from criminal and disruptive behavior. I will divide it into several parts: ingame, website, server, staff. I will try to explain in brief how those attacks are executed, but the focus here is in how to defend from them effectively. I do not want this checklist to serve the purposes of hackers. But be aware; you are never 100% safe - it depends on how much your enemy is willing to work on it. So this should be taken as a bare minimum. And don't forget: the science of destruction evolves constantly. What is considered safe today, might not be so safe tomorrow. Disclaimer: This text reflects 5 years of experience managing a server's technical aspects. I do not do certain things (like quests) for a long time so excuse me for any mistakes I may be making here. Part 1 - Ingame bugs and exploits This part refers to threats that may realize through the game client or external software that acts through the game client. While often overlooked, sometimes these can be more dangerous to your server than any other type of attack. Keep an eye in your server's economy - the average price of items. If prices for a particular item or all of them change suddenly, there may be some obscure reason behind it. That is one of the reasons why we keep public and private statistics on the average market price of every item at WoM. One of the most common mistakes - and I commited this myself - when one wants to extensively edit everything is having an item give you more Yang when you NPC it than it costs to buy it from a shop. This gives unlimited Yang to whoever discovers it. There are even public bots which automate the process of buying and selling these items. The effect on the economy is devastating over a sufficient long period, not to mention that it's unfair that some people are infinitely rich and unbalance is never good for any MMORPG. Have your GM double check that no item can be sold for more than it costs. However, this is not the only way that a player can obtain access to unlimited resources. Badly written quests may allow players to obtain their rewards repeatedly by closing their clients while a quest dialog is open. One simple way to avoid this is to make sure that the commands which reward the player are the last in the code block before changing state. Now going into disruptive behaviour - the most annoying probably are the bugs which cause a server core to crash. The most famous is probably the number_ex bug. This causes several commands which depend on this function such as dice to be exploitable by using certain parameters. This bug is fixed in rev 40k and therefore in any game compiled from the source. If you are using 34k, the best you can do is use iMer's lib which provides several security enhancements. If you are using 2089, there are public diffs that patch this. Another bug exists in the war command in 34k and older which leads to a server crash. You cannot disable this command as it is used by the guild leaders to war other guilds. iMer's Lib takes care of this bug in 34k. Older and less known is the gold drop core crash bug present in 2089 and fixed -I believe- in 34k. Dropping huge amounts of gold or any other item which you can acquire in huge numbers in a map will cause the server to crash. I am not aware of public fixes for this exploit. Another favourite is the kickhack or sync position hack -partially fixed only in 40k- which allows a malicious user to disconnect other players at will. There are even videos of this being done in DE years ago. iMer's lib provides a fix for rev 34k. Finally, we have the long list of cheats which purely seek to gain advantage while playing. There are several client protection tutorials and services around this forum so I won't extend myself here about the subject. Part 2 - Server and OS Here we talk about the threats that affect your server and Operating System Part 2.1 Choosing and preparing your server There is no doubt at the moment of writing this that the french hosting company OVH provides the most cost-effective anti-ddos solution in the market. While many companies provide DDoS protection services, these cost several times as much as OVH offerings and this increase does not necessarily translate into a better protection. Therefore we will assume that you are renting either a dedicated server at OVH or a VPS at Eterhost as those are the ones I'm familiar with. Other providers or resellers may be configured in a different manner. Dedicated Server at OVH There are two flavors of the Anti-DDoS solution: Basic and Pro. Basic is free when renting a Kimsufi or Soyoustart server (cheap and intermediate OVH brands respectively). What it does is detect attacks directed at your IP address and route your traffic through the mitigation system during the attack. This is not enough to deter a dedicated hacker though - before the attack is detected, your server may be collapsed for a few minutes, and this can be repeated every hour by the attacker, as happened with one of the TEC attacks on WoM about 1 month ago. The PRO version comes with all the OVH proper (also known as professional) line of servers. It adds the ability to route traffic permanently through the mitigation system and provides you with a simple hardware firewall. This is what you should get if serious attacks are a concern, specifically an Enterprise line server (cheapest is at about 100€/month, VAT included) How to activate permanent mitigation on OVH Professional servers: - Open the new manager. If you don't know where this is, open the classic manager and click on "Home" and then below on the "Dedicated" icon. - Click on IP on the column at the left - Click the little wheel that appears at the right of your server's IP address - Select "Mitigation: permanent" How to set up the hardware firewall: - Click the wheel again and select "Activate firewall". Wait around a minute and then reload the page. - Click the wheel and select "Configure firewall" - You will be presented with the rules screen. You can add up to 20 rules to deny or allow specific ports on the firewall. Start by adding the allowed ports in the lower numbers and end with a global deny rule. Leaving a field blank in the "Add Rule" dialog will result in a wildcard; so if you leave the IP address field blank, this rule will affect all IPs. Adding an allow port port rule: click on Add Rule; choose rule priority; select protocol (TCP or UDP); select Accept; enter the port number. Adding a global deny: choose rule priority (must be higher than the allow port rules); select protocol (TCP or UDP); select Deny. Here is an example set of rules. We have added the SSH port and the game & auth ports, as well as 3306 so our website can connect to MySQL. You can specify the webserver's IP in the rule to prevent others from connecting to your database, although I personally prefer to do this at the software level with the pf firewall; in any case, port 3306 must not be public. "How do I connect with Navicat then?" Simple, use the SSH Tunnel option. This logs you in to SSH and then connects to the MySQL server as localhost. You must enter your server's SSH login details in the SSH, and your MySQL login details in the General tab, but remember we are connecting to localhost or that's what you must enter in hostname, NOT your server's public address, as MySQL doesn't see us as a remote user anymore. Regarding UDP: UDP is your enemy. Disable it completely as I did in the above ruleset. The official client previously used UDP to check on server status, but it's trivial to override it in python so it always shows "NORM" regardless of the result of servercheck. If you are using 40k or source, the check already uses TCP, but your ports must be lower than 32768 (or the source modified) for it to work. VPS at Eterhost Our VPS are always routed through the mitigation system. Hardware firewall can be activated and configured to your needs for 5€/month extra. Part 2.2 - Hardening SSH First things first: have your OS always updated to the current version. It is often recommended by experts to access your server through a non-administrative account (some operating systems such as CentOS even force you to create one at install), so that's what we will be doing. We will create a restricted user for our game server: adduser game We can leave everything as default except for the login group: enter "wheel" here. Users which are part of the wheel group can use the su command to gain administrator privileges. This allows us to completely block root from remote login. Now it's time to create a SSH key for our new user. This makes bruteforce virtually impossible. Finally, let's prevent login from root, and login without key: ee /etc/ssh/sshd_config Look for the "PermitRootLogin" line and leave it this way, uncommenting if necessary: PermitRootLogin no And next look for the "PasswordAuthentication" setting and edit it so it looks like this: PasswordAuthentication no Now let's restart ssh for changes to take effect: service sshd restart Warning: at this point, you should open a new putty window to test that you can login with the new user and key, and that you can use the su command to gain root privileges. Wrong settings may lock you out of your server. Once everything is working, upload your server files to /home/game. This is the home directory of the user - a bit like "My Documents" in Windows. Make sure you change permissions in the files so the "game" user can read and write them: chown -R game /home/game (this command must be run as root! only root can change someone else's permissions. To switch between the game and root account, you use the su (short for superuser) command: root# su game Password: (game user's password) game# su Password: (root user's password) root# Or: root# su game Password: (game user's password) game# exit root# Finally, it may be a good idea to install ssh-guard for extra security or change your SSH port if you don't like your logs being spammed by portscans. To change your SSH port, edit the Port line in /etc/ssh/sshd_config and restart the sshd service as indicated above. Remember to open the new port if you are using a firewall or you will lock yourself out of the server. Part 2.3 Software Firewall: pf At this point it's a good idea to add a second line of defense with the pf firewall. First we will create the /etc/pf.conf file following this sample config. ee /etc/pf.conf Make sure you enter the correct interface and all the ports which must be open: SSH and game ports in our case. Neither p2p ports or db core port should be open to the public! Under trusted_hosts, enter the IP address of your web server so it can connect to the database (We assume a typical set up of web server + game / db server here) instead of opening port 3306 to everyone. This firewall provides us with scrubbing and rate limiting capabilities which the hardware firewall doesn't. Next we will enable pf: kldload pf pfctl -e Check that everything is working fine and then add the following line to /etc/rc.conf to load pf on boot: pf_enable="YES"
  39. 29 points
    Hi, I am working on a Fork (Open Source) of hennink's metin2 CMS. A lot of people have already tried to recode this system but more or less the most of it is trash. Why a Fork of an outdated CMS? We all know that the used mysql_* functions in this CMS are outdated, the codesemantic is weak and the structure bulding isnt that good, too. Fact is that the Hen! CMS is the most used system and I don't think that the community is ready for new systems because of silly entrenched habit. It is undeniable that a CMS developed from the ground up is much better (like projects by ChuckNorris) but people which have used this system for years wouldn't change to a completely new CMS that fast. Let me explain this by an example: How much people (including me) tried to code a new and better toplist for this com? Unsuccessfully although the basic approaches where much better. What I am NOT doing: - I will not just replace the querys and say its finished! - I will not copy the whole code and say its finished What i am doing: - I will create an OOP Fork of THIS CMS which will be save, timely and familiar to the people. - I will deffently write a beginner friendly documentation. - I will create a simple installer to use this CMS without any problems (check if important tables or column already exist or missing ect.) Techniques: - Rebuild existing code to a semantic code. - MySQLi (we dont have to talk about using PDO or what is the best) - only a few OOP techniques because Object-Oriented Programming is too difficult to comprehend for the most in this com) - Better structure - jQuery features for better usability Main Features: - mod_rewrite (SEO friendly URLs) - language system [IMG01] - auctionhouse (+ Quest for easy implementation) - better statistics - Better Login (login attempts against Bruteforce, login faillogs) - Coinslog for Users (when did i buy coins? where did i spend coins (item Shop, auctionhouse)? and how much ) - Better register (we all know that the current form is shit when having an error) [IMG01] - Rankings (PVP, top player, top guild etc.) - Itemshop - Simple but effective ticketsystem [IMG01 , IMG02] I will not implement this things: Download: https://github.com/iseries/MT2cms Changelog: [14.01.2015] [Add] - Add auto language detection and ACP option > [13.01.2015] [Add] - Add IP and port control (Server Settings) + view > [07.01.2015] [Add] - Coins History for Member. > [07.01.2015] [Add] - Referral System. > [04.01.2015] [Add] - Logs in adminCP. > [03.01.2015] [Add] - Add installer. > [03.01.2015] [Add] - Add some basic settings. > [19.12.2014] [Add] - Add register. > [17.12.2014] [Edit] - Statistics expanded > [15.12.2014] [Edit] - You can enter site title and other website informations in the adminCP now. no need to edit the config.inc.php [15.12.2014] [Add] - statistics in adminCP. > show [15.12.2014] [Add] - backup system in adminCP. > show [12.12.2014] [Add] - implemented overview in adminCP. > show [12.12.2014] [Edit] - Cleaned up language files and split all entries to seperate category groups. > show [12.12.2014] [Add] - New Adminoptions in the ticket sections: disable/enable ticketsystem, disable/enable email notice for new tickets. [12.12.2014] [Add] - Admin CP is now in the sidenavigation. [12.12.2014] [Add] - SA can search tickets by ticket IDs now. > show [12.12.2014] [Edit] - recoded the paginations (more opportunities). > show Important: I will kick your ass if you post shit like: "This is not necessary". It is my intention to do this because I want to do this! You can bring ideas or constructive feedback but no bullshit. I will release this ONLY here (metin2dev) when I'm done. epvp can suck my **** and if someone releases this there, I will report that. Special thanks: Krusty, SoNiice, hennink, Denis, NotEnoughForYou, Yoshix3, Stefan, ManojGeek
  40. 28 points
    Hi, developers! Before you start, create a backup from your source files immediately! Today I'm gonna share with you my last work. I have read every informations from the official binary from beta(metin2client_r11185) and r7071. It was not an easy task to understand functions but successed. I will not write down the implementation step by step, but I wrote some informations into the files what you should to do to implement the system. If you do not understand the steps I put original(from dev branch) and modified files into the archive to compare the original and the changed files with notepad++ or something else comparer tool to see the changes. - There are some files which optional changes to show the mob-aiflag on those monsters which are not aggressive but summoned by aggressive with "/ma" command. - There was a little problem with Python 2.7.3 therefore I split asunder the gui-script. And be careful, the main script is using True and False variables. - You can disable the whole system in common/service.h and UserInterface/Locale_inc.h with undefined or with commented macro. I hope everything are understandable and I did not miss something from the release, and sorry for my bad english. Special thanks to TheSLZ for test the implementation. And last but not least here is the result: Download - Mega.nz
  41. 28 points
    Welcome to the second part of my guide series. This time I'll tell you how you can compile with gcc48 or even gcc49 like it's the case in vanilla and how you can use c++11 which will allow much more and faster instructions than the old one. At first we need to have a look at our Makefile. Make sure you edited the Line SVN_VERSION so you won't receive any errors. Try it e. g. to SVN_VERSION = mt2 Next, you'll have to declare what compiler you want to use. Of course you first need to install the compiler, but I guess it's clear (if you haven't done so, just use cd /usr/ports/lang/gcc49 or even 48 and use make install clean). The line normally say: CC = g++ This is the standard compiler. You may want to change this line to: CC = g++49 Or if you're using 48, change it to CC = g++48 Now before you compile it, you'd recompile all needed libs with gcc48/gcc49 too! So change the compiler in the makefile and recompile the sources in the following directories: libgame/src libpoly libserverkey libsql libthecore/src And then you need to recmopile cryptopp with the newer gcc version too! It's located in the Extern/cryptopp-directory. Now you can compile your game and even your db source with the newer gcc version. You may experience a much smaller file size. The newer compilers will produce an even more faster and smaller gamefile than before. Oh and if you want to carry out the lib-files you're using on your compiling machine (to make sure everything runs smoothly) you may use the following CFLAG: -Wl,-rpath,/usr/local/lib32/metin2 You can change the path to whatever you want! If you specify this, you instruct the linker to use this path so whenever you start your game/dbcache it'll first look in the given directory for the right libs and then, if it can't find the libs there, it'll look elsewhere. Using c++11 is a must-have if you want to make new statements. The source code how to load the database without txt-files needs the newer c++ version, so you'll have to upgrade at least the dbcache for it. But you'll experience even more smaller file sizes with this change so it keeps up with more and more advantages. First you may want to specify the new CFLAG. It's called: -std=c++11 This tells the compiler to use c++11. Keep in mind that not every compiler can use c++11! The newer gcc version can deal with it without any problems. If you compile your source then, you may find a new error occuring! Open every .cpp and .h-file in Notepad++ and do the following things (you can use the mass replacement of Notepad++): replace typeof with __typeof replace auto_ptr with unique_ptr Watch out for the common-directory too! Then you can recompile the source and it's done! Oh and for this you don't need to compile every other sourcecode with c++11. You can e. g. only compile the dbcache with it. Last small hint: You can play with the tuning flags to get even more optimization. -O2 can sometimes be good, but sometimes it's better to use others flags. You can even use -O3 or -Ofast. But be careful with this and consider using -fstrict-aliasing so the compiler won't optimize instructions that'd lead into a crash if it'd optimize them. And always: Pay attention to the warnings your compiler throws at you! They aren't there to just "hang out". They'd lead into crashes, so care about them. Lastly I hope you enjoyed the guide. As in the last one, please tell me if it's good or not and if you have any questions: Feel free to ask.
  42. 28 points
    Hi. I wanted to improve my lua skills, so I thought I could create a useful software, something that I would use, and I'm here to post it if someone wants it too. A friend asked me if I could add a sql option, so I added it. Since it's not a "thing from another world", just run the *.bat file with your item_proto_dump.xml on the same folder. Then wait until the process is finished, and go to output folder and take what you wanted. Download: MEGA. Source v1.5: Pastebin. Changelog: Hope it's useful to anyone.
  43. 27 points
    Hello everyone. It's a good day to share an old code with you. First of all you need to know: I don't help to install it. Don't even take the contact with me about it. The whole code is written by me, and reversed from official binaries. At the beginning do a backup for your files(srcs+pys) and READ CAREFULLY the readme. W/o brain.exe please close this tab, or your browser, thank you for your understanding. Preview: Download.exe Enjoy & #h4v3fun, pngr
  44. 27 points
    Hi devs, I maked new user check system(like IP) with Hardware Needed Files; Server Part: Common -> tables.h, lenght.h Game -> input_auth.cpp, packet.h Client Part: Pack -> intrologin.py, networkmodule.py, constinfo.py Client -> AccountConnector.cpp, AccountConnector.h, Packet.h, PythonNetworkStream.cpp, PythonNetworkStream.h, PythonNetworkStreamModule.cpp, PythonNetworkStreamPhaseLogin.cpp A BACKUP BEFORE YOU START KNOWN BUGS; All Auth Events logging(not only succesfuly) Let's start 1) First Server Part: 1-1) Common 1-1-1) Tables.h Search typedef struct SAccountTable And replace with this typedef struct SAccountTable { DWORD id; char login[LOGIN_MAX_LEN + 1]; char Hwid[HWID_MAX_LEN + 1]; char Snn[SNN_MAX_LEN + 1]; char passwd[PASSWD_MAX_LEN + 1]; char social_id[SOCIAL_ID_MAX_LEN + 1]; char status[ACCOUNT_STATUS_MAX_LEN + 1]; BYTE bEmpire; TSimplePlayer players[PLAYER_PER_ACCOUNT]; } TAccountTable; Search typedef struct SLoginPacket And replace with this typedef struct SLoginPacket { char login[LOGIN_MAX_LEN + 1]; char passwd[PASSWD_MAX_LEN + 1]; char Hwid[HWID_MAX_LEN + 1]; char Snn[SNN_MAX_LEN + 1]; } TLoginPacket; Search typedef struct SPacketGDAuthLogin And replace with this typedef struct SPacketGDAuthLogin { DWORD dwID; DWORD dwLoginKey; char szLogin[LOGIN_MAX_LEN + 1]; char szHwid[HWID_MAX_LEN + 1]; char szSnn[SNN_MAX_LEN + 1]; char szSocialID[SOCIAL_ID_MAX_LEN + 1]; DWORD adwClientKey[4]; BYTE bBillType; DWORD dwBillID; int iPremiumTimes[PREMIUM_MAX_NUM]; } TPacketGDAuthLogin; 1-1-2) Lenght.h Search PASSWD_MAX_LEN = 16, Add it below HWID_MAX_LEN = 50, SNN_MAX_LEN = 50, 1-2) Game 1-2-1) input_auth.cpp Search this function void CInputAuth::Login(LPDESC d, const char * c_pData) Find this char passwd[PASSWD_MAX_LEN + 1]; strlcpy(passwd, pinfo->passwd, sizeof(passwd)); and add it below char Hwid[HWID_MAX_LEN + 1]; strlcpy(Hwid, pinfo->Hwid, sizeof(Hwid)); char Snn[SNN_MAX_LEN + 1]; strlcpy(Snn, pinfo->Snn, sizeof(Snn)); std::auto_ptr<SQLMsg> msg(DBManager::instance().DirectQuery("UPDATE account.account SET hwid = '%s', Snn = '%s' WHERE login = '%s'", pinfo->Hwid, pinfo->Snn, login)); 1-2-2) packet.h Search typedef struct command_login2 and replace with this typedef struct command_login2 { BYTE header; char login[LOGIN_MAX_LEN + 1]; DWORD dwLoginKey; DWORD adwClientKey[4]; char Hwid[HWID_MAX_LEN + 1]; char Snn[SNN_MAX_LEN + 1]; } TPacketCGLogin2; Search typedef struct command_login3 and replace with this typedef struct command_login3 { BYTE header; char login[LOGIN_MAX_LEN + 1]; char passwd[PASSWD_MAX_LEN + 1]; char Hwid[HWID_MAX_LEN + 1]; char Snn[SNN_MAX_LEN + 1]; DWORD adwClientKey[4]; } TPacketCGLogin3; 2) Second Client Part 2-1)Pack 2-1-1)Constinfo.py Add anywhere import os try: Hwid = os.popen("wmic csproduct get uuid").read().split("n")[1] except: Hwid = os.popen("%WINDIR%/system32/wbem/wmic csproduct get uuid").read().split("n")[1] try: Snn = os.popen('wmic path win32_physicalmedia get SerialNumber').read().split("n")[1] except: Snn = os.popen("%WINDIR%/system32/wbem/wmic path win32_physicalmedia get SerialNumber").read().split("n")[1] 2-1-2)Networkmodule.py add this import import constInfo and add it below Hwid=constInfo.Hwid Snn=constInfo.Snn Search self.pwd="" and add it below self.Hwid=constInfo.Hwid self.Snn=constInfo.Snn Search def SetLoginInfo(self, id, pwd) self.id = id self.pwd = pwd net.SetLoginInfo(id, pwd) and replace with this def SetLoginInfo(self, id, pwd, Hwid, Snn): self.id = id self.pwd = pwd self.Hwid = constInfo.Hwid self.Snn = constInfo.Snn net.SetLoginInfo(id, pwd, Hwid, Snn) 2-2-3)introLogin.py Search RUNUP_MATRIX_AUTH = FALSE Add top Hwid = constInfo.Hwid Snn = constInfo.Snn Search this function def Connect(self, id): and replace with this def Connect(self, id, pwd, Hwid, Snn): global Hwid, Snn if constInfo.SEQUENCE_PACKET_ENABLE: net.SetPacketSequenceMode() if IsLoginDelay(): loginDelay = GetLoginDelay() self.connectingDialog = ConnectingDialog() self.connectingDialog.Open(loginDelay) self.connectingDialog.SAFE_SetTimeOverEvent(self.OnEndCountDown) self.connectingDialog.SAFE_SetExitEvent(self.OnPressExitKey) self.isNowCountDown = TRUE else: self.stream.popupWindow.Close() self.stream.popupWindow.Open(localeInfo.LOGIN_CONNETING, self.SetPasswordEditLineFocus, localeInfo.UI_CANCEL) self.stream.SetLoginInfo(id, pwd, Hwid, Snn) self.stream.Connect() Search def __LoadLoginInfo(self, loginInfoFileName): Add it below global Hwid, Snn Search self.pwd = None Add it below self.Hwid = Hwid self.Snn = Snn Search self.Connect(id, pwd) Replace with this self.Connect(id, pwd, Hwid, Snn) Search self.Connect(id, pwd) Replace With This self.Connect(id, pwd, Hwid, Snn) Search def __OnClickLoginButton(self): Add it below global Hwid, Snn 2-2)Client 2-2-1)Packet.h Search PASS_MAX_NUM = 16, and add it below HWID_MAX_NUM = 50, SNN_MAX_NUM = 50, Search typedef struct command_login And replace with this typedef struct command_login { BYTE header; char name[ID_MAX_NUM + 1]; char pwd[PASS_MAX_NUM + 1]; char Hwid[HWID_MAX_NUM + 1]; char Snn[SNN_MAX_NUM + 1]; } TPacketCGLogin; Search typedef struct command_login3 And replace with this typedef struct command_login3 { BYTE header; char name[ID_MAX_NUM + 1]; char pwd[PASS_MAX_NUM + 1]; char Hwid[HWID_MAX_NUM + 1]; char Snn[SNN_MAX_NUM + 1]; DWORD adwClientKey[4]; } TPacketCGLogin3; Search typedef struct command_direct_enter And replace with this typedef struct command_direct_enter { BYTE bHeader; char login[ID_MAX_NUM + 1]; char passwd[PASS_MAX_NUM + 1]; char Hwid[HWID_MAX_NUM + 1]; char Snn[SNN_MAX_NUM + 1]; BYTE index; } TPacketCGDirectEnter; 2-2-2)AccountConnector.h Search void SetLoginInfo(const char * c_szName, const char * c_szPwd Replace with this void SetLoginInfo(const char * c_szName, const char * c_szPwd, const char * c_szHwid, const char * c_szSnn); Search std::string m_strPassword; Add it below std::string m_strHwid; std::string m_strSnn; 2-2-3)AccountConnector.cpp Search this function void CAccountConnector::SetLoginInfo(const char * c_szName, const char * c_szPwd) Replace with this void CAccountConnector::SetLoginInfo(const char * c_szName, const char * c_szPwd, const char * c_szHwid, const char * c_szSnn) { m_strID = c_szName; m_strPassword = c_szPwd; m_strHwid = c_szHwid; m_strSnn = c_szSnn; } Search strncpy(LoginPacket.pwd, m_strPassword.c_str(), PASS_MAX_NUM); add it below strncpy(LoginPacket.Hwid, m_strHwid.c_str(), HWID_MAX_NUM); strncpy(LoginPacket.Snn, m_strSnn.c_str(), SNN_MAX_NUM); Search LoginPacket.pwd[PASS_MAX_NUM] = '0'; Add it below LoginPacket.Hwid[HWID_MAX_NUM] = '0'; LoginPacket.Snn[SNN_MAX_NUM] = '0'; Search SetLoginInfo("", ""); Replace with this SetLoginInfo("", "", "", ""); 2-2-4)PythonNetworkStreamPhaseLogin.cpp Search(2x) if (0 != m_dwLoginKey) and replace with this if (0 != m_dwLoginKey) SendLoginPacketNew(m_stID.c_str(), m_stPassword.c_str(), m_stHwid.c_str(), m_stSnn.c_str()); else SendLoginPacket(m_stID.c_str(), m_stPassword.c_str(), m_stHwid.c_str(), m_stSnn.c_str()); Search this function bool CPythonNetworkStream::SendDirectEnterPacket(const char* c_szID, const char* c_szPassword) replace with this bool CPythonNetworkStream::SendDirectEnterPacket(const char* c_szID, const char* c_szPassword, const char* c_szHwid, const char* c_szSnn, UINT uChrSlot) { TPacketCGDirectEnter kPacketDirectEnter; kPacketDirectEnter.bHeader=HEADER_CG_DIRECT_ENTER; kPacketDirectEnter.index=uChrSlot; strncpy(kPacketDirectEnter.login, c_szID, ID_MAX_NUM); strncpy(kPacketDirectEnter.passwd, c_szPassword, PASS_MAX_NUM); strncpy(kPacketDirectEnter.Hwid, c_szHwid, HWID_MAX_NUM); strncpy(kPacketDirectEnter.Snn, c_szSnn, SNN_MAX_NUM); if (!Send(sizeof(kPacketDirectEnter), &kPacketDirectEnter)) { Tracen("SendDirectEnter"); return false; } return SendSequence(); } Search this function bool CPythonNetworkStream::SendLoginPacket(const char* c_szName, const char* c_szPassword) and replace with this bool CPythonNetworkStream::SendLoginPacket(const char* c_szName, const char* c_szPassword, const char* c_szHwid, const char* c_szSnn) { TPacketCGLogin LoginPacket; LoginPacket.header = HEADER_CG_LOGIN; strncpy(LoginPacket.name, c_szName, sizeof(LoginPacket.name)-1); strncpy(LoginPacket.pwd, c_szPassword, sizeof(LoginPacket.pwd)-1); strncpy(LoginPacket.Hwid, c_szHwid, sizeof(LoginPacket.Hwid)-1); strncpy(LoginPacket.Snn, c_szSnn, sizeof(LoginPacket.Snn)-1); LoginPacket.name[ID_MAX_NUM]='0'; LoginPacket.pwd[PASS_MAX_NUM]='0'; LoginPacket.Hwid[HWID_MAX_NUM]='0'; LoginPacket.Snn[SNN_MAX_NUM]='0'; if (!Send(sizeof(LoginPacket), &LoginPacket)) { Tracen("SendLogin Error"); return false; } return SendSequence(); } Search bool CPythonNetworkStream::SendLoginPacketNew(const char * c_szName, const char * c_szPassword) and replace with this bool CPythonNetworkStream::SendLoginPacketNew(const char * c_szName, const char * c_szPassword, const char * c_szHwid, const char * c_szSnn) 2-2-4)PythonNetworkStreamModule.cpp Search this function PyObject* netSetLoginInfo(PyObject* poSelf, PyObject* poArgs) and replace with this PyObject* netSetLoginInfo(PyObject* poSelf, PyObject* poArgs) { char* szName; if (!PyTuple_GetString(poArgs, 0, &szName)) return Py_BuildException(); char* szPwd; if (!PyTuple_GetString(poArgs, 1, &szPwd)) return Py_BuildException(); char* szHwid; if (!PyTuple_GetString(poArgs, 2, &szHwid)) return Py_BuildException(); char* szSnn; if (!PyTuple_GetString(poArgs, 3, &szSnn)) return Py_BuildException(); CPythonNetworkStream& rkNetStream=CPythonNetworkStream::Instance(); CAccountConnector & rkAccountConnector = CAccountConnector::Instance(); rkNetStream.SetLoginInfo(szName, szPwd, szHwid, szSnn); rkAccountConnector.SetLoginInfo(szName, szPwd, szHwid, szSnn); return Py_BuildNone(); } Search this function PyObject* netSendLoginPacket(PyObject* poSelf, PyObject* poArgs) and replace with this PyObject* netSendLoginPacket(PyObject* poSelf, PyObject* poArgs) { char* szName; if (!PyTuple_GetString(poArgs, 0, &szName)) return Py_BuildException(); char* szPwd; if (!PyTuple_GetString(poArgs, 1, &szPwd)) return Py_BuildException(); char* szHwid; if (!PyTuple_GetString(poArgs, 2, &szHwid)) return Py_BuildException(); char* szSnn; if (!PyTuple_GetString(poArgs, 3, &szSnn)) return Py_BuildException(); CPythonNetworkStream& rkNetStream=CPythonNetworkStream::Instance(); rkNetStream.SendLoginPacket(szName, szPwd, szHwid, szSnn); return Py_BuildNone(); } 2-2-5)PythonNetworkStream.h Search void SetLoginInfo(const char* c_szID, const char* c_szPassword); Replace with this void SetLoginInfo(const char* c_szID, const char* c_szPassword, const char* c_szHwid, const char* c_szSnn); Search bool SendLoginPacket(const char * c_szName, const char * c_szPassword); bool SendLoginPacketNew(const char * c_szName, const char * c_szPassword); Replace with this bool SendLoginPacket(const char * c_szName, const char * c_szPassword, const char * c_szHwid, const char * c_szSnn); bool SendLoginPacketNew(const char * c_szName, const char * c_szPassword, const char * c_szHwid, const char * c_szSnn); Search bool SendDirectEnterPacket(const char * c_szName, const char * c_szPassword, UINT uChrSlot); And replace with this bool SendDirectEnterPacket(const char * c_szName, const char * c_szPassword, const char * c_szHwid, const char * c_szSnn, UINT uChrSlot); Search std::string m_stPassword; Add it below std::string m_stHwid; std::string m_stSnn; 2-2-6)PythonNetworkStream.cpp Search this function void CPythonNetworkStream::SetLoginInfo(const char* c_szID, const char* c_szPassword) And replace with this void CPythonNetworkStream::SetLoginInfo(const char* c_szID, const char* c_szPassword, const char* c_szHwid, const char* c_szSnn) { m_stID=c_szID; m_stPassword=c_szPassword; m_stHwid=c_szHwid; m_stSnn=c_szSnn; } Now run this query commands; ALTER TABLE account.account ADD Hwid VARCHAR(50); ALTER TABLE account.account ADD Snn VARCHAR(50); Create tables DROP TABLE IF EXISTS `snnban`; CREATE TABLE `snnban` ( `Snn` varchar(255) NOT NULL ) ENGINE=InnoDB DEFAULT CHARSET=latin1; DROP TABLE IF EXISTS `hwidban`; CREATE TABLE `hwidban` ( `Hwid` varchar(255) NOT NULL ) ENGINE=InnoDB DEFAULT CHARSET=latin1; Basic php ban script <?php error_reporting(0); if($_GET) { $baglanti = mysqli_connect('localhost', 'root', 'PASSWORD', 'account'); $hwid = mysqli_real_escape_string($baglanti, $_GET['hwid']); $snn = mysqli_real_escape_string($baglanti, $_GET['snn']); if(strlen($snn) == 0) { $hwid_bul = mysqli_query($baglanti, "SELECT null FROM hwidban WHERE hwid='$hwid'"); if(mysqli_num_rows($hwid_bul) > 0) echo 'BLOCK'; mysqli_free_result($hwid_bul); }else{ $snn_bul = mysqli_query($baglanti, "SELECT null FROM snnban WHERE snn='$snn'"); if(mysqli_num_rows($snn_bul) > 0) echo 'BLOCK'; mysqli_free_result($snn_bul); } mysqli_close($baglanti); } ?> Bonus; if you want alternative ways (mac, cpu etc.) check tutorials below #CPU INFO: import platform platform.processor() #MAC INFO: mac = '' for line in os.popen('getmac /nh /fo CSV').readlines(): m = line.split(',')[0] dev = line.split(',')[1] if dev.find('Device') and mac == '': mac = m mac = mac.replace('"', '') #HWID INFO: *DEFAULT hwid = os.popen('wmic csproduct get uuid').read().split("n")[1] #HDD INFO: hddinfo = win32api.GetVolumeInformation("C:") #COMPUTER NAME: pcadi = os.environ['COMPUTERNAME'] #CPU NAME: cpu = os.popen('wmic cpu get name').read().split("n")[1] #MOTHERBOARD INFO: anakart = os.popen('wmic baseboard get serialnumber').read().split("n")[1] #RAM SERIAL: ram = os.popen('wmic memorychip get serialnumber').read().split("n")[2] #BIOS VERSION: biosv = os.popen('wmic bios get smbiosbiosversion').read().split("n")[1] #COMPUTER MODEL: model = os.popen('wmic csproduct get name').read().split("n")[1] #SYSTEM TYPE: systype = os.popen('wmic computersystem get systemtype').read().split("n")[1] #COMPUTER OWNER: owner = os.popen('wmic computersystem get manufacturer').read().split("n")[1] #OS NAME: osname = os.popen('wmic os get Caption,CSDVersion /value').read().split("n")[2].split("Caption=")[-1] #WINDOWS USERNAME: winusnm = os.popen('echo %username%').read().split("n")[0] #VOLUME NAME: volname = os.popen('wmic logicaldisk get volumename').read().split("n")[1] #SMART SNN: *DEFAULT smartsnn = os.popen('wmic path win32_physicalmedia get SerialNumber').read().split("n")[1] #USER SID: usersid = os.popen('wmic useraccount get name,sid').read().split("n")[2].replace(" ", " - ") #TOTAL MEMORY: ramboyut = os.popen('wmic computersystem get TotalPhysicalMemory').read().split("n")[1] Example files: https://www.mediafire.com/?jjjkr0u9jzfezw9 Virustotal: https://www.virustotal.com/en/file/be38451c9ff793199e9431aecabd01226f143eed4bc509e481543c06e9272248/analysis/1417175162/ Result: Sorry my bad english Regards
  45. 26 points
    Hello guys.. So much people got problem with this system then i do FULL TuT exclusive for metin2dev All is tested and all works TuT included in all FILES.. New Link: Pass: When you find some bug post it here.. I will try to fix it.. Have Fun //EnZi EDITED: #New Link UPDATE cmd_general.cpp - Added some new code char_battle.cpp - Added some new code ProtoReader.cpp - Added some new code questlua_pc - Repaired code item_proto - Query for navicat Quest added UP LINK UPDATED
  46. 26 points
    Hi there devs, I made some new reload commands about 2 weeks ago and published a tutorial about it on our Hungarian forum (you may saw them in the samurai core) and today I had some time to make the translation. What can I reload now? refine_proto (this is the only one which is not mine, its @xP3NG3Rx's, and already public here, but I added it, because I think this package has to contain it ) command: /reload p shop_item table (npc's shops) command: /reload p item_attr && item_attr_rare table; command: /reload p etc_drop_item.txt, mob_drop_item.txt, special_item_group.txt; command: /reload drop group.txt, group_group.txt; command: /reload group regen.txt, npc.txt, boss.txt, stone.txt (only on the current map) command: /reload regen because of the new "reload regen" command, I had to write a new purge command that destroys all mobs, npcs, stones (and so on...) on the current map, so I added a new /p map command to the "/p" commands that are already exists (no, the "/p all" only destroys the mobs on the current sectree (current block)) also I had to create a new command that stops all the regens (and ofc. deletes them from the memory) on the current map, so I added a new "/free_regens" command (because why not ) Its only deletes the loaded regens, and prevents the mobs from respawning (its not necessary to use this before the /reload regen) Known bug Well its not a serious problem, but for some unknown reason, when I'm debugging the core on windows server (no, not debug mode, but vs 13's debugger) and I try to do /reload regen, the core starts to consume ~40% cpu, and doesn't want to do anything (so stops working, but doesn't crash). It has no affect on FreeBSD and release or debug mode (without visual studio's debugger) on windows. game/src cmd.cpp cmd_gm.cpp input_db.cpp shop_manager.cpp refine.cpp char_manager.cpp char_manager.h item_manager.h item_manager_read_tables.cpp mob_manager.h mob_manager.cpp char.cpp sectree_manager.cpp regen.h regen.cpp shop.h shop.cpp db/src ClientManager.cpp And finally let me wish you all good luck for the setup If you have further question(s), remark(s), or anything that you want to ask or suggest, feel free to post it here, or send it in PM. If you get error(s) please upload the affected (and edited) file to http://pastebin.com/ and link it in your post, to make my work easier and probably I will be able to help you only in one post, so please spare me from asking basic requests like "Could you upload...". Thank you Have a nice day, ~masodikbela
  47. 26 points
    Hi devs! The original equipment viewer is not updated for the new equipments I am thinking of costumes + rings + belt Here is the extended version. Images: Here are my modified files to root and uiscript package, the .py files: uiEquipDialog.py Pastebin ~ MEGA UIScriptEquipmentDialog.py Pastebin ~ MEGA UIScriptCostumeEquipmentDialog.py Pastebin ~ MEGA Ehm yeah this was the easiest part of this, now comin' the serverside and binary parts. Server: 1.) Open gamepacket.h than search for: "typedef struct pakcet_view_equip" and replace all structure with this: typedef struct pakcet_view_equip { BYTE header; DWORD vid; struct { DWORD vnum; BYTE count; long alSockets[ITEM_SOCKET_MAX_NUM]; TPlayerItemAttribute aAttr[ITEM_ATTRIBUTE_MAX_NUM]; } equips[16]; } TPacketViewEquip; PS: lel "pakcet" xD nevermind Save&Close 2.) Open char.cpp and search for this: "void CHARACTER::SendEquipment(LPCHARACTER ch)" and replace the event with this(Thanks ATAG): void CHARACTER::SendEquipment(LPCHARACTER ch) { TPacketViewEquip p; p.header = HEADER_GC_VIEW_EQUIP; p.vid = GetVID(); int pos[16] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 19, 20, 21, 22, 23 }; for (int i = 0; i < 16; i++) { LPITEM item = GetWear(pos[i]); if (item) { p.equips[i].vnum = item->GetVnum(); p.equips[i].count = item->GetCount(); thecore_memcpy(p.equips[i].alSockets, item->GetSockets(), sizeof(p.equips[i].alSockets)); thecore_memcpy(p.equips[i].aAttr, item->GetAttributes(), sizeof(p.equips[i].aAttr)); } else { p.equips[i].vnum = 0; } } ch->GetDesc()->Packet(&p, sizeof(p)); } Serverside done! - Build! Binary: 1.) Open UserInterfacePacket.h than search for this: "typedef struct pakcet_view_equip" and replace with this: typedef struct pakcet_view_equip { BYTE header; DWORD dwVID; TEquipmentItemSet equips[16]; } TPacketGCViewEquip; PS: we met again with pakcet xD, Save&Close. 2.) Open UserInterfacePythonNetworkStreamPhaseGame.cpp than search for this: "bool CPythonNetworkStream::RecvViewEquipPacket()" and replace with this: bool CPythonNetworkStream::RecvViewEquipPacket() { TPacketGCViewEquip kViewEquipPacket; if (!Recv(sizeof(kViewEquipPacket), &kViewEquipPacket)) return false; PyCallClassMemberFunc(m_apoPhaseWnd[PHASE_WINDOW_GAME], "OpenEquipmentDialog", Py_BuildValue("(i)", kViewEquipPacket.dwVID)); for (int i = 0; i < 16; ++i) { TEquipmentItemSet & rItemSet = kViewEquipPacket.equips[i]; PyCallClassMemberFunc(m_apoPhaseWnd[PHASE_WINDOW_GAME], "SetEquipmentDialogItem", Py_BuildValue("(iiii)", kViewEquipPacket.dwVID, i, rItemSet.vnum, rItemSet.count)); for (int j = 0; j < ITEM_SOCKET_SLOT_MAX_NUM; ++j) PyCallClassMemberFunc(m_apoPhaseWnd[PHASE_WINDOW_GAME], "SetEquipmentDialogSocket", Py_BuildValue("(iiii)", kViewEquipPacket.dwVID, i, j, rItemSet.alSockets[j])); for (int k = 0; k < ITEM_ATTRIBUTE_SLOT_MAX_NUM; ++k) PyCallClassMemberFunc(m_apoPhaseWnd[PHASE_WINDOW_GAME], "SetEquipmentDialogAttr", Py_BuildValue("(iiiii)", kViewEquipPacket.dwVID, i, k, rItemSet.aAttr[k].bType, rItemSet.aAttr[k].sValue)); } return true; } Binaryside done! - Build! ---Edit---- Multiple opening bugfix: Open interFaceModule.py and search for this: "def OpenEquipmentDialog(self, vid):" if you found it replace that function with this: def OpenEquipmentDialog(self, vid): if self.equipmentDialogDict.has_key(vid): self.equipmentDialogDict[vid].Destroy() self.CloseEquipmentDialog(vid) dlg = uiEquipmentDialog.EquipmentDialog() dlg.SetItemToolTip(self.tooltipItem) dlg.SetCloseEvent(ui.__mem_func__(self.CloseEquipmentDialog)) dlg.Open(vid) self.equipmentDialogDict[vid] = dlg Show the "View equip" button on the targetbar: Open uitarget.py and check this diff to fix it for yourself: https://www.diffchecker.com/lqi9xdb7 ( ----EndEdit---- Ohh I almost forgot, here are the bgs ^^-> ui.7z - MEGA All done, press escape to exit... :')
  48. 26 points
    Hi there Dev's, today I'm gonna show you and give you as well, if you want ofc, the old skill effects from Metin2 (M1 to G1). These effects are from the time when Metin2 was opened in .kr and .cn in 2005 and till the new patch. Since my last topic asking for these effects, I've finally managed to do it. So I'm gonna share with you. If you're trying to open an oldschool server, or not, these effects could be useful. Here's some prints. Body Warrior Berserk Dash Sword Spin Three-Way Cut Mental Warrior Spirit Strike (W) Sword Strike Weaponry Sura Dragon Swirl Black Magic Sura Spirit Strike (S) Dark Orb Blade-Fight Force Ninja Rolling Dagger Dragon Force Shaman Dragon's Strength Dragon's Roar Flying Talisman Healing Force Shaman Attack Up (effect on hand) This may be a shitty "release" for you but for me it ain't. I always wanted this and I've finally done it. Download Hope you like it.
  49. 26 points
    Today I release a high-level map made by YMIR and used only in the now closed Korean server. It includes some unique mobs. Everything is in the package, except the regen which is buggy (the groups in regen.txt don't seem to have an entry in groups.txt), if someone wants to create a regen (With BlackYuko's Map Converter for example) I will add it to the package Some screens Included: Map (client & server) , textureset and terrainmaps Mobs (client & server) and mob_proto Minimap https://mega.co.nz/#!LRF2hA5D!WgEpQAxJQBVuY3_whtH-BSDbi_WSJnf67Eoedali__Q
  50. 25 points
    Hi everyone, Today I bring you a collection of maps made by Ymir that were included at some point in an official client but were never used. The maps are: GM Guild Building Field Dungeon Ginseng Valley (b2) - Second version of Dragon Valley (Orcs area) Heavenly Valley (c2) - Third version of Dragon Valley (Orcs area) Dragon Timeattack 1 - Dungeon possibly used in Korea, used by SG for Dragon Timeattack event Dragon Timeattack 2 Dragon Timeattack 3 Test map - Actually a town EW02 - ? Guild Inside - Supposed to be the inside of a guild house Milgyo Pass & Sungzi - A collection of alternative maps for Nation War. Requires editing forked_road.txt in order to add them to this event. Siege - Three maps one for each kingdom, for a kingdom event You might also be interested in the Metin2 Korea Naga map available here The Lost maps of YMIR.zip 74.6 MB https://mega.co.nz/#!XtxVBSzZ!B3q_5Ol1VWgY5GxR4YkLHh8-89iLDrkMKZz_gYUG67k