Jump to content

All Activity

This stream auto-updates

  1. Past hour
  2. Hopefully this is fine to post here, I don't think it is a client issue where most animation posts generally end up I have some skills that properly display skill animations, but they also do the envenom skill animation+sound every time they hit a target (They are not supposed to have this animation/sound). This is just happening on some 4th job skills. Anybody know why this happens, and how to fix it? I can't seem to find much about this. I have been experimenting in skill.cpp (as I assume that is where the problem likely originates), using various lines like clif_skill_damage, clif_skill_nodamage. Even when I removed any lines that would show the skills animation, the "envenom" part still remains.
  3. by default you should be able to login with multiple accounts, maybe you made some modification on the conf folder? perhaps // Maximum users able to connect to the server. // Set to 0 to disable users to log-in. (-1 means unlimited) max_connect_user: -1
  4. Today
  5. yes i using the 2025-05-08 client
  6. Link: https://github.com/TBlazeWarriorT/TBlazeWarriorT-Utility-Scripts/tree/main/NP%2B%2B rAthena Autocomplete Screenshots:
  7. Cool stuff, I make an almost identical thing a few weeks ago to translate mine
  8. con el permiso de no ofender al autor del script, quisiera que me ayudaran a colocarle un comando como el del archivo adjunto que seria fusión. - actualmente se le habla al npc pero quisiera que se le agregara la opción @claim, para tener dialogo desde el comando con el script de codigo de canje. - el archivo andjunto es otro script que ya tiene el @claim por lo cuál quienes me ayuden lo podrian sacar de allí, en realidad yo lo intente pero no lo logre. - si es posible también modificar la opción de que el administrador pueda crear la clave de código en el chat de gm. //--- Coupon NPC 1.1.2 -------------------------------------------// //----------------------------------------------------------------// // ttt 000000000 // ttt 000 000 // ttttttttt rrrrrrrrr 000 000 nnnnnnnnn // ttt rrr 000 000 nnn nnn // ttt rrr 000 000 nnn nnn // ttt rrr 000 000 nnn nnn // ttttt rrr 000000000 nnn nnn //----------------------------------------------------------------// //--- Changelogs: ------------------------------------------------// // 1.0.0 Release // 1.1.0 Added code type feature (normal|md5-hash) // 1.1.0 Added prevention for typing 0 into Item ID or Amount // 1.1.0 Added a feature for gms to see available coupons // 1.1.0 Minor bug fixes // 1.1.1 Fixed a bug that caused duplicating items // 1.1.2 Added announce if player got a item //----------------------------------------------------------------// //--- Main Script ------------------------------------------------// prontera,146,173,5 script Coupon Jack 807,{ //Set code type (0 = normal | 1 = MD5-Hash) set .code_type, 0; //Set code length set .code_length, 16; //Set Min. GM Level to add new coupons set .code_gmlvl, 99; setarray .coupon_code$[0],"a","b","c","d","e","f","g","h","i","j","k","l", "m","n","o","p","q","r","s","t","u","v","w","x", "y","z","0","1","2","3","4","5","6","7","8","9"; if(getgmlevel() >= .code_gmlvl) { mes "[^FF7700Coupon Jack^000000]"; mes "Welcome " + strcharinfo(0) + "."; next; switch(select("Add Coupon:Show Coupons:Exit")) { case 1: mes "[^FF7700Coupon Jack^000000]"; mes "Enter Item ID:"; input @coupon_item; next; if(@coupon_item <= 0) goto L_error; mes "[^FF7700Coupon Jack^000000]"; mes "Enter Item Amount:"; input @coupon_amount; next; if(@coupon_amount <= 0) goto L_error; for(set @i, 0; @i < .code_length; set @i, @i+1) { set @random_char, rand(0,(getarraysize(.coupon_code$)-1)); set @new_coupon$, @new_coupon$ + .coupon_code$[@random_char]; } if(.code_type==1) { set @new_coupon$, md5(@new_coupon$); } mes "[^FF7700Coupon Jack^000000]"; mes "Coupon added."; query_sql "INSERT INTO `coupons` (`code`, `item_id`, `item_amount`) VALUES ('"+@new_coupon$+"', "+@coupon_item+", "+@coupon_amount+")"; set @new_coupon$, ""; close; case 2: mes "[^FF7700Coupon Jack^000000]"; mes "--------------------------------"; query_sql "SELECT `code`, `item_id`, `item_amount` FROM `coupons`", .@available_code$, .@available_item, .@available_amount; for(set @i, 0; @i < getarraysize(.@available_code$); set @i, @i+1) { mes "Item: " + getitemname(.@available_item[@i]); mes "Amount: " + .@available_amount[@i]; mes "Code: " + .@available_code$[@i]; mes "--------------------------------"; } close; case 3: mes "[^FF7700Coupon Jack^000000]"; mes "Have a nice day."; close; } } mes "[^FF7700Coupon Jack^000000]"; mes "Welcome to the Coupon Codes System. How can I help you?"; next; switch(Select("Submit Coupon:Exit")) { case 1: mes "[^FF7700Coupon Jack^000000]"; mes "Please enter your Coupon Code:"; input @my_code$; next; query_sql "SELECT `code`, `item_id`, `item_amount` FROM `coupons`", .@available_code$, .@available_item, .@available_amount; for (set @i, 0; @i < getarraysize(.@available_code$); set @i, @i+1) { if(@my_code$==.@available_code$[@i]) { mes "[^FF7700Coupon Jack^000000]"; mes "You get ^0000FF" + getitemname(.@available_item[@i]) + " - " + .@available_amount[@i] + " ea.^000000"; query_sql "DELETE FROM `coupons` WHERE `code`='"+@my_code$+"'"; getitem .@available_item[@i],.@available_amount[@i]; //announce "Coupon Jack: " + strcharinfo(0) + " got " + .@available_amount[@i] + getitemname(.@available_item[@i]) + "(s).",0; close; } } mes "[^FF7700Coupon Jack^000000]"; mes "This Coupon Code doesn't exist."; close; case 2: mes "[^FF7700Coupon Jack^000000]"; mes "Have a nice day."; close; } L_error: mes "[^FF7700Coupon Jack^000000]"; mes "Invalid Number"; close; OnInit: query_sql "CREATE TABLE IF NOT EXISTS `coupons` (`code` TINYTEXT NOT NULL, `item_id` INT NOT NULL, `item_amount` INT NOT NULL, INDEX `code` (`code`(32)) ) ENGINE=MyISAM"; } npc de tron.txt npc_LIL TROLL.txt
  9. Hello rAthena Community, I'm currently developing a Unity client for an rAthena-based server (PACKETVER 20230302) and I've encountered an unknown packet after character selection. Here's the sequence of packets I'm successfully parsing from the character server: 1. Login and authentication packets (e.g., 0x0065 response) 2. Character slot info (e.g., 0x082D) 3. Character list data (0x006B) - Parsed successfully, character details are correct. 4. Character list page info (0x09A0) - Parsed successfully. Immediately after processing the 0x09A0 packet, my client receives a packet with ID `0x0D00`. My client logs show the following for this `0x0D00` packet: - Packet ID: `0x0D00` - Declared total length (from bytes 2-3 of the packet): `29` (0x001D) - This means the data payload (excluding the 2-byte ID and 2-byte length field) is `25` bytes. The HEX dump of this 25-byte data payload is: `0F 00 00 0F 0F 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00` I've searched through my rAthena server source files (including `char_clif.c`, `mmo.h`, `packets.hpp`, etc.) but I cannot find any explicit definition or usage of a packet with the ID `0x0D00` that would be sent from the character server to the client after character selection with this specific length and payload. I suspect this `0x0D00` packet contains crucial information for connecting to the map server (e.g., selected Character ID for map server, Map Server IP, Port, and session/auth keys). However, without knowing its structure, I cannot parse it correctly. My current attempts to parse it based on common map server info structures with a 25-byte payload yield unusual values (e.g., Map IP 15.0.0.0, Port 0). Could anyone please help me identify the structure of this `0x0D00` packet (with a 25-byte payload) that is sent after character selection? Specifically, what do these 25 bytes represent? Is this a standard rAthena packet for a specific `PACKETVER` (my server is `20230302`), or could it be a custom packet? Any insights or pointers to relevant source code sections would be greatly appreciated. Thank you!
  10. 안녕하세요 rAthena 커뮤니티 여러분, 현재 rAthena 기반 서버(PACKETVER 20230302)용 Unity 클라이언트를 개발 중인데, 캐릭터 선택 후 알 수 없는 패킷을 발견했습니다. 다음은 캐릭터 서버에서 성공적으로 구문 분석한 패킷 시퀀스입니다. 1. 로그인 및 인증 패킷(예: 0x0065 응답) 2. 문자 슬롯 정보(예: 0x082D) 3. 문자 목록 데이터(0x006B) - 성공적으로 구문 분석되었으며, 문자 세부 정보가 정확합니다. 4. 문자 목록 페이지 정보(0x09A0) - 성공적으로 구문 분석되었습니다. 0x09A0 패킷을 처리한 직후, 클라이언트는 ID가 `0x0D00`인 패킷을 수신합니다. 클라이언트 로그에는 이 `0x0D00` 패킷에 대한 다음과 같은 정보가 기록되어 있습니다. - 패킷 ID: `0x0D00` - 선언된 총 길이(패킷의 2~3바이트): `29` (0x001D) - 이는 데이터 페이로드(2바이트 ID와 2바이트 길이 필드 제외)가 `25` 바이트임을 의미합니다. 이 25바이트 데이터 페이로드의 HEX 덤프는 다음과 같습니다. `0F 00 00 0F 0F 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00` rAthena 서버 소스 파일(`char_clif.c`, `mmo.h`, `packets.hpp` 등)을 검색했지만, 이 특정 길이와 페이로드로 문자 선택 후 문자 서버에서 클라이언트로 전송되는 ID가 `0x0D00`인 패킷에 대한 명시적 정의나 사용법을 찾을 수 없습니다. 이 `0x0D00` 패킷에는 맵 서버 연결에 중요한 정보(예: 맵 서버의 선택된 캐릭터 ID, 맵 서버 IP, 포트, 세션/인증 키)가 포함되어 있을 것으로 예상됩니다. 하지만 패킷의 구조를 모르니 제대로 분석할 수 없습니다. 25바이트 페이로드를 사용하는 일반적인 맵 서버 정보 구조를 기반으로 분석하려고 시도했지만, 예상치 못한 값(예: 맵 IP 15.0.0.0, 포트 0)이 생성되었습니다. 문자 선택 후 전송되는 25바이트 페이로드를 가진 `0x0D00` 패킷의 구조를 파악하는 데 도움을 주실 수 있을까요? 구체적으로, 이 25바이트는 무엇을 나타내는 걸까요? 이 패킷은 특정 `PACKETVER`(제 서버는 `20230302`입니다)에 대한 표준 rAthena 패킷인가요, 아니면 사용자 지정 패킷일까요? 관련 소스 코드 섹션에 대한 통찰력이나 지침을 제공해 주시면 감사하겠습니다. 감사합니다!
  11. 안녕하세요 rAthena 커뮤니티 여러분, 현재 rAthena 기반 서버(PACKETVER 20230302)용 Unity 클라이언트를 개발 중인데, 캐릭터 선택 후 알 수 없는 패킷을 발견했습니다. 다음은 캐릭터 서버에서 성공적으로 구문 분석한 패킷 시퀀스입니다. 1. 로그인 및 인증 패킷(예: 0x0065 응답) 2. 문자 슬롯 정보(예: 0x082D) 3. 문자 목록 데이터(0x006B) - 성공적으로 구문 분석되었으며, 문자 세부 정보가 정확합니다. 4. 문자 목록 페이지 정보(0x09A0) - 성공적으로 구문 분석되었습니다. 0x09A0 패킷을 처리한 직후, 클라이언트는 ID가 `0x0D00`인 패킷을 수신합니다. 클라이언트 로그에는 이 `0x0D00` 패킷에 대한 다음과 같은 정보가 기록되어 있습니다. - 패킷 ID: `0x0D00` - 선언된 총 길이(패킷의 2~3바이트): `29` (0x001D) - 이는 데이터 페이로드(2바이트 ID와 2바이트 길이 필드 제외)가 `25` 바이트임을 의미합니다. 이 25바이트 데이터 페이로드의 HEX 덤프는 다음과 같습니다. `0F 00 00 0F 0F 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00` rAthena 서버 소스 파일(`char_clif.c`, `mmo.h`, `packets.hpp` 등)을 검색했지만, 이 특정 길이와 페이로드로 문자 선택 후 문자 서버에서 클라이언트로 전송되는 ID가 `0x0D00`인 패킷에 대한 명시적 정의나 사용법을 찾을 수 없습니다. 이 `0x0D00` 패킷에는 맵 서버 연결에 중요한 정보(예: 맵 서버의 선택된 캐릭터 ID, 맵 서버 IP, 포트, 세션/인증 키)가 포함되어 있을 것으로 예상됩니다. 하지만 패킷의 구조를 모르니 제대로 분석할 수 없습니다. 25바이트 페이로드를 사용하는 일반적인 맵 서버 정보 구조를 기반으로 분석하려고 시도했지만, 예상치 못한 값(예: 맵 IP 15.0.0.0, 포트 0)이 생성되었습니다. 문자 선택 후 전송되는 25바이트 페이로드를 가진 `0x0D00` 패킷의 구조를 파악하는 데 도움을 주실 수 있을까요? 구체적으로, 이 25바이트는 무엇을 나타내는 걸까요? 이 패킷은 특정 `PACKETVER`(제 서버는 `20230302`입니다)에 대한 표준 rAthena 패킷인가요, 아니면 사용자 지정 패킷일까요? 관련 소스 코드 섹션에 대한 통찰력이나 지침을 제공해 주시면 감사하겠습니다. 감사합니다!
  12. Yesterday
  13. Hi there. I've set up a test server and am doing some testing on it. I'd like to be able to have 2 accounts log in at the same time. Is there a setting I'm missing somewhere to allow this? At the mo, the second account is disconnected right after logging in. Thanks in advance for any input
  14. @imdango Thank you for posting the solution! Quickest google search and bug fix of my life thanks to you!
  15. Thanks @Brynner, it's solved my issue.
  16. Another simple update, just added a panel to show currency total for the account and also a Buy Currency button (if configured), can be linked to any page to buy the currency. Either donate module or anything custom.
  17. UPDATES!! NOW, integrated with the Gemini Chatbot API for the Editor! Just ask it, and it will provide code for you directly in rAthena Text Editor. Simply provide your Gemini API key. We're using the latest and fastest Gemini model: "gemini-2.5-flash-preview-05-20".
  18. try to replace the clif_changelook(&sd->bl,LOOK_BODY2,sd->status.body); with clif_changelook(sd,LOOK_BODY2,sd->status.body);
  19. also does anyone know how many itens we can put in to each id before we got a error or doest work?
  20. anyone is able to have more than 4 groups ids? when i put a 5 i get the error "[Error]: script:run_script_main: infinity loop ! "
  21. I tested it with the latest rAthena version, and it works correctly. Are you perhaps using the 2025-05-08 client version?
  22. I'll look into these functions, thanks for the info. Look I'm happy to at least try and come up with a solution for this "puzzle", since I'll likely use it too! I tried to handle Super Novice, but at first glance it doesn't look doable, becuase the job has access to other classes' skills mixed with his skills. I'll try to work some more on Super Novice and Summoner. If I can't do it I'll look into using the functions you mentioned, it will likely require a huge rewrite so I rather try to fix it with the "current code". Edit: I managed to make Super Novice and Summoner work. I also swapped ShowError() with clif_displaymessage() so that the messages appear ingame. enum Job_Tier { Basic = 0, First, First_High, Second, Second_High, Third, Third_High, Fourth, Super_Novice, Super_Novice_E, Hyper_Novice, Summoner, Spirit_Handler, }; // Helper Function: Returns the job tier Job_Tier pc_get_job_tier(uint64 class_) { if (class_ == MAPID_SPIRIT_HANDLER) return Job_Tier::Spirit_Handler; if (class_ == MAPID_SUMMONER) return Job_Tier::Summoner; if (class_ == MAPID_HYPER_NOVICE) return Job_Tier::Hyper_Novice; if (class_ == MAPID_SUPER_NOVICE_E) return Job_Tier::Super_Novice_E; if (class_ == MAPID_SUPER_NOVICE) return Job_Tier::Super_Novice; if (class_ & JOBL_FOURTH) return Job_Tier::Fourth; if (class_ == MAPID_RUNE_KNIGHT_T) return Job_Tier::Third_High; if (class_ == MAPID_WARLOCK_T) return Job_Tier::Third_High; if (class_ == MAPID_RANGER_T) return Job_Tier::Third_High; if (class_ == MAPID_ARCH_BISHOP_T) return Job_Tier::Third_High; if (class_ == MAPID_MECHANIC_T) return Job_Tier::Third_High; if (class_ == MAPID_GUILLOTINE_CROSS_T) return Job_Tier::Third_High; if (class_ == MAPID_ROYAL_GUARD_T) return Job_Tier::Third_High; if (class_ == MAPID_SORCERER_T) return Job_Tier::Third_High; if (class_ == MAPID_MINSTRELWANDERER_T) return Job_Tier::Third_High; if (class_ == MAPID_SURA_T) return Job_Tier::Third_High; if (class_ == MAPID_GENETIC_T) return Job_Tier::Third_High; if (class_ == MAPID_SHADOW_CHASER_T) return Job_Tier::Third_High; if (class_ & JOBL_THIRD) return Job_Tier::Third; if (class_ == MAPID_LORD_KNIGHT) return Job_Tier::Second_High; if (class_ == MAPID_HIGH_WIZARD) return Job_Tier::Second_High; if (class_ == MAPID_SNIPER) return Job_Tier::Second_High; if (class_ == MAPID_HIGH_PRIEST) return Job_Tier::Second_High; if (class_ == MAPID_WHITESMITH) return Job_Tier::Second_High; if (class_ == MAPID_ASSASSIN_CROSS) return Job_Tier::Second_High; if (class_ == MAPID_PALADIN) return Job_Tier::Second_High; if (class_ == MAPID_PROFESSOR) return Job_Tier::Second_High; if (class_ == MAPID_CLOWNGYPSY) return Job_Tier::Second_High; if (class_ == MAPID_CHAMPION) return Job_Tier::Second_High; if (class_ == MAPID_CREATOR) return Job_Tier::Second_High; if (class_ == MAPID_STALKER) return Job_Tier::Second_High; if (class_ & JOBL_2) return Job_Tier::Second; if (class_ == MAPID_SWORDMAN_HIGH) return Job_Tier::First_High; if (class_ == MAPID_MAGE_HIGH) return Job_Tier::First_High; if (class_ == MAPID_ARCHER_HIGH) return Job_Tier::First_High; if (class_ == MAPID_ACOLYTE_HIGH) return Job_Tier::First_High; if (class_ == MAPID_MERCHANT_HIGH) return Job_Tier::First_High; if (class_ == MAPID_THIEF_HIGH) return Job_Tier::First_High; if ((class_ & MAPID_BASEMASK) != MAPID_NOVICE) return Job_Tier::First; return Job_Tier::Basic; // Novice/Summoner } // Helper Function : Returns the skill's job tier Job_Tier skill_get_job_tier(uint16 skill_id) { // Novice if (skill_id > 0 && skill_id < SM_SWORD) return Job_Tier::Basic; // Swordman else if (skill_id >= SM_SWORD && skill_id <= SM_ENDURE) return Job_Tier::First; // Magician else if (skill_id >= MG_SRECOVERY && skill_id <= MG_THUNDERSTORM) return Job_Tier::First; // Acolyte else if (skill_id >= AL_DP && skill_id <= AL_CURE) return Job_Tier::First; // Merchant else if (skill_id >= MC_INCCARRY && skill_id <= MC_MAMMONITE) return Job_Tier::First; // Archer else if (skill_id >= AC_OWL && skill_id <= AC_SHOWER) return Job_Tier::First; // Thief else if (skill_id >= TF_DOUBLE && skill_id <= TF_DETOXIFY) return Job_Tier::First; // Taekwon Kid else if (skill_id >= TK_RUN && skill_id <= TK_HIGHJUMP) return Job_Tier::First; else if (skill_id == TK_MISSION) return Job_Tier::First; // Knight else if (skill_id >= KN_SPEARMASTERY && skill_id <= KN_CAVALIERMASTERY) return Job_Tier::Second; // Priest else if (skill_id >= PR_MACEMASTERY && skill_id <= PR_MAGNUS) return Job_Tier::Second; // Wizard else if (skill_id >= WZ_FIREPILLAR && skill_id <= WZ_ESTIMATION) return Job_Tier::Second; // Blacksmith else if (skill_id >= BS_IRON && skill_id <= BS_MAXIMIZE) return Job_Tier::Second; // Hunter else if (skill_id >= HT_SKIDTRAP && skill_id <= HT_SPRINGTRAP) return Job_Tier::Second; // Assassin else if (skill_id >= AS_RIGHT && skill_id <= AS_SPLASHER) return Job_Tier::Second; // Rogue else if (skill_id >= RG_SNATCHER && skill_id <= RG_PLAGIARISM) return Job_Tier::Second; // Alchemist else if (skill_id >= AM_AXEMASTERY && skill_id <= AM_RESURRECTHOMUN) return Job_Tier::Second; // Crusader else if (skill_id >= CR_TRUST && skill_id <= CR_SPEARQUICKEN) return Job_Tier::Second; // Monk else if (skill_id >= MO_IRONHAND && skill_id <= MO_COMBOFINISH) return Job_Tier::Second; // Sage else if (skill_id >= SA_ADVANCEDBOOK && skill_id <= SA_COMA) return Job_Tier::Second; // Bard & Dancer else if (skill_id >= BD_ADAPTATION && skill_id <= BD_RAGNAROK) return Job_Tier::Second; // Bard else if (skill_id >= BA_MUSICALLESSON && skill_id <= BA_APPLEIDUN) return Job_Tier::Second; // Dancer else if (skill_id >= DC_DANCINGLESSON && skill_id <= DC_SERVICEFORYOU) return Job_Tier::Second; // Lord Knight else if (skill_id >= LK_AURABLADE && skill_id <= LK_FURY) return Job_Tier::Second_High; else if (skill_id >= LK_SPIRALPIERCE && skill_id <= LK_JOINTBEAT) return Job_Tier::Second_High; // High Priest else if (skill_id >= HP_ASSUMPTIO && skill_id <= HP_MEDITATIO) return Job_Tier::Second_High; else if (skill_id == HP_MANARECHARGE) return Job_Tier::Second_High; // High Wizard else if (skill_id >= HW_SOULDRAIN && skill_id <= HW_MAGICPOWER) return Job_Tier::Second_High; else if (skill_id == HW_NAPALMVULCAN) return Job_Tier::Second_High; else if (skill_id >= HW_GANBANTEIN && skill_id <= HW_GRAVITATION) return Job_Tier::Second_High; // Paladin else if (skill_id >= PA_PRESSURE && skill_id <= PA_GOSPEL) return Job_Tier::Second_High; else if (skill_id == PA_SHIELDCHAIN) return Job_Tier::Second_High; // Champion else if (skill_id >= CH_PALMSTRIKE && skill_id <= CH_CHAINCRUSH) return Job_Tier::Second_High; else if (skill_id == CH_SOULCOLLECT) return Job_Tier::Second_High; // Professor else if (skill_id >= PF_HPCONVERSION && skill_id <= PF_SOULBURN) return Job_Tier::Second_High; else if (skill_id >= PF_MINDBREAKER && skill_id <= PF_SPIDERWEB) return Job_Tier::Second_High; else if (skill_id == PF_DOUBLECASTING) return Job_Tier::Second_High; // Assassin Cross else if (skill_id >= ASC_KATAR && skill_id <= ASC_BREAKER) return Job_Tier::Second_High; else if (skill_id >= ASC_METEORASSAULT && skill_id <= ASC_CDP) return Job_Tier::Second_High; // Sniper else if (skill_id >= SN_SIGHT && skill_id <= SN_WINDWALK) return Job_Tier::Second_High; // Whitesmith else if (skill_id >= WS_MELTDOWN && skill_id <= WS_SYSTEMCREATE) return Job_Tier::Second_High; else if (skill_id == WS_WEAPONREFINE) return Job_Tier::Second_High; else if (skill_id >= WS_CARTTERMINATION && skill_id <= WS_OVERTHRUSTMAX) return Job_Tier::Second_High; // Stalker else if (skill_id >= ST_CHASEWALK && skill_id <= ST_STEALBACKPACK) return Job_Tier::Second_High; else if (skill_id >= ST_PRESERVE && skill_id <= ST_FULLSTRIP) return Job_Tier::Second_High; // Creator else if (skill_id >= CR_ALCHEMY && skill_id <= CR_SYNTHESISPOTION) return Job_Tier::Second_High; else if (skill_id >= CR_SLIMPITCHER && skill_id <= CR_FULLPROTECTION) return Job_Tier::Second_High; else if (skill_id == CR_ACIDDEMONSTRATION) return Job_Tier::Second_High; // Clown / Gypsy else if (skill_id >= CG_ARROWVULCAN && skill_id <= CG_MARIONETTE) return Job_Tier::Second_High; else if (skill_id >= CG_LONGINGFREEDOM && skill_id <= CG_TAROTCARD) return Job_Tier::Second_High; else if (skill_id == CG_SPECIALSINGER) return Job_Tier::Second_High; // Star Gladiator else if (skill_id >= SG_FEEL && skill_id <= SG_FUSION) return Job_Tier::Second; // Soul Linker else if (skill_id == SL_ALCHEMIST) return Job_Tier::Second; else if (skill_id >= SL_MONK && skill_id <= SL_SKA) return Job_Tier::Second; else if (skill_id == SL_HIGH) return Job_Tier::Second; // else if (skill_id >= SL_DEATHKNIGHT && skill_id <= SL_GUNNER) return 2; // Gunslinger else if (skill_id >= GS_GLITTERING && skill_id <= GS_GROUNDDRIFT) return Job_Tier::Second_High; // Ninja else if (skill_id >= NJ_TOBIDOUGU && skill_id <= NJ_ISSEN) return Job_Tier::Second_High; // Rune Knight else if (skill_id >= RK_ENCHANTBLADE && skill_id <= RK_PHANTOMTHRUST) return Job_Tier::Third; else if (skill_id >= RK_DRAGONBREATH_WATER && skill_id <= RK_LUXANIMA) return Job_Tier::Third; // Guillotine Cross else if (skill_id >= GC_VENOMIMPRESS && skill_id <= GC_CROSSRIPPERSLASHER) return Job_Tier::Third; else if (skill_id == GC_DARKCROW) return Job_Tier::Third; // Arch-Bishop else if (skill_id >= AB_JUDEX && skill_id <= AB_SILENTIUM) return Job_Tier::Third; else if (skill_id == AB_SECRAMENT) return Job_Tier::Third; else if (skill_id == AB_OFFERTORIUM) return Job_Tier::Third; else if (skill_id >= AB_VITUPERATUM && skill_id <= AB_CONVENIO) return Job_Tier::Third; // Warlock else if (skill_id >= WL_WHITEIMPRISON && skill_id <= WL_FREEZE_SP) return Job_Tier::Third; else if (skill_id == WL_TELEKINESIS_INTENSE) return Job_Tier::Third; // Ranger else if (skill_id >= RA_ARROWSTORM && skill_id <= RA_ICEBOUNDTRAP) return Job_Tier::Third; else if (skill_id == RA_UNLIMIT) return Job_Tier::Third; // Mechanic else if (skill_id >= NC_MADOLICENCE && skill_id <= NC_DISJOINT) return Job_Tier::Third; else if (skill_id == NC_MAGMA_ERUPTION) return Job_Tier::Third; // Shadow Chaser else if (skill_id >= SC_FATALMENACE && skill_id <= SC_FEINTBOMB) return Job_Tier::Third; else if (skill_id == SC_ESCAPE) return Job_Tier::Third; // Royal Guard else if (skill_id >= LG_CANNONSPEAR && skill_id <= LG_INSPIRATION) return Job_Tier::Third; else if (skill_id == LG_KINGS_GRACE) return Job_Tier::Third; // Sura else if (skill_id >= SR_DRAGONCOMBO && skill_id <= SR_GENTLETOUCH_REVITALIZE) return Job_Tier::Third; else if (skill_id >= SR_HOWLINGOFLION && skill_id <= SR_RIDEINLIGHTNING) return Job_Tier::Third; else if (skill_id == SR_FLASHCOMBO) return Job_Tier::Third; // Wanderer else if (skill_id >= WA_SWING_DANCE && skill_id <= WA_MOONLIT_SERENADE) return Job_Tier::Third; // Ministrel else if (skill_id >= MI_RUSH_WINDMILL && skill_id <= MI_HARMONIZE) return Job_Tier::Third; // Wanderer && Ministrel else if (skill_id >= WM_LESSON && skill_id <= WM_UNLIMITED_HUMMING_VOICE) return Job_Tier::Third; else if (skill_id == WM_FRIGG_SONG) return Job_Tier::Third; // Sorcerer else if (skill_id >= SO_FIREWALK && skill_id <= SO_EARTH_INSIGNIA) return Job_Tier::Third; else if (skill_id == SO_ELEMENTAL_SHIELD) return Job_Tier::Third; // Genetic else if (skill_id >= GN_TRAINING_SWORD && skill_id <= GN_SLINGITEM_RANGEMELEEATK) return Job_Tier::Third; else if (skill_id == GN_ILLUSIONDOPING) return Job_Tier::Third; // Rebellion else if (skill_id >= RL_GLITTERING_GREED && skill_id <= RL_B_FLICKER_ATK) return Job_Tier::Third; // Star Emperor else if (skill_id >= SJ_LIGHTOFMOON && skill_id <= SJ_PROMINENCEKICK) return Job_Tier::Third; // Soul Reaper else if (skill_id >= SP_SOULGOLEM && skill_id <= SP_KAUTE) return Job_Tier::Third; // Kagerou && Oboro else if (skill_id >= KO_YAMIKUMO && skill_id <= KO_IZAYOI) return Job_Tier::Third; // Kagerou else if (skill_id >= KG_KAGEHUMI && skill_id <= KG_KAGEMUSYA) return Job_Tier::Third; // Oboro else if (skill_id >= OB_ZANGETSU && skill_id <= OB_AKAITSUKI) return Job_Tier::Third; // Super Novice 2 else if (skill_id >= NV_BREAKTHROUGH && skill_id <= NV_TRANSCENDENCE) return Job_Tier::Third; // Summoner else if (skill_id >= SU_BASIC_SKILL && skill_id <= SU_SPIRITOFSEA) return Job_Tier::Third; // ALL 3rd jobs else if (skill_id == ALL_FULL_THROTTLE) return Job_Tier::Third; // Dragon Knight else if (skill_id >= DK_SERVANTWEAPON && skill_id <= DK_STORMSLASH) return Job_Tier::Fourth; else if (skill_id == DK_DRAGONIC_BREATH) return Job_Tier::Fourth; else if (skill_id == DK_DRAGONIC_PIERCE) return Job_Tier::Fourth; // Arc Mage else if (skill_id >= AG_DEADLY_PROJECTION && skill_id <= AG_FROZEN_SLASH) return Job_Tier::Fourth; else if (skill_id == AG_DESTRUCTIVE_HURRICANE_CLIMAX) return Job_Tier::Fourth; else if (skill_id == AG_ENERGY_CONVERSION) return Job_Tier::Fourth; // Inquisitor else if (skill_id >= IQ_POWERFUL_FAITH && skill_id <= IQ_THIRD_EXOR_FLAME) return Job_Tier::Fourth; else if (skill_id == IQ_BLAZING_FLAME_BLAST) return Job_Tier::Fourth; // Imperial Guard else if (skill_id >= IG_GUARD_STANCE && skill_id <= IG_CROSS_RAIN) return Job_Tier::Fourth; else if (skill_id >= IG_RADIANT_SPEAR && skill_id <= IG_IMPERIAL_PRESSURE) return Job_Tier::Fourth; // Cardinal else if (skill_id >= CD_REPARATIO && skill_id <= CD_FRAMEN) return Job_Tier::Fourth; else if (skill_id == CD_DIVINUS_FLOS) return Job_Tier::Fourth; // Shadow Cross else if (skill_id >= SHC_SHADOW_EXCEED && skill_id <= SHC_FATAL_SHADOW_CROW) return Job_Tier::Fourth; else if (skill_id == SHC_CROSS_SLASH) return Job_Tier::Fourth; // Meister else if (skill_id >= MT_AXE_STOMP && skill_id <= MT_SUMMON_ABR_INFINITY) return Job_Tier::Fourth; else if (skill_id >= MT_SPARK_BLASTER && skill_id <= MT_MIGHTY_SMASH) return Job_Tier::Fourth; else if (skill_id >= MT_RUSH_STRIKE && skill_id <= MT_ENERGY_CANNONADE) return Job_Tier::Fourth; // Biolo else if (skill_id >= BO_ACIDIFIED_ZONE_WATER_ATK && skill_id <= BO_ACIDIFIED_ZONE_FIRE_ATK) return Job_Tier::Fourth; else if (skill_id >= BO_BIONIC_PHARMACY && skill_id <= BO_HELLTREE) return Job_Tier::Fourth; else if (skill_id >= BO_EXPLOSIVE_POWDER && skill_id <= BO_MAYHEMIC_THORNS) return Job_Tier::Fourth; else if (skill_id >= BO_MYSTERY_POWDER && skill_id <= BO_DUST_EXPLOSION) return Job_Tier::Fourth; // Abyss Chaser else if (skill_id >= ABC_DAGGER_AND_BOW_M && skill_id <= ABC_FRENZY_SHOT) return Job_Tier::Fourth; else if (skill_id >= ABC_HIT_AND_SLIDING && skill_id <= ABC_ABYSS_FLAME) return Job_Tier::Fourth; // Wind Hawk else if (skill_id >= WH_ADVANCED_TRAP && skill_id <= WH_FLAMETRAP) return Job_Tier::Fourth; else if (skill_id == WH_WILD_WALK) return Job_Tier::Fourth; // Troubadour && Trouvere else if (skill_id >= TR_STAGE_MANNER && skill_id <= TR_PRON_MARCH) return Job_Tier::Fourth; else if (skill_id == TR_RHYTHMICAL_WAVE) return Job_Tier::Fourth; // Elemental Master else if (skill_id >= EM_MAGIC_BOOK_M && skill_id <= EM_ELEMENTAL_VEIL) return Job_Tier::Fourth; else if (skill_id == EM_PSYCHIC_STREAM) return Job_Tier::Fourth; // Night Watch else if (skill_id >= NW_P_F_I && skill_id <= NW_MISSION_BOMBARD) return Job_Tier::Fourth; else if (skill_id >= NW_WILD_SHOT && skill_id <= NW_MIDNIGHT_FALLEN) return Job_Tier::Fourth; // Soul Ascetic else if (skill_id >= SOA_TALISMAN_MASTERY && skill_id <= SOA_SOUL_OF_HEAVEN_AND_EARTH) return Job_Tier::Fourth; // Spirit Handler else if (skill_id >= SH_MYSTICAL_CREATURE_MASTERY && skill_id <= SH_BLESSING_OF_MYSTICAL_CREATURES) return Job_Tier::Fourth; else if (skill_id >= SH_CHUL_HO_BATTERING && skill_id <= SH_HYUN_ROK_SPIRIT_POWER) return Job_Tier::Fourth; // Hyper Novice else if (skill_id >= HN_SELFSTUDY_TATICS && skill_id <= HN_RULEBREAK) return Job_Tier::Fourth; else if (skill_id == HN_OVERCOMING_CRISIS) return Job_Tier::Fourth; // Sky Emperor else if (skill_id >= SKE_SKY_MASTERY && skill_id <= SKE_ENCHANTING_SKY) return Job_Tier::Fourth; else if (skill_id >= SKE_SKY_SUN && skill_id <= SKE_STAR_LIGHT_KICK) return Job_Tier::Fourth; // Shinkiro && Shiranui else if (skill_id >= SS_TOKEDASU && skill_id <= SS_ANKOKURYUUAKUMU) return Job_Tier::Fourth; else if (skill_id == SS_FOUR_CHARM) return Job_Tier::Fourth; // Sky Emperor else if (skill_id >= SKE_SKY_MASTERY && skill_id <= SKE_ENCHANTING_SKY) return Job_Tier::Fourth; return Job_Tier::Basic; // Default to Novice if unknown } /*========================================== * Update skill_lv for player sd * Skill point allocation *------------------------------------------*/ void pc_skillup(map_session_data *sd,uint16 skill_id) { uint16 idx = skill_get_index(skill_id); nullpo_retv(sd); if (!idx) { if (skill_id) ShowError("pc_skillup: Player attempts to level up invalid skill '%d'\n", skill_id); return; } int32 skill_point = pc_calc_skillpoint( sd ); int32 novice_max_skillpoint = job_db.find( JOB_NOVICE )->max_job_level - 1; int32 summoner_max_skillpoint = job_db.find( JOB_SUMMONER )->max_job_level - 1; int32 max_skillpoint_1st = job_db.find( JOB_SWORDMAN )->max_job_level - 1; int32 max_skillpoint_2nd = job_db.find( JOB_KNIGHT )->max_job_level - 1; int32 max_skillpoint_2nd_high = job_db.find( JOB_LORD_KNIGHT )->max_job_level - 1; int32 max_skillpoint_3rd = job_db.find( JOB_RUNE_KNIGHT )->max_job_level - 1; int32 max_skillpoint_sn = job_db.find( JOB_SUPER_NOVICE )->max_job_level - 1; int32 max_skillpoint_sn_e = job_db.find( JOB_SUPER_NOVICE_E )->max_job_level - 1; int32 max_skillpoint_summ = job_db.find( JOB_SUMMONER )->max_job_level - 1; int32 skillpoint_1st = sd->change_level_2nd - 1; int32 skillpoint_2nd = sd->change_level_3rd - 1; int32 must_spend_novice = novice_max_skillpoint - skill_point; int32 must_spend_1st = min(max_skillpoint_1st, novice_max_skillpoint + skillpoint_1st - skill_point); int32 must_spend_2nd = min(max_skillpoint_2nd, novice_max_skillpoint + skillpoint_1st + skillpoint_2nd - skill_point); int32 must_spend_2nd_high = min(max_skillpoint_2nd_high, novice_max_skillpoint + skillpoint_1st + skillpoint_2nd - skill_point); int32 must_spend_3rd = min(max_skillpoint_3rd, novice_max_skillpoint + skillpoint_1st + skillpoint_2nd + max_skillpoint_3rd - skill_point); int32 must_spend_sn = min(max_skillpoint_sn, novice_max_skillpoint + max_skillpoint_sn - skill_point); int32 must_spend_sn_e = min(max_skillpoint_sn_e, novice_max_skillpoint + max_skillpoint_sn + max_skillpoint_sn_e - skill_point); int32 must_spend_summ = max_skillpoint_summ - skill_point; StringBuf *helper_msg_novice = StringBuf_Malloc(); StringBuf *helper_msg_novice_high = StringBuf_Malloc(); StringBuf *helper_msg_1st = StringBuf_Malloc(); StringBuf *helper_msg_1st_high = StringBuf_Malloc(); StringBuf *helper_msg_2nd = StringBuf_Malloc(); StringBuf *helper_msg_2nd_high = StringBuf_Malloc(); StringBuf *helper_msg_3rd = StringBuf_Malloc(); StringBuf *helper_msg_sn = StringBuf_Malloc(); StringBuf *helper_msg_sn_e = StringBuf_Malloc(); StringBuf *helper_msg_hn = StringBuf_Malloc(); StringBuf *helper_msg_summoner = StringBuf_Malloc(); StringBuf_Printf(helper_msg_novice, "%d %s", must_spend_novice, "more skillpoints are required in Basic Skill\n"); StringBuf_Printf(helper_msg_novice_high, "%d %s", must_spend_novice, "more skillpoints are required in Basic Skill\n"); StringBuf_Printf(helper_msg_1st, "%d %s", must_spend_1st, "more skillpoints are required in 1st Job Skill Tree\n"); StringBuf_Printf(helper_msg_1st_high, "%d %s", must_spend_1st, "more skillpoints are required in 1st High Job Skill Tree\n"); StringBuf_Printf(helper_msg_2nd, "%d %s", must_spend_2nd, "more skillpoints are required in 2nd Job Skill Tree\n"); StringBuf_Printf(helper_msg_2nd_high, "%d %s", must_spend_2nd_high, "more skillpoints are required in 2nd High Job Skill Tree\n"); StringBuf_Printf(helper_msg_3rd, "%d %s", must_spend_3rd, "more skillpoints are required in 3rd Job Skill Tree\n"); StringBuf_Printf(helper_msg_sn, "%d %s", must_spend_sn, "more skillpoints are required in Super Novice (considered Novice Job) Skill Tree\n"); StringBuf_Printf(helper_msg_sn_e, "%d %s", must_spend_sn_e, "more skillpoints are required in Expanded Super Novice (considered 2nd Job) Skill Tree\n"); StringBuf_Printf(helper_msg_summoner, "%d %s", must_spend_summ, "more skillpoints are required in Summoner Skill Tree\n"); // Special Case for Super Novice if (pc_get_job_tier(sd->class_) == Job_Tier::Super_Novice) { if (skill_get_job_tier(skill_id) == Job_Tier::First && (skill_point < novice_max_skillpoint)) { // ShowError(helper_msg_novice, must_spend_novice); clif_displaymessage(sd->fd, StringBuf_Value(helper_msg_novice)); } } // Special Case for Expanded Super Novice else if (pc_get_job_tier(sd->class_) == Job_Tier::Super_Novice_E) { if (skill_get_job_tier(skill_id) == Job_Tier::First && (skill_point < novice_max_skillpoint)) { if (skill_point < novice_max_skillpoint) { // ShowError(helper_msg_novice, must_spend_novice); clif_displaymessage(sd->fd, StringBuf_Value(helper_msg_novice)); } } if (skill_get_job_tier(skill_id) == Job_Tier::Second || skill_get_job_tier(skill_id) == Job_Tier::Third && (skill_point < novice_max_skillpoint + max_skillpoint_sn)) { if (skill_point < novice_max_skillpoint) { // ShowError(helper_msg_novice, must_spend_novice); clif_displaymessage(sd->fd, StringBuf_Value(helper_msg_novice)); } if (skill_point < novice_max_skillpoint + skillpoint_1st) { // ShowError(helper_msg_sn, must_spend_sn); clif_displaymessage(sd->fd, StringBuf_Value(helper_msg_sn)); } } } // Special Case for Hyper Novice else if (pc_get_job_tier(sd->class_) == Job_Tier::Hyper_Novice) { if (skill_get_job_tier(skill_id) == Job_Tier::First && (skill_point < novice_max_skillpoint)) { if (skill_point < novice_max_skillpoint) { // ShowError(helper_msg_novice, must_spend_novice); clif_displaymessage(sd->fd, StringBuf_Value(helper_msg_novice)); } } if (skill_get_job_tier(skill_id) == Job_Tier::Second || skill_get_job_tier(skill_id) == Job_Tier::Third && (skill_point < novice_max_skillpoint + max_skillpoint_sn)) { if (skill_point < novice_max_skillpoint) { // ShowError(helper_msg_novice, must_spend_novice); clif_displaymessage(sd->fd, StringBuf_Value(helper_msg_novice)); } if (skill_point < novice_max_skillpoint + max_skillpoint_sn) { // ShowError(helper_msg_sn, must_spend_sn); clif_displaymessage(sd->fd, StringBuf_Value(helper_msg_sn)); } } if (skill_get_job_tier(skill_id) == Job_Tier::Fourth && (skill_point < novice_max_skillpoint + max_skillpoint_sn + max_skillpoint_sn_e)) { if (skill_point < novice_max_skillpoint) { // ShowError(helper_msg_novice, must_spend_novice); clif_displaymessage(sd->fd, StringBuf_Value(helper_msg_novice)); } if (skill_point < novice_max_skillpoint + max_skillpoint_sn) { // ShowError(helper_msg_sn, must_spend_sn); clif_displaymessage(sd->fd, StringBuf_Value(helper_msg_sn)); } if (skill_point < novice_max_skillpoint + max_skillpoint_sn + max_skillpoint_sn_e) { // ShowError(helper_msg_sn_e, must_spend_sn_e); clif_displaymessage(sd->fd, StringBuf_Value(helper_msg_sn_e)); } } } // Special Case for Spirit Handler else if (pc_get_job_tier(sd->class_) == Job_Tier::Spirit_Handler) { if (skill_get_job_tier(skill_id) == Job_Tier::Fourth && (skill_point < max_skillpoint_summ)) { // ShowError(helper_msg_summoner, must_spend_summ); clif_displaymessage(sd->fd, StringBuf_Value(helper_msg_summoner)); } } else if (pc_get_job_tier(sd->class_) == Job_Tier::First) { if (skill_get_job_tier(skill_id) == Job_Tier::First && (skill_point < novice_max_skillpoint)) { // ShowError(helper_msg_novice, must_spend_novice); clif_displaymessage(sd->fd, StringBuf_Value(helper_msg_novice)); } } else if (pc_get_job_tier(sd->class_) == Job_Tier::First_High) { if (skill_get_job_tier(skill_id) == Job_Tier::First && (skill_point < novice_max_skillpoint)) { if (skill_point < novice_max_skillpoint) { // ShowError(helper_msg_novice, must_spend_novice); clif_displaymessage(sd->fd, StringBuf_Value(helper_msg_novice)); } } } else if (pc_get_job_tier(sd->class_) == Job_Tier::Second) { if (skill_get_job_tier(skill_id) == Job_Tier::First && (skill_point < novice_max_skillpoint)) { if (skill_point < novice_max_skillpoint) { // ShowError(helper_msg_novice, must_spend_novice); clif_displaymessage(sd->fd, StringBuf_Value(helper_msg_novice)); } } if (skill_get_job_tier(skill_id) == Job_Tier::Second && (skill_point < novice_max_skillpoint + skillpoint_1st)) { if (skill_point < novice_max_skillpoint) { // ShowError(helper_msg_novice, must_spend_novice); clif_displaymessage(sd->fd, StringBuf_Value(helper_msg_novice)); } if (skill_point < novice_max_skillpoint + skillpoint_1st) { // ShowError(helper_msg_1st, must_spend_1st); clif_displaymessage(sd->fd, StringBuf_Value(helper_msg_1st)); } } } else if (pc_get_job_tier(sd->class_) == Job_Tier::Second_High) { if (skill_get_job_tier(skill_id) == Job_Tier::First && (skill_point < novice_max_skillpoint)) { if (skill_point < novice_max_skillpoint) { // ShowError(helper_msg_novice_high, must_spend_novice); clif_displaymessage(sd->fd, StringBuf_Value(helper_msg_novice_high)); } } if (skill_get_job_tier(skill_id) == Job_Tier::Second && (skill_point < novice_max_skillpoint + skillpoint_1st)) { if (skill_point < novice_max_skillpoint) { // ShowError(helper_msg_novice_high, must_spend_novice); clif_displaymessage(sd->fd, StringBuf_Value(helper_msg_novice_high)); } if (skill_point < novice_max_skillpoint + skillpoint_1st) { // ShowError(helper_msg_1st_high, must_spend_1st); clif_displaymessage(sd->fd, StringBuf_Value(helper_msg_1st_high)); } } } else if (pc_get_job_tier(sd->class_) == Job_Tier::Third) { if (skill_get_job_tier(skill_id) == Job_Tier::First && (skill_point < novice_max_skillpoint)) { if (skill_point < novice_max_skillpoint) { // ShowError(helper_msg_novice, must_spend_novice); clif_displaymessage(sd->fd, StringBuf_Value(helper_msg_novice)); } } if (skill_get_job_tier(skill_id) == Job_Tier::Second && (skill_point < novice_max_skillpoint + skillpoint_1st)) { if (skill_point < novice_max_skillpoint) { // ShowError(helper_msg_novice, must_spend_novice); clif_displaymessage(sd->fd, StringBuf_Value(helper_msg_novice)); } if (skill_point < novice_max_skillpoint + skillpoint_1st) { // ShowError(helper_msg_1st, must_spend_1st); clif_displaymessage(sd->fd, StringBuf_Value(helper_msg_1st)); } } if (skill_get_job_tier(skill_id) == Job_Tier::Third && (skill_point < novice_max_skillpoint + skillpoint_1st + max_skillpoint_2nd)) { if (skill_point < novice_max_skillpoint) { // ShowError(helper_msg_novice, must_spend_novice); clif_displaymessage(sd->fd, StringBuf_Value(helper_msg_novice)); } if (skill_point < novice_max_skillpoint + skillpoint_1st) { // ShowError(helper_msg_1st, must_spend_1st); clif_displaymessage(sd->fd, StringBuf_Value(helper_msg_1st)); } if (skill_point < novice_max_skillpoint + skillpoint_1st + skillpoint_2nd) { // ShowError(helper_msg_2nd, must_spend_2nd); clif_displaymessage(sd->fd, StringBuf_Value(helper_msg_2nd)); } } } else if (pc_get_job_tier(sd->class_) == Job_Tier::Third_High) { if (skill_get_job_tier(skill_id) == Job_Tier::First && (skill_point < novice_max_skillpoint)) { if (skill_point < novice_max_skillpoint) { // ShowError(helper_msg_novice_high, must_spend_novice); clif_displaymessage(sd->fd, StringBuf_Value(helper_msg_novice_high)); } } if (skill_get_job_tier(skill_id) == Job_Tier::Second && (skill_point < novice_max_skillpoint + skillpoint_1st)) { if (skill_point < novice_max_skillpoint) { // ShowError(helper_msg_novice_high, must_spend_novice); clif_displaymessage(sd->fd, StringBuf_Value(helper_msg_novice_high)); } if (skill_point < novice_max_skillpoint + skillpoint_1st) { // ShowError(helper_msg_1st_high, must_spend_1st); clif_displaymessage(sd->fd, StringBuf_Value(helper_msg_1st_high)); } } if ((skill_get_job_tier(skill_id) == Job_Tier::Third || Job_Tier::Third_High) && (skill_point < novice_max_skillpoint + skillpoint_1st + max_skillpoint_2nd)) { if (skill_point < novice_max_skillpoint) { // ShowError(helper_msg_novice_high, must_spend_novice); clif_displaymessage(sd->fd, StringBuf_Value(helper_msg_novice_high)); } if (skill_point < novice_max_skillpoint + skillpoint_1st) { // ShowError(helper_msg_1st_high, must_spend_1st); clif_displaymessage(sd->fd, StringBuf_Value(helper_msg_1st_high)); } if (skill_point < novice_max_skillpoint + skillpoint_1st + skillpoint_2nd) { // ShowError(helper_msg_2nd_high, must_spend_2nd_high); clif_displaymessage(sd->fd, StringBuf_Value(helper_msg_2nd_high)); } } } else if (pc_get_job_tier(sd->class_) == Job_Tier::Fourth) { if (skill_get_job_tier(skill_id) == Job_Tier::First && (skill_point < novice_max_skillpoint)) { if (skill_point < novice_max_skillpoint) { // ShowError(helper_msg_novice, must_spend_novice); clif_displaymessage(sd->fd, StringBuf_Value(helper_msg_novice)); } } if (skill_get_job_tier(skill_id) == Job_Tier::Second && (skill_point < novice_max_skillpoint + skillpoint_1st)) { if (skill_point < novice_max_skillpoint) { // ShowError(helper_msg_novice, must_spend_novice); clif_displaymessage(sd->fd, StringBuf_Value(helper_msg_novice)); } if (skill_point < novice_max_skillpoint + skillpoint_1st) { // ShowError(helper_msg_1st, must_spend_1st); clif_displaymessage(sd->fd, StringBuf_Value(helper_msg_1st)); } } if (skill_get_job_tier(skill_id) == Job_Tier::Third && (skill_point < novice_max_skillpoint + skillpoint_1st + max_skillpoint_2nd)) { if (skill_point < novice_max_skillpoint) { // ShowError(helper_msg_novice, must_spend_novice); clif_displaymessage(sd->fd, StringBuf_Value(helper_msg_novice)); } if (skill_point < novice_max_skillpoint + skillpoint_1st) { // ShowError(helper_msg_1st, must_spend_1st); clif_displaymessage(sd->fd, StringBuf_Value(helper_msg_1st)); } // If character went rebirth 2nd and 3rd if ((skill_point < novice_max_skillpoint + skillpoint_1st + skillpoint_2nd) && (skillpoint_2nd == max_skillpoint_2nd_high)) { // ShowError(helper_msg_2nd_high, must_spend_2nd_high); clif_displaymessage(sd->fd, StringBuf_Value(helper_msg_2nd_high)); } // If character went non-rebirth 2nd and 3rd else if ((skill_point < novice_max_skillpoint + skillpoint_1st + skillpoint_2nd) && (skillpoint_2nd == max_skillpoint_2nd)) { // ShowError(helper_msg_2nd, must_spend_2nd); clif_displaymessage(sd->fd, StringBuf_Value(helper_msg_2nd)); } } if (skill_get_job_tier(skill_id) == Job_Tier::Fourth && (skill_point < novice_max_skillpoint + skillpoint_1st + max_skillpoint_2nd + max_skillpoint_3rd)) { if (skill_point < novice_max_skillpoint) { // ShowError(helper_msg_novice, must_spend_novice); clif_displaymessage(sd->fd, StringBuf_Value(helper_msg_novice)); } if (skill_point < novice_max_skillpoint + skillpoint_1st) { // ShowError(helper_msg_1st, must_spend_1st); clif_displaymessage(sd->fd, StringBuf_Value(helper_msg_1st)); } // if (skill_point < novice_max_skillpoint + skillpoint_1st + skillpoint_2nd) { // // ShowError(helper_msg_2nd, must_spend_2nd); // clif_displaymessage(sd->fd, StringBuf_Value(helper_msg_2nd)); // } // If character went rebirth 2nd and 3rd then 4th if ((skill_point < novice_max_skillpoint + skillpoint_1st + skillpoint_2nd) && (skillpoint_2nd == max_skillpoint_2nd_high)) { // ShowError(helper_msg_2nd_high, must_spend_2nd_high); clif_displaymessage(sd->fd, StringBuf_Value(helper_msg_2nd_high)); } // If character went non-rebirth 2nd and 3rd then 4th else if ((skill_point < novice_max_skillpoint + skillpoint_1st + skillpoint_2nd) && (skillpoint_2nd == max_skillpoint_2nd)) { // ShowError(helper_msg_2nd, must_spend_2nd); clif_displaymessage(sd->fd, StringBuf_Value(helper_msg_2nd)); } if (skill_point < novice_max_skillpoint + skillpoint_1st + skillpoint_2nd + max_skillpoint_3rd) { // ShowError(helper_msg_3rd, must_spend_3rd); clif_displaymessage(sd->fd, StringBuf_Value(helper_msg_3rd)); } } } StringBuf_Free(helper_msg_novice); StringBuf_Free(helper_msg_novice_high); StringBuf_Free(helper_msg_1st); StringBuf_Free(helper_msg_1st_high); StringBuf_Free(helper_msg_2nd); StringBuf_Free(helper_msg_2nd_high); StringBuf_Free(helper_msg_3rd); StringBuf_Free(helper_msg_sn); StringBuf_Free(helper_msg_sn_e); StringBuf_Free(helper_msg_hn); StringBuf_Free(helper_msg_summoner); ... Rest of the function code ... }
  23. Modified to use for latest rA git keitenai_SpeedHack_Protection_V5.diff tested got no errors in console
  24. I modified this src to the latest rathena git singe_soul_link_mod_v1-1.patch i've tried it and no errors occurred
  25. That script is old so if you use newest git of rathena you need to add it manually and ofcourse there are more changes needed.
  26. Oh my God, thank you very much for going to such length. Unfortunately, I cannot contribute as much as you do as I am a newbie in the coding department. That is why I'm posting it in a source request sub-forum... I did some digging though. I think we should be able to make use of something like this? std::shared_ptr<s_job_info> job = job_db.find(sd->status.class_); std::shared_ptr<s_skill_tree> tree = skill_tree_db.find(job_class); If we make the code find the class and find the skill instead using that, it should make the code smaller no? The only problem is, I don't know how to use it.
  27. Last week
  28. I tried this already, but it didn’t work. Any other way I could try?
  1. Load more activity
×
×
  • Create New...