Explorar o código

Implemented 'NeedLevel' for Homunculus skill tree
* Changed 'JobLevel' to 'NeedLevel' and don't make it as optional.
* Make sure homun_skill_tree.txt column number is 15!

Signed-off-by: Cydh Ramdh <house.bad@gmail.com>

Cydh Ramdh %!s(int64=10) %!d(string=hai) anos
pai
achega
2ae4bcb694
Modificáronse 5 ficheiros con 155 adicións e 130 borrados
  1. 84 84
      db/homun_skill_tree.txt
  2. 2 2
      db/import-tmpl/homun_skill_tree.txt
  3. 2 2
      src/map/clif.c
  4. 56 33
      src/map/homunculus.c
  5. 11 9
      src/map/homunculus.h

+ 84 - 84
db/homun_skill_tree.txt

@@ -1,12 +1,12 @@
 // Homunculus Skill Tree Database
 //
 // Structure of Database:
-// Class,SkillID,MaxLv[,JobLevel],Prerequisite SkillID1,Prerequisite SkillLv1,PrereqSkillID2,PrereqSkillLv2,PrereqSkillID3,PrereqSkillLv3,PrereqSkillID4,PrereqSkillLv4,PrereqSkillID5,PrereqSkillLv5,IntimacyLvReq //SKILLNAME#Skill Name#
+// Class,SkillID,MaxLv,NeedLevel,Prerequisite SkillID1,Prerequisite SkillLv1,PrereqSkillID2,PrereqSkillLv2,PrereqSkillID3,PrereqSkillLv3,PrereqSkillID4,PrereqSkillLv4,PrereqSkillID5,PrereqSkillLv5,IntimacyLvReq //SKILLNAME#Skill Name#
 //
 // 01. Class                    Homunculus ID.
 // 02. SkillID                  Skill ID of the homunuculus skill.
 // 03. MaxLv                    Maximum level of the homunuculus skill.
-// 04. JobLevel                 Job level required for the skill to become available (optional, reserved, not used by server).
+// 04. NeedLevel                Homunculus level required for the skill to become available
 // 05. Prerequisite SkillID     Homunculus skill required for the skill to become available.
 // 06. Prerequisite SkillLv     Level of the required homunculus skill.
 // ...
@@ -15,105 +15,105 @@
 // NOTE: MAX_PC_SKILL_REQUIRE (typically 5) ID/Lv pairs must be specified.
 
 //Lif
-6001,8001,5,0,0,0,0,0,0,0,0,0,0,0 //HLIF_HEAL
-6001,8002,5,8001,3,0,0,0,0,0,0,0,0,0 //HLIF_AVOID
-6001,8003,5,8001,5,0,0,0,0,0,0,0,0,0 //HLIF_BRAIN
+6001,8001,5,0,0,0,0,0,0,0,0,0,0,0,0 //HLIF_HEAL
+6001,8002,5,0,8001,3,0,0,0,0,0,0,0,0,0 //HLIF_AVOID
+6001,8003,5,0,8001,5,0,0,0,0,0,0,0,0,0 //HLIF_BRAIN
 //Amistr
-6002,8005,5,0,0,0,0,0,0,0,0,0,0,0 //HAMI_CASTLE
-6002,8006,5,8005,5,0,0,0,0,0,0,0,0,0 //HAMI_DEFENCE
-6002,8007,5,8006,3,0,0,0,0,0,0,0,0,0 //HAMI_SKIN
+6002,8005,5,0,0,0,0,0,0,0,0,0,0,0,0 //HAMI_CASTLE
+6002,8006,5,0,8005,5,0,0,0,0,0,0,0,0,0 //HAMI_DEFENCE
+6002,8007,5,0,8006,3,0,0,0,0,0,0,0,0,0 //HAMI_SKIN
 //Filir
-6003,8009,5,0,0,0,0,0,0,0,0,0,0,0 //HFLI_MOON
-6003,8010,5,8009,3,0,0,0,0,0,0,0,0,0 //HFLI_FLEET
-6003,8011,5,8010,3,0,0,0,0,0,0,0,0,0 //HFLI_SPEED
+6003,8009,5,0,0,0,0,0,0,0,0,0,0,0,0 //HFLI_MOON
+6003,8010,5,0,8009,3,0,0,0,0,0,0,0,0,0 //HFLI_FLEET
+6003,8011,5,0,8010,3,0,0,0,0,0,0,0,0,0 //HFLI_SPEED
 //Vanilmirth
-6004,8013,5,0,0,0,0,0,0,0,0,0,0,0 //HVAN_CAPRICE
-6004,8014,5,8013,3,0,0,0,0,0,0,0,0,0 //HVAN_CHAOTIC
-6004,8015,5,8013,5,0,0,0,0,0,0,0,0,0 //HVAN_INSTRUCT
+6004,8013,5,0,0,0,0,0,0,0,0,0,0,0,0 //HVAN_CAPRICE
+6004,8014,5,0,8013,3,0,0,0,0,0,0,0,0,0 //HVAN_CHAOTIC
+6004,8015,5,0,8013,5,0,0,0,0,0,0,0,0,0 //HVAN_INSTRUCT
 //Lif2
-6005,8001,5,0,0,0,0,0,0,0,0,0,0,0 //HLIF_HEAL
-6005,8002,5,8001,3,0,0,0,0,0,0,0,0,0 //HLIF_AVOID
-6005,8003,5,8001,5,0,0,0,0,0,0,0,0,0 //HLIF_BRAIN
+6005,8001,5,0,0,0,0,0,0,0,0,0,0,0,0 //HLIF_HEAL
+6005,8002,5,0,8001,3,0,0,0,0,0,0,0,0,0 //HLIF_AVOID
+6005,8003,5,0,8001,5,0,0,0,0,0,0,0,0,0 //HLIF_BRAIN
 //Amistr2
-6006,8005,5,0,0,0,0,0,0,0,0,0,0,0 //HAMI_CASTLE
-6006,8006,5,8005,5,0,0,0,0,0,0,0,0,0 //HAMI_DEFENCE
-6006,8007,5,8006,3,0,0,0,0,0,0,0,0,0 //HAMI_SKIN
+6006,8005,5,0,0,0,0,0,0,0,0,0,0,0,0 //HAMI_CASTLE
+6006,8006,5,0,8005,5,0,0,0,0,0,0,0,0,0 //HAMI_DEFENCE
+6006,8007,5,0,8006,3,0,0,0,0,0,0,0,0,0 //HAMI_SKIN
 //Filir2
-6007,8009,5,0,0,0,0,0,0,0,0,0,0,0 //HFLI_MOON
-6007,8010,5,8009,3,0,0,0,0,0,0,0,0,0 //HFLI_FLEET
-6007,8011,5,8010,3,0,0,0,0,0,0,0,0,0 //HFLI_SPEED
+6007,8009,5,0,0,0,0,0,0,0,0,0,0,0,0 //HFLI_MOON
+6007,8010,5,0,8009,3,0,0,0,0,0,0,0,0,0 //HFLI_FLEET
+6007,8011,5,0,8010,3,0,0,0,0,0,0,0,0,0 //HFLI_SPEED
 //Vanilmirth2
-6008,8013,5,0,0,0,0,0,0,0,0,0,0,0 //HVAN_CAPRICE
-6008,8014,5,8013,3,0,0,0,0,0,0,0,0,0 //HVAN_CHAOTIC
-6008,8015,5,8013,5,0,0,0,0,0,0,0,0,0 //HVAN_INSTRUCT
+6008,8013,5,0,0,0,0,0,0,0,0,0,0,0,0 //HVAN_CAPRICE
+6008,8014,5,0,8013,3,0,0,0,0,0,0,0,0,0 //HVAN_CHAOTIC
+6008,8015,5,0,8013,5,0,0,0,0,0,0,0,0,0 //HVAN_INSTRUCT
 //Lif_H
-6009,8001,5,0,0,0,0,0,0,0,0,0,0,0 //HLIF_HEAL
-6009,8002,5,8001,3,0,0,0,0,0,0,0,0,0 //HLIF_AVOID
-6009,8003,5,8001,5,0,0,0,0,0,0,0,0,0 //HLIF_BRAIN
-6009,8004,3,0,0,0,0,0,0,0,0,0,0,910 //HLIF_CHANGE
+6009,8001,5,0,0,0,0,0,0,0,0,0,0,0,0 //HLIF_HEAL
+6009,8002,5,0,8001,3,0,0,0,0,0,0,0,0,0 //HLIF_AVOID
+6009,8003,5,0,8001,5,0,0,0,0,0,0,0,0,0 //HLIF_BRAIN
+6009,8004,3,0,0,0,0,0,0,0,0,0,0,0,910 //HLIF_CHANGE
 //Amistr_H
-6010,8005,5,0,0,0,0,0,0,0,0,0,0,0 //HAMI_CASTLE
-6010,8006,5,8005,5,0,0,0,0,0,0,0,0,0 //HAMI_DEFENCE
-6010,8007,5,8006,3,0,0,0,0,0,0,0,0,0 //HAMI_SKIN
-6010,8008,3,0,0,0,0,0,0,0,0,0,0,910 //HAMI_BLOODLUST
+6010,8005,5,0,0,0,0,0,0,0,0,0,0,0,0 //HAMI_CASTLE
+6010,8006,5,0,8005,5,0,0,0,0,0,0,0,0,0 //HAMI_DEFENCE
+6010,8007,5,0,8006,3,0,0,0,0,0,0,0,0,0 //HAMI_SKIN
+6010,8008,3,0,0,0,0,0,0,0,0,0,0,0,910 //HAMI_BLOODLUST
 //Filir_H
-6011,8009,5,0,0,0,0,0,0,0,0,0,0,0 //HFLI_MOON
-6011,8010,5,8009,3,0,0,0,0,0,0,0,0,0 //HFLI_FLEET
-6011,8011,5,8010,3,0,0,0,0,0,0,0,0,0 //HFLI_SPEED
-6011,8012,3,0,0,0,0,0,0,0,0,0,0,910 //HFLI_SBR44
+6011,8009,5,0,0,0,0,0,0,0,0,0,0,0,0 //HFLI_MOON
+6011,8010,5,0,8009,3,0,0,0,0,0,0,0,0,0 //HFLI_FLEET
+6011,8011,5,0,8010,3,0,0,0,0,0,0,0,0,0 //HFLI_SPEED
+6011,8012,3,0,0,0,0,0,0,0,0,0,0,0,910 //HFLI_SBR44
 //Vanilmirth_H
-6012,8013,5,0,0,0,0,0,0,0,0,0,0,0 //HVAN_CAPRICE
-6012,8014,5,8013,3,0,0,0,0,0,0,0,0,0 //HVAN_CHAOTIC
-6012,8015,5,8013,5,0,0,0,0,0,0,0,0,0 //HVAN_INSTRUCT
-6012,8016,3,0,0,0,0,0,0,0,0,0,0,910 //HVAN_EXPLOSION
+6012,8013,5,0,0,0,0,0,0,0,0,0,0,0,0 //HVAN_CAPRICE
+6012,8014,5,0,8013,3,0,0,0,0,0,0,0,0,0 //HVAN_CHAOTIC
+6012,8015,5,0,8013,5,0,0,0,0,0,0,0,0,0 //HVAN_INSTRUCT
+6012,8016,3,0,0,0,0,0,0,0,0,0,0,0,910 //HVAN_EXPLOSION
 //Lif2_H
-6013,8001,5,0,0,0,0,0,0,0,0,0,0,0 //HLIF_HEAL
-6013,8002,5,8001,3,0,0,0,0,0,0,0,0,0 //HLIF_AVOID
-6013,8003,5,8001,5,0,0,0,0,0,0,0,0,0 //HLIF_BRAIN
-6013,8004,3,0,0,0,0,0,0,0,0,0,0,910 //HLIF_CHANGE
+6013,8001,5,0,0,0,0,0,0,0,0,0,0,0,0 //HLIF_HEAL
+6013,8002,5,0,8001,3,0,0,0,0,0,0,0,0,0 //HLIF_AVOID
+6013,8003,5,0,8001,5,0,0,0,0,0,0,0,0,0 //HLIF_BRAIN
+6013,8004,3,0,0,0,0,0,0,0,0,0,0,0,910 //HLIF_CHANGE
 //Amistr2_H
-6014,8005,5,0,0,0,0,0,0,0,0,0,0,0 //HAMI_CASTLE
-6014,8006,5,8005,5,0,0,0,0,0,0,0,0,0 //HAMI_DEFENCE
-6014,8007,5,8006,3,0,0,0,0,0,0,0,0,0 //HAMI_SKIN
-6014,8008,3,0,0,0,0,0,0,0,0,0,0,910 //HAMI_BLOODLUST
+6014,8005,5,0,0,0,0,0,0,0,0,0,0,0,0 //HAMI_CASTLE
+6014,8006,5,0,8005,5,0,0,0,0,0,0,0,0,0 //HAMI_DEFENCE
+6014,8007,5,0,8006,3,0,0,0,0,0,0,0,0,0 //HAMI_SKIN
+6014,8008,3,0,0,0,0,0,0,0,0,0,0,0,910 //HAMI_BLOODLUST
 //Filir2_H
-6015,8009,5,0,0,0,0,0,0,0,0,0,0,0 //HFLI_MOON
-6015,8010,5,8009,3,0,0,0,0,0,0,0,0,0 //HFLI_FLEET
-6015,8011,5,8010,3,0,0,0,0,0,0,0,0,0 //HFLI_SPEED
-6015,8012,3,0,0,0,0,0,0,0,0,0,0,910 //HFLI_SBR44
+6015,8009,5,0,0,0,0,0,0,0,0,0,0,0,0 //HFLI_MOON
+6015,8010,5,0,8009,3,0,0,0,0,0,0,0,0,0 //HFLI_FLEET
+6015,8011,5,0,8010,3,0,0,0,0,0,0,0,0,0 //HFLI_SPEED
+6015,8012,3,0,0,0,0,0,0,0,0,0,0,0,910 //HFLI_SBR44
 //Vanilmirth2_H
-6016,8013,5,0,0,0,0,0,0,0,0,0,0,0 //HVAN_CAPRICE
-6016,8014,5,8013,3,0,0,0,0,0,0,0,0,0 //HVAN_CHAOTIC
-6016,8015,5,8013,5,0,0,0,0,0,0,0,0,0 //HVAN_INSTRUCT
-6016,8016,3,0,0,0,0,0,0,0,0,0,0,910 //HVAN_EXPLOSION
+6016,8013,5,0,0,0,0,0,0,0,0,0,0,0,0 //HVAN_CAPRICE
+6016,8014,5,0,8013,3,0,0,0,0,0,0,0,0,0 //HVAN_CHAOTIC
+6016,8015,5,0,8013,5,0,0,0,0,0,0,0,0,0 //HVAN_INSTRUCT
+6016,8016,3,0,0,0,0,0,0,0,0,0,0,0,910 //HVAN_EXPLOSION
 //Eira
-6048,8022,5,0,0,0,0,0,0,0,0,0,0,0 	//MH_LIGHT_OF_REGENE
-6048,8023,5,0,0,0,0,0,0,0,0,0,0,0	//MH_OVERED_BOOST
-6048,8024,5,0,0,0,0,0,0,0,0,0,0,0	//MH_ERASER_CUTTER
-6048,8025,5,0,0,0,0,0,0,0,0,0,0,0 	//MH_XENO_SLASHER
-6048,8026,5,0,0,0,0,0,0,0,0,0,0,0 	//MH_SILENT_BREEZE
+6048,8022,5,128,0,0,0,0,0,0,0,0,0,0,0 	//MH_LIGHT_OF_REGENE
+6048,8023,5,114,0,0,0,0,0,0,0,0,0,0,0	//MH_OVERED_BOOST
+6048,8024,5,106,0,0,0,0,0,0,0,0,0,0,0	//MH_ERASER_CUTTER
+6048,8025,5,121,0,0,0,0,0,0,0,0,0,0,0 	//MH_XENO_SLASHER
+6048,8026,5,137,0,0,0,0,0,0,0,0,0,0,0 	//MH_SILENT_BREEZE
 //Bayeri
-6049,8031,5,0,0,0,0,0,0,0,0,0,0,0 	//MH_STAHL_HORN
-6049,8032,5,0,0,0,0,0,0,0,0,0,0,0 	//MH_GOLDENE_FERSE
-6049,8033,5,0,0,0,0,0,0,0,0,0,0,0 	//MH_STEINWAND
-6049,8034,5,0,0,0,0,0,0,0,0,0,0,0	//MH_HEILIGE_STANGE
-6049,8035,5,0,0,0,0,0,0,0,0,0,0,0	//MH_ANGRIFFS_MODUS
+6049,8031,5,105,0,0,0,0,0,0,0,0,0,0,0 	//MH_STAHL_HORN
+6049,8032,5,112,0,0,0,0,0,0,0,0,0,0,0 	//MH_GOLDENE_FERSE
+6049,8033,5,121,0,0,0,0,0,0,0,0,0,0,0 	//MH_STEINWAND
+6049,8034,5,138,0,0,0,0,0,0,0,0,0,0,0	//MH_HEILIGE_STANGE
+6049,8035,5,130,0,0,0,0,0,0,0,0,0,0,0	//MH_ANGRIFFS_MODUS
 //Sera
-6050,8018,5,0,0,0,0,0,0,0,0,0,0,0 	//MH_SUMMON_LEGION
-6050,8019,5,0,0,0,0,0,0,0,0,0,0,0 	//MH_NEEDLE_OF_PARALYZE
-6050,8020,5,0,0,0,0,0,0,0,0,0,0,0 	//MH_POISON_MIST
-6050,8021,5,0,0,0,0,0,0,0,0,0,0,0 	//MH_PAIN_KILLER
+6050,8018,5,132,0,0,0,0,0,0,0,0,0,0,0 	//MH_SUMMON_LEGION
+6050,8019,5,105,0,0,0,0,0,0,0,0,0,0,0 	//MH_NEEDLE_OF_PARALYZE
+6050,8020,5,116,0,0,0,0,0,0,0,0,0,0,0 	//MH_POISON_MIST
+6050,8021,5,123,0,0,0,0,0,0,0,0,0,0,0 	//MH_PAIN_KILLER
 //Dieter
-6051,8039,5,0,0,0,0,0,0,0,0,0,0,0 	//MH_MAGMA_FLOW
-6051,8040,5,0,0,0,0,0,0,0,0,0,0,0 	//MH_GRANITIC_ARMOR
-6051,8041,5,0,0,0,0,0,0,0,0,0,0,0 	//MH_LAVA_SLIDE
-6051,8042,5,0,0,0,0,0,0,0,0,0,0,0 	//MH_PYROCLASTIC
-6051,8043,5,0,0,0,0,0,0,0,0,0,0,0 	//MH_VOLCANIC_ASH
+6051,8039,5,122,0,0,0,0,0,0,0,0,0,0,0 	//MH_MAGMA_FLOW
+6051,8040,5,116,0,0,0,0,0,0,0,0,0,0,0 	//MH_GRANITIC_ARMOR
+6051,8041,5,109,0,0,0,0,0,0,0,0,0,0,0 	//MH_LAVA_SLIDE
+6051,8042,5,131,0,0,0,0,0,0,0,0,0,0,0 	//MH_PYROCLASTIC
+6051,8043,5,102,0,0,0,0,0,0,0,0,0,0,0 	//MH_VOLCANIC_ASH
 //Elanor
-6052,8027,1,0,0,0,0,0,0,0,0,0,0,0 	//MH_STYLE_CHANGE
-6052,8028,5,0,0,0,0,0,0,0,0,0,0,0 	//MH_SONIC_CRAW
-6052,8029,5,0,0,0,0,0,0,0,0,0,0,0 	//MH_SILVERVEIN_RUSH
-6052,8030,5,0,0,0,0,0,0,0,0,0,0,0 	//MH_MIDNIGHT_FRENZY
-6052,8036,5,0,0,0,0,0,0,0,0,0,0,0 	//MH_TINDER_BREAKER
-6052,8037,5,0,0,0,0,0,0,0,0,0,0,0 	//MH_CBC
-6052,8038,5,0,0,0,0,0,0,0,0,0,0,0 	//MH_EQC
+6052,8027,1,100,0,0,0,0,0,0,0,0,0,0,0 	//MH_STYLE_CHANGE
+6052,8028,5,100,0,0,0,0,0,0,0,0,0,0,0 	//MH_SONIC_CRAW
+6052,8029,5,114,0,0,0,0,0,0,0,0,0,0,0 	//MH_SILVERVEIN_RUSH
+6052,8030,5,128,0,0,0,0,0,0,0,0,0,0,0 	//MH_MIDNIGHT_FRENZY
+6052,8036,5,100,0,0,0,0,0,0,0,0,0,0,0 	//MH_TINDER_BREAKER
+6052,8037,5,112,0,0,0,0,0,0,0,0,0,0,0 	//MH_CBC
+6052,8038,5,133,0,0,0,0,0,0,0,0,0,0,0 	//MH_EQC

+ 2 - 2
db/import-tmpl/homun_skill_tree.txt

@@ -1,12 +1,12 @@
 // Homunculus Skill Tree Database
 //
 // Structure of Database:
-// Class,SkillID,MaxLv[,JobLevel],Prerequisite SkillID1,Prerequisite SkillLv1,PrereqSkillID2,PrereqSkillLv2,PrereqSkillID3,PrereqSkillLv3,PrereqSkillID4,PrereqSkillLv4,PrereqSkillID5,PrereqSkillLv5,IntimacyLvReq //SKILLNAME#Skill Name#
+// Class,SkillID,MaxLv,NeedLevel,Prerequisite SkillID1,Prerequisite SkillLv1,PrereqSkillID2,PrereqSkillLv2,PrereqSkillID3,PrereqSkillLv3,PrereqSkillID4,PrereqSkillLv4,PrereqSkillID5,PrereqSkillLv5,IntimacyLvReq //SKILLNAME#Skill Name#
 //
 // 01. Class                    Homunculus ID.
 // 02. SkillID                  Skill ID of the homunuculus skill.
 // 03. MaxLv                    Maximum level of the homunuculus skill.
-// 04. JobLevel                 Job level required for the skill to become available (optional, reserved, not used by server).
+// 04. NeedLevel                Homunculus level required for the skill to become available
 // 05. Prerequisite SkillID     Homunculus skill required for the skill to become available.
 // 06. Prerequisite SkillLv     Level of the required homunculus skill.
 // ...

+ 2 - 2
src/map/clif.c

@@ -1515,7 +1515,7 @@ int clif_homskillinfoblock(struct map_session_data *sd)
 			WFIFOW(fd,len+8) = skill_get_sp(id,hd->homunculus.hskill[j].lv);
 			WFIFOW(fd,len+10)= skill_get_range2(&sd->hd->bl, id,hd->homunculus.hskill[j].lv);
 			safestrncpy((char*)WFIFOP(fd,len+12), skill_get_name(id), NAME_LENGTH);
-			WFIFOB(fd,len+36) = (hd->homunculus.hskill[j].lv < hom_skill_tree_get_max(id, hd->homunculus.class_))?1:0;
+			WFIFOB(fd,len+36) = (hd->homunculus.level < hom_skill_get_min_level(hd->homunculus.class_, id) || hd->homunculus.hskill[j].lv >= hom_skill_tree_get_max(id, hd->homunculus.class_)) ? 0 : 1;
 			len+=37;
 		}
 	}
@@ -1541,7 +1541,7 @@ void clif_homskillup(struct map_session_data *sd, uint16 skill_id)
 	WFIFOW(fd,4) = hd->homunculus.hskill[idx].lv;
 	WFIFOW(fd,6) = skill_get_sp(skill_id,hd->homunculus.hskill[idx].lv);
 	WFIFOW(fd,8) = skill_get_range2(&hd->bl, skill_id,hd->homunculus.hskill[idx].lv);
-	WFIFOB(fd,10) = (hd->homunculus.hskill[idx].lv < skill_get_max(hd->homunculus.hskill[idx].id)) ? 1 : 0;
+	WFIFOB(fd,10) = (hd->homunculus.level < hom_skill_get_min_level(hd->homunculus.class_, skill_id) || hd->homunculus.hskill[idx].lv >= hom_skill_tree_get_max(hd->homunculus.hskill[idx].id, hd->homunculus.class_)) ? 0 : 1;
 	WFIFOSET(fd,packet_len(0x239));
 }
 

+ 56 - 33
src/map/homunculus.c

@@ -273,10 +273,9 @@ int hom_delete(struct homun_data *hd, int emote)
 * @param hd
 * @param flag_envolve
 */
-void hom_calc_skilltree(struct homun_data *hd, int flag_evolve)
-{
-	int i, skill_id = 0;
-	int f = 1;
+void hom_calc_skilltree(struct homun_data *hd, bool flag_evolve) {
+	uint8 i;
+	uint16 skill_id = 0;
 	short c = 0;
 
 	nullpo_retv(hd);
@@ -284,26 +283,28 @@ void hom_calc_skilltree(struct homun_data *hd, int flag_evolve)
 	/* load previous homunculus form skills first. */
 	if (hd->homunculus.prev_class != 0 && (c = hom_class2index(hd->homunculus.prev_class)) >= 0) {
 		for (i = 0; i < MAX_HOM_SKILL_TREE && (skill_id = hskill_tree[c][i].id) > 0; i++) {
-			int idx = hom_skill_get_index(skill_id);
+			bool fail = false;
+			short idx = hom_skill_get_index(skill_id);
 			if (idx < 0)
 				continue;
 			if (hd->homunculus.hskill[idx].id)
 				continue; //Skill already known.
 			if (!battle_config.skillfree) {
-				int j;
+				uint8 j;
+				if (hskill_tree[c][i].need_level > hd->homunculus.level)
+					continue;
 				for (j = 0; j < MAX_HOM_SKILL_REQUIRE; j++) {
 					if (hskill_tree[c][i].need[j].id &&
 						hom_checkskill(hd,hskill_tree[c][i].need[j].id) < hskill_tree[c][i].need[j].lv)
 					{
-						f = 0;
+						fail = true;
 						break;
 					}
 				}
 			}
-			if (f)
+			if (!fail)
 				hd->homunculus.hskill[idx].id = skill_id;
 		}
-		f = 1;
 	}
 
 
@@ -311,27 +312,30 @@ void hom_calc_skilltree(struct homun_data *hd, int flag_evolve)
 		return;
 
 	for (i = 0; i < MAX_HOM_SKILL_TREE && (skill_id = hskill_tree[c][i].id) > 0; i++) {
-		int intimacy;
-		int idx = hom_skill_get_index(skill_id);
+		bool fail = false;
+		unsigned int intimacy = 0;
+		short idx = hom_skill_get_index(skill_id);
 		if (idx < 0)
 			continue;
 		if (hd->homunculus.hskill[idx].id)
 			continue; //Skill already known.
 		intimacy = (flag_evolve) ? 10 : hd->homunculus.intimacy;
-		if (intimacy < hskill_tree[c][i].intimacylv * 100)
+		if (intimacy < hskill_tree[c][i].intimacy * 100)
 			continue;
 		if (!battle_config.skillfree) {
-			int j;
+			uint8 j;
+			if (hskill_tree[c][i].need_level > hd->homunculus.level)
+				continue;
 			for (j = 0; j < MAX_HOM_SKILL_REQUIRE; j++) {
 				if (hskill_tree[c][i].need[j].id &&
 					hom_checkskill(hd,hskill_tree[c][i].need[j].id) < hskill_tree[c][i].need[j].lv)
 				{
-					f = 0;
+					fail = true;
 					break;
 				}
 			}
 		}
-		if (f)
+		if (!fail)
 			hd->homunculus.hskill[idx].id = skill_id;
 	}
 
@@ -377,6 +381,24 @@ int hom_skill_tree_get_max(int skill_id, int b_class){
 	return skill_get_max(skill_id);
 }
 
+ /**
+ * Get required minimum level to learn the skill
+ * @param class_ Homunculus class
+ * @param skill_id Homunculus skill ID
+ * @return Level required or 0 if invalid
+ **/
+uint8 hom_skill_get_min_level(int class_, uint16 skill_id) {
+	short class_idx = hom_class2index(class_), skill_idx = -1;
+	uint8 i;
+	if (class_idx == -1 || (skill_idx = hom_skill_get_index(skill_id)) == -1)
+		return 0;
+	ARR_FIND(0, MAX_HOM_SKILL_REQUIRE, i, hskill_tree[class_idx][i].id == skill_id);
+	if (i == MAX_HOM_SKILL_REQUIRE)
+		return 0;
+
+	return hskill_tree[class_idx][i].need_level;
+}
+
 /**
  * Level up an homunculus skill
  * @param hd
@@ -395,6 +417,7 @@ void hom_skillup(struct homun_data *hd, uint16 skill_id)
 	if (hd->homunculus.skillpts > 0 &&
 		hd->homunculus.hskill[idx].id &&
 		hd->homunculus.hskill[idx].flag == SKILL_FLAG_PERMANENT && //Don't allow raising while you have granted skills. [Skotlex]
+		hd->homunculus.level >= hom_skill_get_min_level(hd->homunculus.class_, skill_id) &&
 		hd->homunculus.hskill[idx].lv < hom_skill_tree_get_max(skill_id, hd->homunculus.class_)
 		)
 	{
@@ -1485,15 +1508,11 @@ void read_homunculusdb(void) {
 
 /**
 * Read homunculus skill db
+* <hom class>,<skill id>,<max level>,<need level>,<req id1>,<req lv1>,<req id2>,<req lv2>,<req id3>,<req lv3>,<req id4>,<req lv4>,<req id5>,<req lv5>,<intimacy lv req>
 */
-static bool read_homunculus_skilldb_sub(char* split[], int columns, int current)
-{// <hom class>,<skill id>,<max level>[,<job level>],<req id1>,<req lv1>,<req id2>,<req lv2>,<req id3>,<req lv3>,<req id4>,<req lv4>,<req id5>,<req lv5>,<intimacy lv req>
+static bool read_homunculus_skilldb_sub(char* split[], int columns, int current) {
 	int skill_id, class_idx;
-	int i, j;
-	int minJobLevelPresent = 0;
-
-	if (columns == 15)
-		minJobLevelPresent = 1;	// MinJobLvl has been added
+	int8 i, j;
 
 	// check for bounds [celest]
 	if ((class_idx = hom_class2index(atoi(split[0]))) == -1) {
@@ -1511,30 +1530,34 @@ static bool read_homunculus_skilldb_sub(char* split[], int columns, int current)
 
 	hskill_tree[class_idx][j].id = skill_id;
 	hskill_tree[class_idx][j].max = atoi(split[2]);
-	if (minJobLevelPresent)
-		hskill_tree[class_idx][j].joblv = atoi(split[3]);
+	hskill_tree[class_idx][j].need_level = atoi(split[3]);
 
 	for (i = 0; i < MAX_HOM_SKILL_REQUIRE; i++) {
-		hskill_tree[class_idx][j].need[i].id = atoi(split[3+i*2+minJobLevelPresent]);
-		hskill_tree[class_idx][j].need[i].lv = atoi(split[3+i*2+minJobLevelPresent+1]);
+		uint16 id = atoi(split[4+i*2]), idx = 0;
+		if (!id)
+			continue;
+		if (!(idx = skill_get_index(id))) {
+			ShowWarning("read_homunculus_skilldb_sub: Invalid skill %d as requirement for skill %hu class %d. Skipping\n", id, skill_id, atoi(split[0]));
+			continue;
+		}
+		hskill_tree[class_idx][j].need[i].id = id;
+		hskill_tree[class_idx][j].need[i].lv = atoi(split[4+i*2+1]);
 	}
 
-	hskill_tree[class_idx][j].intimacylv = atoi(split[13+minJobLevelPresent]);
+	hskill_tree[class_idx][j].intimacy = atoi(split[14]);
 	return true;
 }
 
 /**
 * Read homunculus skill db (check the files)
 */
-int read_homunculus_skilldb(void)
-{
-	const char *filename[]={ "homun_skill_tree.txt",DBIMPORT"/homun_skill_tree.txt"};
+static void read_homunculus_skilldb(void) {
+	const char *filename[] = { "homun_skill_tree.txt", DBIMPORT"/homun_skill_tree.txt"};
 	int i;
 	memset(hskill_tree,0,sizeof(hskill_tree));
-	for(i = 0; i<ARRAYLENGTH(filename); i++){
-		sv_readdb(db_path, filename[i], ',', 14, 15, -1, &read_homunculus_skilldb_sub, i);
+	for (i = 0; i<ARRAYLENGTH(filename); i++) {
+		sv_readdb(db_path, filename[i], ',', 15, 15, -1, &read_homunculus_skilldb_sub, i);
 	}
-	return 0;
 }
 
 /**

+ 11 - 9
src/map/homunculus.h

@@ -70,16 +70,17 @@ struct homun_data {
 #define MAX_HOM_SKILL_REQUIRE 5
 #define MAX_HOM_SKILL_TREE 8
 
+/// Homunculus skill entry [Celest]
 struct homun_skill_tree_entry {
-	short id;
-	unsigned char max;
-	unsigned char joblv;
-	short intimacylv;
+	uint16 id;			///< Skill ID
+	uint8 max;			///< Max level for this tree
+	uint8 need_level;	///< Homunculus level required
+	uint16 intimacy;	///< Intimacy required (n/100)
 	struct {
-		short id;
-		unsigned char lv;
-	} need[MAX_HOM_SKILL_REQUIRE];
-}; // Celest
+		uint16 id;		///< Skill ID
+		uint8 lv;		///< Level of skill
+	} need[MAX_HOM_SKILL_REQUIRE]; ///< Skills needed
+};
 
 #define HOM_EVO 0x100 //256
 #define HOM_S 0x200 //512
@@ -147,8 +148,9 @@ enum homun_type hom_class2type(int class_);
 void hom_damage(struct homun_data *hd);
 int hom_dead(struct homun_data *hd);
 void hom_skillup(struct homun_data *hd,uint16 skill_id);
-void hom_calc_skilltree(struct homun_data *hd, int flag_evolve);
+void hom_calc_skilltree(struct homun_data *hd, bool flag_evolve);
 short hom_checkskill(struct homun_data *hd,uint16 skill_id);
+uint8 hom_skill_get_min_level(int class_, uint16 skill_id);
 void hom_gainexp(struct homun_data *hd,int exp);
 int hom_levelup(struct homun_data *hd);
 int hom_evolution(struct homun_data *hd);