Merge branch 'cleanup/skill_db-2'

This commit is contained in:
aleos89 2015-02-21 15:44:22 -05:00
commit 20695d629a
70 changed files with 1490 additions and 1202 deletions

View File

@ -4648,5 +4648,10 @@ BSF_PERMANENT 0x200
BSF_FORCE_REPLACE 0x400 BSF_FORCE_REPLACE 0x400
BSF_FORCE_DUPLICATE 0x800 BSF_FORCE_DUPLICATE 0x800
SKILL_PERM 0
SKILL_TEMP 1
SKILL_TEMPLEVEL 2
SKILL_PERM_GRANT 3
false 0 false 0
true 1 true 1

View File

@ -504,7 +504,7 @@
357,0,6,4,0,0x1,0,5,1,no,0,0,0,weapon,0,0x0, LK_CONCENTRATION,Concentration 357,0,6,4,0,0x1,0,5,1,no,0,0,0,weapon,0,0x0, LK_CONCENTRATION,Concentration
358,0,6,4,0,0x1,0,1,1,no,0,0,0,weapon,0,0x0, LK_TENSIONRELAX,Relax 358,0,6,4,0,0x1,0,1,1,no,0,0,0,weapon,0,0x0, LK_TENSIONRELAX,Relax
359,0,6,4,0,0x1,0,1,1,no,0,0,0,weapon,0,0x0, LK_BERSERK,Frenzy 359,0,6,4,0,0x1,0,1,1,no,0,0,0,weapon,0,0x0, LK_BERSERK,Frenzy
//360,0,6,4,0,0x1,0,1,1,no,0,0,0,weapon,0,0x0, LK_FURY,Fury 360,0,6,4,0,0x1,0,1,1,no,0,0,0,weapon,0,0x0, LK_FURY,Fury
//**** //****
// High Priest // High Priest
@ -553,10 +553,10 @@
//**** //****
// Whitesmith // Whitesmith
384,0,0,4,0,0x1,0,10,1,yes,0,0,0,weapon,0,0x4000, WS_MELTDOWN,Shattering Strike 384,0,0,4,0,0x1,0,10,1,yes,0,0,0,weapon,0,0x4000, WS_MELTDOWN,Shattering Strike
//385,0,0,4,0,0x1,0,1,1,yes,0,0,0,none,0,0x0, WS_CREATECOIN,Create Coins 385,0,0,4,0,0x1,0,1,1,yes,0,0,0,none,0,0x0, WS_CREATECOIN,Create Coins
//386,0,0,4,0,0x1,0,1,1,yes,0,0,0,none,0,0x0, WS_CREATENUGGET,Create Nuggets 386,0,0,4,0,0x1,0,1,1,yes,0,0,0,none,0,0x0, WS_CREATENUGGET,Create Nuggets
387,0,6,4,0,0x1,0,1,1,no,0,0,0,weapon,0,0x4000, WS_CARTBOOST,Cart Boost 387,0,6,4,0,0x1,0,1,1,no,0,0,0,weapon,0,0x4000, WS_CARTBOOST,Cart Boost
//388,9,6,2,0,0x1,0,5,1,no,0,0,0,none,0,0x0, WS_SYSTEMCREATE,Auto Attack System 388,9,6,2,0,0x1,0,5,1,no,0,0,0,none,0,0x0, WS_SYSTEMCREATE,Auto Attack System
//**** //****
// Stalker // Stalker
@ -768,6 +768,11 @@
543,0,6,4,0,0x1,0,5,1,yes,0,0,0,none,0,0x0, NJ_NEN,Soul 543,0,6,4,0,0x1,0,5,1,yes,0,0,0,none,0,0x0, NJ_NEN,Soul
544,-5,6,1,0,0x40,0,10,1,no,0,0,0,weapon,0,0x0, NJ_ISSEN,Final Strike 544,-5,6,1,0,0x40,0,10,1,no,0,0,0,weapon,0,0x0, NJ_ISSEN,Final Strike
572,0,0,0,0,0,0,5,0,no,0,0,0,none,0,0x0, SL_DEATHKNIGHT,SL_DEATHKNIGHT
573,0,0,0,0,0,0,5,0,no,0,0,0,none,0,0x0, SL_COLLECTOR,SL_COLLECTOR
574,0,0,0,0,0,0,5,0,no,0,0,0,none,0,0x0, SL_NINJA,SL_NINJA
575,0,0,0,0,0,0,5,0,no,0,0,0,none,0,0x0, SL_GUNNER,SL_GUNNER
//**** //****
// Additional NPC Skills (Episode 11.3) // Additional NPC Skills (Episode 11.3)
653,0,8,4,0,0x6,5:7:9:11:13:5:7:9:11:13,10,1,no,0,0x2,0,magic,0,0x0, NPC_EARTHQUAKE,Earthquake 653,0,8,4,0,0x6,5:7:9:11:13:5:7:9:11:13,10,1,no,0,0x2,0,magic,0,0x0, NPC_EARTHQUAKE,Earthquake
@ -818,12 +823,12 @@
689,0,6,4,0,0x3,-1,10,1,yes,0,0x2,0,magic,0,0x1000, CASH_BLESSING,Party Blessing 689,0,6,4,0,0x3,-1,10,1,yes,0,0x2,0,magic,0,0x1000, CASH_BLESSING,Party Blessing
690,0,6,4,0,0x3,-1,10,1,yes,0,0x2,0,magic,0,0x1000, CASH_INCAGI,Party Increase AGI 690,0,6,4,0,0x3,-1,10,1,yes,0,0x2,0,magic,0,0x1000, CASH_INCAGI,Party Increase AGI
691,0,6,4,0,0x3,-1,5,1,yes,0,0x2,0,magic,0,0x0, CASH_ASSUMPTIO,Party Assumptio 691,0,6,4,0,0x3,-1,5,1,yes,0,0x2,0,magic,0,0x0, CASH_ASSUMPTIO,Party Assumptio
//692,0,0,0,0,0,0,9,0,no,0,0x2,0,none,0,0x0, ALL_CATCRY,Cat Cry 692,0,0,0,0,0,0,9,0,no,0,0x2,0,none,0,0x0, ALL_CATCRY,Cat Cry
693,0,6,4,0,0x3,-1,1,1,yes,0,0x2,0,magic,0,0x0, ALL_PARTYFLEE,Party Flee 693,0,6,4,0,0x3,-1,1,1,yes,0,0x2,0,magic,0,0x0, ALL_PARTYFLEE,Party Flee
//694,0,0,0,0,0,0,9,0,no,0,0x2,0,none,0,0x0, ALL_ANGEL_PROTECT,Angel's Protection //694,0,0,0,0,0,0,9,0,no,0,0x2,0,none,0,0x0, ALL_ANGEL_PROTECT,Angel's Protection
//695,0,0,0,0,0,0,9,0,no,0,0x2,0,none,0,0x0, ALL_DREAM_SUMMERNIGHT,Summer Night Dream 695,0,0,0,0,0,0,9,0,no,0,0x2,0,none,0,0x0, ALL_DREAM_SUMMERNIGHT,Summer Night Dream
//696,0,0,0,0,0,0,9,0,no,0,0x2,0,none,0,0x0, NPC_CHANGEUNDEAD2,Change Undead //696,0,0,0,0,0,0,9,0,no,0,0x2,0,none,0,0x0, NPC_CHANGEUNDEAD2,Change Undead
//697,9,6,4,0,0x1,0,1,1,yes,0,0x2,0,magic,0,0x0, ALL_REVERSEORCISH,Reverse Orcish 697,9,6,4,0,0x1,0,1,1,yes,0,0x2,0,magic,0,0x0, ALL_REVERSEORCISH,Reverse Orcish
698,0,6,4,0,0x01,0,1,1,no,0,0x2,0,none,0,0x0, ALL_WEWISH,Christmas Carol 698,0,6,4,0,0x01,0,1,1,no,0,0x2,0,none,0,0x0, ALL_WEWISH,Christmas Carol
//699,0,0,0,0,0,0,9,0,no,0,0x2,0,none,0,0x0, ALL_SONKRAN,ALL_SONKRAN //699,0,0,0,0,0,0,9,0,no,0,0x2,0,none,0,0x0, ALL_SONKRAN,ALL_SONKRAN

View File

@ -504,7 +504,7 @@
357,0,6,4,0,0x1,0,5,1,no,0,0,0,weapon,0,0x0, LK_CONCENTRATION,Concentration 357,0,6,4,0,0x1,0,5,1,no,0,0,0,weapon,0,0x0, LK_CONCENTRATION,Concentration
358,0,6,4,0,0x1,0,1,1,no,0,0,0,weapon,0,0x0, LK_TENSIONRELAX,Relax 358,0,6,4,0,0x1,0,1,1,no,0,0,0,weapon,0,0x0, LK_TENSIONRELAX,Relax
359,0,6,4,0,0x1,0,1,1,no,0,0,0,weapon,0,0x0, LK_BERSERK,Frenzy 359,0,6,4,0,0x1,0,1,1,no,0,0,0,weapon,0,0x0, LK_BERSERK,Frenzy
//360,0,6,4,0,0x1,0,1,1,no,0,0,0,weapon,0,0x0, LK_FURY,Fury 360,0,6,4,0,0x1,0,1,1,no,0,0,0,weapon,0,0x0, LK_FURY,Fury
//**** //****
// High Priest // High Priest
@ -553,10 +553,10 @@
//**** //****
// Whitesmith // Whitesmith
384,0,0,4,0,0x1,0,10,1,yes,0,0,0,weapon,0,0x4000, WS_MELTDOWN,Shattering Strike 384,0,0,4,0,0x1,0,10,1,yes,0,0,0,weapon,0,0x4000, WS_MELTDOWN,Shattering Strike
//385,0,0,4,0,0x1,0,1,1,yes,0,0,0,none,0,0x0, WS_CREATECOIN,Create Coins 385,0,0,4,0,0x1,0,1,1,yes,0,0,0,none,0,0x0, WS_CREATECOIN,Create Coins
//386,0,0,4,0,0x1,0,1,1,yes,0,0,0,none,0,0x0, WS_CREATENUGGET,Create Nuggets 386,0,0,4,0,0x1,0,1,1,yes,0,0,0,none,0,0x0, WS_CREATENUGGET,Create Nuggets
387,0,6,4,0,0x1,0,1,1,no,0,0,0,weapon,0,0x4000, WS_CARTBOOST,Cart Boost 387,0,6,4,0,0x1,0,1,1,no,0,0,0,weapon,0,0x4000, WS_CARTBOOST,Cart Boost
//388,9,6,2,0,0x1,0,5,1,no,0,0,0,none,0,0x0, WS_SYSTEMCREATE,Auto Attack System 388,9,6,2,0,0x1,0,5,1,no,0,0,0,none,0,0x0, WS_SYSTEMCREATE,Auto Attack System
//**** //****
// Stalker // Stalker
@ -768,6 +768,11 @@
543,0,6,4,0,0x1,0,5,1,yes,0,0,0,none,0,0x0, NJ_NEN,Soul 543,0,6,4,0,0x1,0,5,1,yes,0,0,0,none,0,0x0, NJ_NEN,Soul
544,-5,8,1,0,0x40,0,10,1,no,0,0,0,misc,0,0x0, NJ_ISSEN,Final Strike 544,-5,8,1,0,0x40,0,10,1,no,0,0,0,misc,0,0x0, NJ_ISSEN,Final Strike
572,0,0,0,0,0,0,5,0,no,0,0,0,none,0,0x0, SL_DEATHKNIGHT,SL_DEATHKNIGHT
573,0,0,0,0,0,0,5,0,no,0,0,0,none,0,0x0, SL_COLLECTOR,SL_COLLECTOR
574,0,0,0,0,0,0,5,0,no,0,0,0,none,0,0x0, SL_NINJA,SL_NINJA
575,0,0,0,0,0,0,5,0,no,0,0,0,none,0,0x0, SL_GUNNER,SL_GUNNER
//**** //****
// Additional NPC Skills (Episode 11.3) // Additional NPC Skills (Episode 11.3)
653,0,8,4,0,0x6,5:7:9:11:13:5:7:9:11:13,10,1,no,0,0x2,0,magic,0,0x0, NPC_EARTHQUAKE,Earthquake 653,0,8,4,0,0x6,5:7:9:11:13:5:7:9:11:13,10,1,no,0,0x2,0,magic,0,0x0, NPC_EARTHQUAKE,Earthquake
@ -818,10 +823,10 @@
689,0,6,4,0,0x3,-1,10,1,yes,0,0x2,0,magic,0,0x0, CASH_BLESSING,Party Blessing 689,0,6,4,0,0x3,-1,10,1,yes,0,0x2,0,magic,0,0x0, CASH_BLESSING,Party Blessing
690,0,6,4,0,0x3,-1,10,1,yes,0,0x2,0,magic,0,0x0, CASH_INCAGI,Party Increase AGI 690,0,6,4,0,0x3,-1,10,1,yes,0,0x2,0,magic,0,0x0, CASH_INCAGI,Party Increase AGI
691,0,6,4,0,0x3,-1,5,1,yes,0,0x2,0,magic,0,0x0, CASH_ASSUMPTIO,Party Assumptio 691,0,6,4,0,0x3,-1,5,1,yes,0,0x2,0,magic,0,0x0, CASH_ASSUMPTIO,Party Assumptio
//692,0,0,0,0,0,0,9,0,no,0,0x2,0,none,0,0x0, ALL_CATCRY,Cat Cry 692,0,0,0,0,0,0,9,0,no,0,0x2,0,none,0,0x0, ALL_CATCRY,Cat Cry
693,0,6,4,0,0x3,-1,1,1,yes,0,0x2,0,magic,0,0x0, ALL_PARTYFLEE,Party Flee 693,0,6,4,0,0x3,-1,1,1,yes,0,0x2,0,magic,0,0x0, ALL_PARTYFLEE,Party Flee
//694,0,0,0,0,0,0,9,0,no,0,0x2,0,none,0,0x0, ALL_ANGEL_PROTECT,Angel's Protection 694,0,0,0,0,0,0,9,0,no,0,0x2,0,none,0,0x0, ALL_ANGEL_PROTECT,Angel's Protection
//695,0,0,0,0,0,0,9,0,no,0,0x2,0,none,0,0x0, ALL_DREAM_SUMMERNIGHT,Summer Night Dream 695,0,0,0,0,0,0,9,0,no,0,0x2,0,none,0,0x0, ALL_DREAM_SUMMERNIGHT,Summer Night Dream
//696,0,0,0,0,0,0,9,0,no,0,0x2,0,none,0,0x0, NPC_CHANGEUNDEAD2,Change Undead //696,0,0,0,0,0,0,9,0,no,0,0x2,0,none,0,0x0, NPC_CHANGEUNDEAD2,Change Undead
697,9,6,4,0,0x1,0,1,1,yes,0,0x2,0,magic,0,0x0, ALL_REVERSEORCISH,Reverse Orcish 697,9,6,4,0,0x1,0,1,1,yes,0,0x2,0,magic,0,0x0, ALL_REVERSEORCISH,Reverse Orcish
698,0,6,4,0,0x01,0,1,1,no,0,0x2,0,none,0,0x0, ALL_WEWISH,Christmas Carol 698,0,6,4,0,0x01,0,1,1,no,0,0x2,0,none,0,0x0, ALL_WEWISH,Christmas Carol

View File

@ -5411,9 +5411,15 @@ Flag 2 means that the level parameter is to be interpreted as a stackable
additional bonus to the skill level. If the character did not have that skill additional bonus to the skill level. If the character did not have that skill
previously, they will now at 0+the level given. previously, they will now at 0+the level given.
Flag 4 is the same as flag 1 in that it saves to the database. However, these skills Flag 3 is the same as flag 1 in that it saves to the database. However, these skills
are ignored when any action is taken that adjusts the skill tree (reset/job change). are ignored when any action is taken that adjusts the skill tree (reset/job change).
Flag contants:
0 - SKILL_PERM
1 - SKILL_TEMP
2 - SKILL_TEMPLEVEL
3 - SKILL_PERM_GRANT
// This will permanently give the character Stone Throw (TF_THROWSTONE,152), at // This will permanently give the character Stone Throw (TF_THROWSTONE,152), at
// level 1. // level 1.
skill 152,1,0; skill 152,1,0;

View File

@ -206,87 +206,87 @@ function Job_Menu {
} }
Get_Platinum: Get_Platinum:
skill "NV_FIRSTAID",1,0; skill "NV_FIRSTAID",1,SKILL_PERM;
switch (BaseClass) { switch (BaseClass) {
case Job_Novice: case Job_Novice:
if (Class != Job_SuperNovice) if (Class != Job_SuperNovice)
skill "NV_TRICKDEAD",1,0; skill "NV_TRICKDEAD",1,SKILL_PERM;
break; break;
case Job_Swordman: case Job_Swordman:
skill "SM_MOVINGRECOVERY",1,0; skill "SM_MOVINGRECOVERY",1,SKILL_PERM;
skill "SM_FATALBLOW",1,0; skill "SM_FATALBLOW",1,SKILL_PERM;
skill "SM_AUTOBERSERK",1,0; skill "SM_AUTOBERSERK",1,SKILL_PERM;
break; break;
case Job_Mage: case Job_Mage:
skill "MG_ENERGYCOAT",1,0; skill "MG_ENERGYCOAT",1,SKILL_PERM;
break; break;
case Job_Archer: case Job_Archer:
skill "AC_MAKINGARROW",1,0; skill "AC_MAKINGARROW",1,SKILL_PERM;
skill "AC_CHARGEARROW",1,0; skill "AC_CHARGEARROW",1,SKILL_PERM;
break; break;
case Job_Acolyte: case Job_Acolyte:
skill "AL_HOLYLIGHT",1,0; skill "AL_HOLYLIGHT",1,SKILL_PERM;
break; break;
case Job_Merchant: case Job_Merchant:
skill "MC_CARTREVOLUTION",1,0; skill "MC_CARTREVOLUTION",1,SKILL_PERM;
skill "MC_CHANGECART",1,0; skill "MC_CHANGECART",1,SKILL_PERM;
skill "MC_LOUD",1,0; skill "MC_LOUD",1,SKILL_PERM;
break; break;
case Job_Thief: case Job_Thief:
skill "TF_SPRINKLESAND",1,0; skill "TF_SPRINKLESAND",1,SKILL_PERM;
skill "TF_BACKSLIDING",1,0; skill "TF_BACKSLIDING",1,SKILL_PERM;
skill "TF_PICKSTONE",1,0; skill "TF_PICKSTONE",1,SKILL_PERM;
skill "TF_THROWSTONE",1,0; skill "TF_THROWSTONE",1,SKILL_PERM;
break; break;
default: default:
break; break;
} }
switch (BaseJob) { switch (BaseJob) {
case Job_Knight: case Job_Knight:
skill "KN_CHARGEATK",1,0; skill "KN_CHARGEATK",1,SKILL_PERM;
break; break;
case Job_Priest: case Job_Priest:
skill "PR_REDEMPTIO",1,0; skill "PR_REDEMPTIO",1,SKILL_PERM;
break; break;
case Job_Wizard: case Job_Wizard:
skill "WZ_SIGHTBLASTER",1,0; skill "WZ_SIGHTBLASTER",1,SKILL_PERM;
break; break;
case Job_Blacksmith: case Job_Blacksmith:
skill "BS_UNFAIRLYTRICK",1,0; skill "BS_UNFAIRLYTRICK",1,SKILL_PERM;
skill "BS_GREED",1,0; skill "BS_GREED",1,SKILL_PERM;
break; break;
case Job_Hunter: case Job_Hunter:
skill "HT_PHANTASMIC",1,0; skill "HT_PHANTASMIC",1,SKILL_PERM;
break; break;
case Job_Assassin: case Job_Assassin:
skill "AS_SONICACCEL",1,0; skill "AS_SONICACCEL",1,SKILL_PERM;
skill "AS_VENOMKNIFE",1,0; skill "AS_VENOMKNIFE",1,SKILL_PERM;
break; break;
case Job_Crusader: case Job_Crusader:
skill "CR_SHRINK",1,0; skill "CR_SHRINK",1,SKILL_PERM;
break; break;
case Job_Monk: case Job_Monk:
skill "MO_KITRANSLATION",1,0; skill "MO_KITRANSLATION",1,SKILL_PERM;
skill "MO_BALKYOUNG",1,0; skill "MO_BALKYOUNG",1,SKILL_PERM;
break; break;
case Job_Sage: case Job_Sage:
skill "SA_CREATECON",1,0; skill "SA_CREATECON",1,SKILL_PERM;
skill "SA_ELEMENTWATER",1,0; skill "SA_ELEMENTWATER",1,SKILL_PERM;
skill "SA_ELEMENTGROUND",1,0; skill "SA_ELEMENTGROUND",1,SKILL_PERM;
skill "SA_ELEMENTFIRE",1,0; skill "SA_ELEMENTFIRE",1,SKILL_PERM;
skill "SA_ELEMENTWIND",1,0; skill "SA_ELEMENTWIND",1,SKILL_PERM;
break; break;
case Job_Rogue: case Job_Rogue:
skill "RG_CLOSECONFINE",1,0; skill "RG_CLOSECONFINE",1,SKILL_PERM;
break; break;
case Job_Alchemist: case Job_Alchemist:
skill "AM_BIOETHICS",1,0; skill "AM_BIOETHICS",1,SKILL_PERM;
break; break;
case Job_Bard: case Job_Bard:
skill "BA_PANGVOICE",1,0; skill "BA_PANGVOICE",1,SKILL_PERM;
break; break;
case Job_Dancer: case Job_Dancer:
skill "DC_WINKCHARM",1,0; skill "DC_WINKCHARM",1,SKILL_PERM;
break; break;
default: default:
break; break;

View File

@ -30,87 +30,87 @@ prontera,128,200,6 script Platinum Skill NPC 94,{
mes "Have a nice day... >.>"; mes "Have a nice day... >.>";
close; close;
} }
skill "NV_FIRSTAID",1,0; skill "NV_FIRSTAID",1,SKILL_PERM;
switch (BaseClass) { switch (BaseClass) {
case Job_Novice: case Job_Novice:
if (Class != Job_SuperNovice) if (Class != Job_SuperNovice)
skill "NV_TRICKDEAD",1,0; skill "NV_TRICKDEAD",1,SKILL_PERM;
break; break;
case Job_Swordman: case Job_Swordman:
skill "SM_MOVINGRECOVERY",1,0; skill "SM_MOVINGRECOVERY",1,SKILL_PERM;
skill "SM_FATALBLOW",1,0; skill "SM_FATALBLOW",1,SKILL_PERM;
skill "SM_AUTOBERSERK",1,0; skill "SM_AUTOBERSERK",1,SKILL_PERM;
break; break;
case Job_Mage: case Job_Mage:
skill "MG_ENERGYCOAT",1,0; skill "MG_ENERGYCOAT",1,SKILL_PERM;
break; break;
case Job_Archer: case Job_Archer:
skill "AC_MAKINGARROW",1,0; skill "AC_MAKINGARROW",1,SKILL_PERM;
skill "AC_CHARGEARROW",1,0; skill "AC_CHARGEARROW",1,SKILL_PERM;
break; break;
case Job_Acolyte: case Job_Acolyte:
skill "AL_HOLYLIGHT",1,0; skill "AL_HOLYLIGHT",1,SKILL_PERM;
break; break;
case Job_Merchant: case Job_Merchant:
skill "MC_CARTREVOLUTION",1,0; skill "MC_CARTREVOLUTION",1,SKILL_PERM;
skill "MC_CHANGECART",1,0; skill "MC_CHANGECART",1,SKILL_PERM;
skill "MC_LOUD",1,0; skill "MC_LOUD",1,SKILL_PERM;
break; break;
case Job_Thief: case Job_Thief:
skill "TF_SPRINKLESAND",1,0; skill "TF_SPRINKLESAND",1,SKILL_PERM;
skill "TF_BACKSLIDING",1,0; skill "TF_BACKSLIDING",1,SKILL_PERM;
skill "TF_PICKSTONE",1,0; skill "TF_PICKSTONE",1,SKILL_PERM;
skill "TF_THROWSTONE",1,0; skill "TF_THROWSTONE",1,SKILL_PERM;
break; break;
default: default:
break; break;
} }
switch (BaseJob) { switch (BaseJob) {
case Job_Knight: case Job_Knight:
skill "KN_CHARGEATK",1,0; skill "KN_CHARGEATK",1,SKILL_PERM;
break; break;
case Job_Priest: case Job_Priest:
skill "PR_REDEMPTIO",1,0; skill "PR_REDEMPTIO",1,SKILL_PERM;
break; break;
case Job_Wizard: case Job_Wizard:
skill "WZ_SIGHTBLASTER",1,0; skill "WZ_SIGHTBLASTER",1,SKILL_PERM;
break; break;
case Job_Blacksmith: case Job_Blacksmith:
skill "BS_UNFAIRLYTRICK",1,0; skill "BS_UNFAIRLYTRICK",1,SKILL_PERM;
skill "BS_GREED",1,0; skill "BS_GREED",1,SKILL_PERM;
break; break;
case Job_Hunter: case Job_Hunter:
skill "HT_PHANTASMIC",1,0; skill "HT_PHANTASMIC",1,SKILL_PERM;
break; break;
case Job_Assassin: case Job_Assassin:
skill "AS_SONICACCEL",1,0; skill "AS_SONICACCEL",1,SKILL_PERM;
skill "AS_VENOMKNIFE",1,0; skill "AS_VENOMKNIFE",1,SKILL_PERM;
break; break;
case Job_Crusader: case Job_Crusader:
skill "CR_SHRINK",1,0; skill "CR_SHRINK",1,SKILL_PERM;
break; break;
case Job_Monk: case Job_Monk:
skill "MO_KITRANSLATION",1,0; skill "MO_KITRANSLATION",1,SKILL_PERM;
skill "MO_BALKYOUNG",1,0; skill "MO_BALKYOUNG",1,SKILL_PERM;
break; break;
case Job_Sage: case Job_Sage:
skill "SA_CREATECON",1,0; skill "SA_CREATECON",1,SKILL_PERM;
skill "SA_ELEMENTWATER",1,0; skill "SA_ELEMENTWATER",1,SKILL_PERM;
skill "SA_ELEMENTGROUND",1,0; skill "SA_ELEMENTGROUND",1,SKILL_PERM;
skill "SA_ELEMENTFIRE",1,0; skill "SA_ELEMENTFIRE",1,SKILL_PERM;
skill "SA_ELEMENTWIND",1,0; skill "SA_ELEMENTWIND",1,SKILL_PERM;
break; break;
case Job_Rogue: case Job_Rogue:
skill "RG_CLOSECONFINE",1,0; skill "RG_CLOSECONFINE",1,SKILL_PERM;
break; break;
case Job_Alchemist: case Job_Alchemist:
skill "AM_BIOETHICS",1,0; skill "AM_BIOETHICS",1,SKILL_PERM;
break; break;
case Job_Bard: case Job_Bard:
skill "BA_PANGVOICE",1,0; skill "BA_PANGVOICE",1,SKILL_PERM;
break; break;
case Job_Dancer: case Job_Dancer:
skill "DC_WINKCHARM",1,0; skill "DC_WINKCHARM",1,SKILL_PERM;
break; break;
default: default:
break; break;

View File

@ -101,7 +101,7 @@ valkyrie,53,50,3 script Biochemist#Valkyrie 122,{
mes "responsibility in using these"; mes "responsibility in using these";
mes "secrets for the right ends..."; mes "secrets for the right ends...";
next; next;
skill "AM_BIOETHICS",1,0; skill "AM_BIOETHICS",1,SKILL_PERM;
mes "[Biochemist]"; mes "[Biochemist]";
mes "Open your eyes..."; mes "Open your eyes...";
mes "Now that you have"; mes "Now that you have";

View File

@ -151,8 +151,8 @@ valkyrie,48,86,4 script Valkyrie# 811,{
jobchange Job_Novice_High; jobchange Job_Novice_High;
resetlvl(1); resetlvl(1);
set MISC_QUEST,MISC_QUEST | 1024; //<-reset Skill Reset Event set MISC_QUEST,MISC_QUEST | 1024; //<-reset Skill Reset Event
skill "NV_FIRSTAID",1,0; skill "NV_FIRSTAID",1,SKILL_PERM;
skill "NV_TRICKDEAD",1,0; skill "NV_TRICKDEAD",1,SKILL_PERM;
completequest 1000; completequest 1000;
next; next;
mes "[Valkyrie]"; mes "[Valkyrie]";

View File

@ -225,7 +225,7 @@ alberta_in,58,52,4 script Purchasing Team#Buying 59,{
mes "Okay, you're now approved to open the Bulk Buyer Shop."; mes "Okay, you're now approved to open the Bulk Buyer Shop.";
set Zeny,Zeny-10000; set Zeny,Zeny-10000;
getitem 6377,5; //Buy_Stall_Permit getitem 6377,5; //Buy_Stall_Permit
skill "ALL_BUYING_STORE",1,4; skill "ALL_BUYING_STORE",1,SKILL_PERM_GRANT;
next; next;
mes "[Mr. Hugh]"; mes "[Mr. Hugh]";
mes "Currently, only normal items ^8C2121EXCEPT^000000 equipment, certain potions, and hand-crafted items can be purchased in bulk, but this can still be very beneficial to you, depending on how you use it."; mes "Currently, only normal items ^8C2121EXCEPT^000000 equipment, certain potions, and hand-crafted items can be purchased in bulk, but this can still be very beneficial to you, depending on how you use it.";

View File

@ -79,7 +79,7 @@ payon,173,141,4 script Ripped Cabus#GymPass 899,{
mes "training together like this."; mes "training together like this.";
delitem 7776,1; //Max_Weight_Up_Scroll delitem 7776,1; //Max_Weight_Up_Scroll
set gympassmemory,.@add_carry; set gympassmemory,.@add_carry;
skill "ALL_INCCARRY",.@add_carry,4; skill "ALL_INCCARRY",.@add_carry,SKILL_PERM_GRANT;
close; close;
} }
else { else {
@ -135,7 +135,7 @@ payon,173,141,4 script Ripped Cabus#GymPass 899,{
mes "muscles grew back,"; mes "muscles grew back,";
mes "just like that! Try not to"; mes "just like that! Try not to";
mes "wimp out again, okay?"; mes "wimp out again, okay?";
skill "ALL_INCCARRY",gympassmemory,4; skill "ALL_INCCARRY",gympassmemory,SKILL_PERM_GRANT;
close; close;
} }
else { else {

View File

@ -56,9 +56,9 @@ prt_church,184,41,4 script Cleric#aco 60,{
mes "wish you luck on your"; mes "wish you luck on your";
mes "new life's journey."; mes "new life's journey.";
next; next;
skill "NV_TRICKDEAD",0,0; skill "NV_TRICKDEAD",0,SKILL_PERM;
jobchange Job_Acolyte_High; jobchange Job_Acolyte_High;
skill "AL_HOLYLIGHT",1,0; skill "AL_HOLYLIGHT",1,SKILL_PERM;
mes "[Father Mareusis]"; mes "[Father Mareusis]";
mes "Now, venture forth and seek those who need your help. May God light your path."; mes "Now, venture forth and seek those who need your help. May God light your path.";
close; close;
@ -181,7 +181,7 @@ prt_church,184,41,4 script Cleric#aco 60,{
mes "[Father Mareusis]"; mes "[Father Mareusis]";
mes "I am proud to say that you are now ready to become an Acolyte!"; mes "I am proud to say that you are now ready to become an Acolyte!";
next; next;
skill "NV_TRICKDEAD",0,0; skill "NV_TRICKDEAD",0,SKILL_PERM;
callfunc "Job_Change",Job_Acolyte; callfunc "Job_Change",Job_Acolyte;
callfunc "F_ClearJobVar"; callfunc "F_ClearJobVar";
if(checkquest(1001) != -1) { if(checkquest(1001) != -1) {

View File

@ -51,10 +51,10 @@ payon_in02,64,71,4 script Archer Guildsman#archer 85,{
mes "need to say anything else."; mes "need to say anything else.";
mes "I know you'll make a great Archer..."; mes "I know you'll make a great Archer...";
next; next;
skill "NV_TRICKDEAD",0,0; skill "NV_TRICKDEAD",0,SKILL_PERM;
jobchange Job_Archer_high; jobchange Job_Archer_high;
skill "AC_MAKINGARROW",1,0; skill "AC_MAKINGARROW",1,SKILL_PERM;
skill "AC_CHARGEARROW",1,0; skill "AC_CHARGEARROW",1,SKILL_PERM;
mes "[Archer Guildsman]"; mes "[Archer Guildsman]";
mes "Although there's no special"; mes "Although there's no special";
mes "reward for you this time, I hope you understand. Take care of yourself."; mes "reward for you this time, I hope you understand. Take care of yourself.";

View File

@ -46,9 +46,9 @@ geffen_in,164,124,4 script Mage Guildsman 123,{
mes "[Mage Guildsman]"; mes "[Mage Guildsman]";
mes "Well, since you have passed the Mage test once, I will not question your qualification. You want to have your magic skills back immediately, don't you?"; mes "Well, since you have passed the Mage test once, I will not question your qualification. You want to have your magic skills back immediately, don't you?";
next; next;
skill "NV_TRICKDEAD",0,0; skill "NV_TRICKDEAD",0,SKILL_PERM;
jobchange Job_Mage_High; jobchange Job_Mage_High;
skill "MG_ENERGYCOAT",1,0; skill "MG_ENERGYCOAT",1,SKILL_PERM;
mes "[Mage Guildsman]"; mes "[Mage Guildsman]";
mes "Wow, for some reason, you look way better than you did before. Anyway, I believe you will do a better job being a Mage as well."; mes "Wow, for some reason, you look way better than you did before. Anyway, I believe you will do a better job being a Mage as well.";
close; close;

View File

@ -56,11 +56,11 @@ alberta_in,53,43,6 script Merchant#mer 86,{
mes "[Chief Mahnsoo]"; mes "[Chief Mahnsoo]";
mes "I guess it's destiny that we meet like this once more. Alright. Once again, let me change you into a Merchant!"; mes "I guess it's destiny that we meet like this once more. Alright. Once again, let me change you into a Merchant!";
next; next;
skill "NV_TRICKDEAD",0,0; skill "NV_TRICKDEAD",0,SKILL_PERM;
jobchange Job_Merchant_High; jobchange Job_Merchant_High;
skill "MC_CARTREVOLUTION",1,0; skill "MC_CARTREVOLUTION",1,SKILL_PERM;
skill "MC_CHANGECART",1,0; skill "MC_CHANGECART",1,SKILL_PERM;
skill "MC_LOUD",1,0; skill "MC_LOUD",1,SKILL_PERM;
mes "[Chief Mahnsoo]"; mes "[Chief Mahnsoo]";
mes "Ah~ How nostalgic. Just like old times! Alright, do your best!"; mes "Ah~ How nostalgic. Just like old times! Alright, do your best!";
close; close;

View File

@ -59,11 +59,11 @@ izlude_in,74,172,4 script Swordman#swd_1 119,{
mes "[Swordman]"; mes "[Swordman]";
mes "Excellent! Let me promote you to a Swordman right away!"; mes "Excellent! Let me promote you to a Swordman right away!";
next; next;
skill "NV_TRICKDEAD",0,0; skill "NV_TRICKDEAD",0,SKILL_PERM;
jobchange Job_Swordman_High; jobchange Job_Swordman_High;
skill "SM_MOVINGRECOVERY",1,0; skill "SM_MOVINGRECOVERY",1,SKILL_PERM;
skill "SM_FATALBLOW",1,0; skill "SM_FATALBLOW",1,SKILL_PERM;
skill "SM_AUTOBERSERK",1,0; skill "SM_AUTOBERSERK",1,SKILL_PERM;
mes "[Swordman]"; mes "[Swordman]";
mes "Hmm... You look like a well-experienced Swordman. Still, I'm sure that you must train to improve your skills and gain strength!"; mes "Hmm... You look like a well-experienced Swordman. Still, I'm sure that you must train to improve your skills and gain strength!";
close; close;

View File

@ -40,12 +40,12 @@ moc_prydb1,39,129,2 script Thief Guide 69,{
mes "[Thief Guide]"; mes "[Thief Guide]";
mes "Well, I got this feeling like you've been through a lifetime of fighting, so I'm promoting you to a Thief right this minute. I better give you tough guys what you want..."; mes "Well, I got this feeling like you've been through a lifetime of fighting, so I'm promoting you to a Thief right this minute. I better give you tough guys what you want...";
next; next;
skill "NV_TRICKDEAD",0,0; skill "NV_TRICKDEAD",0,SKILL_PERM;
jobchange Job_Thief_High; jobchange Job_Thief_High;
skill "TF_SPRINKLESAND",1,0; skill "TF_SPRINKLESAND",1,SKILL_PERM;
skill "TF_BACKSLIDING",1,0; skill "TF_BACKSLIDING",1,SKILL_PERM;
skill "TF_PICKSTONE",1,0; skill "TF_PICKSTONE",1,SKILL_PERM;
skill "TF_THROWSTONE",1,0; skill "TF_THROWSTONE",1,SKILL_PERM;
mes "[Thief Guide]"; mes "[Thief Guide]";
mes "Since you've become a Thief, live as a Thief. Now, go for it! Next~"; mes "Since you've become a Thief, live as a Thief. Now, go for it! Next~";
close; close;

View File

@ -753,7 +753,7 @@ new_1-2,83,111,3 script Skill Tutor#nv 753,{
next; next;
mes "^3355FFYou have learned"; mes "^3355FFYou have learned";
mes "the ^4A708BFirst Aid^3355FF skill.^000000"; mes "the ^4A708BFirst Aid^3355FF skill.^000000";
skill "NV_FIRSTAID",1,0; skill "NV_FIRSTAID",1,SKILL_PERM;
set NOV_SK,3; set NOV_SK,3;
set nov_get_item03,11; set nov_get_item03,11;
next; next;

View File

@ -79,7 +79,7 @@ prt_church,173,23,4 script Cleric 79,{
delitem 727,1; //White_Jewel delitem 727,1; //White_Jewel
delitem 991,1; //Crystal_Blue delitem 991,1; //Crystal_Blue
delitem 2608,1; //Rosary delitem 2608,1; //Rosary
skill "AL_HOLYLIGHT",1,0; skill "AL_HOLYLIGHT",1,SKILL_PERM;
mes "[Acolyte Klift]"; mes "[Acolyte Klift]";
mes "You now know ' Holy Light '"; mes "You now know ' Holy Light '";
mes "May you use this skill only in the"; mes "May you use this skill only in the";

View File

@ -1205,7 +1205,7 @@ lhz_in01,224,140,3 script Kellasus#qsk_al 57,{
mes "" + strcharinfo(0) + "."; mes "" + strcharinfo(0) + ".";
next; next;
set bioeth,13; set bioeth,13;
skill "AM_BIOETHICS",1,0; skill "AM_BIOETHICS",1,SKILL_PERM;
mes "[Kellasus]"; mes "[Kellasus]";
mes "Ah..."; mes "Ah...";
mes "" + strcharinfo(0) + "."; mes "" + strcharinfo(0) + ".";

View File

@ -51,7 +51,7 @@ moc_ruins,118,99,5 script Roberto 88,{
delitem 906,41; //Tough_Scalelike_Stem delitem 906,41; //Tough_Scalelike_Stem
delitem 1019,13; //Wooden_Block delitem 1019,13; //Wooden_Block
delitem 501,1; //Red_Potion delitem 501,1; //Red_Potion
skill "AC_MAKINGARROW",1,0; skill "AC_MAKINGARROW",1,SKILL_PERM;
mes "[Roberto]"; mes "[Roberto]";
mes "No need to worry about arrows now."; mes "No need to worry about arrows now.";
mes "Oh, and did you happen to see"; mes "Oh, and did you happen to see";
@ -224,7 +224,7 @@ payon,103,63,3 script Jason 88,3,3,{
delitem 962,10; //Tentacle delitem 962,10; //Tentacle
delitem 925,10; //Bill_Of_Birds delitem 925,10; //Bill_Of_Birds
delitem 532,36; //Banana_Juice delitem 532,36; //Banana_Juice
skill "AC_CHARGEARROW",1,0; skill "AC_CHARGEARROW",1,SKILL_PERM;
mes "[Jason]"; mes "[Jason]";
mes "Oh, works better than I expected!"; mes "Oh, works better than I expected!";
mes "Won't be needing to modify the bow!"; mes "Won't be needing to modify the bow!";

View File

@ -64,7 +64,7 @@ in_moc_16,14,27,5 script Assassin#realman 884,{
mes "skill. Leave me now, and"; mes "skill. Leave me now, and";
mes "always fight for the honor"; mes "always fight for the honor";
mes "of the Assassin Guild!"; mes "of the Assassin Guild!";
skill "AS_VENOMKNIFE",1,0; skill "AS_VENOMKNIFE",1,SKILL_PERM;
close; close;
} }
else { else {
@ -234,7 +234,7 @@ in_moc_16,14,27,5 script Assassin#realman 884,{
mes "Knife pretty easily in battle."; mes "Knife pretty easily in battle.";
set ASSN_SK2,1; set ASSN_SK2,1;
set ASSN_SK,1; set ASSN_SK,1;
skill "AS_VENOMKNIFE",1,0; skill "AS_VENOMKNIFE",1,SKILL_PERM;
next; next;
mes "[Killtin]"; mes "[Killtin]";
mes "Well, that's all I can"; mes "Well, that's all I can";
@ -358,7 +358,7 @@ in_moc_16,23,27,5 script Assassin#realgirl 885,{
mes "Yes, that's it...!"; mes "Yes, that's it...!";
mes "Very well executed."; mes "Very well executed.";
mes "Good work, "+ strcharinfo(0) +"."; mes "Good work, "+ strcharinfo(0) +".";
skill "AS_SONICACCEL",1,0; skill "AS_SONICACCEL",1,SKILL_PERM;
set ASSN_SK,7; set ASSN_SK,7;
next; next;
mes "[Esmille]"; mes "[Esmille]";
@ -455,7 +455,7 @@ in_moc_16,23,27,5 script Assassin#realgirl 885,{
mes "Yes, that's it...!"; mes "Yes, that's it...!";
mes "Very well executed."; mes "Very well executed.";
mes "Good work, "+ strcharinfo(0) +"."; mes "Good work, "+ strcharinfo(0) +".";
skill "AS_SONICACCEL",1,0; skill "AS_SONICACCEL",1,SKILL_PERM;
set ASSN_SK,7; set ASSN_SK,7;
next; next;
mes "[Esmille]"; mes "[Esmille]";
@ -538,7 +538,7 @@ in_moc_16,23,27,5 script Assassin#realgirl 885,{
mes "Yes, that's it...!"; mes "Yes, that's it...!";
mes "Very well executed."; mes "Very well executed.";
mes "Good work, "+ strcharinfo(0) +"."; mes "Good work, "+ strcharinfo(0) +".";
skill "AS_SONICACCEL",1,0; skill "AS_SONICACCEL",1,SKILL_PERM;
set ASSN_SK,7; set ASSN_SK,7;
next; next;
mes "[Esmille]"; mes "[Esmille]";

View File

@ -436,7 +436,7 @@ morocc_in,169,72,7 script Spiteful-Looking Bard#bs 741,3,3,{
mes "confuse people and disrupt"; mes "confuse people and disrupt";
mes "control of their bodies. It's not a fatal skill, but it is effective"; mes "control of their bodies. It's not a fatal skill, but it is effective";
mes "in mentally upsetting your enemy. Make very wise use of this skill."; mes "in mentally upsetting your enemy. Make very wise use of this skill.";
skill "BA_PANGVOICE",1,0; skill "BA_PANGVOICE",1,SKILL_PERM;
close; close;
} }
} }
@ -489,7 +489,7 @@ morocc_in,169,72,7 script Spiteful-Looking Bard#bs 741,3,3,{
mes "spinning, head spinning...!''"; mes "spinning, head spinning...!''";
specialeffect2 EF_TALK_FROSTJOKE; specialeffect2 EF_TALK_FROSTJOKE;
delitem 7277,1; //Munak_Doll delitem 7277,1; //Munak_Doll
skill "BA_PANGVOICE",1,0; skill "BA_PANGVOICE",1,SKILL_PERM;
set qskill_bard,9; set qskill_bard,9;
next; next;
mes "[Riott]"; mes "[Riott]";
@ -571,7 +571,7 @@ morocc_in,169,72,7 script Spiteful-Looking Bard#bs 741,3,3,{
mes "spinning, head spinning...!''"; mes "spinning, head spinning...!''";
specialeffect2 EF_TALK_FROSTJOKE; specialeffect2 EF_TALK_FROSTJOKE;
delitem 574,5; //Egg delitem 574,5; //Egg
skill "BA_PANGVOICE",1,0; skill "BA_PANGVOICE",1,SKILL_PERM;
set qskill_bard,9; set qskill_bard,9;
next; next;
mes "[Riott]"; mes "[Riott]";

View File

@ -31,7 +31,7 @@ geffen,178,72,3 script Akkie#qsk_bs 726,{
mes "Dubious Salesmanship? You"; mes "Dubious Salesmanship? You";
mes "should be able to use it now..."; mes "should be able to use it now...";
set BLACK_SK,8; set BLACK_SK,8;
skill "BS_UNFAIRLYTRICK",1,0; skill "BS_UNFAIRLYTRICK",1,SKILL_PERM;
close; close;
} }
else if (BLACK_SK == 8) { else if (BLACK_SK == 8) {
@ -371,7 +371,7 @@ geffen,178,72,3 script Akkie#qsk_bs 726,{
mes "this... Isn't it easy? Of course, you can only use this in battle to"; mes "this... Isn't it easy? Of course, you can only use this in battle to";
mes "reduce Mammonite's zeny cost..."; mes "reduce Mammonite's zeny cost...";
set BLACK_SK,7; set BLACK_SK,7;
skill "BS_UNFAIRLYTRICK",1,0; skill "BS_UNFAIRLYTRICK",1,SKILL_PERM;
next; next;
mes "[Akkie]"; mes "[Akkie]";
mes "Also, 90% of the cost of"; mes "Also, 90% of the cost of";
@ -490,7 +490,7 @@ geffen,172,52,1 script Goodman#qsk_bs 826,{
mes "just looking at me should"; mes "just looking at me should";
mes "jog the memories you require"; mes "jog the memories you require";
mes "to use this skill once again~"; mes "to use this skill once again~";
skill "BS_GREED",1,0; skill "BS_GREED",1,SKILL_PERM;
set BLACK_SK2,3; set BLACK_SK2,3;
close; close;
} }
@ -608,7 +608,7 @@ geffen,172,52,1 script Goodman#qsk_bs 826,{
mes "is different than its name."; mes "is different than its name.";
mes "Don't forget that, and I hope"; mes "Don't forget that, and I hope";
mes "you craft true masterpieces."; mes "you craft true masterpieces.";
skill "BS_GREED",1,0; skill "BS_GREED",1,SKILL_PERM;
set BLACK_SK2,2; set BLACK_SK2,2;
close; close;
} }

View File

@ -24,7 +24,7 @@ geffen,110,117,3 script Ford#11 752,{
mes "the Shrink skill, so I'll teach"; mes "the Shrink skill, so I'll teach";
mes "it to you real quick... There!"; mes "it to you real quick... There!";
set CRUS_SK,10; set CRUS_SK,10;
skill "CR_SHRINK",1,0; skill "CR_SHRINK",1,SKILL_PERM;
close; close;
} }
@ -519,7 +519,7 @@ gef_fild13,297,242,3 script Soldier#277 751,{
mes "and protect the weak. Ah, and"; mes "and protect the weak. Ah, and";
mes "if I learn any new skills, I'll be sure to teach you right away."; mes "if I learn any new skills, I'll be sure to teach you right away.";
set CRUS_SK,8; set CRUS_SK,8;
skill "CR_SHRINK",1,0; skill "CR_SHRINK",1,SKILL_PERM;
close; close;
} }
mes "^3355FFYou carefully pour the"; mes "^3355FFYou carefully pour the";

View File

@ -317,7 +317,7 @@ comodo,204,172,5 script Canell#qsk_dan01 724,{
mes "the Charming Wink skill.^000000"; mes "the Charming Wink skill.^000000";
set DANCER_SK,9; set DANCER_SK,9;
specialeffect2 EF_ABSORBSPIRITS; specialeffect2 EF_ABSORBSPIRITS;
skill "DC_WINKCHARM",1,0; skill "DC_WINKCHARM",1,SKILL_PERM;
close; close;
} }
} }
@ -360,7 +360,7 @@ comodo,204,172,5 script Canell#qsk_dan01 724,{
mes "^3355FFYou have learned the"; mes "^3355FFYou have learned the";
mes "Charming Wink skill.^000000"; mes "Charming Wink skill.^000000";
specialeffect2 EF_ABSORBSPIRITS; specialeffect2 EF_ABSORBSPIRITS;
skill "DC_WINKCHARM",1,0; skill "DC_WINKCHARM",1,SKILL_PERM;
close; close;
} }
} }

View File

@ -85,7 +85,7 @@ pay_arche,109,169,3 script Arpesto 712,{
mes "You should be able to use the"; mes "You should be able to use the";
mes "Phantasmic Arrow skill now."; mes "Phantasmic Arrow skill now.";
mes "Travel safely now, you hear?"; mes "Travel safely now, you hear?";
skill "HT_PHANTASMIC",1,0; skill "HT_PHANTASMIC",1,SKILL_PERM;
close; close;
} }
} }
@ -213,7 +213,7 @@ pay_arche,109,169,3 script Arpesto 712,{
delitem 7115,5; //Harpy's_Feather delitem 7115,5; //Harpy's_Feather
delitem 537,30; //Pet_Food delitem 537,30; //Pet_Food
set qskill_hunter,100; set qskill_hunter,100;
skill "HT_PHANTASMIC",1,0; skill "HT_PHANTASMIC",1,SKILL_PERM;
close; close;
} else { } else {
mes "[Arpesto]"; mes "[Arpesto]";

View File

@ -62,7 +62,7 @@ prt_in,85,99,3 script Knight#kabuto 734,{
mes "is greater risk to yourself."; mes "is greater risk to yourself.";
mes "For now, it would be best to practice this skill on your own."; mes "For now, it would be best to practice this skill on your own.";
set KNGT_SK,10; set KNGT_SK,10;
skill "KN_CHARGEATK",1,0; skill "KN_CHARGEATK",1,SKILL_PERM;
next; next;
mes "[Essofeit]"; mes "[Essofeit]";
mes "Good luck on your"; mes "Good luck on your";
@ -112,7 +112,7 @@ prt_in,85,99,3 script Knight#kabuto 734,{
mes "is greater risk to yourself."; mes "is greater risk to yourself.";
mes "For now, it would be best to practice this skill on your own."; mes "For now, it would be best to practice this skill on your own.";
set KNGT_SK,9; set KNGT_SK,9;
skill "KN_CHARGEATK",1,0; skill "KN_CHARGEATK",1,SKILL_PERM;
next; next;
mes "[Essofeit]"; mes "[Essofeit]";
mes "I hope you make good"; mes "I hope you make good";

View File

@ -119,7 +119,7 @@ geffen_in,151,119,4 script Great Wizard 64,{
delitem 730,1; //Crystal_Jewel delitem 730,1; //Crystal_Jewel
delitem 935,5; //Shell delitem 935,5; //Shell
delitem 943,1; //Solid_Shell delitem 943,1; //Solid_Shell
skill "MG_ENERGYCOAT",1,0; skill "MG_ENERGYCOAT",1,SKILL_PERM;
mes "[BLIZZARDRISS]"; mes "[BLIZZARDRISS]";
mes ". . . . ."; mes ". . . . .";
mes "It is done. . ."; mes "It is done. . .";

View File

@ -79,7 +79,7 @@ alberta,83,96,5 script Necko 98,7,7,{
delitem 722,7; //Scarlet_Jewel delitem 722,7; //Scarlet_Jewel
delitem 532,1; //Banana_Juice delitem 532,1; //Banana_Juice
delitem 921,50; //Mushroom_Spore delitem 921,50; //Mushroom_Spore
skill "MC_LOUD",1,0; skill "MC_LOUD",1,SKILL_PERM;
mes "[Necko]"; mes "[Necko]";
mes "You have learned Crazy Uproar!!"; mes "You have learned Crazy Uproar!!";
mes "Shout as much as you wish!"; mes "Shout as much as you wish!";
@ -223,7 +223,7 @@ alberta,119,221,6 script Charlron 107,{
delitem 1019,50; //Wooden_Block delitem 1019,50; //Wooden_Block
delitem 998,10; //Iron delitem 998,10; //Iron
delitem 919,20; //Animal's_Skin delitem 919,20; //Animal's_Skin
skill "MC_CHANGECART",1,0; skill "MC_CHANGECART",1,SKILL_PERM;
mes "[Charlron]"; mes "[Charlron]";
mes "Congratulations."; mes "Congratulations.";
mes "You can choose a cart"; mes "You can choose a cart";
@ -376,7 +376,7 @@ alberta,119,221,6 script Charlron 107,{
delitem 938,30; //Sticky_Mucus delitem 938,30; //Sticky_Mucus
delitem 601,20; //Wing_Of_Fly delitem 601,20; //Wing_Of_Fly
delitem 962,5; //Tentacle delitem 962,5; //Tentacle
skill "MC_CARTREVOLUTION",1,0; skill "MC_CARTREVOLUTION",1,SKILL_PERM;
mes "Now you can use Cart Revolution"; mes "Now you can use Cart Revolution";
mes "I expect you to make merchants"; mes "I expect you to make merchants";
mes "famous by using this amazing"; mes "famous by using this amazing";
@ -448,7 +448,7 @@ alberta,119,221,6 script Charlron 107,{
delitem 938,25; //Sticky_Mucus delitem 938,25; //Sticky_Mucus
delitem 601,15; //Wing_Of_Fly delitem 601,15; //Wing_Of_Fly
delitem 962,5; //Tentacle delitem 962,5; //Tentacle
skill "MC_CARTREVOLUTION",1,0; skill "MC_CARTREVOLUTION",1,SKILL_PERM;
mes "Now you can use Cart Revolution"; mes "Now you can use Cart Revolution";
mes "I expect you to make merchants"; mes "I expect you to make merchants";
mes "famous by using its amazing"; mes "famous by using its amazing";
@ -521,7 +521,7 @@ alberta,119,221,6 script Charlron 107,{
delitem 938,32; //Sticky_Mucus delitem 938,32; //Sticky_Mucus
delitem 601,23; //Wing_Of_Fly delitem 601,23; //Wing_Of_Fly
delitem 962,6; //Tentacle delitem 962,6; //Tentacle
skill "MC_CARTREVOLUTION",1,0; skill "MC_CARTREVOLUTION",1,SKILL_PERM;
mes "Now you can use Cart Revolution"; mes "Now you can use Cart Revolution";
mes "I expect you to make merchants"; mes "I expect you to make merchants";
mes "famous by using its amazing"; mes "famous by using its amazing";

View File

@ -59,8 +59,8 @@ prt_monk,270,198,3 script Apprentice Monk#qsk_mo 753,{
mes "tap-tap-tap-tap-tap-tap-tap-tap- tap-tap-tap-tap-tap-tap-tap-tap-"; mes "tap-tap-tap-tap-tap-tap-tap-tap- tap-tap-tap-tap-tap-tap-tap-tap-";
mes "tap-tap-tap-tap-tap-tap* *POKE*^000000"; mes "tap-tap-tap-tap-tap-tap* *POKE*^000000";
set MONK_SK,7; set MONK_SK,7;
skill "MO_KITRANSLATION",1,0; skill "MO_KITRANSLATION",1,SKILL_PERM;
skill "MO_BALKYOUNG",1,0; skill "MO_BALKYOUNG",1,SKILL_PERM;
next; next;
mes "[Monk]"; mes "[Monk]";
mes "It is done. Please"; mes "It is done. Please";
@ -147,7 +147,7 @@ prt_monk,270,198,3 script Apprentice Monk#qsk_mo 753,{
mes "times, but it is a means to an"; mes "times, but it is a means to an";
mes "end, and not an end in itself."; mes "end, and not an end in itself.";
set MONK_SK,3; set MONK_SK,3;
skill "MO_KITRANSLATION",1,0; skill "MO_KITRANSLATION",1,SKILL_PERM;
next; next;
mes "[Monk]"; mes "[Monk]";
mes "Our skills should not be"; mes "Our skills should not be";
@ -252,7 +252,7 @@ monk_test,316,69,5 script Monk#qsk_mo 823,{
mes "to do it since you've learned"; mes "to do it since you've learned";
mes "Spiritual Endowment."; mes "Spiritual Endowment.";
set MONK_SK,6; set MONK_SK,6;
skill "MO_BALKYOUNG",1,0; skill "MO_BALKYOUNG",1,SKILL_PERM;
next; next;
mes "[Monk]"; mes "[Monk]";
mes "Well, we've completed"; mes "Well, we've completed";

View File

@ -137,7 +137,7 @@ prt_in,234,133,4 script Nami 66,{
mes "and combine them together and. . ."; mes "and combine them together and. . .";
mes "Presto !!"; mes "Presto !!";
next; next;
skill "NV_FIRSTAID",1,0; skill "NV_FIRSTAID",1,SKILL_PERM;
set skill_nov,3; set skill_nov,3;
mes "[Nami]"; mes "[Nami]";
mes "Yes yes, that's right!"; mes "Yes yes, that's right!";
@ -314,7 +314,7 @@ prt_in,73,87,4 script Chivalry Member 65,{
mes "Okay okay, See you around ! ! !"; mes "Okay okay, See you around ! ! !";
set skill_nov,6; set skill_nov,6;
delitem 7039,1; //Novice_Nametag delitem 7039,1; //Novice_Nametag
skill "NV_TRICKDEAD",1,0; skill "NV_TRICKDEAD",1,SKILL_PERM;
close; close;
} }
mes "[Bulma]"; mes "[Bulma]";

View File

@ -40,7 +40,7 @@ prt_church,111,112,1 script Sister Linus 79,{
mes "with your light. Give us the"; mes "with your light. Give us the";
mes "strength to walk the path of"; mes "strength to walk the path of";
mes "love and sacrifice. Redemptio!^000000"; mes "love and sacrifice. Redemptio!^000000";
skill "PR_REDEMPTIO",1,0; skill "PR_REDEMPTIO",1,SKILL_PERM;
next; next;
mes "[Sister Linus]"; mes "[Sister Linus]";
mes "There..."; mes "There...";
@ -310,7 +310,7 @@ prt_church,111,112,1 script Sister Linus 79,{
delitem 717,20; //Blue_Gemstone delitem 717,20; //Blue_Gemstone
delitem 523,30; //Holy_Water delitem 523,30; //Holy_Water
set PRIEST_SK,100; set PRIEST_SK,100;
skill "PR_REDEMPTIO",1,0; skill "PR_REDEMPTIO",1,SKILL_PERM;
close; close;
} }
else { else {

View File

@ -140,7 +140,7 @@ in_rogue,355,179,0 script Haijara Greg#rogueguild 46,{
mes "eh? Then I will teach you the"; mes "eh? Then I will teach you the";
mes "Close Confine skill once again."; mes "Close Confine skill once again.";
specialeffect2 EF_LIGHTSPHERE; specialeffect2 EF_LIGHTSPHERE;
skill "RG_CLOSECONFINE",1,0; skill "RG_CLOSECONFINE",1,SKILL_PERM;
set ROG_SK,13; set ROG_SK,13;
close; close;
} }
@ -493,7 +493,7 @@ in_rogue,355,179,0 script Haijara Greg#rogueguild 46,{
mes "more about this skill through"; mes "more about this skill through";
mes "practice, and that you become as great a legend as Chae Takbae."; mes "practice, and that you become as great a legend as Chae Takbae.";
set ROG_SK,12; set ROG_SK,12;
skill "RG_CLOSECONFINE",1,0; skill "RG_CLOSECONFINE",1,SKILL_PERM;
specialeffect2 EF_LIGHTSPHERE; specialeffect2 EF_LIGHTSPHERE;
close; close;
} }
@ -505,7 +505,7 @@ in_rogue,355,179,0 script Haijara Greg#rogueguild 46,{
mes "practice. Good luck, and"; mes "practice. Good luck, and";
mes "thanks again for your help."; mes "thanks again for your help.";
set ROG_SK,12; set ROG_SK,12;
skill "RG_CLOSECONFINE",1,0; skill "RG_CLOSECONFINE",1,SKILL_PERM;
specialeffect2 EF_LIGHTSPHERE; specialeffect2 EF_LIGHTSPHERE;
close; close;
} }

View File

@ -117,9 +117,9 @@ yuno_in03,176,24,3 script Mischna 755,{
mes "learned the "+.@Skill$[.@i]+" Elemental"; mes "learned the "+.@Skill$[.@i]+" Elemental";
mes "Change skill and the Elemental"; mes "Change skill and the Elemental";
mes "Converter Creation skill.^000000"; mes "Converter Creation skill.^000000";
skill .@Skill[.@i],1,0; skill .@Skill[.@i],1,SKILL_PERM;
if(.@Convert == 0) if(.@Convert == 0)
skill "SA_CREATECON",1,0; skill "SA_CREATECON",1,SKILL_PERM;
next; next;
break; break;
} }
@ -146,7 +146,7 @@ yuno_in03,176,24,3 script Mischna 755,{
mes "the Elemental Coverter"; mes "the Elemental Coverter";
mes "Creation skill and are"; mes "Creation skill and are";
mes "able to use it again.^000000"; mes "able to use it again.^000000";
skill "SA_CREATECON",1,0; skill "SA_CREATECON",1,SKILL_PERM;
next; next;
} }
mes "[Mishuna]"; mes "[Mishuna]";
@ -316,7 +316,7 @@ yuno_in03,176,24,3 script Mischna 755,{
delitem 946,10; // Snail's_Shell delitem 946,10; // Snail's_Shell
delitem 7433,4; // Blank_Scroll delitem 7433,4; // Blank_Scroll
set SAG_SK,2; set SAG_SK,2;
skill "SA_CREATECON",1,0; skill "SA_CREATECON",1,SKILL_PERM;
next; next;
mes "[Mishuna]"; mes "[Mishuna]";
mes "Wow, "+strcharinfo(0)+"!"; mes "Wow, "+strcharinfo(0)+"!";
@ -337,7 +337,7 @@ yuno_in03,176,24,3 script Mischna 755,{
} }
else if(SAG_SK == 2) { else if(SAG_SK == 2) {
if(getskilllv("SA_CREATECON") == 0) { if(getskilllv("SA_CREATECON") == 0) {
skill "SA_CREATECON",1,0; skill "SA_CREATECON",1,SKILL_PERM;
mes "- I recalled ^ff0000Elemental Converter Creation skill^000000 While I talk to Mishuna! -"; mes "- I recalled ^ff0000Elemental Converter Creation skill^000000 While I talk to Mishuna! -";
next; next;
} }
@ -389,7 +389,7 @@ yuno_in03,176,24,3 script Mischna 755,{
} }
else if(SAG_SK == 10 || SAG_SK == 20 || SAG_SK == 30 || SAG_SK == 40) { else if(SAG_SK == 10 || SAG_SK == 20 || SAG_SK == 30 || SAG_SK == 40) {
if(getskilllv("SA_CREATECON") == 0) { if(getskilllv("SA_CREATECON") == 0) {
skill "SA_CREATECON",1,0; skill "SA_CREATECON",1,SKILL_PERM;
mes "- I recalled ^ff0000Elemental Converter Creation skill^000000 While I talk to Mishuna! -"; mes "- I recalled ^ff0000Elemental Converter Creation skill^000000 While I talk to Mishuna! -";
next; next;
} }

View File

@ -43,7 +43,7 @@
next; next;
delitem 713,200; //Empty_Bottle delitem 713,200; //Empty_Bottle
delitem 1058,1; //Wing_Of_Moth delitem 1058,1; //Wing_Of_Moth
skill "SM_MOVINGRECOVERY",1,0; skill "SM_MOVINGRECOVERY",1,SKILL_PERM;
mes "[De Thomas]"; mes "[De Thomas]";
mes "There you go!"; mes "There you go!";
mes "Try it yourself."; mes "Try it yourself.";
@ -176,7 +176,7 @@ prt_in,75,88,5 script Leon Von Frich 85,3,3,{
delitem 532,1; //Banana_Juice delitem 532,1; //Banana_Juice
delitem 962,30; //Tentacle delitem 962,30; //Tentacle
delitem 526,5; //Royal_Jelly delitem 526,5; //Royal_Jelly
skill "SM_FATALBLOW",1,0; skill "SM_FATALBLOW",1,SKILL_PERM;
mes "[Leon]"; mes "[Leon]";
mes "Success!"; mes "Success!";
mes "Go use your new skill to its full potential."; mes "Go use your new skill to its full potential.";
@ -342,7 +342,7 @@ prt_in,94,57,3 script Juan 85,4,4,{
delitem 958,10; //Horrendous_Mouth delitem 958,10; //Horrendous_Mouth
delitem 957,10; //Decayed_Nail delitem 957,10; //Decayed_Nail
delitem 518,10; //Honey delitem 518,10; //Honey
skill "SM_AUTOBERSERK",1,0; skill "SM_AUTOBERSERK",1,SKILL_PERM;
mes "[Juan]"; mes "[Juan]";
mes "You have just become a swordsman"; mes "You have just become a swordsman";
mes "that can use Auto Berserk."; mes "that can use Auto Berserk.";

View File

@ -148,7 +148,7 @@ moc_prydb1,154,128,4 script Alcouskou 118,{
mes "I hope that this skill will"; mes "I hope that this skill will";
mes "aid you in the future. -"; mes "aid you in the future. -";
delitem 7042,1; //Leather_Bag_Of_Infinity delitem 7042,1; //Leather_Bag_Of_Infinity
skill "TF_SPRINKLESAND",1,0; skill "TF_SPRINKLESAND",1,SKILL_PERM;
close; close;
} }
case 2: case 2:
@ -170,7 +170,7 @@ moc_prydb1,154,128,4 script Alcouskou 118,{
mes "I am sure you can increase"; mes "I am sure you can increase";
mes "your skill on your own."; mes "your skill on your own.";
delitem 940,20; //Grasshopper's_Leg delitem 940,20; //Grasshopper's_Leg
skill "TF_BACKSLIDING",1,0; skill "TF_BACKSLIDING",1,SKILL_PERM;
close; close;
} }
mes "[Alcouskou]"; mes "[Alcouskou]";
@ -262,7 +262,7 @@ moc_prydb1,154,128,4 script Alcouskou 118,{
delitem 912,1; //Zargon delitem 912,1; //Zargon
delitem 948,1; //Bear's_Foot delitem 948,1; //Bear's_Foot
delitem 908,5; //Spawn delitem 908,5; //Spawn
skill "TF_PICKSTONE",1,0; skill "TF_PICKSTONE",1,SKILL_PERM;
close; close;
} }
mes "[Alcouskou]"; mes "[Alcouskou]";
@ -344,7 +344,7 @@ moc_prydb1,154,128,4 script Alcouskou 118,{
mes "I wish you luck!"; mes "I wish you luck!";
delitem 910,2; //Garlet delitem 910,2; //Garlet
delitem 911,2; //Scell delitem 911,2; //Scell
skill "TF_THROWSTONE",1,0; skill "TF_THROWSTONE",1,SKILL_PERM;
close; close;
} }
mes "[Alcouskou]"; mes "[Alcouskou]";

View File

@ -42,7 +42,7 @@ gef_tower,115,36,4 script Meow#q_wiz 876,{
mes "Meow can administer another"; mes "Meow can administer another";
mes "vicious beating to you."; mes "vicious beating to you.";
specialeffect2 EF_ABSORBSPIRITS; specialeffect2 EF_ABSORBSPIRITS;
skill "WZ_SIGHTBLASTER",1,0; skill "WZ_SIGHTBLASTER",1,SKILL_PERM;
next; next;
mes "[Meow]"; mes "[Meow]";
mes "Remember now?"; mes "Remember now?";
@ -295,7 +295,7 @@ gef_tower,115,36,4 script Meow#q_wiz 876,{
delitem 990,10; //Boody_Red delitem 990,10; //Boody_Red
delitem 992,10; //Wind_Of_Verdure delitem 992,10; //Wind_Of_Verdure
set WIZ_SK,100; set WIZ_SK,100;
skill "WZ_SIGHTBLASTER",1,0; skill "WZ_SIGHTBLASTER",1,SKILL_PERM;
next; next;
mes "[Meow]"; mes "[Meow]";
mes "I'm so tired from all of"; mes "I'm so tired from all of";

View File

@ -39,9 +39,9 @@ prt_church,184,41,4 script Cleric#aco 60,{
mes "wish you luck on your"; mes "wish you luck on your";
mes "new life's journey."; mes "new life's journey.";
next; next;
skill "NV_TRICKDEAD",0,0; skill "NV_TRICKDEAD",0,SKILL_PERM;
jobchange Job_Acolyte_High; jobchange Job_Acolyte_High;
skill "AL_HOLYLIGHT",1,0; skill "AL_HOLYLIGHT",1,SKILL_PERM;
mes "[Father Mareusis]"; mes "[Father Mareusis]";
mes "Now, venture forth and seek those who need your help. May God light your path."; mes "Now, venture forth and seek those who need your help. May God light your path.";
close; close;

View File

@ -39,10 +39,10 @@ payon_in02,64,71,4 script Archer Guildsman#archer 85,{
mes "need to say anything else."; mes "need to say anything else.";
mes "I know you'll make a great Archer..."; mes "I know you'll make a great Archer...";
next; next;
skill "NV_TRICKDEAD",0,0; skill "NV_TRICKDEAD",0,SKILL_PERM;
jobchange Job_Archer_high; jobchange Job_Archer_high;
skill "AC_MAKINGARROW",1,0; skill "AC_MAKINGARROW",1,SKILL_PERM;
skill "AC_CHARGEARROW",1,0; skill "AC_CHARGEARROW",1,SKILL_PERM;
mes "[Archer Guildsman]"; mes "[Archer Guildsman]";
mes "Although there's no special"; mes "Although there's no special";
mes "reward for you this time, I hope you understand. Take care of yourself."; mes "reward for you this time, I hope you understand. Take care of yourself.";

View File

@ -33,9 +33,9 @@ geffen_in,164,124,4 script Mage Guildsman#mage 123,{
mes "[Mage Guildsman]"; mes "[Mage Guildsman]";
mes "Well, since you have passed the Mage test once, I will not question your qualification. You want to have your magic skills back immediately, don't you?"; mes "Well, since you have passed the Mage test once, I will not question your qualification. You want to have your magic skills back immediately, don't you?";
next; next;
skill "NV_TRICKDEAD",0,0; skill "NV_TRICKDEAD",0,SKILL_PERM;
jobchange Job_Mage_High; jobchange Job_Mage_High;
skill "MG_ENERGYCOAT",1,0; skill "MG_ENERGYCOAT",1,SKILL_PERM;
mes "[Mage Guildsman]"; mes "[Mage Guildsman]";
mes "Wow, for some reason, you look way better than you did before. Anyway, I believe you will do a better job being a Mage as well."; mes "Wow, for some reason, you look way better than you did before. Anyway, I believe you will do a better job being a Mage as well.";
close; close;

View File

@ -37,11 +37,11 @@ alberta_in,53,43,6 script Merchant#mer 86,{
mes "[Chief Mahnsoo]"; mes "[Chief Mahnsoo]";
mes "I guess it's destiny that we meet like this once more. Alright. Once again, let me change you into a Merchant!"; mes "I guess it's destiny that we meet like this once more. Alright. Once again, let me change you into a Merchant!";
next; next;
skill "NV_TRICKDEAD",0,0; skill "NV_TRICKDEAD",0,SKILL_PERM;
jobchange Job_Merchant_High; jobchange Job_Merchant_High;
skill "MC_CARTREVOLUTION",1,0; skill "MC_CARTREVOLUTION",1,SKILL_PERM;
skill "MC_CHANGECART",1,0; skill "MC_CHANGECART",1,SKILL_PERM;
skill "MC_LOUD",1,0; skill "MC_LOUD",1,SKILL_PERM;
mes "[Chief Mahnsoo]"; mes "[Chief Mahnsoo]";
mes "Ah~ How nostalgic. Just like old times! Alright, do your best!"; mes "Ah~ How nostalgic. Just like old times! Alright, do your best!";
close; close;

View File

@ -34,11 +34,11 @@ izlude_in,74,172,4 script Swordman#swd 119,{
mes "[Swordman]"; mes "[Swordman]";
mes "Excellent! Let me promote you to a Swordman right away!"; mes "Excellent! Let me promote you to a Swordman right away!";
next; next;
skill "NV_TRICKDEAD",0,0; skill "NV_TRICKDEAD",0,SKILL_PERM;
jobchange Job_Swordman_High; jobchange Job_Swordman_High;
skill "SM_MOVINGRECOVERY",1,0; skill "SM_MOVINGRECOVERY",1,SKILL_PERM;
skill "SM_FATALBLOW",1,0; skill "SM_FATALBLOW",1,SKILL_PERM;
skill "SM_AUTOBERSERK",1,0; skill "SM_AUTOBERSERK",1,SKILL_PERM;
mes "[Swordman]"; mes "[Swordman]";
mes "Hmm... You look like a well-experienced Swordman. Still, I'm sure that you must train to improve your skills and gain strength!"; mes "Hmm... You look like a well-experienced Swordman. Still, I'm sure that you must train to improve your skills and gain strength!";
close; close;

View File

@ -30,12 +30,12 @@ moc_prydb1,39,129,2 script Thief Guide#thief 69,{
mes "[Thief Guide]"; mes "[Thief Guide]";
mes "Well, I got this feeling like you've been through a lifetime of fighting, so I'm promoting you to a Thief right this minute. I better give you tough guys what you want..."; mes "Well, I got this feeling like you've been through a lifetime of fighting, so I'm promoting you to a Thief right this minute. I better give you tough guys what you want...";
next; next;
skill "NV_TRICKDEAD",0,0; skill "NV_TRICKDEAD",0,SKILL_PERM;
jobchange Job_Thief_High; jobchange Job_Thief_High;
skill "TF_SPRINKLESAND",1,0; skill "TF_SPRINKLESAND",1,SKILL_PERM;
skill "TF_BACKSLIDING",1,0; skill "TF_BACKSLIDING",1,SKILL_PERM;
skill "TF_PICKSTONE",1,0; skill "TF_PICKSTONE",1,SKILL_PERM;
skill "TF_THROWSTONE",1,0; skill "TF_THROWSTONE",1,SKILL_PERM;
mes "[Thief Guide]"; mes "[Thief Guide]";
mes "Since you've become a Thief, live as a Thief. Now, go for it! Next~"; mes "Since you've become a Thief, live as a Thief. Now, go for it! Next~";
close; close;

View File

@ -539,7 +539,7 @@ new_5-2,100,105,3 duplicate(NvBradeA) Brade#nv5a 733
mes "You can open the Skill Window by pressing the ^4d4dffskill^000000 button in the Basic Window."; mes "You can open the Skill Window by pressing the ^4d4dffskill^000000 button in the Basic Window.";
mes "Hot Key is ^4d4dffALT + S^000000."; mes "Hot Key is ^4d4dffALT + S^000000.";
mes "Why don't you try the skill?"; mes "Why don't you try the skill?";
skill "NV_FIRSTAID",1,0; skill "NV_FIRSTAID",1,SKILL_PERM;
set skill_nov,3; // Has future uses - do not remove! [Euphy] set skill_nov,3; // Has future uses - do not remove! [Euphy]
set job_novice_q,6; set job_novice_q,6;
next; next;

View File

@ -0,0 +1,6 @@
-- Resetting all `lv` of skills that has `flag` >= 3 (the skill that its `learned_lv` has been changed by script or special case by `learned_lv` + SKILL_FLAG_REPLACED_LV_0)
-- If there's ALL_INCCARRY and ALL_BUYING_STORE, set the `flag` to SKILL_FLAG_PERM_GRANTED (new value is 3), those are exclusive skills given in our official scripts!
UPDATE `skill` SET `lv` = `flag` - 3 WHERE `flag` >= 3;
UPDATE `skill` SET `flag` = 0 WHERE `flag` >= 3;
UPDATE `skill` SET `flag` = 3 WHERE `id` = 681 OR `id` = 2535;

View File

@ -434,12 +434,6 @@ int char_mmo_char_tosql(uint32 char_id, struct mmo_charstatus* p){
strcat(save_status, " memo"); strcat(save_status, " memo");
} }
//FIXME: is this neccessary? [ultramage]
for(i=0;i<MAX_SKILL;i++)
if ((p->skill[i].lv != 0) && (p->skill[i].id == 0))
p->skill[i].id = i; // Fix skill tree
//skills //skills
if( memcmp(p->skill, cp->skill, sizeof(p->skill)) ) if( memcmp(p->skill, cp->skill, sizeof(p->skill)) )
{ {
@ -944,7 +938,6 @@ int char_mmo_chars_fromsql(struct char_session_data* sd, uint8* buf) {
//===================================================================================================== //=====================================================================================================
int char_mmo_char_fromsql(uint32 char_id, struct mmo_charstatus* p, bool load_everything) { int char_mmo_char_fromsql(uint32 char_id, struct mmo_charstatus* p, bool load_everything) {
int i,j; int i,j;
char t_msg[128] = "";
struct mmo_charstatus* cp; struct mmo_charstatus* cp;
StringBuf buf; StringBuf buf;
SqlStmt* stmt; SqlStmt* stmt;
@ -954,11 +947,13 @@ int char_mmo_char_fromsql(uint32 char_id, struct mmo_charstatus* p, bool load_ev
struct point tmp_point; struct point tmp_point;
struct item tmp_item; struct item tmp_item;
struct s_skill tmp_skill; struct s_skill tmp_skill;
uint16 skill_count = 0;
struct s_friend tmp_friend; struct s_friend tmp_friend;
#ifdef HOTKEY_SAVING #ifdef HOTKEY_SAVING
struct hotkey tmp_hotkey; struct hotkey tmp_hotkey;
int hotkey_num; int hotkey_num;
#endif #endif
StringBuf msg_buf;
memset(p, 0, sizeof(struct mmo_charstatus)); memset(p, 0, sizeof(struct mmo_charstatus));
@ -1065,11 +1060,13 @@ int char_mmo_char_fromsql(uint32 char_id, struct mmo_charstatus* p, bool load_ev
p->save_point.y = charserv_config.default_map_y; p->save_point.y = charserv_config.default_map_y;
} }
strcat(t_msg, " status"); StringBuf_Init(&msg_buf);
StringBuf_AppendStr(&msg_buf, " status");
if (!load_everything) // For quick selection of data when displaying the char menu if (!load_everything) // For quick selection of data when displaying the char menu
{ {
SqlStmt_Free(stmt); SqlStmt_Free(stmt);
StringBuf_Destroy(&msg_buf);
return 1; return 1;
} }
@ -1088,7 +1085,7 @@ int char_mmo_char_fromsql(uint32 char_id, struct mmo_charstatus* p, bool load_ev
tmp_point.map = mapindex_name2id(point_map); tmp_point.map = mapindex_name2id(point_map);
memcpy(&p->memo_point[i], &tmp_point, sizeof(tmp_point)); memcpy(&p->memo_point[i], &tmp_point, sizeof(tmp_point));
} }
strcat(t_msg, " memo"); StringBuf_AppendStr(&msg_buf, " memo");
//read inventory //read inventory
//`inventory` (`id`,`char_id`, `nameid`, `amount`, `equip`, `identify`, `refine`, `attribute`, `card0`, `card1`, `card2`, `card3`, `expire_time`, `favorite`, `unique_id`) //`inventory` (`id`,`char_id`, `nameid`, `amount`, `equip`, `identify`, `refine`, `attribute`, `card0`, `card1`, `card2`, `card3`, `expire_time`, `favorite`, `unique_id`)
@ -1120,7 +1117,7 @@ int char_mmo_char_fromsql(uint32 char_id, struct mmo_charstatus* p, bool load_ev
for( i = 0; i < MAX_INVENTORY && SQL_SUCCESS == SqlStmt_NextRow(stmt); ++i ) for( i = 0; i < MAX_INVENTORY && SQL_SUCCESS == SqlStmt_NextRow(stmt); ++i )
memcpy(&p->inventory[i], &tmp_item, sizeof(tmp_item)); memcpy(&p->inventory[i], &tmp_item, sizeof(tmp_item));
strcat(t_msg, " inventory"); StringBuf_AppendStr(&msg_buf, " inventory");
//read cart //read cart
//`cart_inventory` (`id`,`char_id`, `nameid`, `amount`, `equip`, `identify`, `refine`, `attribute`, `card0`, `card1`, `card2`, `card3`, expire_time`, `unique_id`) //`cart_inventory` (`id`,`char_id`, `nameid`, `amount`, `equip`, `identify`, `refine`, `attribute`, `card0`, `card1`, `card2`, `card3`, expire_time`, `unique_id`)
@ -1150,33 +1147,34 @@ int char_mmo_char_fromsql(uint32 char_id, struct mmo_charstatus* p, bool load_ev
for( i = 0; i < MAX_CART && SQL_SUCCESS == SqlStmt_NextRow(stmt); ++i ) for( i = 0; i < MAX_CART && SQL_SUCCESS == SqlStmt_NextRow(stmt); ++i )
memcpy(&p->cart[i], &tmp_item, sizeof(tmp_item)); memcpy(&p->cart[i], &tmp_item, sizeof(tmp_item));
strcat(t_msg, " cart"); StringBuf_AppendStr(&msg_buf, " cart");
//read storage //read storage
storage_fromsql(p->account_id, &p->storage); storage_fromsql(p->account_id, &p->storage);
strcat(t_msg, " storage"); StringBuf_AppendStr(&msg_buf, " storage");
//read skill //read skill
//`skill` (`char_id`, `id`, `lv`) //`skill` (`char_id`, `id`, `lv`)
if( SQL_ERROR == SqlStmt_Prepare(stmt, "SELECT `id`, `lv`,`flag` FROM `%s` WHERE `char_id`=? LIMIT %d", schema_config.skill_db, MAX_SKILL) if( SQL_ERROR == SqlStmt_Prepare(stmt, "SELECT `id`, `lv`,`flag` FROM `%s` WHERE `char_id`=? LIMIT %d", schema_config.skill_db, MAX_SKILL)
|| SQL_ERROR == SqlStmt_BindParam(stmt, 0, SQLDT_INT, &char_id, 0) || SQL_ERROR == SqlStmt_BindParam(stmt, 0, SQLDT_INT, &char_id, 0)
|| SQL_ERROR == SqlStmt_Execute(stmt) || SQL_ERROR == SqlStmt_Execute(stmt)
|| SQL_ERROR == SqlStmt_BindColumn(stmt, 0, SQLDT_USHORT, &tmp_skill.id , 0, NULL, NULL) || SQL_ERROR == SqlStmt_BindColumn(stmt, 0, SQLDT_UINT16, &tmp_skill.id , 0, NULL, NULL)
|| SQL_ERROR == SqlStmt_BindColumn(stmt, 1, SQLDT_UCHAR , &tmp_skill.lv , 0, NULL, NULL) || SQL_ERROR == SqlStmt_BindColumn(stmt, 1, SQLDT_UINT8 , &tmp_skill.lv , 0, NULL, NULL)
|| SQL_ERROR == SqlStmt_BindColumn(stmt, 2, SQLDT_UCHAR , &tmp_skill.flag, 0, NULL, NULL) ) || SQL_ERROR == SqlStmt_BindColumn(stmt, 2, SQLDT_UINT8 , &tmp_skill.flag, 0, NULL, NULL) )
SqlStmt_ShowDebug(stmt); SqlStmt_ShowDebug(stmt);
if( tmp_skill.flag != SKILL_FLAG_PERM_GRANTED ) if( tmp_skill.flag != SKILL_FLAG_PERM_GRANTED )
tmp_skill.flag = SKILL_FLAG_PERMANENT; tmp_skill.flag = SKILL_FLAG_PERMANENT;
for( i = 0; i < MAX_SKILL && SQL_SUCCESS == SqlStmt_NextRow(stmt); ++i ) for( i = 0; skill_count < MAX_SKILL && SQL_SUCCESS == SqlStmt_NextRow(stmt); i++ ) {
{ if( tmp_skill.id > 0 && tmp_skill.id < MAX_SKILL_ID ) {
if( tmp_skill.id < ARRAYLENGTH(p->skill) ) memcpy(&p->skill[i], &tmp_skill, sizeof(tmp_skill));
memcpy(&p->skill[tmp_skill.id], &tmp_skill, sizeof(tmp_skill)); skill_count++;
}
else else
ShowWarning("mmo_char_fromsql: ignoring invalid skill (id=%u,lv=%u) of character %s (AID=%d,CID=%d)\n", tmp_skill.id, tmp_skill.lv, p->name, p->account_id, p->char_id); ShowWarning("mmo_char_fromsql: ignoring invalid skill (id=%u,lv=%u) of character %s (AID=%d,CID=%d)\n", tmp_skill.id, tmp_skill.lv, p->name, p->account_id, p->char_id);
} }
strcat(t_msg, " skills"); StringBuf_Printf(&msg_buf, " %d skills", skill_count);
//read friends //read friends
//`friends` (`char_id`, `friend_account`, `friend_id`) //`friends` (`char_id`, `friend_account`, `friend_id`)
@ -1190,7 +1188,7 @@ int char_mmo_char_fromsql(uint32 char_id, struct mmo_charstatus* p, bool load_ev
for( i = 0; i < MAX_FRIENDS && SQL_SUCCESS == SqlStmt_NextRow(stmt); ++i ) for( i = 0; i < MAX_FRIENDS && SQL_SUCCESS == SqlStmt_NextRow(stmt); ++i )
memcpy(&p->friends[i], &tmp_friend, sizeof(tmp_friend)); memcpy(&p->friends[i], &tmp_friend, sizeof(tmp_friend));
strcat(t_msg, " friends"); StringBuf_AppendStr(&msg_buf, " friends");
#ifdef HOTKEY_SAVING #ifdef HOTKEY_SAVING
//read hotkeys //read hotkeys
@ -1211,20 +1209,21 @@ int char_mmo_char_fromsql(uint32 char_id, struct mmo_charstatus* p, bool load_ev
else else
ShowWarning("mmo_char_fromsql: ignoring invalid hotkey (hotkey=%d,type=%u,id=%u,lv=%u) of character %s (AID=%d,CID=%d)\n", hotkey_num, tmp_hotkey.type, tmp_hotkey.id, tmp_hotkey.lv, p->name, p->account_id, p->char_id); ShowWarning("mmo_char_fromsql: ignoring invalid hotkey (hotkey=%d,type=%u,id=%u,lv=%u) of character %s (AID=%d,CID=%d)\n", hotkey_num, tmp_hotkey.type, tmp_hotkey.id, tmp_hotkey.lv, p->name, p->account_id, p->char_id);
} }
strcat(t_msg, " hotkeys"); StringBuf_AppendStr(&msg_buf, " hotkeys");
#endif #endif
/* Mercenary Owner DataBase */ /* Mercenary Owner DataBase */
mercenary_owner_fromsql(char_id, p); mercenary_owner_fromsql(char_id, p);
strcat(t_msg, " mercenary"); StringBuf_AppendStr(&msg_buf, " mercenary");
if (charserv_config.save_log) ShowInfo("Loaded char (%d - %s): %s\n", char_id, p->name, t_msg); //ok. all data load successfuly! if (charserv_config.save_log) ShowInfo("Loaded char (%d - %s): %s\n", char_id, p->name, StringBuf_Value(&msg_buf)); //ok. all data load successfuly!
SqlStmt_Free(stmt); SqlStmt_Free(stmt);
StringBuf_Destroy(&buf); StringBuf_Destroy(&buf);
cp = idb_ensure(char_db_, char_id, char_create_charstatus); cp = idb_ensure(char_db_, char_id, char_create_charstatus);
memcpy(cp, p, sizeof(struct mmo_charstatus)); memcpy(cp, p, sizeof(struct mmo_charstatus));
StringBuf_Destroy(&msg_buf);
return 1; return 1;
} }

View File

@ -55,7 +55,7 @@
#define MAX_BANK_ZENY SINT32_MAX ///Max zeny in Bank #define MAX_BANK_ZENY SINT32_MAX ///Max zeny in Bank
#define MAX_FAME 1000000000 ///Max fame points #define MAX_FAME 1000000000 ///Max fame points
#define MAX_CART 100 ///Maximum item in cart #define MAX_CART 100 ///Maximum item in cart
#define MAX_SKILL 5020 ///Maximum skill data #define MAX_SKILL 1200 ///Maximum skill can be hold by Player, Homunculus, & Mercenary (skill list) AND skill_db limit
#define GLOBAL_REG_NUM 256 ///Max permanent character variables per char #define GLOBAL_REG_NUM 256 ///Max permanent character variables per char
#define ACCOUNT_REG_NUM 64 ///Max permanent local account variables per account #define ACCOUNT_REG_NUM 64 ///Max permanent local account variables per account
#define ACCOUNT_REG2_NUM 16 ///Max permanent global account variables per account #define ACCOUNT_REG2_NUM 16 ///Max permanent global account variables per account
@ -224,10 +224,11 @@ enum e_skill_flag
SKILL_FLAG_PERMANENT, SKILL_FLAG_PERMANENT,
SKILL_FLAG_TEMPORARY, SKILL_FLAG_TEMPORARY,
SKILL_FLAG_PLAGIARIZED, SKILL_FLAG_PLAGIARIZED,
SKILL_FLAG_REPLACED_LV_0, // temporary skill overshadowing permanent skill of level 'N - SKILL_FLAG_REPLACED_LV_0', SKILL_FLAG_PERM_GRANTED, // Permanent, granted through someway e.g. script
SKILL_FLAG_PERM_GRANTED, // permanent, granted through someway e.g. script SKILL_FLAG_TMP_COMBO, //@FIXME for homunculus combo atm
SKILL_FLAG_TMP_COMBO, //@FIXME for homon combo atm
//... //! NOTE: This flag be the last flag, and don't change the value if not needed!
SKILL_FLAG_REPLACED_LV_0 = 10, // temporary skill overshadowing permanent skill of level 'N - SKILL_FLAG_REPLACED_LV_0',
}; };
enum e_mmo_charstatus_opt { enum e_mmo_charstatus_opt {
@ -237,9 +238,9 @@ enum e_mmo_charstatus_opt {
}; };
struct s_skill { struct s_skill {
unsigned short id; uint16 id;
unsigned char lv; uint8 lv;
unsigned char flag; // see enum e_skill_flag uint8 flag; // see enum e_skill_flag
}; };
struct global_reg { struct global_reg {
@ -633,6 +634,7 @@ enum e_guild_skill {
GD_MAX, GD_MAX,
}; };
#define MAX_SKILL_ID GD_MAX
//These mark the ID of the jobs, as expected by the client. [Skotlex] //These mark the ID of the jobs, as expected by the client. [Skotlex]
enum e_job { enum e_job {

View File

@ -32,6 +32,7 @@
#include "trade.h" #include "trade.h"
#include "mapreg.h" #include "mapreg.h"
#include "quest.h" #include "quest.h"
#include "pc.h"
#include <stdlib.h> #include <stdlib.h>
#include <math.h> #include <math.h>
@ -3250,7 +3251,7 @@ ACMD_FUNC(questskill)
return -1; return -1;
} }
if (skill_id >= MAX_SKILL_DB) { if (skill_id >= MAX_SKILL_ID) {
clif_displaymessage(fd, msg_txt(sd,198)); // This skill number doesn't exist. clif_displaymessage(fd, msg_txt(sd,198)); // This skill number doesn't exist.
return -1; return -1;
} }
@ -3263,7 +3264,7 @@ ACMD_FUNC(questskill)
return -1; return -1;
} }
pc_skill(sd, skill_id, 1, 0); pc_skill(sd, skill_id, 1, ADDSKILL_PERMANENT);
clif_displaymessage(fd, msg_txt(sd,70)); // You have learned the skill. clif_displaymessage(fd, msg_txt(sd,70)); // You have learned the skill.
return 0; return 0;
@ -3274,7 +3275,7 @@ ACMD_FUNC(questskill)
*------------------------------------------*/ *------------------------------------------*/
ACMD_FUNC(lostskill) ACMD_FUNC(lostskill)
{ {
uint16 skill_id; uint16 skill_id = 0, sk_idx = 0;
nullpo_retr(-1, sd); nullpo_retr(-1, sd);
if (!message || !*message || (skill_id = atoi(message)) <= 0) if (!message || !*message || (skill_id = atoi(message)) <= 0)
@ -3294,7 +3295,7 @@ ACMD_FUNC(lostskill)
return -1; return -1;
} }
if (skill_id >= MAX_SKILL) { if (!(sk_idx = skill_get_index(skill_id))) {
clif_displaymessage(fd, msg_txt(sd,198)); // This skill number doesn't exist. clif_displaymessage(fd, msg_txt(sd,198)); // This skill number doesn't exist.
return -1; return -1;
} }
@ -3307,8 +3308,8 @@ ACMD_FUNC(lostskill)
return -1; return -1;
} }
sd->status.skill[skill_id].lv = 0; sd->status.skill[sk_idx].lv = 0;
sd->status.skill[skill_id].flag = SKILL_FLAG_PERMANENT; sd->status.skill[sk_idx].flag = SKILL_FLAG_PERMANENT;
clif_deleteskill(sd,skill_id); clif_deleteskill(sd,skill_id);
clif_displaymessage(fd, msg_txt(sd,71)); // You have forgotten the skill. clif_displaymessage(fd, msg_txt(sd,71)); // You have forgotten the skill.
@ -5507,11 +5508,11 @@ ACMD_FUNC(skillid) {
for( data = iter->first(iter,&key); iter->exists(iter); data = iter->next(iter,&key) ) { for( data = iter->first(iter,&key); iter->exists(iter); data = iter->next(iter,&key) ) {
int idx = skill_get_index(db_data2i(data)); int idx = skill_get_index(db_data2i(data));
if (strnicmp(key.str, message, skillen) == 0 || strnicmp(skill_db[idx].desc, message, skillen) == 0) { if (strnicmp(key.str, message, skillen) == 0 || strnicmp(skill_db[idx]->desc, message, skillen) == 0) {
sprintf(atcmd_output, msg_txt(sd,1164), db_data2i(data), skill_db[idx].desc, key.str); // skill %d: %s (%s) sprintf(atcmd_output, msg_txt(sd,1164), db_data2i(data), skill_db[idx]->desc, key.str); // skill %d: %s (%s)
clif_displaymessage(fd, atcmd_output); clif_displaymessage(fd, atcmd_output);
} else if ( found < MAX_SKILLID_PARTIAL_RESULTS && ( stristr(key.str,message) || stristr(skill_db[idx].desc,message) ) ) { } else if ( found < MAX_SKILLID_PARTIAL_RESULTS && ( stristr(key.str,message) || stristr(skill_db[idx]->desc,message) ) ) {
snprintf(partials[found++], MAX_SKILLID_PARTIAL_RESULTS_LEN, msg_txt(sd,1164), db_data2i(data), skill_db[idx].desc, key.str); snprintf(partials[found++], MAX_SKILLID_PARTIAL_RESULTS_LEN, msg_txt(sd,1164), db_data2i(data), skill_db[idx]->desc, key.str);
} }
} }
@ -5559,7 +5560,7 @@ ACMD_FUNC(useskill)
return -1; return -1;
} }
if (skill_id >= HM_SKILLBASE && skill_id < HM_SKILLBASE+MAX_HOMUNSKILL if (SKILL_CHK_HOMUN(skill_id)
&& sd->hd && hom_is_active(sd->hd)) // (If used with @useskill, put the homunc as dest) && sd->hd && hom_is_active(sd->hd)) // (If used with @useskill, put the homunc as dest)
bl = &sd->hd->bl; bl = &sd->hd->bl;
else else
@ -5643,7 +5644,7 @@ ACMD_FUNC(skilltree)
{ {
if( ent->need[j].id && pc_checkskill(sd,ent->need[j].id) < ent->need[j].lv) if( ent->need[j].id && pc_checkskill(sd,ent->need[j].id) < ent->need[j].lv)
{ {
sprintf(atcmd_output, msg_txt(sd,1170), ent->need[j].lv, skill_db[ent->need[j].id].desc); // Player requires level %d of skill %s. sprintf(atcmd_output, msg_txt(sd,1170), ent->need[j].lv, skill_db[skill_get_index(ent->need[j].id)]->desc); // Player requires level %d of skill %s.
clif_displaymessage(fd, atcmd_output); clif_displaymessage(fd, atcmd_output);
meets = 0; meets = 0;
} }
@ -9118,13 +9119,14 @@ ACMD_FUNC(unloadnpcfile) {
return 0; return 0;
} }
ACMD_FUNC(cart) { ACMD_FUNC(cart) {
#define MC_CART_MDFY(x) \ #define MC_CART_MDFY(idx, x) \
sd->status.skill[MC_PUSHCART].id = x?MC_PUSHCART:0; \ sd->status.skill[(idx)].id = x?MC_PUSHCART:0; \
sd->status.skill[MC_PUSHCART].lv = x?1:0; \ sd->status.skill[(idx)].lv = x?1:0; \
sd->status.skill[MC_PUSHCART].flag = x?SKILL_FLAG_TEMPORARY:SKILL_FLAG_PERMANENT; sd->status.skill[(idx)].flag = x?SKILL_FLAG_TEMPORARY:SKILL_FLAG_PERMANENT;
int val = atoi(message); int val = atoi(message);
bool need_skill = (pc_checkskill(sd, MC_PUSHCART) == 0); bool need_skill = (pc_checkskill(sd, MC_PUSHCART) == 0);
uint16 sk_idx = 0;
if( !message || !*message || val < 0 || val > MAX_CARTS ) { if( !message || !*message || val < 0 || val > MAX_CARTS ) {
sprintf(atcmd_output, msg_txt(sd,1390),command,MAX_CARTS); // Unknown Cart (usage: %s <0-%d>). sprintf(atcmd_output, msg_txt(sd,1390),command,MAX_CARTS); // Unknown Cart (usage: %s <0-%d>).
@ -9137,19 +9139,22 @@ ACMD_FUNC(cart) {
return -1; return -1;
} }
if (!(sk_idx = skill_get_index(MC_PUSHCART)))
return -1;
if( need_skill ) { if( need_skill ) {
MC_CART_MDFY(1); MC_CART_MDFY(sk_idx,1);
} }
if( !pc_setcart(sd, val) ) { if( !pc_setcart(sd, val) ) {
if( need_skill ) { if( need_skill ) {
MC_CART_MDFY(0); MC_CART_MDFY(sk_idx,0);
} }
return -1;/* @cart failed */ return -1;/* @cart failed */
} }
if( need_skill ) { if( need_skill ) {
MC_CART_MDFY(0); MC_CART_MDFY(sk_idx,0);
} }
clif_displaymessage(fd, msg_txt(sd,1392)); // Cart Added clif_displaymessage(fd, msg_txt(sd,1392)); // Cart Added

View File

@ -1883,10 +1883,10 @@ static int battle_skill_damage_skill(struct block_list *src, struct block_list *
struct s_skill_damage *damage = NULL; struct s_skill_damage *damage = NULL;
struct map_data *mapd = &map[m]; struct map_data *mapd = &map[m];
if (!idx || !skill_db[idx].damage.map) if (!idx || !skill_db[idx]->damage.map)
return 0; return 0;
damage = &skill_db[idx].damage; damage = &skill_db[idx]->damage;
//check the adjustment works for specified type //check the adjustment works for specified type
if (!battle_skill_damage_iscaster(damage->caster, src->type)) if (!battle_skill_damage_iscaster(damage->caster, src->type))
@ -6957,11 +6957,12 @@ enum damage_lv battle_weapon_attack(struct block_list* src, struct block_list* t
} }
} }
if (sd) { if (sd) {
uint16 r_skill = 0, sk_idx = 0;
if( wd.flag&BF_SHORT && sc && sc->data[SC__AUTOSHADOWSPELL] && rnd()%100 < sc->data[SC__AUTOSHADOWSPELL]->val3 && if( wd.flag&BF_SHORT && sc && sc->data[SC__AUTOSHADOWSPELL] && rnd()%100 < sc->data[SC__AUTOSHADOWSPELL]->val3 &&
sd->status.skill[sc->data[SC__AUTOSHADOWSPELL]->val1].id != 0 && sd->status.skill[sc->data[SC__AUTOSHADOWSPELL]->val1].flag == SKILL_FLAG_PLAGIARIZED ) (r_skill = (uint16)sc->data[SC__AUTOSHADOWSPELL]->val1) && (sk_idx = skill_get_index(r_skill)) &&
sd->status.skill[sk_idx].id != 0 && sd->status.skill[sk_idx].flag == SKILL_FLAG_PLAGIARIZED )
{ {
int r_skill = sd->status.skill[sc->data[SC__AUTOSHADOWSPELL]->val1].id, int r_lv = sc->data[SC__AUTOSHADOWSPELL]->val2;
r_lv = sc->data[SC__AUTOSHADOWSPELL]->val2;
if (r_skill != AL_HOLYLIGHT && r_skill != PR_MAGNUS) { if (r_skill != AL_HOLYLIGHT && r_skill != PR_MAGNUS) {
int type; int type;
@ -7801,7 +7802,7 @@ static const struct _battle_data {
{ "show_hp_sp_gain", &battle_config.show_hp_sp_gain, 1, 0, 1, }, { "show_hp_sp_gain", &battle_config.show_hp_sp_gain, 1, 0, 1, },
{ "mob_npc_event_type", &battle_config.mob_npc_event_type, 1, 0, 1, }, { "mob_npc_event_type", &battle_config.mob_npc_event_type, 1, 0, 1, },
{ "character_size", &battle_config.character_size, 1|2, 0, 1|2, }, { "character_size", &battle_config.character_size, 1|2, 0, 1|2, },
{ "mob_max_skilllvl", &battle_config.mob_max_skilllvl, MAX_SKILL_LEVEL, 1, MAX_SKILL_LEVEL, }, { "mob_max_skilllvl", &battle_config.mob_max_skilllvl, MAX_MOBSKILL_LEVEL, 1, MAX_MOBSKILL_LEVEL, },
{ "retaliate_to_master", &battle_config.retaliate_to_master, 1, 0, 1, }, { "retaliate_to_master", &battle_config.retaliate_to_master, 1, 0, 1, },
{ "rare_drop_announce", &battle_config.rare_drop_announce, 0, 0, 10000, }, { "rare_drop_announce", &battle_config.rare_drop_announce, 0, 0, 10000, },
{ "duel_allow_pvp", &battle_config.duel_allow_pvp, 0, 0, 1, }, { "duel_allow_pvp", &battle_config.duel_allow_pvp, 0, 0, 1, },

View File

@ -965,19 +965,21 @@ int chrif_changedsex(int fd) {
if ((sd->class_&MAPID_UPPERMASK) == MAPID_BARDDANCER) { if ((sd->class_&MAPID_UPPERMASK) == MAPID_BARDDANCER) {
int i; int i;
// remove specifical skills of Bard classes // remove specifical skills of Bard classes
for(i = 315; i <= 322; i++) { for(i = BA_MUSICALLESSON; i <= BA_APPLEIDUN; i++) {
if (sd->status.skill[i].id > 0 && sd->status.skill[i].flag == SKILL_FLAG_PERMANENT) { uint16 sk_idx = skill_get_index(i);
sd->status.skill_point += sd->status.skill[i].lv; if (sd->status.skill[sk_idx].id > 0 && sd->status.skill[sk_idx].flag == SKILL_FLAG_PERMANENT) {
sd->status.skill[i].id = 0; sd->status.skill_point += sd->status.skill[sk_idx].lv;
sd->status.skill[i].lv = 0; sd->status.skill[sk_idx].id = 0;
sd->status.skill[sk_idx].lv = 0;
} }
} }
// remove specifical skills of Dancer classes // remove specifical skills of Dancer classes
for(i = 323; i <= 330; i++) { for(i = DC_DANCINGLESSON; i <= DC_SERVICEFORYOU; i++) {
if (sd->status.skill[i].id > 0 && sd->status.skill[i].flag == SKILL_FLAG_PERMANENT) { uint16 sk_idx = skill_get_index(i);
sd->status.skill_point += sd->status.skill[i].lv; if (sd->status.skill[sk_idx].id > 0 && sd->status.skill[sk_idx].flag == SKILL_FLAG_PERMANENT) {
sd->status.skill[i].id = 0; sd->status.skill_point += sd->status.skill[sk_idx].lv;
sd->status.skill[i].lv = 0; sd->status.skill[sk_idx].id = 0;
sd->status.skill[sk_idx].lv = 0;
} }
} }
clif_updatestatus(sd, SP_SKILLPOINT); clif_updatestatus(sd, SP_SKILLPOINT);
@ -1044,7 +1046,7 @@ int chrif_divorceack(uint32 char_id, int partner_id) {
*------------------------------------------*/ *------------------------------------------*/
int chrif_deadopt(int father_id, int mother_id, int child_id) { int chrif_deadopt(int father_id, int mother_id, int child_id) {
struct map_session_data* sd; struct map_session_data* sd;
int idx = skill_get_index(WE_CALLBABY); uint16 idx = skill_get_index(WE_CALLBABY);
if( father_id && ( sd = map_charid2sd(father_id) ) != NULL && sd->status.child == child_id ) { if( father_id && ( sd = map_charid2sd(father_id) ) != NULL && sd->status.child == child_id ) {
sd->status.child = 0; sd->status.child = 0;

View File

@ -1495,7 +1495,7 @@ int clif_homskillinfoblock(struct map_session_data *sd)
{ //[orn] { //[orn]
struct homun_data *hd; struct homun_data *hd;
int fd = sd->fd; int fd = sd->fd;
int i,j,len=4; int i, len=4;
WFIFOHEAD(fd, 4+37*MAX_HOMUNSKILL); WFIFOHEAD(fd, 4+37*MAX_HOMUNSKILL);
hd = sd->hd; hd = sd->hd;
@ -1507,15 +1507,17 @@ int clif_homskillinfoblock(struct map_session_data *sd)
int id = hd->homunculus.hskill[i].id; int id = hd->homunculus.hskill[i].id;
if( id != 0 ){ if( id != 0 ){
int combo = (hd->homunculus.hskill[i].flag)&SKILL_FLAG_TMP_COMBO; int combo = (hd->homunculus.hskill[i].flag)&SKILL_FLAG_TMP_COMBO;
j = id - HM_SKILLBASE; short idx = hom_skill_get_index(id);
if (idx == -1)
continue;
WFIFOW(fd,len ) = id; WFIFOW(fd,len ) = id;
WFIFOW(fd,len+2) = ((combo)?INF_SELF_SKILL:skill_get_inf(id)); WFIFOW(fd,len+2) = ((combo)?INF_SELF_SKILL:skill_get_inf(id));
WFIFOW(fd,len+4) = 0; WFIFOW(fd,len+4) = 0;
WFIFOW(fd,len+6) = hd->homunculus.hskill[j].lv; WFIFOW(fd,len+6) = hd->homunculus.hskill[idx].lv;
WFIFOW(fd,len+8) = skill_get_sp(id,hd->homunculus.hskill[j].lv); WFIFOW(fd,len+8) = skill_get_sp(id,hd->homunculus.hskill[idx].lv);
WFIFOW(fd,len+10)= skill_get_range2(&sd->hd->bl, id,hd->homunculus.hskill[j].lv); WFIFOW(fd,len+10)= skill_get_range2(&sd->hd->bl, id,hd->homunculus.hskill[idx].lv);
safestrncpy((char*)WFIFOP(fd,len+12), skill_get_name(id), NAME_LENGTH); safestrncpy((char*)WFIFOP(fd,len+12), skill_get_name(id), NAME_LENGTH);
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; WFIFOB(fd,len+36) = (hd->homunculus.level < hom_skill_get_min_level(hd->homunculus.class_, id) || hd->homunculus.hskill[idx].lv >= hom_skill_tree_get_max(id, hd->homunculus.class_)) ? 0 : 1;
len+=37; len+=37;
} }
} }
@ -1528,9 +1530,12 @@ int clif_homskillinfoblock(struct map_session_data *sd)
void clif_homskillup(struct map_session_data *sd, uint16 skill_id) void clif_homskillup(struct map_session_data *sd, uint16 skill_id)
{ //[orn] { //[orn]
struct homun_data *hd; struct homun_data *hd;
int fd, idx; int fd;
short idx = -1;
nullpo_retv(sd); nullpo_retv(sd);
idx = skill_id - HM_SKILLBASE;
if ((idx = hom_skill_get_index(skill_id) == -1))
return;
fd = sd->fd; fd = sd->fd;
hd = sd->hd; hd = sd->hd;
@ -4826,7 +4831,8 @@ void clif_skillinfoblock(struct map_session_data *sd)
nullpo_retv(sd); nullpo_retv(sd);
fd = sd->fd; fd = sd->fd;
if (!fd) return; if (!fd)
return;
WFIFOHEAD(fd, MAX_SKILL * 37 + 4); WFIFOHEAD(fd, MAX_SKILL * 37 + 4);
WFIFOW(fd,0) = 0x10f; WFIFOW(fd,0) = 0x10f;
@ -4870,28 +4876,30 @@ void clif_skillinfoblock(struct map_session_data *sd)
/// Adds new skill to the skill tree (ZC_ADD_SKILL). /// Adds new skill to the skill tree (ZC_ADD_SKILL).
/// 0111 <skill id>.W <type>.L <level>.W <sp cost>.W <attack range>.W <skill name>.24B <upgradable>.B /// 0111 <skill id>.W <type>.L <level>.W <sp cost>.W <attack range>.W <skill name>.24B <upgradable>.B
void clif_addskill(struct map_session_data *sd, int id) void clif_addskill(struct map_session_data *sd, int skill_id)
{ {
int fd; int fd;
uint16 idx = 0;
nullpo_retv(sd); nullpo_retv(sd);
fd = sd->fd; fd = sd->fd;
if (!fd) return; if (!fd || !(idx = skill_get_index(skill_id)))
return;
if( sd->status.skill[id].id <= 0 ) if( sd->status.skill[idx].id <= 0 )
return; return;
WFIFOHEAD(fd, packet_len(0x111)); WFIFOHEAD(fd, packet_len(0x111));
WFIFOW(fd,0) = 0x111; WFIFOW(fd,0) = 0x111;
WFIFOW(fd,2) = id; WFIFOW(fd,2) = skill_id;
WFIFOL(fd,4) = skill_get_inf(id); WFIFOL(fd,4) = skill_get_inf(skill_id);
WFIFOW(fd,8) = sd->status.skill[id].lv; WFIFOW(fd,8) = sd->status.skill[idx].lv;
WFIFOW(fd,10) = skill_get_sp(id,sd->status.skill[id].lv); WFIFOW(fd,10) = skill_get_sp(skill_id,sd->status.skill[idx].lv);
WFIFOW(fd,12)= skill_get_range2(&sd->bl, id,sd->status.skill[id].lv); WFIFOW(fd,12)= skill_get_range2(&sd->bl, skill_id,sd->status.skill[idx].lv);
safestrncpy((char*)WFIFOP(fd,14), skill_get_name(id), NAME_LENGTH); safestrncpy((char*)WFIFOP(fd,14), skill_get_name(skill_id), NAME_LENGTH);
if( sd->status.skill[id].flag == SKILL_FLAG_PERMANENT ) if( sd->status.skill[idx].flag == SKILL_FLAG_PERMANENT )
WFIFOB(fd,38) = (sd->status.skill[id].lv < skill_tree_get_max(id, sd->status.class_))? 1:0; WFIFOB(fd,38) = (sd->status.skill[idx].lv < skill_tree_get_max(skill_id, sd->status.class_))? 1:0;
else else
WFIFOB(fd,38) = 0; WFIFOB(fd,38) = 0;
WFIFOSET(fd,packet_len(0x111)); WFIFOSET(fd,packet_len(0x111));
@ -4900,18 +4908,21 @@ void clif_addskill(struct map_session_data *sd, int id)
/// Deletes a skill from the skill tree (ZC_SKILLINFO_DELETE). /// Deletes a skill from the skill tree (ZC_SKILLINFO_DELETE).
/// 0441 <skill id>.W /// 0441 <skill id>.W
void clif_deleteskill(struct map_session_data *sd, int id) void clif_deleteskill(struct map_session_data *sd, int skill_id)
{ {
#if PACKETVER >= 20081217 #if PACKETVER >= 20081217
int fd; int fd;
uint16 idx = 0;
nullpo_retv(sd); nullpo_retv(sd);
fd = sd->fd; fd = sd->fd;
if( !fd ) return; if (!fd || !(idx = skill_get_index(skill_id)))
return;
WFIFOHEAD(fd,packet_len(0x441)); WFIFOHEAD(fd,packet_len(0x441));
WFIFOW(fd,0) = 0x441; WFIFOW(fd,0) = 0x441;
WFIFOW(fd,2) = id; WFIFOW(fd,2) = skill_id;
WFIFOSET(fd,packet_len(0x441)); WFIFOSET(fd,packet_len(0x441));
#endif #endif
clif_skillinfoblock(sd); clif_skillinfoblock(sd);
@ -4938,19 +4949,22 @@ void clif_skillup(struct map_session_data *sd, uint16 skill_id, int lv, int rang
/// Updates a skill in the skill tree (ZC_SKILLINFO_UPDATE2). /// Updates a skill in the skill tree (ZC_SKILLINFO_UPDATE2).
/// 07e1 <skill id>.W <type>.L <level>.W <sp cost>.W <attack range>.W <upgradable>.B /// 07e1 <skill id>.W <type>.L <level>.W <sp cost>.W <attack range>.W <upgradable>.B
void clif_skillinfo(struct map_session_data *sd,int skill, int inf) void clif_skillinfo(struct map_session_data *sd,int skill_id, int inf)
{ {
const int fd = sd->fd; const int fd = sd->fd;
uint16 idx = skill_get_index(skill_id);
if (!idx)
return;
WFIFOHEAD(fd,packet_len(0x7e1)); WFIFOHEAD(fd,packet_len(0x7e1));
WFIFOW(fd,0) = 0x7e1; WFIFOW(fd,0) = 0x7e1;
WFIFOW(fd,2) = skill; WFIFOW(fd,2) = skill_id;
WFIFOL(fd,4) = inf?inf:skill_get_inf(skill); WFIFOL(fd,4) = inf?inf:skill_get_inf(skill_id);
WFIFOW(fd,8) = sd->status.skill[skill].lv; WFIFOW(fd,8) = sd->status.skill[idx].lv;
WFIFOW(fd,10) = skill_get_sp(skill,sd->status.skill[skill].lv); WFIFOW(fd,10) = skill_get_sp(skill_id,sd->status.skill[idx].lv);
WFIFOW(fd,12) = skill_get_range2(&sd->bl,skill,sd->status.skill[skill].lv); WFIFOW(fd,12) = skill_get_range2(&sd->bl,skill_id,sd->status.skill[idx].lv);
if( sd->status.skill[skill].flag == SKILL_FLAG_PERMANENT ) if( sd->status.skill[idx].flag == SKILL_FLAG_PERMANENT )
WFIFOB(fd,14) = (sd->status.skill[skill].lv < skill_tree_get_max(skill, sd->status.class_))? 1:0; WFIFOB(fd,14) = (sd->status.skill[idx].lv < skill_tree_get_max(skill_id, sd->status.class_))? 1:0;
else else
WFIFOB(fd,14) = 0; WFIFOB(fd,14) = 0;
WFIFOSET(fd,packet_len(0x7e1)); WFIFOSET(fd,packet_len(0x7e1));
@ -11384,12 +11398,12 @@ void clif_parse_UseSkillToId(int fd, struct map_session_data *sd)
if (tmp&INF_GROUND_SKILL || !tmp) if (tmp&INF_GROUND_SKILL || !tmp)
return; //Using a ground/passive skill on a target? WRONG. return; //Using a ground/passive skill on a target? WRONG.
if( skill_id >= HM_SKILLBASE && skill_id < HM_SKILLBASE + MAX_HOMUNSKILL ) { if( SKILL_CHK_HOMUN(skill_id) ) {
clif_parse_UseSkillToId_homun(sd->hd, sd, tick, skill_id, skill_lv, target_id); clif_parse_UseSkillToId_homun(sd->hd, sd, tick, skill_id, skill_lv, target_id);
return; return;
} }
if( skill_id >= MC_SKILLBASE && skill_id < MC_SKILLBASE + MAX_MERCSKILL ) { if( SKILL_CHK_MERC(skill_id) ) {
clif_parse_UseSkillToId_mercenary(sd->md, sd, tick, skill_id, skill_lv, target_id); clif_parse_UseSkillToId_mercenary(sd->md, sd, tick, skill_id, skill_lv, target_id);
return; return;
} }
@ -11458,7 +11472,7 @@ void clif_parse_UseSkillToId(int fd, struct map_session_data *sd)
sd->skillitem = sd->skillitemlv = 0; sd->skillitem = sd->skillitemlv = 0;
if( skill_id >= GD_SKILLBASE ) { if( SKILL_CHK_GUILD(skill_id) ) {
if( sd->state.gmaster_flag ) if( sd->state.gmaster_flag )
skill_lv = guild_checkskill(sd->guild, skill_id); skill_lv = guild_checkskill(sd->guild, skill_id);
else else
@ -11485,12 +11499,12 @@ static void clif_parse_UseSkillToPosSub(int fd, struct map_session_data *sd, uin
if( !(skill_get_inf(skill_id)&INF_GROUND_SKILL) ) if( !(skill_get_inf(skill_id)&INF_GROUND_SKILL) )
return; //Using a target skill on the ground? WRONG. return; //Using a target skill on the ground? WRONG.
if( skill_id >= HM_SKILLBASE && skill_id < HM_SKILLBASE + MAX_HOMUNSKILL ) { if( SKILL_CHK_HOMUN(skill_id) ) {
clif_parse_UseSkillToPos_homun(sd->hd, sd, tick, skill_id, skill_lv, x, y, skillmoreinfo); clif_parse_UseSkillToPos_homun(sd->hd, sd, tick, skill_id, skill_lv, x, y, skillmoreinfo);
return; return;
} }
if( skill_id >= MC_SKILLBASE && skill_id < MC_SKILLBASE + MAX_MERCSKILL ) { if( SKILL_CHK_MERC(skill_id) ) {
clif_parse_UseSkillToPos_mercenary(sd->md, sd, tick, skill_id, skill_lv, x, y, skillmoreinfo); clif_parse_UseSkillToPos_mercenary(sd->md, sd, tick, skill_id, skill_lv, x, y, skillmoreinfo);
return; return;
} }
@ -15699,15 +15713,18 @@ void clif_mercenary_skillblock(struct map_session_data *sd)
WFIFOW(fd,0) = 0x29d; WFIFOW(fd,0) = 0x29d;
for( i = 0; i < MAX_MERCSKILL; i++ ) for( i = 0; i < MAX_MERCSKILL; i++ )
{ {
int id, j; uint16 id;
short idx = -1;
if( (id = md->db->skill[i].id) == 0 ) if( (id = md->db->skill[i].id) == 0 )
continue; continue;
j = id - MC_SKILLBASE; if ((idx = mercenary_skill_get_index(id)) == -1)
continue;
WFIFOW(fd,len) = id; WFIFOW(fd,len) = id;
WFIFOL(fd,len+2) = skill_get_inf(id); WFIFOL(fd,len+2) = skill_get_inf(id);
WFIFOW(fd,len+6) = md->db->skill[j].lv; WFIFOW(fd,len+6) = md->db->skill[idx].lv;
WFIFOW(fd,len+8) = skill_get_sp(id, md->db->skill[j].lv); WFIFOW(fd,len+8) = skill_get_sp(id, md->db->skill[idx].lv);
WFIFOW(fd,len+10) = skill_get_range2(&md->bl, id, md->db->skill[j].lv); WFIFOW(fd,len+10) = skill_get_range2(&md->bl, id, md->db->skill[idx].lv);
safestrncpy((char*)WFIFOP(fd,len+12), skill_get_name(id), NAME_LENGTH); safestrncpy((char*)WFIFOP(fd,len+12), skill_get_name(id), NAME_LENGTH);
WFIFOB(fd,len+36) = 0; // Skillable for Mercenary? WFIFOB(fd,len+36) = 0; // Skillable for Mercenary?
len += 37; len += 37;

View File

@ -532,9 +532,9 @@ void clif_class_change(struct block_list *bl,int class_,int type);
void clif_skillinfoblock(struct map_session_data *sd); void clif_skillinfoblock(struct map_session_data *sd);
void clif_skillup(struct map_session_data *sd, uint16 skill_id, int lv, int range, int upgradable); void clif_skillup(struct map_session_data *sd, uint16 skill_id, int lv, int range, int upgradable);
void clif_skillinfo(struct map_session_data *sd,int skill, int inf); void clif_skillinfo(struct map_session_data *sd,int skill_id, int inf);
void clif_addskill(struct map_session_data *sd, int id); void clif_addskill(struct map_session_data *sd, int skill_id);
void clif_deleteskill(struct map_session_data *sd, int id); void clif_deleteskill(struct map_session_data *sd, int skill_id);
void clif_skillcasting(struct block_list* bl, int src_id, int dst_id, int dst_x, int dst_y, uint16 skill_id, int property, int casttime); void clif_skillcasting(struct block_list* bl, int src_id, int dst_id, int dst_x, int dst_y, uint16 skill_id, int property, int casttime);
void clif_skillcastcancel(struct block_list* bl); void clif_skillcastcancel(struct block_list* bl);

View File

@ -9,6 +9,7 @@
#include "../common/showmsg.h" #include "../common/showmsg.h"
#include "../common/random.h" #include "../common/random.h"
#include "../common/strlib.h" #include "../common/strlib.h"
#include "../common/utils.h"
#include "log.h" #include "log.h"
#include "clif.h" #include "clif.h"
@ -560,11 +561,10 @@ struct skill_condition elemental_skill_get_requirements(uint16 skill_id, uint16
if( idx == 0 ) // invalid skill id if( idx == 0 ) // invalid skill id
return req; return req;
if( skill_lv < 1 || skill_lv > MAX_SKILL_LEVEL ) skill_lv = cap_value(skill_lv, 1, MAX_SKILL_LEVEL);
return req;
req.hp = skill_db[idx].require.hp[skill_lv-1]; req.hp = skill_db[idx]->require.hp[skill_lv-1];
req.sp = skill_db[idx].require.sp[skill_lv-1]; req.sp = skill_db[idx]->require.sp[skill_lv-1];
return req; return req;
} }
@ -815,6 +815,7 @@ void read_elementaldb(void) {
uint8 i; uint8 i;
elemental_count = 0; elemental_count = 0;
memset(elemental_db, 0, sizeof(elemental_db));
for(i = 0; i<ARRAYLENGTH(filename); i++){ for(i = 0; i<ARRAYLENGTH(filename); i++){
sv_readdb(db_path, filename[i], ',', 26, 26, -1, &read_elementaldb_sub, i); sv_readdb(db_path, filename[i], ',', 26, 26, -1, &read_elementaldb_sub, i);
} }
@ -825,7 +826,8 @@ void read_elementaldb(void) {
* ElementalID,SkillID,SkillLevel,ReqMode * ElementalID,SkillID,SkillLevel,ReqMode
*/ */
static bool read_elemental_skilldb_sub(char* str[], int columns, int current) { static bool read_elemental_skilldb_sub(char* str[], int columns, int current) {
uint16 class_ = atoi(str[0]), i, skill_id, skill_lv, skillmode; uint16 class_ = atoi(str[0]), skill_id, skill_lv, skillmode;
uint8 i;
struct s_elemental_db *db; struct s_elemental_db *db;
ARR_FIND(0, MAX_ELEMENTAL_CLASS, i, class_ == elemental_db[i].class_); ARR_FIND(0, MAX_ELEMENTAL_CLASS, i, class_ == elemental_db[i].class_);
@ -835,8 +837,8 @@ static bool read_elemental_skilldb_sub(char* str[], int columns, int current) {
} }
skill_id = atoi(str[1]); skill_id = atoi(str[1]);
if( skill_id < EL_SKILLBASE || skill_id >= EL_SKILLBASE + MAX_ELEMENTALSKILL ) { if( !SKILL_CHK_ELEM(skill_id) ) {
ShowError("read_elemental_skilldb_sub: Skill out of range, line %d.\n", current); ShowError("read_elemental_skilldb_sub: Invalid Elemental skill '%d'.\n", skill_id);
return false; return false;
} }

View File

@ -64,6 +64,20 @@ static int guild_send_xy_timer(int tid, unsigned int tick, int id, intptr_t data
struct npc_data **guild_flags; struct npc_data **guild_flags;
unsigned short guild_flags_count; unsigned short guild_flags_count;
/**
* Get guild skill index in guild_skill_tree
* @param skill_id
* @return Index in skill_tree or -1
**/
static short guild_skill_get_index(uint16 skill_id) {
if (!SKILL_CHK_GUILD(skill_id))
return -1;
skill_id -= GD_SKILLBASE;
if (skill_id >= MAX_GUILDSKILL)
return -1;
return skill_id;
}
/*========================================== /*==========================================
* Retrieves and validates the sd pointer for this guild member [Skotlex] * Retrieves and validates the sd pointer for this guild member [Skotlex]
*------------------------------------------*/ *------------------------------------------*/
@ -84,44 +98,41 @@ static TBL_PC* guild_sd_check(int guild_id, uint32 account_id, uint32 char_id) {
// Modified [Komurka] // Modified [Komurka]
int guild_skill_get_max (int id) { int guild_skill_get_max (int id) {
if (id < GD_SKILLBASE || id >= GD_SKILLBASE+MAX_GUILDSKILL) if ((id = guild_skill_get_index(id)) < 0)
return 0; return 0;
return guild_skill_tree[id-GD_SKILLBASE].max; return guild_skill_tree[id].max;
} }
// Retrive skill_lv learned by guild // Retrive skill_lv learned by guild
int guild_checkskill(struct guild *g, int id) { int guild_checkskill(struct guild *g, int id) {
int idx = id - GD_SKILLBASE; if ((id = guild_skill_get_index(id)) < 0)
if (idx < 0 || idx >= MAX_GUILDSKILL)
return 0; return 0;
return g->skill[idx].lv; return g->skill[id].lv;
} }
/*========================================== /*==========================================
* guild_skill_tree.txt reading - from jA [Komurka] * guild_skill_tree.txt reading - from jA [Komurka]
*------------------------------------------*/ *------------------------------------------*/
static bool guild_read_guildskill_tree_db(char* split[], int columns, int current) {// <skill id>,<max lv>,<req id1>,<req lv1>,<req id2>,<req lv2>,<req id3>,<req lv3>,<req id4>,<req lv4>,<req id5>,<req lv5> static bool guild_read_guildskill_tree_db(char* split[], int columns, int current) {// <skill id>,<max lv>,<req id1>,<req lv1>,<req id2>,<req lv2>,<req id3>,<req lv3>,<req id4>,<req lv4>,<req id5>,<req lv5>
int k, id, skill_id; int k, skill_id = atoi(split[0]);
short idx = -1;
skill_id = atoi(split[0]); if ((idx = guild_skill_get_index(skill_id)) < 0) {
id = skill_id - GD_SKILLBASE; ShowError("guild_read_guildskill_tree_db: Invalid Guild skill '%s'.\n", split[1]);
if( id < 0 || id >= MAX_GUILDSKILL ) {
ShowWarning("guild_read_guildskill_tree_db: Invalid skill id %d.\n", skill_id);
return false; return false;
} }
guild_skill_tree[id].id = skill_id; guild_skill_tree[idx].id = skill_id;
guild_skill_tree[id].max = atoi(split[1]); guild_skill_tree[idx].max = atoi(split[1]);
if( guild_skill_tree[id].id == GD_GLORYGUILD && battle_config.require_glory_guild && guild_skill_tree[id].max == 0 ) {// enable guild's glory when required for emblems if( guild_skill_tree[idx].id == GD_GLORYGUILD && battle_config.require_glory_guild && guild_skill_tree[idx].max == 0 ) {// enable guild's glory when required for emblems
guild_skill_tree[id].max = 1; guild_skill_tree[idx].max = 1;
} }
for( k = 0; k < MAX_GUILD_SKILL_REQUIRE; k++ ) { for( k = 0; k < MAX_GUILD_SKILL_REQUIRE; k++ ) {
guild_skill_tree[id].need[k].id = atoi(split[k*2+2]); guild_skill_tree[idx].need[k].id = atoi(split[k*2+2]);
guild_skill_tree[id].need[k].lv = atoi(split[k*2+3]); guild_skill_tree[idx].need[k].lv = atoi(split[k*2+3]);
} }
return true; return true;
@ -131,13 +142,13 @@ static bool guild_read_guildskill_tree_db(char* split[], int columns, int curren
* Guild skill check - from jA [Komurka] * Guild skill check - from jA [Komurka]
*------------------------------------------*/ *------------------------------------------*/
int guild_check_skill_require(struct guild *g,int id) { int guild_check_skill_require(struct guild *g,int id) {
int i; uint8 i;
int idx = id-GD_SKILLBASE; short idx = -1;
if(g == NULL) if(g == NULL)
return 0; return 0;
if (idx < 0 || idx >= MAX_GUILDSKILL) if ((idx = guild_skill_get_index(id)) < 0)
return 0; return 0;
for(i=0;i<MAX_GUILD_SKILL_REQUIRE;i++) for(i=0;i<MAX_GUILD_SKILL_REQUIRE;i++)
@ -1257,24 +1268,26 @@ int guild_getexp(struct map_session_data *sd,int exp) {
/*==================================================== /*====================================================
* Ask to increase guildskill skill_id * Ask to increase guildskill skill_id
*---------------------------------------------------*/ *---------------------------------------------------*/
int guild_skillup(TBL_PC* sd, uint16 skill_id) { void guild_skillup(TBL_PC* sd, uint16 skill_id) {
struct guild* g; struct guild* g;
int idx = skill_id - GD_SKILLBASE; short idx = guild_skill_get_index(skill_id);
int max = guild_skill_get_max(skill_id); short max = 0;
nullpo_ret(sd); nullpo_retv(sd);
if( idx < 0 || idx >= MAX_GUILDSKILL || // not a guild skill if (idx == -1)
sd->status.guild_id == 0 || (g=sd->guild) == NULL || // no guild return;
if( sd->status.guild_id == 0 || (g=sd->guild) == NULL || // no guild
strcmp(sd->status.name, g->master) ) // not the guild master strcmp(sd->status.name, g->master) ) // not the guild master
return 0; return;
max = guild_skill_get_max(skill_id);
if( g->skill_point > 0 && if( g->skill_point > 0 &&
g->skill[idx].id != 0 && g->skill[idx].id != 0 &&
g->skill[idx].lv < max ) g->skill[idx].lv < max )
intif_guild_skillup(g->guild_id, skill_id, sd->status.account_id, max); intif_guild_skillup(g->guild_id, skill_id, sd->status.account_id, max);
return 0;
} }
/*==================================================== /*====================================================
@ -1284,10 +1297,12 @@ int guild_skillupack(int guild_id,uint16 skill_id,uint32 account_id) {
struct map_session_data *sd = map_id2sd(account_id); struct map_session_data *sd = map_id2sd(account_id);
struct guild *g = guild_search(guild_id); struct guild *g = guild_search(guild_id);
int i; int i;
if(g==NULL) short idx = guild_skill_get_index(skill_id);
if (g == NULL || idx == -1)
return 0; return 0;
if (sd != NULL) { if (sd != NULL) {
int lv = g->skill[skill_id-GD_SKILLBASE].lv; int lv = g->skill[idx].lv;
int range = skill_get_range(skill_id, lv); int range = skill_get_range(skill_id, lv);
clif_skillup(sd,skill_id,lv,range,1); clif_skillup(sd,skill_id,lv,range,1);
@ -1297,7 +1312,7 @@ int guild_skillupack(int guild_id,uint16 skill_id,uint32 account_id) {
case GD_GLORYWOUNDS: case GD_GLORYWOUNDS:
case GD_SOULCOLD: case GD_SOULCOLD:
case GD_HAWKEYES: case GD_HAWKEYES:
guild_guildaura_refresh(sd,skill_id,g->skill[skill_id-GD_SKILLBASE].lv); guild_guildaura_refresh(sd,skill_id,g->skill[idx].lv);
break; break;
} }
} }

View File

@ -60,7 +60,7 @@ int guild_member_withdraw(int guild_id,uint32 account_id,uint32 char_id,int flag
const char *name,const char *mes); const char *name,const char *mes);
int guild_expulsion(struct map_session_data *sd,int guild_id, int guild_expulsion(struct map_session_data *sd,int guild_id,
uint32 account_id,uint32 char_id,const char *mes); uint32 account_id,uint32 char_id,const char *mes);
int guild_skillup(struct map_session_data* sd, uint16 skill_id); void guild_skillup(struct map_session_data* sd, uint16 skill_id);
void guild_block_skill(struct map_session_data *sd, int time); void guild_block_skill(struct map_session_data *sd, int time);
int guild_reqalliance(struct map_session_data *sd,struct map_session_data *tsd); int guild_reqalliance(struct map_session_data *sd,struct map_session_data *tsd);
int guild_reply_reqalliance(struct map_session_data *sd,uint32 account_id,int flag); int guild_reply_reqalliance(struct map_session_data *sd,uint32 account_id,int flag);

View File

@ -54,10 +54,11 @@ static struct s_homun_intimacy_grade intimacy_grades[] = {
* @param skill_id * @param skill_id
* @return -1 if invalid skill or skill index for homunculus skill in s_homunculus::hskill * @return -1 if invalid skill or skill index for homunculus skill in s_homunculus::hskill
*/ */
static short hom_skill_get_index(int skill_id) { short hom_skill_get_index(uint16 skill_id) {
if (!skill_get_index(skill_id)) if (!SKILL_CHK_HOMUN(skill_id))
return -1; return -1;
if ((skill_id -= HM_SKILLBASE) < 0 || skill_id >= MAX_HOMUNSKILL) skill_id -= HM_SKILLBASE;
if (skill_id >= MAX_HOMUNSKILL)
return -1; return -1;
return skill_id; return skill_id;
} }
@ -140,8 +141,8 @@ int hom_class2mapid(int hom_class)
void hom_addspiritball(TBL_HOM *hd, int max) { void hom_addspiritball(TBL_HOM *hd, int max) {
nullpo_retv(hd); nullpo_retv(hd);
if (max > MAX_SKILL_LEVEL) if (max > MAX_SPIRITBALL)
max = MAX_SKILL_LEVEL; max = MAX_SPIRITBALL;
if (hd->homunculus.spiritball < 0) if (hd->homunculus.spiritball < 0)
hd->homunculus.spiritball = 0; hd->homunculus.spiritball = 0;
@ -168,8 +169,8 @@ void hom_delspiritball(TBL_HOM *hd, int count, int type) {
} }
if (count <= 0) if (count <= 0)
return; return;
if (count > MAX_SKILL_LEVEL) if (count > MAX_SPIRITBALL)
count = MAX_SKILL_LEVEL; count = MAX_SPIRITBALL;
if (count > hd->homunculus.spiritball) if (count > hd->homunculus.spiritball)
count = hd->homunculus.spiritball; count = hd->homunculus.spiritball;
@ -275,17 +276,17 @@ int hom_delete(struct homun_data *hd, int emote)
*/ */
void hom_calc_skilltree(struct homun_data *hd, bool flag_evolve) { void hom_calc_skilltree(struct homun_data *hd, bool flag_evolve) {
uint8 i; uint8 i;
uint16 skill_id = 0;
short c = 0; short c = 0;
nullpo_retv(hd); nullpo_retv(hd);
/* load previous homunculus form skills first. */ /* load previous homunculus form skills first. */
if (hd->homunculus.prev_class != 0 && (c = hom_class2index(hd->homunculus.prev_class)) >= 0) { 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++) { for (i = 0; i < MAX_SKILL_TREE; i++) {
uint16 skill_id;
short idx = -1;
bool fail = false; bool fail = false;
short idx = hom_skill_get_index(skill_id); if (!(skill_id = hskill_tree[c][i].id) || (idx = hom_skill_get_index(skill_id)) == -1)
if (idx < 0)
continue; continue;
if (hd->homunculus.hskill[idx].id) if (hd->homunculus.hskill[idx].id)
continue; //Skill already known. continue; //Skill already known.
@ -311,11 +312,12 @@ void hom_calc_skilltree(struct homun_data *hd, bool flag_evolve) {
if ((c = hom_class2index(hd->homunculus.class_)) < 0) if ((c = hom_class2index(hd->homunculus.class_)) < 0)
return; return;
for (i = 0; i < MAX_HOM_SKILL_TREE && (skill_id = hskill_tree[c][i].id) > 0; i++) { for (i = 0; i < MAX_SKILL_TREE; i++) {
bool fail = false;
unsigned int intimacy = 0; unsigned int intimacy = 0;
short idx = hom_skill_get_index(skill_id); uint16 skill_id;
if (idx < 0) short idx = -1;
bool fail = false;
if (!(skill_id = hskill_tree[c][i].id) || (idx = hom_skill_get_index(skill_id)) == -1)
continue; continue;
if (hd->homunculus.hskill[idx].id) if (hd->homunculus.hskill[idx].id)
continue; //Skill already known. continue; //Skill already known.
@ -351,7 +353,7 @@ void hom_calc_skilltree(struct homun_data *hd, bool flag_evolve) {
*/ */
short hom_checkskill(struct homun_data *hd,uint16 skill_id) short hom_checkskill(struct homun_data *hd,uint16 skill_id)
{ {
int idx = hom_skill_get_index(skill_id); short idx = hom_skill_get_index(skill_id);
if (idx < 0) // Invalid skill if (idx < 0) // Invalid skill
return 0; return 0;
@ -390,6 +392,7 @@ int hom_skill_tree_get_max(int skill_id, int b_class){
uint8 hom_skill_get_min_level(int class_, uint16 skill_id) { uint8 hom_skill_get_min_level(int class_, uint16 skill_id) {
short class_idx = hom_class2index(class_), skill_idx = -1; short class_idx = hom_class2index(class_), skill_idx = -1;
uint8 i; uint8 i;
if (class_idx == -1 || (skill_idx = hom_skill_get_index(skill_id)) == -1) if (class_idx == -1 || (skill_idx = hom_skill_get_index(skill_id)) == -1)
return 0; return 0;
ARR_FIND(0, MAX_HOM_SKILL_REQUIRE, i, hskill_tree[class_idx][i].id == skill_id); ARR_FIND(0, MAX_HOM_SKILL_REQUIRE, i, hskill_tree[class_idx][i].id == skill_id);
@ -1511,40 +1514,32 @@ void read_homunculusdb(void) {
* <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> * <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) { static bool read_homunculus_skilldb_sub(char* split[], int columns, int current) {
int skill_id, class_idx; uint16 skill_id;
int8 i, j; int8 i;
short class_idx, idx = -1;
// check for bounds [celest] // check for bounds [celest]
if ((class_idx = hom_class2index(atoi(split[0]))) == -1) { if ((class_idx = hom_class2index(atoi(split[0]))) == -1) {
ShowWarning("read_homunculus_skilldb: Invalud homunculus class %d.\n", atoi(split[0])); ShowWarning("read_homunculus_skilldb: Invalid homunculus class %d.\n", atoi(split[0]));
return false; return false;
} }
skill_id = atoi(split[1]); //This is to avoid adding two lines for the same skill. [Skotlex] skill_id = atoi(split[1]);
// Search an empty line or a line with the same skill_id (stored in j) if ((idx = hom_skill_get_index(skill_id)) == -1) {
ARR_FIND( 0, MAX_HOM_SKILL_TREE, j, !hskill_tree[class_idx][j].id || hskill_tree[class_idx][j].id == skill_id ); ShowError("read_homunculus_skilldb: Invalid Homunculus skill '%s'.\n", split[1]);
if (j == MAX_HOM_SKILL_TREE) {
ShowWarning("Unable to load skill %d into homunculus %d's tree. Maximum number of skills per class has been reached.\n", skill_id, atoi(split[0]));
return false; return false;
} }
hskill_tree[class_idx][j].id = skill_id; hskill_tree[class_idx][idx].id = skill_id;
hskill_tree[class_idx][j].max = atoi(split[2]); hskill_tree[class_idx][idx].max = atoi(split[2]);
hskill_tree[class_idx][j].need_level = atoi(split[3]); hskill_tree[class_idx][idx].need_level = atoi(split[3]);
for (i = 0; i < MAX_HOM_SKILL_REQUIRE; i++) { for (i = 0; i < MAX_HOM_SKILL_REQUIRE; i++) {
uint16 id = atoi(split[4+i*2]), idx = 0; hskill_tree[class_idx][idx].need[i].id = atoi(split[4+i*2]);
if (!id) hskill_tree[class_idx][idx].need[i].lv = atoi(split[4+i*2+1]);
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].intimacy = atoi(split[14]); hskill_tree[class_idx][idx].intimacy = atoi(split[14]);
return true; return true;
} }

View File

@ -186,6 +186,8 @@ uint8 hom_get_intimacy_grade(struct homun_data *hd);
uint32 hom_intimacy_grade2intimacy(enum e_homun_grade grade); uint32 hom_intimacy_grade2intimacy(enum e_homun_grade grade);
enum e_homun_grade hom_intimacy_intimacy2grade(uint32 intimacy); enum e_homun_grade hom_intimacy_intimacy2grade(uint32 intimacy);
short hom_skill_get_index(uint16 skill_id);
void do_final_homunculus(void); void do_final_homunculus(void);
void do_init_homunculus(void); void do_init_homunculus(void);

View File

@ -325,8 +325,12 @@ enum e_item_ammo
AMMO_KUNAI, AMMO_KUNAI,
AMMO_CANNONBALL, AMMO_CANNONBALL,
AMMO_THROWABLE_ITEM, ///Sling items AMMO_THROWABLE_ITEM, ///Sling items
MAX_AMMO_TYPE,
}; };
#define AMMO_TYPE_ALL ((1<<MAX_AMMO_TYPE)-1)
///Item combo struct ///Item combo struct
struct item_combo struct item_combo
{ {

View File

@ -59,6 +59,20 @@ struct view_data * mercenary_get_viewdata(int class_){
return &mercenary_db[i].vd; return &mercenary_db[i].vd;
} }
/**
* Get mercenary skill index for mercenary skill tree
* @param skill_id
* @return Index in skill_tree or -1
**/
short mercenary_skill_get_index(uint16 skill_id) {
if (!SKILL_CHK_MERC(skill_id))
return -1;
skill_id -= MC_SKILLBASE;
if (skill_id >= MAX_MERCSKILL)
return -1;
return skill_id;
}
/** /**
* Create a new Mercenary for Player * Create a new Mercenary for Player
* @param sd The Player * @param sd The Player
@ -445,14 +459,11 @@ void mercenary_kills(struct mercenary_data *md){
* @return Skill Level or 0 if Mercenary doesn't have the skill * @return Skill Level or 0 if Mercenary doesn't have the skill
**/ **/
int mercenary_checkskill(struct mercenary_data *md, uint16 skill_id) { int mercenary_checkskill(struct mercenary_data *md, uint16 skill_id) {
int i = skill_id - MC_SKILLBASE; short idx = mercenary_skill_get_index(skill_id);
if( !md || !md->db )
return 0;
if( md->db->skill[i].id == skill_id )
return md->db->skill[i].lv;
if( !md || !md->db || idx == -1)
return 0; return 0;
return md->db->skill[idx].lv;
} }
/** /**
@ -529,6 +540,7 @@ static bool mercenary_readdb_sub(char* str[], int columns, int current)
void mercenary_readdb(void) { void mercenary_readdb(void) {
const char *filename[]={ "mercenary_db.txt",DBIMPORT"/mercenary_db.txt"}; const char *filename[]={ "mercenary_db.txt",DBIMPORT"/mercenary_db.txt"};
uint8 i; uint8 i;
mercenary_count = 0; //Reset the counter mercenary_count = 0; //Reset the counter
memset(mercenary_db,0,sizeof(mercenary_db)); memset(mercenary_db,0,sizeof(mercenary_db));
for(i = 0; i<ARRAYLENGTH(filename); i++){ for(i = 0; i<ARRAYLENGTH(filename); i++){
@ -542,7 +554,9 @@ void mercenary_readdb(void) {
static bool mercenary_read_skilldb_sub(char* str[], int columns, int current) static bool mercenary_read_skilldb_sub(char* str[], int columns, int current)
{// <merc id>,<skill id>,<skill level> {// <merc id>,<skill id>,<skill level>
struct s_mercenary_db *db; struct s_mercenary_db *db;
uint16 i, class_, skill_id, skill_lv; uint16 class_, skill_id, skill_lv;
uint8 i = 0;
short idx = -1;
class_ = atoi(str[0]); class_ = atoi(str[0]);
ARR_FIND(0, MAX_MERCENARY_CLASS, i, class_ == mercenary_db[i].class_); ARR_FIND(0, MAX_MERCENARY_CLASS, i, class_ == mercenary_db[i].class_);
@ -553,18 +567,16 @@ static bool mercenary_read_skilldb_sub(char* str[], int columns, int current)
} }
skill_id = atoi(str[1]); skill_id = atoi(str[1]);
if( skill_id < MC_SKILLBASE || skill_id >= MC_SKILLBASE + MAX_MERCSKILL ) if( (idx = mercenary_skill_get_index(skill_id)) == -1 ) {
{ ShowError("read_mercenary_skilldb: Invalid Mercenary skill '%s'.\n", str[1]);
ShowError("read_mercenary_skilldb : Skill %d out of range.\n", skill_id);
return false; return false;
} }
db = &mercenary_db[i]; db = &mercenary_db[i];
skill_lv = atoi(str[2]); skill_lv = atoi(str[2]);
i = skill_id - MC_SKILLBASE; db->skill[idx].id = skill_id;
db->skill[i].id = skill_id; db->skill[idx].lv = skill_lv;
db->skill[i].lv = skill_lv;
return true; return true;
} }
@ -575,6 +587,7 @@ static bool mercenary_read_skilldb_sub(char* str[], int columns, int current)
void mercenary_read_skilldb(void){ void mercenary_read_skilldb(void){
const char *filename[]={ "mercenary_skill_db.txt",DBIMPORT"/mercenary_skill_db.txt"}; const char *filename[]={ "mercenary_skill_db.txt",DBIMPORT"/mercenary_skill_db.txt"};
uint8 i; uint8 i;
for(i = 0; i<ARRAYLENGTH(filename); i++){ for(i = 0; i<ARRAYLENGTH(filename); i++){
sv_readdb(db_path, filename[i], ',', 3, 3, -1, &mercenary_read_skilldb_sub, i); sv_readdb(db_path, filename[i], ',', 3, 3, -1, &mercenary_read_skilldb_sub, i);
} }

View File

@ -71,6 +71,7 @@ void mercenary_set_calls(struct mercenary_data *md, int value);
void mercenary_kills(struct mercenary_data *md); void mercenary_kills(struct mercenary_data *md);
int mercenary_checkskill(struct mercenary_data *md, uint16 skill_id); int mercenary_checkskill(struct mercenary_data *md, uint16 skill_id);
short mercenary_skill_get_index(uint16 skill_id);
/** /**
* atcommand.c required * atcommand.c required

View File

@ -3492,8 +3492,9 @@ int mob_clone_spawn(struct map_session_data *sd, int16 m, int16 x, int16 y, cons
//Go Backwards to give better priority to advanced skills. //Go Backwards to give better priority to advanced skills.
for (i=0,j = MAX_SKILL_TREE-1;j>=0 && i< MAX_MOBSKILL ;j--) { for (i=0,j = MAX_SKILL_TREE-1;j>=0 && i< MAX_MOBSKILL ;j--) {
int skill_id = skill_tree[pc_class2idx(sd->status.class_)][j].id; uint16 skill_id = skill_tree[pc_class2idx(sd->status.class_)][j].id;
if (!skill_id || sd->status.skill[skill_id].lv < 1 || uint16 sk_idx = 0;
if (!skill_id || !(sk_idx = skill_get_index(skill_id)) || sd->status.skill[sk_idx].lv < 1 ||
(skill_get_inf2(skill_id)&(INF2_WEDDING_SKILL|INF2_GUILD_SKILL)) || (skill_get_inf2(skill_id)&(INF2_WEDDING_SKILL|INF2_GUILD_SKILL)) ||
skill_get_nocast(skill_id)&16 skill_get_nocast(skill_id)&16
) )
@ -3508,12 +3509,12 @@ int mob_clone_spawn(struct map_session_data *sd, int16 m, int16 x, int16 y, cons
/** /**
* The clone should be able to cast the skill (e.g. have the required weapon) bugreport:5299) * The clone should be able to cast the skill (e.g. have the required weapon) bugreport:5299)
**/ **/
if( !skill_check_condition_castbegin(sd,skill_id,sd->status.skill[skill_id].lv) ) if( !skill_check_condition_castbegin(sd,skill_id,sd->status.skill[sk_idx].lv) )
continue; continue;
memset (&ms[i], 0, sizeof(struct mob_skill)); memset (&ms[i], 0, sizeof(struct mob_skill));
ms[i].skill_id = skill_id; ms[i].skill_id = skill_id;
ms[i].skill_lv = sd->status.skill[skill_id].lv; ms[i].skill_lv = sd->status.skill[sk_idx].lv;
ms[i].state = MSS_ANY; ms[i].state = MSS_ANY;
ms[i].permillage = 500*battle_config.mob_skill_rate/100; //Default chance of all skills: 5% ms[i].permillage = 500*battle_config.mob_skill_rate/100; //Default chance of all skills: 5%
ms[i].emotion = -1; ms[i].emotion = -1;
@ -4289,7 +4290,7 @@ static bool mob_parse_row_mobskilldb(char** str, int columns, int current)
//Skill ID //Skill ID
j = atoi(str[3]); j = atoi(str[3]);
if (j <= 0 || j > MAX_SKILL_DB) //fixed Lupus if (j <= 0 || j > MAX_SKILL_ID || !skill_get_index(j)) //fixed Lupus
{ {
if (mob_id < 0) if (mob_id < 0)
ShowError("mob_parse_row_mobskilldb: Invalid Skill ID (%d) for all mobs\n", j); ShowError("mob_parse_row_mobskilldb: Invalid Skill ID (%d) for all mobs\n", j);

View File

@ -112,12 +112,12 @@ int npc_isnear_sub(struct block_list* bl, va_list args) {
if (skill_id > 0) { //If skill_id > 0 that means is used for INF2_NO_NEARNPC [Cydh] if (skill_id > 0) { //If skill_id > 0 that means is used for INF2_NO_NEARNPC [Cydh]
uint16 idx = skill_get_index(skill_id); uint16 idx = skill_get_index(skill_id);
if (idx > 0 && skill_db[idx].unit_nonearnpc_type) { if (idx > 0 && skill_db[idx]->unit_nonearnpc_type) {
while (1) { while (1) {
if (skill_db[idx].unit_nonearnpc_type&1 && nd->subtype == NPCTYPE_WARP) break; if (skill_db[idx]->unit_nonearnpc_type&1 && nd->subtype == NPCTYPE_WARP) break;
if (skill_db[idx].unit_nonearnpc_type&2 && nd->subtype == NPCTYPE_SHOP) break; if (skill_db[idx]->unit_nonearnpc_type&2 && nd->subtype == NPCTYPE_SHOP) break;
if (skill_db[idx].unit_nonearnpc_type&4 && nd->subtype == NPCTYPE_SCRIPT) break; if (skill_db[idx]->unit_nonearnpc_type&4 && nd->subtype == NPCTYPE_SCRIPT) break;
if (skill_db[idx].unit_nonearnpc_type&8 && nd->subtype == NPCTYPE_TOMB) break; if (skill_db[idx]->unit_nonearnpc_type&8 && nd->subtype == NPCTYPE_TOMB) break;
return 0; return 0;
} }
} }
@ -1687,8 +1687,9 @@ int npc_buylist(struct map_session_data* sd, int n, unsigned short* item_list)
// custom merchant shop exp bonus // custom merchant shop exp bonus
if( battle_config.shop_exp > 0 && z > 0 && (skill = pc_checkskill(sd,MC_DISCOUNT)) > 0 ) if( battle_config.shop_exp > 0 && z > 0 && (skill = pc_checkskill(sd,MC_DISCOUNT)) > 0 )
{ {
if( sd->status.skill[MC_DISCOUNT].flag >= SKILL_FLAG_REPLACED_LV_0 ) uint16 sk_idx = skill_get_index(MC_DISCOUNT);
skill = sd->status.skill[MC_DISCOUNT].flag - SKILL_FLAG_REPLACED_LV_0; if( sd->status.skill[sk_idx].flag >= SKILL_FLAG_REPLACED_LV_0 )
skill = sd->status.skill[sk_idx].flag - SKILL_FLAG_REPLACED_LV_0;
if( skill > 0 ) if( skill > 0 )
{ {
@ -1850,8 +1851,9 @@ int npc_selllist(struct map_session_data* sd, int n, unsigned short* item_list)
// custom merchant shop exp bonus // custom merchant shop exp bonus
if( battle_config.shop_exp > 0 && z > 0 && ( skill = pc_checkskill(sd,MC_OVERCHARGE) ) > 0) if( battle_config.shop_exp > 0 && z > 0 && ( skill = pc_checkskill(sd,MC_OVERCHARGE) ) > 0)
{ {
if( sd->status.skill[MC_OVERCHARGE].flag >= SKILL_FLAG_REPLACED_LV_0 ) uint16 sk_idx = skill_get_index(MC_OVERCHARGE);
skill = sd->status.skill[MC_OVERCHARGE].flag - SKILL_FLAG_REPLACED_LV_0; if( sd->status.skill[sk_idx].flag >= SKILL_FLAG_REPLACED_LV_0 )
skill = sd->status.skill[sk_idx].flag - SKILL_FLAG_REPLACED_LV_0;
if( skill > 0 ) if( skill > 0 )
{ {

View File

@ -934,12 +934,12 @@ bool pc_adoption(struct map_session_data *p1_sd, struct map_session_data *p2_sd,
clif_updatestatus(b_sd, SP_JOBEXP); clif_updatestatus(b_sd, SP_JOBEXP);
// Baby Skills // Baby Skills
pc_skill(b_sd, WE_BABY, 1, 0); pc_skill(b_sd, WE_BABY, 1, ADDSKILL_PERMANENT);
pc_skill(b_sd, WE_CALLPARENT, 1, 0); pc_skill(b_sd, WE_CALLPARENT, 1, ADDSKILL_PERMANENT);
// Parents Skills // Parents Skills
pc_skill(p1_sd, WE_CALLBABY, 1, 0); pc_skill(p1_sd, WE_CALLBABY, 1, ADDSKILL_PERMANENT);
pc_skill(p2_sd, WE_CALLBABY, 1, 0); pc_skill(p2_sd, WE_CALLBABY, 1, ADDSKILL_PERMANENT);
return true; return true;
} }
@ -1246,6 +1246,7 @@ bool pc_authok(struct map_session_data *sd, uint32 login_id2, time_t expiration_
* Check if player have any item cooldowns on * Check if player have any item cooldowns on
**/ **/
pc_itemcd_do(sd,true); pc_itemcd_do(sd,true);
pc_validate_skill(sd);
#ifdef BOUND_ITEMS #ifdef BOUND_ITEMS
// Party bound item check // Party bound item check
@ -1356,7 +1357,7 @@ void pc_reg_received(struct map_session_data *sd)
if ((i = pc_checkskill(sd,RG_PLAGIARISM)) > 0) { if ((i = pc_checkskill(sd,RG_PLAGIARISM)) > 0) {
sd->cloneskill_idx = skill_get_index(pc_readglobalreg(sd,SKILL_VAR_PLAGIARISM)); sd->cloneskill_idx = skill_get_index(pc_readglobalreg(sd,SKILL_VAR_PLAGIARISM));
if (sd->cloneskill_idx >= 0) { if (sd->cloneskill_idx > 0) {
sd->status.skill[sd->cloneskill_idx].id = pc_readglobalreg(sd,SKILL_VAR_PLAGIARISM); sd->status.skill[sd->cloneskill_idx].id = pc_readglobalreg(sd,SKILL_VAR_PLAGIARISM);
sd->status.skill[sd->cloneskill_idx].lv = pc_readglobalreg(sd,SKILL_VAR_PLAGIARISM_LV); sd->status.skill[sd->cloneskill_idx].lv = pc_readglobalreg(sd,SKILL_VAR_PLAGIARISM_LV);
if (sd->status.skill[sd->cloneskill_idx].lv > i) if (sd->status.skill[sd->cloneskill_idx].lv > i)
@ -1366,7 +1367,7 @@ void pc_reg_received(struct map_session_data *sd)
} }
if ((i = pc_checkskill(sd,SC_REPRODUCE)) > 0) { if ((i = pc_checkskill(sd,SC_REPRODUCE)) > 0) {
sd->reproduceskill_idx = skill_get_index(pc_readglobalreg(sd,SKILL_VAR_REPRODUCE)); sd->reproduceskill_idx = skill_get_index(pc_readglobalreg(sd,SKILL_VAR_REPRODUCE));
if (sd->reproduceskill_idx >= 0) { if (sd->reproduceskill_idx > 0) {
sd->status.skill[sd->reproduceskill_idx].id = pc_readglobalreg(sd,SKILL_VAR_REPRODUCE); sd->status.skill[sd->reproduceskill_idx].id = pc_readglobalreg(sd,SKILL_VAR_REPRODUCE);
sd->status.skill[sd->reproduceskill_idx].lv = pc_readglobalreg(sd,SKILL_VAR_REPRODUCE_LV); sd->status.skill[sd->reproduceskill_idx].lv = pc_readglobalreg(sd,SKILL_VAR_REPRODUCE_LV);
if (i < sd->status.skill[sd->reproduceskill_idx].lv) if (i < sd->status.skill[sd->reproduceskill_idx].lv)
@ -1454,16 +1455,15 @@ static int pc_calc_skillpoint(struct map_session_data* sd)
nullpo_ret(sd); nullpo_ret(sd);
for(i = 1; i < MAX_SKILL; i++) { for(i = 1; i < MAX_SKILL; i++) {
uint8 skill_lv; if( sd->status.skill[i].id && sd->status.skill[i].lv > 0) {
if( (skill_lv = pc_checkskill(sd,i)) > 0) { uint16 inf2 = skill_get_inf2(sd->status.skill[i].id);
uint16 inf2 = skill_get_inf2(i);
if ((!(inf2&INF2_QUEST_SKILL) || battle_config.quest_skill_learn) && if ((!(inf2&INF2_QUEST_SKILL) || battle_config.quest_skill_learn) &&
!(inf2&(INF2_WEDDING_SKILL|INF2_SPIRIT_SKILL)) //Do not count wedding/link skills. [Skotlex] !(inf2&(INF2_WEDDING_SKILL|INF2_SPIRIT_SKILL)) //Do not count wedding/link skills. [Skotlex]
) { )
{
if(sd->status.skill[i].flag == SKILL_FLAG_PERMANENT) if(sd->status.skill[i].flag == SKILL_FLAG_PERMANENT)
skill_point += skill_lv; skill_point += sd->status.skill[i].lv;
else else if(sd->status.skill[i].flag >= SKILL_FLAG_REPLACED_LV_0)
if(sd->status.skill[i].flag == SKILL_FLAG_REPLACED_LV_0)
skill_point += (sd->status.skill[i].flag - SKILL_FLAG_REPLACED_LV_0); skill_point += (sd->status.skill[i].flag - SKILL_FLAG_REPLACED_LV_0);
} }
} }
@ -1472,6 +1472,57 @@ static int pc_calc_skillpoint(struct map_session_data* sd)
return skill_point; return skill_point;
} }
static bool pc_grant_allskills(struct map_session_data *sd, bool addlv) {
uint16 i = 0;
if (!sd || !pc_has_permission(sd, PC_PERM_ALL_SKILL) || !SKILL_MAX_DB())
return false;
/**
* Dummy skills must NOT be added here otherwise they'll be displayed in the,
* skill tree and since they have no icons they'll give resource errors
* Get ALL skills except npc/guild ones. [Skotlex]
* Don't add SG_DEVIL [Komurka] and MO_TRIPLEATTACK and RG_SNATCHER [ultramage]
**/
for( i = 0; i < MAX_SKILL; i++ ) {
uint16 skill_id = skill_idx2id(i);
if (!skill_id || (skill_get_inf2(skill_id)&(INF2_NPC_SKILL|INF2_GUILD_SKILL)))
continue;
switch (skill_id) {
case SM_SELFPROVOKE:
case AB_DUPLELIGHT_MELEE:
case AB_DUPLELIGHT_MAGIC:
case WL_CHAINLIGHTNING_ATK:
case WL_TETRAVORTEX_FIRE:
case WL_TETRAVORTEX_WATER:
case WL_TETRAVORTEX_WIND:
case WL_TETRAVORTEX_GROUND:
case WL_SUMMON_ATK_FIRE:
case WL_SUMMON_ATK_WIND:
case WL_SUMMON_ATK_WATER:
case WL_SUMMON_ATK_GROUND:
case LG_OVERBRAND_BRANDISH:
case LG_OVERBRAND_PLUSATK:
case WM_SEVERE_RAINSTORM_MELEE:
case RL_R_TRIP_PLUSATK:
case SG_DEVIL:
case MO_TRIPLEATTACK:
case RG_SNATCHER:
continue;
default:
{
uint8 lv = (uint8)skill_get_max(skill_id);
if (lv > 0) {
sd->status.skill[i].id = skill_id;
if (addlv)
sd->status.skill[i].lv = lv;
}
}
break;
}
}
return true;
}
/*========================================== /*==========================================
* Calculation of skill level. * Calculation of skill level.
@ -1494,10 +1545,19 @@ void pc_calc_skilltree(struct map_session_data *sd)
for( i = 0; i < MAX_SKILL; i++ ) { for( i = 0; i < MAX_SKILL; i++ ) {
if( sd->status.skill[i].flag != SKILL_FLAG_PLAGIARIZED && sd->status.skill[i].flag != SKILL_FLAG_PERM_GRANTED ) //Don't touch these if( sd->status.skill[i].flag != SKILL_FLAG_PLAGIARIZED && sd->status.skill[i].flag != SKILL_FLAG_PERM_GRANTED ) //Don't touch these
{
sd->status.skill[i].id = 0; //First clear skills. sd->status.skill[i].id = 0; //First clear skills.
}
/* permanent skills that must be re-checked */ /* permanent skills that must be re-checked */
if( sd->status.skill[i].flag == SKILL_FLAG_PERM_GRANTED ) { if( sd->status.skill[i].flag == SKILL_FLAG_PERM_GRANTED ) {
switch( i ) { uint16 sk_id = skill_idx2id(i);
if (!sk_id) {
sd->status.skill[i].id = 0;
sd->status.skill[i].lv = 0;
sd->status.skill[i].flag = SKILL_FLAG_PERMANENT;
continue;
}
switch (sk_id) {
case NV_TRICKDEAD: case NV_TRICKDEAD:
if( (sd->class_&MAPID_UPPERMASK) != MAPID_NOVICE ) { if( (sd->class_&MAPID_UPPERMASK) != MAPID_NOVICE ) {
sd->status.skill[i].id = 0; sd->status.skill[i].id = 0;
@ -1509,29 +1569,33 @@ void pc_calc_skilltree(struct map_session_data *sd)
} }
} }
for( i = 0; i < MAX_SKILL; i++ ) for( i = 0; i < MAX_SKILL; i++ ) {
{ uint16 skill_id = 0;
if( sd->status.skill[i].flag != SKILL_FLAG_PERMANENT && sd->status.skill[i].flag != SKILL_FLAG_PERM_GRANTED && sd->status.skill[i].flag != SKILL_FLAG_PLAGIARIZED )
{ // Restore original level of skills after deleting earned skills. // Restore original level of skills after deleting earned skills.
if( sd->status.skill[i].flag != SKILL_FLAG_PERMANENT && sd->status.skill[i].flag != SKILL_FLAG_PERM_GRANTED && sd->status.skill[i].flag != SKILL_FLAG_PLAGIARIZED ) {
sd->status.skill[i].lv = (sd->status.skill[i].flag == SKILL_FLAG_TEMPORARY) ? 0 : sd->status.skill[i].flag - SKILL_FLAG_REPLACED_LV_0; sd->status.skill[i].lv = (sd->status.skill[i].flag == SKILL_FLAG_TEMPORARY) ? 0 : sd->status.skill[i].flag - SKILL_FLAG_REPLACED_LV_0;
sd->status.skill[i].flag = SKILL_FLAG_PERMANENT; sd->status.skill[i].flag = SKILL_FLAG_PERMANENT;
} }
if( sd->sc.count && sd->sc.data[SC_SPIRIT] && sd->sc.data[SC_SPIRIT]->val2 == SL_BARDDANCER && i >= DC_HUMMING && i<= DC_SERVICEFORYOU ) //Enable Bard/Dancer spirit linked skills.
{ //Enable Bard/Dancer spirit linked skills. if (!(skill_id = skill_idx2id(i)) || skill_id < DC_HUMMING || skill_id > DC_SERVICEFORYOU)
if( sd->status.sex ) continue;
{ //Link dancer skills to bard.
if( &sd->sc && sd->sc.count && sd->sc.data[SC_SPIRIT] && sd->sc.data[SC_SPIRIT]->val2 == SL_BARDDANCER ) {
//Link Dancer skills to bard.
if( sd->status.sex ) {
if( sd->status.skill[i-8].lv < 10 ) if( sd->status.skill[i-8].lv < 10 )
continue; continue;
sd->status.skill[i].id = i; sd->status.skill[i].id = skill_id;
sd->status.skill[i].lv = sd->status.skill[i-8].lv; // Set the level to the same as the linking skill sd->status.skill[i].lv = sd->status.skill[i-8].lv; // Set the level to the same as the linking skill
sd->status.skill[i].flag = SKILL_FLAG_TEMPORARY; // Tag it as a non-savable, non-uppable, bonus skill sd->status.skill[i].flag = SKILL_FLAG_TEMPORARY; // Tag it as a non-savable, non-uppable, bonus skill
} }
else //Link Bard skills to dancer.
{ //Link bard skills to dancer. else {
if( sd->status.skill[i].lv < 10 ) if( sd->status.skill[i].lv < 10 )
continue; continue;
sd->status.skill[i-8].id = i - 8; sd->status.skill[i-8].id = skill_id - 8;
sd->status.skill[i-8].lv = sd->status.skill[i].lv; // Set the level to the same as the linking skill sd->status.skill[i-8].lv = sd->status.skill[i].lv; // Set the level to the same as the linking skill
sd->status.skill[i-8].flag = SKILL_FLAG_TEMPORARY; // Tag it as a non-savable, non-uppable, bonus skill sd->status.skill[i-8].flag = SKILL_FLAG_TEMPORARY; // Tag it as a non-savable, non-uppable, bonus skill
} }
@ -1541,105 +1605,86 @@ void pc_calc_skilltree(struct map_session_data *sd)
// Removes Taekwon Ranker skill bonus // Removes Taekwon Ranker skill bonus
if ((sd->class_&MAPID_UPPERMASK) != MAPID_TAEKWON) { if ((sd->class_&MAPID_UPPERMASK) != MAPID_TAEKWON) {
uint16 c_ = pc_class2idx(JOB_TAEKWON); uint16 c_ = pc_class2idx(JOB_TAEKWON);
for (i = 0; i < MAX_SKILL_TREE; i++) { for (i = 0; i < MAX_SKILL_TREE; i++) {
uint16 x = skill_get_index(skill_tree[c_][i].id), skid = sd->status.skill[x].id; uint16 sk_id = skill_tree[c_][i].id;
if (skid && x > 0 && sd->status.skill[x].flag != SKILL_FLAG_PLAGIARIZED && sd->status.skill[x].flag != SKILL_FLAG_PERM_GRANTED) { uint16 sk_idx = 0;
if (skid == NV_BASIC || skid == NV_FIRSTAID || skid == WE_CALLBABY)
if (!sk_id || !(sk_idx = skill_get_index(skill_tree[c_][i].id)))
continue; continue;
sd->status.skill[x].id = 0;
if (sd->status.skill[sk_idx].flag != SKILL_FLAG_PLAGIARIZED && sd->status.skill[sk_idx].flag != SKILL_FLAG_PERM_GRANTED) {
if (sk_id == NV_BASIC || sk_id == NV_FIRSTAID || sk_id == WE_CALLBABY)
continue;
sd->status.skill[sk_idx].id = 0;
sd->status.skill[sk_idx].lv = 0;
sd->status.skill[sk_idx].flag = SKILL_FLAG_PERMANENT;
} }
} }
} }
if( pc_has_permission(sd, PC_PERM_ALL_SKILL) ) { // Grant all skills
for( i = 0; i < MAX_SKILL; i++ ) { pc_grant_allskills(sd, false);
switch(i) {
/**
* Dummy skills must be added here otherwise they'll be displayed in the,
* skill tree and since they have no icons they'll give resource errors
**/
case SM_SELFPROVOKE:
case AB_DUPLELIGHT_MELEE:
case AB_DUPLELIGHT_MAGIC:
case WL_CHAINLIGHTNING_ATK:
case WL_TETRAVORTEX_FIRE:
case WL_TETRAVORTEX_WATER:
case WL_TETRAVORTEX_WIND:
case WL_TETRAVORTEX_GROUND:
case WL_SUMMON_ATK_FIRE:
case WL_SUMMON_ATK_WIND:
case WL_SUMMON_ATK_WATER:
case WL_SUMMON_ATK_GROUND:
case LG_OVERBRAND_BRANDISH:
case LG_OVERBRAND_PLUSATK:
case WM_SEVERE_RAINSTORM_MELEE:
case RL_R_TRIP_PLUSATK:
continue;
default:
break;
}
if( skill_get_inf2(i)&(INF2_NPC_SKILL|INF2_GUILD_SKILL) )
continue; //Only skills you can't have are npc/guild ones
if( skill_get_max(i) > 0 )
sd->status.skill[i].id = i;
}
return;
}
do { do {
short skid=0; uint16 skid = 0;
flag = 0; flag = 0;
for( i = 0; i < MAX_SKILL_TREE && (skid = skill_tree[c][i].id) > 0; i++ ) for (i = 0; i < MAX_SKILL_TREE && (skid = skill_tree[c][i].id) > 0; i++) {
{ bool fail = false;
int f; uint16 sk_idx = skill_get_index(skid);
if( sd->status.skill[skid].id )
if (sd->status.skill[sk_idx].id)
continue; //Skill already known. continue; //Skill already known.
f = 1;
if (!battle_config.skillfree) { if (!battle_config.skillfree) {
int j; uint8 j;
// Checking required skills
for(j = 0; j < MAX_PC_SKILL_REQUIRE; j++) { for(j = 0; j < MAX_PC_SKILL_REQUIRE; j++) {
int k; uint16 sk_need_id = skill_tree[c][i].need[j].id;
if((k=skill_tree[c][i].need[j].id)) uint16 sk_need_idx = 0;
{
if (sd->status.skill[k].id == 0 || sd->status.skill[k].flag == SKILL_FLAG_TEMPORARY || sd->status.skill[k].flag == SKILL_FLAG_PLAGIARIZED) if (sk_need_id && (sk_need_idx = skill_get_index(sk_need_id))) {
k = 0; //Not learned. short sk_need = sk_need_id;
if (sd->status.skill[sk_need_idx].id == 0 || sd->status.skill[sk_need_idx].flag == SKILL_FLAG_TEMPORARY || sd->status.skill[sk_need_idx].flag == SKILL_FLAG_PLAGIARIZED)
sk_need = 0; //Not learned.
else if (sd->status.skill[sk_need_idx].flag >= SKILL_FLAG_REPLACED_LV_0) //Real learned level
sk_need = sd->status.skill[sk_need_idx].flag - SKILL_FLAG_REPLACED_LV_0;
else else
if (sd->status.skill[k].flag >= SKILL_FLAG_REPLACED_LV_0) //Real learned level sk_need = pc_checkskill(sd,sk_need_id);
k = sd->status.skill[skill_tree[c][i].need[j].id].flag - SKILL_FLAG_REPLACED_LV_0;
else if (sk_need < skill_tree[c][i].need[j].lv) {
k = pc_checkskill(sd,k); fail = true;
if (k < skill_tree[c][i].need[j].lv)
{
f = 0;
break; break;
} }
} }
} }
if (sd->status.job_level < skill_tree[c][i].joblv) { //We need to get the actual class in this case if (sd->status.job_level < skill_tree[c][i].joblv) { //We need to get the actual class in this case
int class_ = pc_mapid2jobid(sd->class_, sd->status.sex); int class_ = pc_mapid2jobid(sd->class_, sd->status.sex);
class_ = pc_class2idx(class_); class_ = pc_class2idx(class_);
if (class_ == c || (class_ != c && sd->status.job_level < skill_tree[class_][i].joblv)) if (class_ == c || (class_ != c && sd->status.job_level < skill_tree[class_][i].joblv))
f = 0; // job level requirement wasn't satisfied fail = true; // job level requirement wasn't satisfied
} }
} }
if( f ) { if (!fail) {
int inf2; int inf2 = skill_get_inf2(skid);
inf2 = skill_get_inf2(skid);
if(!sd->status.skill[skid].lv && ( if (!sd->status.skill[sk_idx].lv && (
(inf2&INF2_QUEST_SKILL && !battle_config.quest_skill_learn) || (inf2&INF2_QUEST_SKILL && !battle_config.quest_skill_learn) ||
inf2&INF2_WEDDING_SKILL || inf2&INF2_WEDDING_SKILL ||
(inf2&INF2_SPIRIT_SKILL && !sd->sc.data[SC_SPIRIT]) (inf2&INF2_SPIRIT_SKILL && !sd->sc.data[SC_SPIRIT])
)) ))
continue; //Cannot be learned via normal means. Note this check DOES allows raising already known skills. continue; //Cannot be learned via normal means. Note this check DOES allows raising already known skills.
sd->status.skill[skid].id = skid; sd->status.skill[sk_idx].id = skid;
if(inf2&INF2_SPIRIT_SKILL) { //Spirit skills cannot be learned, they will only show up on your tree when you get buffed. if(inf2&INF2_SPIRIT_SKILL) { //Spirit skills cannot be learned, they will only show up on your tree when you get buffed.
sd->status.skill[skid].lv = 1; // need to manually specify a skill level sd->status.skill[sk_idx].lv = 1; // need to manually specify a skill level
sd->status.skill[skid].flag = SKILL_FLAG_TEMPORARY; //So it is not saved, and tagged as a "bonus" skill. sd->status.skill[sk_idx].flag = SKILL_FLAG_TEMPORARY; //So it is not saved, and tagged as a "bonus" skill.
} }
flag = 1; // skill list has changed, perform another pass flag = 1; // skill list has changed, perform another pass
} }
@ -1647,7 +1692,7 @@ void pc_calc_skilltree(struct map_session_data *sd)
} while(flag); } while(flag);
if( c > 0 && sd->status.skill_point == 0 && pc_is_taekwon_ranker(sd) ) { if( c > 0 && sd->status.skill_point == 0 && pc_is_taekwon_ranker(sd) ) {
short skid=0; unsigned short skid = 0;
/* Taekwon Ranker Bonus Skill Tree /* Taekwon Ranker Bonus Skill Tree
============================================ ============================================
- Grant All Taekwon Tree, but only as Bonus Skills in case they drop from ranking. - Grant All Taekwon Tree, but only as Bonus Skills in case they drop from ranking.
@ -1655,22 +1700,25 @@ void pc_calc_skilltree(struct map_session_data *sd)
- (sd->status.skill_point == 0) to wait until all skill points are assigned to avoid problems with Job Change quest. */ - (sd->status.skill_point == 0) to wait until all skill points are assigned to avoid problems with Job Change quest. */
for( i = 0; i < MAX_SKILL_TREE && (skid = skill_tree[c][i].id) > 0; i++ ) { for( i = 0; i < MAX_SKILL_TREE && (skid = skill_tree[c][i].id) > 0; i++ ) {
uint16 sk_idx = 0;
if (!(sk_idx = skill_get_index(skid)))
continue;
if( (skill_get_inf2(skid)&(INF2_QUEST_SKILL|INF2_WEDDING_SKILL)) ) if( (skill_get_inf2(skid)&(INF2_QUEST_SKILL|INF2_WEDDING_SKILL)) )
continue; //Do not include Quest/Wedding skills. continue; //Do not include Quest/Wedding skills.
if( sd->status.skill[skid].id == 0 ) { //do we really want skid as index ? //Lighta if( sd->status.skill[sk_idx].id == 0 ) { //do we really want skid as index ? //Lighta
sd->status.skill[skid].id = skid; sd->status.skill[sk_idx].id = skid;
sd->status.skill[skid].flag = SKILL_FLAG_TEMPORARY; // So it is not saved, and tagged as a "bonus" skill. sd->status.skill[sk_idx].flag = SKILL_FLAG_TEMPORARY; // So it is not saved, and tagged as a "bonus" skill.
} else if( skid != NV_BASIC ) } else if( skid != NV_BASIC )
sd->status.skill[skid].flag = SKILL_FLAG_REPLACED_LV_0 + sd->status.skill[skid].lv; // Remember original level sd->status.skill[sk_idx].flag = SKILL_FLAG_REPLACED_LV_0 + sd->status.skill[sk_idx].lv; // Remember original level
sd->status.skill[skid].lv = skill_tree_get_max(skid, sd->status.class_); sd->status.skill[sk_idx].lv = skill_tree_get_max(skid, sd->status.class_);
} }
} }
} }
//Checks if you can learn a new skill after having leveled up a skill. //Checks if you can learn a new skill after having leveled up a skill.
static void pc_check_skilltree(struct map_session_data *sd, int skill) static void pc_check_skilltree(struct map_session_data *sd)
{ {
int i,id=0,flag; int i, flag = 0;
int c = 0; int c = 0;
if (battle_config.skillfree) if (battle_config.skillfree)
@ -1683,44 +1731,55 @@ static void pc_check_skilltree(struct map_session_data *sd, int skill)
return; return;
} }
c = pc_class2idx(c); c = pc_class2idx(c);
do { do {
uint16 skid = 0;
flag = 0; flag = 0;
for( i = 0; i < MAX_SKILL_TREE && (id=skill_tree[c][i].id)>0; i++ ) for (i = 0; i < MAX_SKILL_TREE && (skid = skill_tree[c][i].id) > 0; i++ ) {
{ uint16 sk_idx = skill_get_index(skid);
int j, f = 1; bool fail = false;
if( sd->status.skill[id].id ) //Already learned uint8 j = 0;
if (sd->status.skill[sk_idx].id) //Already learned
continue; continue;
// Checking required skills
for (j = 0; j < MAX_PC_SKILL_REQUIRE; j++) { for (j = 0; j < MAX_PC_SKILL_REQUIRE; j++) {
int k = skill_tree[c][i].need[j].id; uint16 sk_need_id = skill_tree[c][i].need[j].id;
if( k != 0 ){ uint16 sk_need_idx = 0;
if( sd->status.skill[k].id == 0 || sd->status.skill[k].flag == SKILL_FLAG_TEMPORARY || sd->status.skill[k].flag == SKILL_FLAG_PLAGIARIZED )
k = 0; //Not learned. if (sk_need_id && (sk_need_idx = skill_get_index(sk_need_id))) {
short sk_need = sk_need_id;
if (sd->status.skill[sk_need_idx].id == 0 || sd->status.skill[sk_need_idx].flag == SKILL_FLAG_TEMPORARY || sd->status.skill[sk_need_idx].flag == SKILL_FLAG_PLAGIARIZED)
sk_need = 0; //Not learned.
else if (sd->status.skill[sk_need_idx].flag >= SKILL_FLAG_REPLACED_LV_0) //Real lerned level
sk_need = sd->status.skill[sk_need_idx].flag - SKILL_FLAG_REPLACED_LV_0;
else else
if( sd->status.skill[k].flag >= SKILL_FLAG_REPLACED_LV_0) //Real lerned level sk_need = pc_checkskill(sd,sk_need_id);
k = sd->status.skill[skill_tree[c][i].need[j].id].flag - SKILL_FLAG_REPLACED_LV_0;
else if (sk_need < skill_tree[c][i].need[j].lv) {
k = pc_checkskill(sd,k); fail = true;
if( k < skill_tree[c][i].need[j].lv )
{
f = 0;
break; break;
} }
} }
} }
if( !f )
if( fail )
continue; continue;
if( sd->status.job_level < skill_tree[c][i].joblv ) if( sd->status.job_level < skill_tree[c][i].joblv )
continue; continue;
j = skill_get_inf2(id); j = skill_get_inf2(skid);
if( !sd->status.skill[id].lv && ( if( !sd->status.skill[sk_idx].lv && (
(j&INF2_QUEST_SKILL && !battle_config.quest_skill_learn) || (j&INF2_QUEST_SKILL && !battle_config.quest_skill_learn) ||
j&INF2_WEDDING_SKILL || j&INF2_WEDDING_SKILL ||
(j&INF2_SPIRIT_SKILL && !sd->sc.data[SC_SPIRIT]) (j&INF2_SPIRIT_SKILL && !sd->sc.data[SC_SPIRIT])
) ) ) )
continue; //Cannot be learned via normal means. continue; //Cannot be learned via normal means.
sd->status.skill[id].id = id; sd->status.skill[sk_idx].id = skid;
flag = 1; flag = 1;
} }
} while(flag); } while(flag);
@ -1732,14 +1791,12 @@ void pc_clean_skilltree(struct map_session_data *sd)
{ {
uint16 i; uint16 i;
for (i = 0; i < MAX_SKILL; i++){ for (i = 0; i < MAX_SKILL; i++){
if (sd->status.skill[i].flag == SKILL_FLAG_TEMPORARY || sd->status.skill[i].flag == SKILL_FLAG_PLAGIARIZED) if (sd->status.skill[i].flag == SKILL_FLAG_TEMPORARY || sd->status.skill[i].flag == SKILL_FLAG_PLAGIARIZED) {
{
sd->status.skill[i].id = 0; sd->status.skill[i].id = 0;
sd->status.skill[i].lv = 0; sd->status.skill[i].lv = 0;
sd->status.skill[i].flag = SKILL_FLAG_PERMANENT; sd->status.skill[i].flag = SKILL_FLAG_PERMANENT;
} }
else else if (sd->status.skill[i].flag >= SKILL_FLAG_REPLACED_LV_0){
if (sd->status.skill[i].flag == SKILL_FLAG_REPLACED_LV_0){
sd->status.skill[i].lv = sd->status.skill[i].flag - SKILL_FLAG_REPLACED_LV_0; sd->status.skill[i].lv = sd->status.skill[i].flag - SKILL_FLAG_REPLACED_LV_0;
sd->status.skill[i].flag = SKILL_FLAG_PERMANENT; sd->status.skill[i].flag = SKILL_FLAG_PERMANENT;
} }
@ -3833,74 +3890,78 @@ void pc_bonus5(struct map_session_data *sd,int type,int type2,int type3,int type
* 2 - Like 1, except the level granted can stack with previously learned level. * 2 - Like 1, except the level granted can stack with previously learned level.
* 4 - Like 0, except the skill will ignore skill tree (saves through job changes and resets). * 4 - Like 0, except the skill will ignore skill tree (saves through job changes and resets).
*------------------------------------------*/ *------------------------------------------*/
int pc_skill(TBL_PC* sd, int id, int level, int flag) bool pc_skill(TBL_PC* sd, uint16 skill_id, int level, enum e_addskill_type type) {
{ uint16 idx = 0;
nullpo_ret(sd); nullpo_ret(sd);
if( id <= 0 || id >= MAX_SKILL || skill_db[id].name == NULL) { if (!skill_id || !(idx = skill_get_index(skill_id))) {
ShowError("pc_skill: Skill with id %d does not exist in the skill database\n", id); ShowError("pc_skill: Skill with id %d does not exist in the skill database\n", skill_id);
return 0; return false;
} }
if (level > MAX_SKILL_LEVEL) { if (level > MAX_SKILL_LEVEL) {
ShowError("pc_skill: Skill level %d too high. Max lv supported is %d\n", level, MAX_SKILL_LEVEL); ShowError("pc_skill: Skill level %d too high. Max lv supported is %d\n", level, MAX_SKILL_LEVEL);
return 0; return false;
} }
if( flag == 2 && sd->status.skill[id].lv + level > MAX_SKILL_LEVEL ) { if (type == ADDSKILL_TEMP_ADDLEVEL && sd->status.skill[idx].lv + level > MAX_SKILL_LEVEL) {
ShowError("pc_skill: Skill level bonus %d too high. Max lv supported is %d. Curr lv is %d\n", level, MAX_SKILL_LEVEL, sd->status.skill[id].lv); ShowWarning("pc_skill: Skill level bonus %d too high. Max lv supported is %d. Curr lv is %d. Set to max level.\n", level, MAX_SKILL_LEVEL, sd->status.skill[idx].lv);
return 0; level = MAX_SKILL_LEVEL - sd->status.skill[idx].lv;
} }
switch( flag ){ switch (type) {
case 0: //Set skill data overwriting whatever was there before. case ADDSKILL_PERMANENT: //Set skill data overwriting whatever was there before.
sd->status.skill[id].id = id; sd->status.skill[idx].id = skill_id;
sd->status.skill[id].lv = level; sd->status.skill[idx].lv = level;
sd->status.skill[id].flag = SKILL_FLAG_PERMANENT; sd->status.skill[idx].flag = SKILL_FLAG_PERMANENT;
if (level == 0) { //Remove skill. if (level == 0) { //Remove skill.
sd->status.skill[id].id = 0; sd->status.skill[idx].id = 0;
clif_deleteskill(sd,id); clif_deleteskill(sd,skill_id);
} else } else
clif_addskill(sd,id); clif_addskill(sd,skill_id);
if( !skill_get_inf(id) ) //Only recalculate for passive skills. if (!skill_get_inf(skill_id)) //Only recalculate for passive skills.
status_calc_pc(sd, SCO_NONE); status_calc_pc(sd, SCO_NONE);
break; break;
case 1: //Item bonus skill.
if( sd->status.skill[id].id == id ) { case ADDSKILL_TEMP: //Item bonus skill.
if( sd->status.skill[id].lv >= level ) if (sd->status.skill[idx].id != 0) {
return 0; if (sd->status.skill[idx].lv >= level)
if( sd->status.skill[id].flag == SKILL_FLAG_PERMANENT ) //Non-granted skill, store it's level. return true;
sd->status.skill[id].flag = SKILL_FLAG_REPLACED_LV_0 + sd->status.skill[id].lv; if (sd->status.skill[idx].flag == SKILL_FLAG_PERMANENT) //Non-granted skill, store it's level.
sd->status.skill[idx].flag = SKILL_FLAG_REPLACED_LV_0 + sd->status.skill[idx].lv;
} else { } else {
sd->status.skill[id].id = id; sd->status.skill[idx].id = skill_id;
sd->status.skill[id].flag = SKILL_FLAG_TEMPORARY; sd->status.skill[idx].flag = SKILL_FLAG_TEMPORARY;
} }
sd->status.skill[id].lv = level; sd->status.skill[idx].lv = level;
break; break;
case 2: //Add skill bonus on top of what you had.
if( sd->status.skill[id].id == id ) { case ADDSKILL_TEMP_ADDLEVEL: //Add skill bonus on top of what you had.
if( sd->status.skill[id].flag == SKILL_FLAG_PERMANENT ) if (sd->status.skill[idx].id != 0) {
sd->status.skill[id].flag = SKILL_FLAG_REPLACED_LV_0 + sd->status.skill[id].lv; // Store previous level. if (sd->status.skill[idx].flag == SKILL_FLAG_PERMANENT)
sd->status.skill[idx].flag = SKILL_FLAG_REPLACED_LV_0 + sd->status.skill[idx].lv; // Store previous level.
} else { } else {
sd->status.skill[id].id = id; sd->status.skill[idx].id = skill_id;
sd->status.skill[id].flag = SKILL_FLAG_TEMPORARY; //Set that this is a bonus skill. sd->status.skill[idx].flag = SKILL_FLAG_TEMPORARY; //Set that this is a bonus skill.
} }
sd->status.skill[id].lv += level; sd->status.skill[idx].lv += level;
break; break;
case 4: //Permanent granted skills ignore the skill tree
sd->status.skill[id].id = id; case ADDSKILL_PERMANENT_GRANTED: //Permanent granted skills ignore the skill tree
sd->status.skill[id].lv = level; sd->status.skill[idx].id = skill_id;
sd->status.skill[id].flag = SKILL_FLAG_PERM_GRANTED; sd->status.skill[idx].lv = level;
sd->status.skill[idx].flag = SKILL_FLAG_PERM_GRANTED;
if (level == 0) { //Remove skill. if (level == 0) { //Remove skill.
sd->status.skill[id].id = 0; sd->status.skill[idx].id = 0;
clif_deleteskill(sd,id); clif_deleteskill(sd,skill_id);
} else } else
clif_addskill(sd,id); clif_addskill(sd,skill_id);
if( !skill_get_inf(id) ) //Only recalculate for passive skills. if (!skill_get_inf(skill_id)) //Only recalculate for passive skills.
status_calc_pc(sd, SCO_NONE); status_calc_pc(sd, SCO_NONE);
break; break;
default: //Unknown flag?
return 0; default:
return false;
} }
return 1; return true;
} }
/*========================================== /*==========================================
* Append a card to an item ? * Append a card to an item ?
@ -5446,8 +5507,8 @@ int pc_get_skillcooldown(struct map_session_data *sd, uint16 skill_id, uint16 sk
int cooldown = 0, cooldownlen = ARRAYLENGTH(sd->skillcooldown); int cooldown = 0, cooldownlen = ARRAYLENGTH(sd->skillcooldown);
if (!idx) return 0; if (!idx) return 0;
if (skill_db[idx].cooldown[skill_lv - 1]) if (skill_db[idx]->cooldown[skill_lv - 1])
cooldown = skill_db[idx].cooldown[skill_lv - 1]; cooldown = skill_db[idx]->cooldown[skill_lv - 1];
ARR_FIND(0, cooldownlen, i, sd->skillcooldown[i].id == skill_id); ARR_FIND(0, cooldownlen, i, sd->skillcooldown[i].id == skill_id);
if (i < cooldownlen) { if (i < cooldownlen) {
@ -5462,22 +5523,21 @@ int pc_get_skillcooldown(struct map_session_data *sd, uint16 skill_id, uint16 sk
*------------------------------------------*/ *------------------------------------------*/
uint8 pc_checkskill(struct map_session_data *sd, uint16 skill_id) uint8 pc_checkskill(struct map_session_data *sd, uint16 skill_id)
{ {
if(sd == NULL) return 0; uint16 i = 0, idx = 0;
if( skill_id >= GD_SKILLBASE && skill_id < GD_MAX ) { if (sd == NULL)
return 0;
if ((idx = skill_get_index(skill_id)) == 0) {
ShowError("pc_checkskill: Invalid skill id %d (char_id=%d).\n", skill_id, sd->status.char_id);
return 0;
}
if (SKILL_CHK_GUILD(skill_id) ) {
struct guild *g; struct guild *g;
if( sd->status.guild_id>0 && (g=sd->guild)!=NULL) if( sd->status.guild_id>0 && (g=sd->guild)!=NULL)
return guild_checkskill(g,skill_id); return guild_checkskill(g,skill_id);
return 0; return 0;
} else if(skill_id >= ARRAYLENGTH(sd->status.skill) ) {
ShowError("pc_checkskill: Invalid skill id %d (char_id=%d).\n", skill_id, sd->status.char_id);
return 0;
} }
return sd->status.skill[idx].lv;
if(sd->status.skill[skill_id].id == skill_id)
return (sd->status.skill[skill_id].lv);
return 0;
} }
/** /**
@ -6649,43 +6709,47 @@ int pc_statusup2(struct map_session_data* sd, int type, int val)
* Update skill_lv for player sd * Update skill_lv for player sd
* Skill point allocation * Skill point allocation
*------------------------------------------*/ *------------------------------------------*/
int pc_skillup(struct map_session_data *sd,uint16 skill_id) void pc_skillup(struct map_session_data *sd,uint16 skill_id)
{ {
nullpo_ret(sd); uint16 idx = skill_get_index(skill_id);
if( skill_id >= GD_SKILLBASE && skill_id < GD_SKILLBASE+MAX_GUILDSKILL ) nullpo_retv(sd);
{
if (!idx) {
if (skill_id)
ShowError("pc_skillup: Player attempts to level up invalid skill '%d'\n", skill_id);
return;
}
// Level up guild skill
if (SKILL_CHK_GUILD(skill_id)) {
guild_skillup(sd, skill_id); guild_skillup(sd, skill_id);
return 0; return;
} }
// Level up homunculus skill
if( skill_id >= HM_SKILLBASE && skill_id < HM_SKILLBASE+MAX_HOMUNSKILL && sd->hd ) else if (sd->hd && SKILL_CHK_HOMUN(skill_id)) {
{
hom_skillup(sd->hd, skill_id); hom_skillup(sd->hd, skill_id);
return 0; return;
} }
else {
if(skill_id >= MAX_SKILL )
return 0;
if( sd->status.skill_point > 0 && if( sd->status.skill_point > 0 &&
sd->status.skill[skill_id].id && sd->status.skill[idx].id &&
sd->status.skill[skill_id].flag == SKILL_FLAG_PERMANENT && //Don't allow raising while you have granted skills. [Skotlex] sd->status.skill[idx].flag == SKILL_FLAG_PERMANENT && //Don't allow raising while you have granted skills. [Skotlex]
sd->status.skill[skill_id].lv < skill_tree_get_max(skill_id, sd->status.class_) ) sd->status.skill[idx].lv < skill_tree_get_max(skill_id, sd->status.class_) )
{ {
int lv, range, upgradable; int lv, range, upgradable;
sd->status.skill[skill_id].lv++; sd->status.skill[idx].lv++;
sd->status.skill_point--; sd->status.skill_point--;
if( !skill_get_inf(skill_id) ) if( !skill_get_inf(skill_id) )
status_calc_pc(sd,SCO_NONE); // Only recalculate for passive skills. status_calc_pc(sd,SCO_NONE); // Only recalculate for passive skills.
else if( sd->status.skill_point == 0 && pc_is_taekwon_ranker(sd) ) else if( sd->status.skill_point == 0 && pc_is_taekwon_ranker(sd) )
pc_calc_skilltree(sd); // Required to grant all TK Ranker skills. pc_calc_skilltree(sd); // Required to grant all TK Ranker skills.
else else
pc_check_skilltree(sd, skill_id); // Check if a new skill can Lvlup pc_check_skilltree(sd); // Check if a new skill can Lvlup
lv = sd->status.skill[skill_id].lv; lv = sd->status.skill[idx].lv;
range = skill_get_range2(&sd->bl, skill_id, lv); range = skill_get_range2(&sd->bl, skill_id, lv);
upgradable = (lv < skill_tree_get_max(sd->status.skill[skill_id].id, sd->status.class_)) ? 1 : 0; upgradable = (lv < skill_tree_get_max(sd->status.skill[idx].id, sd->status.class_)) ? 1 : 0;
clif_skillup(sd,skill_id,lv,range,upgradable); clif_skillup(sd,skill_id,lv,range,upgradable);
clif_updatestatus(sd,SP_SKILLPOINT); clif_updatestatus(sd,SP_SKILLPOINT);
if( skill_id == GN_REMODELING_CART ) /* cart weight info was updated by status_calc_pc */ if( skill_id == GN_REMODELING_CART ) /* cart weight info was updated by status_calc_pc */
@ -6693,8 +6757,9 @@ int pc_skillup(struct map_session_data *sd,uint16 skill_id)
if (!pc_has_permission(sd, PC_PERM_ALL_SKILL)) // may skill everything at any time anyways, and this would cause a huge slowdown if (!pc_has_permission(sd, PC_PERM_ALL_SKILL)) // may skill everything at any time anyways, and this would cause a huge slowdown
clif_skillinfoblock(sd); clif_skillinfoblock(sd);
} }
else
return 0; ShowDebug("Skill Level up failed. ID:%d idx:%d (CID=%d. AID=%d)\n", skill_id, idx, sd->status.char_id, sd->status.account_id);
}
} }
/*========================================== /*==========================================
@ -6715,34 +6780,23 @@ int pc_allskillup(struct map_session_data *sd)
} }
} }
if (pc_has_permission(sd, PC_PERM_ALL_SKILL)) if (!pc_grant_allskills(sd, true)) {
{ //Get ALL skills except npc/guild ones. [Skotlex] uint16 sk_id;
//and except SG_DEVIL [Komurka] and MO_TRIPLEATTACK and RG_SNATCHER [ultramage] for (i = 0; i < MAX_SKILL_TREE && (sk_id = skill_tree[pc_class2idx(sd->status.class_)][i].id) > 0;i++){
for(i=0;i<MAX_SKILL;i++){ int inf2 = 0;
switch( i ) { uint16 sk_idx = 0;
case SG_DEVIL: if (!sk_id || !(sk_idx = skill_get_index(sk_id)))
case MO_TRIPLEATTACK:
case RG_SNATCHER:
continue; continue;
default: inf2 = skill_get_inf2(sk_id);
if( !(skill_get_inf2(i)&(INF2_NPC_SKILL|INF2_GUILD_SKILL)) )
if ( ( sd->status.skill[i].lv = skill_get_max(i) ) )//Nonexistant skills should return a max of 0 anyway.
sd->status.skill[i].id = i;
}
}
} else {
int id;
for(i=0;i < MAX_SKILL_TREE && (id=skill_tree[pc_class2idx(sd->status.class_)][i].id)>0;i++){
int inf2 = skill_get_inf2(id);
if ( if (
(inf2&INF2_QUEST_SKILL && !battle_config.quest_skill_learn) || (inf2&INF2_QUEST_SKILL && !battle_config.quest_skill_learn) ||
(inf2&(INF2_WEDDING_SKILL|INF2_SPIRIT_SKILL)) || (inf2&(INF2_WEDDING_SKILL|INF2_SPIRIT_SKILL)) ||
id==SG_DEVIL sk_id == SG_DEVIL
) )
continue; //Cannot be learned normally. continue; //Cannot be learned normally.
sd->status.skill[id].id = id; sd->status.skill[sk_idx].id = sk_id;
sd->status.skill[id].lv = skill_tree_get_max(id, sd->status.class_); // celest sd->status.skill[sk_idx].lv = skill_tree_get_max(sk_id, sd->status.class_); // celest
} }
} }
status_calc_pc(sd,SCO_NONE); status_calc_pc(sd,SCO_NONE);
@ -6782,8 +6836,8 @@ int pc_resetlvl(struct map_session_data* sd,int type)
if(sd->status.class_ == JOB_NOVICE_HIGH) { if(sd->status.class_ == JOB_NOVICE_HIGH) {
sd->status.status_point=100; // not 88 [celest] sd->status.status_point=100; // not 88 [celest]
// give platinum skills upon changing // give platinum skills upon changing
pc_skill(sd,142,1,0); pc_skill(sd,NV_FIRSTAID,1,ADDSKILL_PERMANENT);
pc_skill(sd,143,1,0); pc_skill(sd,NV_TRICKDEAD,1,ADDSKILL_PERMANENT);
} }
} }
@ -6957,9 +7011,11 @@ int pc_resetskill(struct map_session_data* sd, int flag)
for( i = 1; i < MAX_SKILL; i++ ) for( i = 1; i < MAX_SKILL; i++ )
{ {
int lv = sd->status.skill[i].lv; uint8 lv = sd->status.skill[i].lv;
int inf2; int inf2;
if (lv < 1) continue; uint16 skill_id = skill_idx2id(i);
if (lv == 0 || skill_id == 0)
continue;
inf2 = skill_get_inf2(i); inf2 = skill_get_inf2(i);
@ -6967,7 +7023,7 @@ int pc_resetskill(struct map_session_data* sd, int flag)
continue; continue;
// Don't reset trick dead if not a novice/baby // Don't reset trick dead if not a novice/baby
if( i == NV_TRICKDEAD && (sd->class_&MAPID_UPPERMASK) != MAPID_NOVICE ) if( skill_id == NV_TRICKDEAD && (sd->class_&MAPID_UPPERMASK) != MAPID_NOVICE )
{ {
sd->status.skill[i].lv = 0; sd->status.skill[i].lv = 0;
sd->status.skill[i].flag = SKILL_FLAG_PERMANENT; sd->status.skill[i].flag = SKILL_FLAG_PERMANENT;
@ -6975,13 +7031,13 @@ int pc_resetskill(struct map_session_data* sd, int flag)
} }
// do not reset basic skill // do not reset basic skill
if( i == NV_BASIC && (sd->class_&MAPID_UPPERMASK) != MAPID_NOVICE ) if( skill_id == NV_BASIC && (sd->class_&MAPID_UPPERMASK) != MAPID_NOVICE )
continue; continue;
if( sd->status.skill[i].flag == SKILL_FLAG_PERM_GRANTED ) if( sd->status.skill[i].flag == SKILL_FLAG_PERM_GRANTED )
continue; continue;
if( flag&4 && !skill_ischangesex(i) ) if( flag&4 && !skill_ischangesex(skill_id) )
continue; continue;
if( inf2&INF2_QUEST_SKILL && !battle_config.quest_skill_learn ) if( inf2&INF2_QUEST_SKILL && !battle_config.quest_skill_learn )
@ -6996,7 +7052,7 @@ int pc_resetskill(struct map_session_data* sd, int flag)
if( sd->status.skill[i].flag == SKILL_FLAG_PERMANENT ) if( sd->status.skill[i].flag == SKILL_FLAG_PERMANENT )
skill_point += lv; skill_point += lv;
else else
if( sd->status.skill[i].flag == SKILL_FLAG_REPLACED_LV_0 ) if( sd->status.skill[i].flag >= SKILL_FLAG_REPLACED_LV_0 )
skill_point += (sd->status.skill[i].flag - SKILL_FLAG_REPLACED_LV_0); skill_point += (sd->status.skill[i].flag - SKILL_FLAG_REPLACED_LV_0);
if( !(flag&2) ) if( !(flag&2) )
@ -8030,26 +8086,26 @@ bool pc_jobchange(struct map_session_data *sd,int job, char upper)
pc_setglobalreg (sd, "jobchange_level_3rd", sd->change_level_3rd); pc_setglobalreg (sd, "jobchange_level_3rd", sd->change_level_3rd);
} }
if(sd->cloneskill_idx >= 0) { if(sd->cloneskill_idx > 0) {
if( sd->status.skill[sd->cloneskill_idx].flag == SKILL_FLAG_PLAGIARIZED ) { if( sd->status.skill[sd->cloneskill_idx].flag == SKILL_FLAG_PLAGIARIZED ) {
sd->status.skill[sd->cloneskill_idx].id = 0; sd->status.skill[sd->cloneskill_idx].id = 0;
sd->status.skill[sd->cloneskill_idx].lv = 0; sd->status.skill[sd->cloneskill_idx].lv = 0;
sd->status.skill[sd->cloneskill_idx].flag = SKILL_FLAG_PERMANENT; sd->status.skill[sd->cloneskill_idx].flag = SKILL_FLAG_PERMANENT;
clif_deleteskill(sd,pc_readglobalreg(sd,SKILL_VAR_PLAGIARISM)); clif_deleteskill(sd,pc_readglobalreg(sd,SKILL_VAR_PLAGIARISM));
} }
sd->cloneskill_idx = -1; sd->cloneskill_idx = 0;
pc_setglobalreg(sd,SKILL_VAR_PLAGIARISM, 0); pc_setglobalreg(sd,SKILL_VAR_PLAGIARISM, 0);
pc_setglobalreg(sd,SKILL_VAR_PLAGIARISM_LV, 0); pc_setglobalreg(sd,SKILL_VAR_PLAGIARISM_LV, 0);
} }
if(sd->reproduceskill_idx >= 0) { if(sd->reproduceskill_idx > 0) {
if( sd->status.skill[sd->reproduceskill_idx].flag == SKILL_FLAG_PLAGIARIZED ) { if( sd->status.skill[sd->reproduceskill_idx].flag == SKILL_FLAG_PLAGIARIZED ) {
sd->status.skill[sd->reproduceskill_idx].id = 0; sd->status.skill[sd->reproduceskill_idx].id = 0;
sd->status.skill[sd->reproduceskill_idx].lv = 0; sd->status.skill[sd->reproduceskill_idx].lv = 0;
sd->status.skill[sd->reproduceskill_idx].flag = SKILL_FLAG_PERMANENT; sd->status.skill[sd->reproduceskill_idx].flag = SKILL_FLAG_PERMANENT;
clif_deleteskill(sd,pc_readglobalreg(sd,SKILL_VAR_REPRODUCE)); clif_deleteskill(sd,pc_readglobalreg(sd,SKILL_VAR_REPRODUCE));
} }
sd->reproduceskill_idx = -1; sd->reproduceskill_idx = 0;
pc_setglobalreg(sd,SKILL_VAR_REPRODUCE,0); pc_setglobalreg(sd,SKILL_VAR_REPRODUCE,0);
pc_setglobalreg(sd,SKILL_VAR_REPRODUCE_LV,0); pc_setglobalreg(sd,SKILL_VAR_REPRODUCE_LV,0);
} }
@ -11441,6 +11497,32 @@ uint64 pc_generate_unique_id(struct map_session_data *sd) {
return ((uint64)sd->status.char_id << 32) | sd->status.uniqueitem_counter++; return ((uint64)sd->status.char_id << 32) | sd->status.uniqueitem_counter++;
} }
/**
* Validating skill from player after logged on
* @param sd
**/
void pc_validate_skill(struct map_session_data *sd) {
if (sd) {
uint16 i = 0, count = 0;
struct s_skill tmp_skills[MAX_SKILL] = {{ 0 }};
memcpy(tmp_skills, sd->status.skill, sizeof(sd->status.skill));
memset(sd->status.skill, 0, sizeof(sd->status.skill));
for (i = 0; i < MAX_SKILL; i++) {
uint16 idx = 0;
if (tmp_skills[i].id == 0 || tmp_skills[i].lv == 0)
continue;
if ((idx = skill_get_index(tmp_skills[i].id))) {
memcpy(&sd->status.skill[idx], &tmp_skills[i], sizeof(tmp_skills[i]));
count++;
}
else
ShowWarning("pc_validate_skill: Removing invalid skill '%d' from player (AID=%d CID=%d).\n", tmp_skills[i].id, sd->status.account_id, sd->status.char_id);
}
}
}
/*========================================== /*==========================================
* pc Init/Terminate * pc Init/Terminate
*------------------------------------------*/ *------------------------------------------*/

View File

@ -444,7 +444,7 @@ struct map_session_data {
short catch_target_class; // pet catching, stores a pet class to catch (short now) [zzo] short catch_target_class; // pet catching, stores a pet class to catch (short now) [zzo]
short spiritball, spiritball_old; int8 spiritball, spiritball_old;
int spirit_timer[MAX_SPIRITBALL]; int spirit_timer[MAX_SPIRITBALL];
short talisman[ELE_POISON+1]; // There are actually 5 talisman Fire, Ice, Wind, Earth & Poison maybe because its color violet. short talisman[ELE_POISON+1]; // There are actually 5 talisman Fire, Ice, Wind, Earth & Poison maybe because its color violet.
int talisman_timer[ELE_POISON+1][10]; int talisman_timer[ELE_POISON+1][10];
@ -669,6 +669,8 @@ enum weapon_type {
W_DOUBLE_SA, // sword + axe W_DOUBLE_SA, // sword + axe
}; };
#define WEAPON_TYPE_ALL ((1<<MAX_WEAPON_TYPE)-1)
enum ammo_type { enum ammo_type {
A_ARROW = 1, A_ARROW = 1,
A_DAGGER, //2 A_DAGGER, //2
@ -926,7 +928,15 @@ void pc_bonus2(struct map_session_data *sd, int type, int type2, int val);
void pc_bonus3(struct map_session_data *sd, int type, int type2, int type3, int val); void pc_bonus3(struct map_session_data *sd, int type, int type2, int type3, int val);
void pc_bonus4(struct map_session_data *sd, int type, int type2, int type3, int type4, int val); void pc_bonus4(struct map_session_data *sd, int type, int type2, int type3, int type4, int val);
void pc_bonus5(struct map_session_data *sd, int type, int type2, int type3, int type4, int type5, int val); void pc_bonus5(struct map_session_data *sd, int type, int type2, int type3, int type4, int type5, int val);
int pc_skill(struct map_session_data *sd, int id, int level, int flag);
enum e_addskill_type {
ADDSKILL_PERMANENT = 0, ///< Permanent skill. Remove the skill if level is 0
ADDSKILL_TEMP = 1, ///< Temporary skill. If player learned the skill and the given level is higher, level will be replaced and learned level will be palced in skill flag. `flag = learned + SKILL_FLAG_REPLACED_LV_0; learned_level = level;`
ADDSKILL_TEMP_ADDLEVEL = 2, ///< Like PCSKILL_TEMP, except the level will be stacked. `learned_level += level`. The flag is used to store original learned level
ADDSKILL_PERMANENT_GRANTED = 3, ///< Grant permanent skill, ignore skill tree and learned level
};
bool pc_skill(struct map_session_data *sd, uint16 skill_id, int level, enum e_addskill_type type);
int pc_insert_card(struct map_session_data *sd,int idx_card,int idx_equip); int pc_insert_card(struct map_session_data *sd,int idx_card,int idx_equip);
@ -953,7 +963,7 @@ int pc_need_status_point(struct map_session_data *,int,int);
int pc_maxparameterincrease(struct map_session_data*,int); int pc_maxparameterincrease(struct map_session_data*,int);
bool pc_statusup(struct map_session_data*,int,int); bool pc_statusup(struct map_session_data*,int,int);
int pc_statusup2(struct map_session_data*,int,int); int pc_statusup2(struct map_session_data*,int,int);
int pc_skillup(struct map_session_data*,uint16 skill_id); void pc_skillup(struct map_session_data*,uint16 skill_id);
int pc_allskillup(struct map_session_data*); int pc_allskillup(struct map_session_data*);
int pc_resetlvl(struct map_session_data*,int type); int pc_resetlvl(struct map_session_data*,int type);
int pc_resetstate(struct map_session_data*); int pc_resetstate(struct map_session_data*);
@ -1038,12 +1048,12 @@ int pc_mapid2jobid(unsigned short class_, int sex); // Skotlex
const char * job_name(int class_); const char * job_name(int class_);
struct skill_tree_entry { struct skill_tree_entry {
short id; uint16 id;
unsigned char max; uint8 max;
unsigned char joblv; uint8 joblv;
struct { struct {
short id; uint16 id;
unsigned char lv; uint8 lv;
} need[MAX_PC_SKILL_REQUIRE]; } need[MAX_PC_SKILL_REQUIRE];
}; // Celest }; // Celest
extern struct skill_tree_entry skill_tree[CLASS_COUNT][MAX_SKILL_TREE]; extern struct skill_tree_entry skill_tree[CLASS_COUNT][MAX_SKILL_TREE];
@ -1146,6 +1156,8 @@ bool pc_is_same_equip_index(enum equip_index eqi, short *equip_index, short inde
int pc_autotrade_timer(int tid, unsigned int tick, int id, intptr_t data); int pc_autotrade_timer(int tid, unsigned int tick, int id, intptr_t data);
void pc_validate_skill(struct map_session_data *sd);
#if defined(RENEWAL_DROP) || defined(RENEWAL_EXP) #if defined(RENEWAL_DROP) || defined(RENEWAL_EXP)
int pc_level_penalty_mod(struct map_session_data *sd, int mob_level, uint32 mob_class, int type); int pc_level_penalty_mod(struct map_session_data *sd, int mob_level, uint32 mob_class, int type);
#endif #endif

View File

@ -8598,53 +8598,25 @@ BUILDIN_FUNC(skill)
{ {
int id; int id;
int level; int level;
int flag = 1; int flag = ADDSKILL_TEMP;
TBL_PC* sd; TBL_PC* sd;
struct script_data *data; struct script_data *data;
const char* command = script_getfuncname(st);
sd = script_rid2sd(st); sd = script_rid2sd(st);
if( sd == NULL ) if( sd == NULL )
return 0;// no player attached, report source return 0;// no player attached, report source
if (strcmpi(command, "addtoskill") == 0)
flag = ADDSKILL_TEMP_ADDLEVEL;
data = script_getdata(st, 2); data = script_getdata(st, 2);
get_val(st, data); // Convert into value in case of a variable get_val(st, data); // Convert into value in case of a variable
id = ( data_isstring(data) ? skill_name2id(script_getstr(st,2)) : script_getnum(st,2) ); id = ( data_isstring(data) ? skill_name2id(script_getstr(st,2)) : script_getnum(st,2) );
level = script_getnum(st,3); level = script_getnum(st,3);
if( script_hasdata(st,4) ) if( script_hasdata(st,4) )
flag = script_getnum(st,4); flag = script_getnum(st,4);
pc_skill(sd, id, level, flag); pc_skill(sd, id, level, (enum e_addskill_type)flag);
return SCRIPT_CMD_SUCCESS;
}
/// Changes the level of a player skill.
/// like skill, but <flag> defaults to 2
///
/// addtoskill <skill id>,<amount>,<flag>
/// addtoskill <skill id>,<amount>
/// addtoskill "<skill name>",<amount>,<flag>
/// addtoskill "<skill name>",<amount>
///
/// @see skill
BUILDIN_FUNC(addtoskill)
{
int id;
int level;
int flag = 2;
TBL_PC* sd;
struct script_data *data;
sd = script_rid2sd(st);
if( sd == NULL )
return 0;// no player attached, report source
data = script_getdata(st, 2);
get_val(st, data); // Convert into value in case of a variable
id = ( data_isstring(data) ? skill_name2id(script_getstr(st,2)) : script_getnum(st,2) );
level = script_getnum(st,3);
if( script_hasdata(st,4) )
flag = script_getnum(st,4);
pc_skill(sd, id, level, flag);
return SCRIPT_CMD_SUCCESS; return SCRIPT_CMD_SUCCESS;
} }
@ -19356,7 +19328,7 @@ struct script_function buildin_func[] = {
BUILDIN_DEF(autobonus2,"sii??"), BUILDIN_DEF(autobonus2,"sii??"),
BUILDIN_DEF(autobonus3,"siiv?"), BUILDIN_DEF(autobonus3,"siiv?"),
BUILDIN_DEF(skill,"vi?"), BUILDIN_DEF(skill,"vi?"),
BUILDIN_DEF(addtoskill,"vi?"), // [Valaris] BUILDIN_DEF2(skill,"addtoskill","vi?"), // [Valaris]
BUILDIN_DEF(guildskill,"vi"), BUILDIN_DEF(guildskill,"vi"),
BUILDIN_DEF(getskilllv,"v"), BUILDIN_DEF(getskilllv,"v"),
BUILDIN_DEF(getgdskilllv,"iv"), BUILDIN_DEF(getgdskilllv,"iv"),

File diff suppressed because it is too large Load Diff

View File

@ -13,14 +13,14 @@ struct skill_unit;
struct skill_unit_group; struct skill_unit_group;
struct status_change_entry; struct status_change_entry;
#define MAX_SKILL_DB MAX_SKILL /// Max Skill DB
#define MAX_SKILL_PRODUCE_DB 270 /// Max Produce DB #define MAX_SKILL_PRODUCE_DB 270 /// Max Produce DB
#define MAX_PRODUCE_RESOURCE 12 /// Max Produce requirements #define MAX_PRODUCE_RESOURCE 12 /// Max Produce requirements
#define MAX_SKILL_ARROW_DB 150 /// Max Arrow Creation DB #define MAX_SKILL_ARROW_DB 150 /// Max Arrow Creation DB
#define MAX_ARROW_RESULT 5 /// Max Arrow results/created #define MAX_ARROW_RESULT 5 /// Max Arrow results/created
#define MAX_SKILL_ABRA_DB 160 /// Max Skill list of Abracadabra DB #define MAX_SKILL_ABRA_DB 160 /// Max Skill list of Abracadabra DB
#define MAX_SKILL_IMPROVISE_DB 30 /// Max Skill for Improvise #define MAX_SKILL_IMPROVISE_DB 30 /// Max Skill for Improvise
#define MAX_SKILL_LEVEL 100 /// Max Skill Level #define MAX_SKILL_LEVEL 10 /// Max Skill Level (for skill_db storage)
#define MAX_MOBSKILL_LEVEL 100 /// Max monster skill level (on skill usage)
#define MAX_SKILL_CRIMSON_MARKER 3 /// Max Crimson Marker targets (RL_C_MARKER) #define MAX_SKILL_CRIMSON_MARKER 3 /// Max Crimson Marker targets (RL_C_MARKER)
#define SKILL_NAME_LENGTH 31 /// Max Skill Name length #define SKILL_NAME_LENGTH 31 /// Max Skill Name length
#define SKILL_DESC_LENGTH 31 /// Max Skill Desc length #define SKILL_DESC_LENGTH 31 /// Max Skill Desc length
@ -111,80 +111,116 @@ enum e_skill_display {
#define MAX_SKILL_ITEM_REQUIRE 10 /// Maximum required items #define MAX_SKILL_ITEM_REQUIRE 10 /// Maximum required items
#define MAX_SKILL_STATUS_REQUIRE 3 /// Maximum required statuses #define MAX_SKILL_STATUS_REQUIRE 3 /// Maximum required statuses
#define MAX_SKILL_EQUIP_REQUIRE 10 /// Maximum required equipped item #define MAX_SKILL_EQUIP_REQUIRE 10 /// Maximum required equipped item
/// Single skill requirement. !TODO: Cleanup the variable types
struct skill_condition { struct skill_condition {
int hp, /// HP cost int16 hp; ///< HP cost
mhp, /// Max HP to trigger int16 mhp; ///< Max HP to trigger
sp, /// SP cost int16 sp; /// SP cost
hp_rate, /// HP cost (%) int16 hp_rate; /// HP cost (%)
sp_rate, /// SP cost (%) int16 sp_rate; /// SP cost (%)
ammo, /// Ammo type uint32 zeny; /// Zeny cost
ammo_qty, /// Amount of ammo uint32 weapon; /// Weapon type. Combined bitmask of enum weapon_type (1<<weapon)
weapon, /// Weapon type uint16 ammo; /// Ammo type. Combine bitmask of enum ammo_type (1<<ammo)
zeny, /// Zeny cost int8 ammo_qty; /// Amount of ammo
state, /// State/condition uint8 state; /// State/condition. @see enum e_require_state
spiritball, /// Spiritball cost int8 spiritball; /// Spiritball cost
itemid[MAX_SKILL_ITEM_REQUIRE], /// Required item uint16 itemid[MAX_SKILL_ITEM_REQUIRE]; /// Required item
amount[MAX_SKILL_ITEM_REQUIRE]; /// Amount of item uint16 amount[MAX_SKILL_ITEM_REQUIRE]; /// Amount of item
uint16 *eqItem; /// List of equipped item uint16 *eqItem; /// List of equipped item
enum sc_type *status; /// List of Status required (SC) enum sc_type *status; /// List of Status required (SC)
uint8 status_count, /// Count of SC uint8 status_count, /// Count of SC
eqItem_count; /// Count of equipped item eqItem_count; /// Count of equipped item
}; };
/// Skill requirement structure. !TODO: Cleanup the variable types that use array [MAX_SKILL_LEVEL]
struct s_skill_require { struct s_skill_require {
int hp[MAX_SKILL_LEVEL], /// HP cost int hp[MAX_SKILL_LEVEL]; ///< HP cost
mhp[MAX_SKILL_LEVEL], /// Max HP to trigger int mhp[MAX_SKILL_LEVEL]; ///< Max HP to trigger
sp[MAX_SKILL_LEVEL], /// SP cost int sp[MAX_SKILL_LEVEL]; /// SP cost
hp_rate[MAX_SKILL_LEVEL], /// HP cost (%) int hp_rate[MAX_SKILL_LEVEL]; /// HP cost (%)
sp_rate[MAX_SKILL_LEVEL], /// SP cost (%) int sp_rate[MAX_SKILL_LEVEL]; /// SP cost (%)
zeny[MAX_SKILL_LEVEL], /// Zeny cost int zeny[MAX_SKILL_LEVEL]; /// Zeny cost
weapon, /// Weapon type uint32 weapon; /// Weapon type. Combined bitmask of enum weapon_type (1<<weapon)
ammo, /// Ammo type uint16 ammo; /// Ammo type. Combine bitmask of enum ammo_type (1<<ammo)
ammo_qty[MAX_SKILL_LEVEL], /// Amount of ammo int ammo_qty[MAX_SKILL_LEVEL]; /// Amount of ammo
state, /// State/condition uint8 state; /// State/condition. @see enum e_require_state
spiritball[MAX_SKILL_LEVEL], /// Spiritball cost int spiritball[MAX_SKILL_LEVEL]; /// Spiritball cost
itemid[MAX_SKILL_ITEM_REQUIRE], /// Required item int itemid[MAX_SKILL_ITEM_REQUIRE]; /// Required item
amount[MAX_SKILL_ITEM_REQUIRE]; /// Amount of item int amount[MAX_SKILL_ITEM_REQUIRE]; /// Amount of item
uint16 *eqItem; /// List of equipped item uint16 *eqItem; /// List of equipped item
enum sc_type *status; /// List of Status required (SC) enum sc_type *status; /// List of Status required (SC)
uint8 status_count, /// Count of SC uint8 status_count, /// Count of SC
eqItem_count; /// Count of equipped item eqItem_count; /// Count of equipped item
}; };
/// Database skills /// Database skills. !TODO: Cleanup the variable types that use array [MAX_SKILL_LEVEL]
struct s_skill_db { struct s_skill_db {
char name[SKILL_NAME_LENGTH]; // skill_db.txt
char desc[SKILL_DESC_LENGTH]; uint16 nameid; ///< Skill ID
int range[MAX_SKILL_LEVEL],hit,inf,element[MAX_SKILL_LEVEL],nk,splash[MAX_SKILL_LEVEL],max; char name[SKILL_NAME_LENGTH]; ///< AEGIS_Name
int num[MAX_SKILL_LEVEL]; char desc[SKILL_DESC_LENGTH]; ///< English Name
int cast[MAX_SKILL_LEVEL],walkdelay[MAX_SKILL_LEVEL],delay[MAX_SKILL_LEVEL]; int range[MAX_SKILL_LEVEL]; ///< Range
int8 hit; ///< Hit type
uint8 inf; ///< Inf: 0- passive, 1- enemy, 2- place, 4- self, 16- friend, 32- trap
int element[MAX_SKILL_LEVEL]; ///< Element
uint8 nk; ///< Damage properties
int splash[MAX_SKILL_LEVEL]; ///< Splash effect
uint8 max; ///< Max level
int num[MAX_SKILL_LEVEL]; ///< Number of hit
bool castcancel; ///< Cancel cast when being hit
int16 cast_def_rate; ///< Def rate during cast a skill
uint16 skill_type; ///< Skill type
int blewcount[MAX_SKILL_LEVEL]; ///< Blew count
uint32 inf2; ///<
uint32 inf3; ///<
int maxcount[MAX_SKILL_LEVEL]; ///< Max number skill can be casted in same map
// skill_castnodex_db.txt
uint8 castnodex; ///< 1 - Not affected by dex, 2 - Not affected by SC, 4 - Not affected by item
uint8 delaynodex; ///< 1 - Not affected by dex, 2 - Not affected by SC, 4 - Not affected by item
// skill_nocast_db.txt
uint32 nocast; ///< Skill cannot be casted at this zone
// skill_unit_db.txt
uint16 unit_id[2]; ///< Unit ID. @see enum s_skill_unit_id
int unit_layout_type[MAX_SKILL_LEVEL]; ///< Layout type. -1 is special layout, others are square with lenght*width: (val*2+1)^2
int unit_range[MAX_SKILL_LEVEL]; ///< Unit cell effect range
int16 unit_interval; ///< Interval
uint32 unit_target; ///< Unit target. @see enum e_battle_check_target
uint32 unit_flag; ///< Unit flags. @see enum e_skill_unit_flag
// skill_cast_db.txt
int cast[MAX_SKILL_LEVEL]; ///< Variable casttime
#ifdef RENEWAL_CAST #ifdef RENEWAL_CAST
int fixed_cast[MAX_SKILL_LEVEL]; int fixed_cast[MAX_SKILL_LEVEL]; ///< If -1 means 20% than 'cast'
#endif #endif
int upkeep_time[MAX_SKILL_LEVEL],upkeep_time2[MAX_SKILL_LEVEL],cooldown[MAX_SKILL_LEVEL]; int walkdelay[MAX_SKILL_LEVEL]; ///< Delay to walk after casting
int castcancel,cast_def_rate; int delay[MAX_SKILL_LEVEL]; ///< Global delay (delay before reusing all skills)
int inf2,maxcount[MAX_SKILL_LEVEL],skill_type,inf3; int cooldown[MAX_SKILL_LEVEL]; ///< Cooldown (delay before reusing same skill)
int blewcount[MAX_SKILL_LEVEL]; int upkeep_time[MAX_SKILL_LEVEL]; ///< Duration
struct s_skill_require require; int upkeep_time2[MAX_SKILL_LEVEL]; ///< Duration2
int castnodex[MAX_SKILL_LEVEL], delaynodex[MAX_SKILL_LEVEL];
int32 nocast; // skill_require_db.txt
int unit_id[2]; struct s_skill_require require; ///< Skill requirement
int unit_layout_type[MAX_SKILL_LEVEL];
int unit_range[MAX_SKILL_LEVEL]; // skill_nonearnpc_db.txt
int unit_interval;
int unit_target;
int unit_flag;
uint8 unit_nonearnpc_range; //additional range for UF_NONEARNPC or INF2_NO_NEARNPC [Cydh] uint8 unit_nonearnpc_range; //additional range for UF_NONEARNPC or INF2_NO_NEARNPC [Cydh]
uint8 unit_nonearnpc_type; //type of NPC [Cydh] uint8 unit_nonearnpc_type; //type of NPC [Cydh]
// skill_damage_db.txt
#ifdef ADJUST_SKILL_DAMAGE #ifdef ADJUST_SKILL_DAMAGE
struct s_skill_damage damage; struct s_skill_damage damage;
#endif #endif
// skill_copyable_db.txt
struct s_copyable { // [Cydh] struct s_copyable { // [Cydh]
uint8 option; uint8 option;
uint16 joballowed, req_opt; uint16 joballowed, req_opt;
} copyable; } copyable;
}; };
extern struct s_skill_db skill_db[MAX_SKILL_DB]; extern struct s_skill_db **skill_db;
#define MAX_SKILL_UNIT_LAYOUT 52 #define MAX_SKILL_UNIT_LAYOUT 52
#define MAX_SKILL_UNIT_LAYOUT2 17 #define MAX_SKILL_UNIT_LAYOUT2 17
@ -261,7 +297,7 @@ struct skill_unit_group_tickset {
}; };
enum { enum e_skill_unit_flag {
UF_DEFNOTENEMY = 0x00001, // If 'defunit_not_enemy' is set, the target is changed to 'friend' UF_DEFNOTENEMY = 0x00001, // If 'defunit_not_enemy' is set, the target is changed to 'friend'
UF_NOREITERATION = 0x00002, // Spell cannot be stacked UF_NOREITERATION = 0x00002, // Spell cannot be stacked
UF_NOFOOTSET = 0x00004, // Spell cannot be cast near/on targets UF_NOFOOTSET = 0x00004, // Spell cannot be cast near/on targets
@ -321,7 +357,9 @@ const char* skill_get_desc( uint16 skill_id ); // [Skotlex]
int skill_tree_get_max( uint16 skill_id, int b_class ); // Celest int skill_tree_get_max( uint16 skill_id, int b_class ); // Celest
// Accessor to the skills database // Accessor to the skills database
int skill_get_index( uint16 skill_id ); int skill_get_index_( uint16 skill_id, bool silent, const char *func, const char *file, int line );
#define skill_get_index(skill_id) skill_get_index_((skill_id), false, __FUNCTION__, __FILE__, __LINE__) /// Get skill index from skill_id (common usage on source)
#define skill_get_index2(skill_id) skill_get_index_((skill_id), true, __FUNCTION__, __FILE__, __LINE__) /// Get skill index from skill_id (used when reading skill_db files)
int skill_get_type( uint16 skill_id ); int skill_get_type( uint16 skill_id );
int skill_get_hit( uint16 skill_id ); int skill_get_hit( uint16 skill_id );
int skill_get_inf( uint16 skill_id ); int skill_get_inf( uint16 skill_id );
@ -337,7 +375,7 @@ int skill_get_delay( uint16 skill_id ,uint16 skill_lv );
int skill_get_walkdelay( uint16 skill_id ,uint16 skill_lv ); int skill_get_walkdelay( uint16 skill_id ,uint16 skill_lv );
int skill_get_time( uint16 skill_id ,uint16 skill_lv ); int skill_get_time( uint16 skill_id ,uint16 skill_lv );
int skill_get_time2( uint16 skill_id ,uint16 skill_lv ); int skill_get_time2( uint16 skill_id ,uint16 skill_lv );
int skill_get_castnodex( uint16 skill_id ,uint16 skill_lv ); int skill_get_castnodex( uint16 skill_id );
int skill_get_castdef( uint16 skill_id ); int skill_get_castdef( uint16 skill_id );
int skill_get_nocast( uint16 skill_id ); int skill_get_nocast( uint16 skill_id );
int skill_get_unit_id(uint16 skill_id,int flag); int skill_get_unit_id(uint16 skill_id,int flag);
@ -367,6 +405,9 @@ int skill_get_itemid( uint16 skill_id, int idx );
int skill_get_itemqty( uint16 skill_id, int idx ); int skill_get_itemqty( uint16 skill_id, int idx );
int skill_name2id(const char* name); int skill_name2id(const char* name);
uint16 skill_idx2id(uint16 idx);
uint16 SKILL_MAX_DB(void);
int skill_isammotype(struct map_session_data *sd, unsigned short skill_id); int skill_isammotype(struct map_session_data *sd, unsigned short skill_id);
int skill_castend_id(int tid, unsigned int tick, int id, intptr_t data); int skill_castend_id(int tid, unsigned int tick, int id, intptr_t data);
@ -1815,7 +1856,7 @@ enum e_skill {
}; };
/// The client view ids for land skills. /// The client view ids for land skills.
enum { enum s_skill_unit_id {
UNT_SAFETYWALL = 0x7e, UNT_SAFETYWALL = 0x7e,
UNT_FIREWALL, UNT_FIREWALL,
UNT_WARP_WAITING, UNT_WARP_WAITING,
@ -2055,4 +2096,9 @@ enum e_skill_damage_caster {
/// Variable name of copied skill level by Reproduce /// Variable name of copied skill level by Reproduce
#define SKILL_VAR_REPRODUCE_LV "REPRODUCE_SKILL_LV" #define SKILL_VAR_REPRODUCE_LV "REPRODUCE_SKILL_LV"
#define SKILL_CHK_HOMUN(skill_id) ( (skill_id) >= HM_SKILLBASE && (skill_id) < HM_SKILLBASE+MAX_HOMUNSKILL )
#define SKILL_CHK_MERC(skill_id) ( (skill_id) >= MC_SKILLBASE && (skill_id) < MC_SKILLBASE+MAX_MERCSKILL )
#define SKILL_CHK_ELEM(skill_id) ( (skill_id) >= EL_SKILLBASE && (skill_id) < EL_SKILLBASE+MAX_ELEMENTALSKILL )
#define SKILL_CHK_GUILD(skill_id) ( (skill_id) >= GD_SKILLBASE && (skill_id) < GD_SKILLBASE+MAX_GUILDSKILL )
#endif /* _SKILL_H_ */ #endif /* _SKILL_H_ */

View File

@ -154,11 +154,11 @@ static void set_sc(uint16 skill_id, sc_type sc, int icon, unsigned int flag)
{ {
uint16 idx = skill_get_index(skill_id); uint16 idx = skill_get_index(skill_id);
if( idx == 0 ) { if( idx == 0 ) {
ShowError("set_sc: Unsupported skill id %d\n", skill_id); ShowError("set_sc: Unsupported skill id %d (SC: %d. Icon: %d)\n", skill_id, sc, icon);
return; return;
} }
if( sc < 0 || sc >= SC_MAX ) { if( sc < 0 || sc >= SC_MAX ) {
ShowError("set_sc: Unsupported status change id %d\n", sc); ShowError("set_sc: Unsupported status change id %d (Skill: %d. Icon: %d)\n", sc, skill_id, icon);
return; return;
} }
@ -172,6 +172,16 @@ static void set_sc(uint16 skill_id, sc_type sc, int icon, unsigned int flag)
SkillStatusChangeTable[idx] = sc; SkillStatusChangeTable[idx] = sc;
} }
static void set_sc_with_vfx_noskill(sc_type sc, int icon, unsigned flag) {
if (sc > SC_NONE && sc < SC_MAX) {
if (StatusIconChangeTable[sc] == SI_BLANK)
StatusIconChangeTable[sc] = icon;
StatusChangeFlagTable[sc] |= flag;
}
if (icon > SI_BLANK && icon < SI_MAX)
StatusRelevantBLTypes[icon] |= BL_SCEFFECT;
}
void initChangeTables(void) void initChangeTables(void)
{ {
int i; int i;
@ -791,8 +801,6 @@ void initChangeTables(void)
set_sc( OB_OBOROGENSOU , SC_GENSOU , SI_GENSOU , SCB_NONE ); set_sc( OB_OBOROGENSOU , SC_GENSOU , SI_GENSOU , SCB_NONE );
set_sc( ALL_FULL_THROTTLE , SC_FULL_THROTTLE , SI_FULL_THROTTLE , SCB_SPEED|SCB_STR|SCB_AGI|SCB_VIT|SCB_INT|SCB_DEX|SCB_LUK ); set_sc( ALL_FULL_THROTTLE , SC_FULL_THROTTLE , SI_FULL_THROTTLE , SCB_SPEED|SCB_STR|SCB_AGI|SCB_VIT|SCB_INT|SCB_DEX|SCB_LUK );
set_sc_with_vfx( SC_MOONSTAR , SC_MOONSTAR , SI_MOONSTAR , SCB_NONE );
set_sc_with_vfx( SC_SUPER_STAR , SC_SUPER_STAR , SI_SUPER_STAR , SCB_NONE );
/* Rebellion */ /* Rebellion */
add_sc( RL_MASS_SPIRAL , SC_BLEEDING ); add_sc( RL_MASS_SPIRAL , SC_BLEEDING );
@ -806,24 +814,26 @@ void initChangeTables(void)
set_sc_with_vfx( RL_C_MARKER , SC_C_MARKER , SI_C_MARKER , SCB_FLEE ); set_sc_with_vfx( RL_C_MARKER , SC_C_MARKER , SI_C_MARKER , SCB_FLEE );
set_sc_with_vfx( RL_AM_BLAST , SC_ANTI_M_BLAST , SI_ANTI_M_BLAST , SCB_NONE ); set_sc_with_vfx( RL_AM_BLAST , SC_ANTI_M_BLAST , SI_ANTI_M_BLAST , SCB_NONE );
set_sc_with_vfx( SC_ALL_RIDING , SC_ALL_RIDING , SI_ALL_RIDING , SCB_SPEED ); set_sc_with_vfx_noskill( SC_MOONSTAR , SI_MOONSTAR , SCB_NONE );
set_sc_with_vfx_noskill( SC_SUPER_STAR , SI_SUPER_STAR , SCB_NONE );
set_sc_with_vfx_noskill( SC_ALL_RIDING , SI_ALL_RIDING , SCB_SPEED );
/* Storing the target job rather than simply SC_SPIRIT simplifies code later on */ /* Storing the target job rather than simply SC_SPIRIT simplifies code later on */
SkillStatusChangeTable[SL_ALCHEMIST] = (sc_type)MAPID_ALCHEMIST, SkillStatusChangeTable[skill_get_index(SL_ALCHEMIST)] = (sc_type)MAPID_ALCHEMIST,
SkillStatusChangeTable[SL_MONK] = (sc_type)MAPID_MONK, SkillStatusChangeTable[skill_get_index(SL_MONK)] = (sc_type)MAPID_MONK,
SkillStatusChangeTable[SL_STAR] = (sc_type)MAPID_STAR_GLADIATOR, SkillStatusChangeTable[skill_get_index(SL_STAR)] = (sc_type)MAPID_STAR_GLADIATOR,
SkillStatusChangeTable[SL_SAGE] = (sc_type)MAPID_SAGE, SkillStatusChangeTable[skill_get_index(SL_SAGE)] = (sc_type)MAPID_SAGE,
SkillStatusChangeTable[SL_CRUSADER] = (sc_type)MAPID_CRUSADER, SkillStatusChangeTable[skill_get_index(SL_CRUSADER)] = (sc_type)MAPID_CRUSADER,
SkillStatusChangeTable[SL_SUPERNOVICE] = (sc_type)MAPID_SUPER_NOVICE, SkillStatusChangeTable[skill_get_index(SL_SUPERNOVICE)] = (sc_type)MAPID_SUPER_NOVICE,
SkillStatusChangeTable[SL_KNIGHT] = (sc_type)MAPID_KNIGHT, SkillStatusChangeTable[skill_get_index(SL_KNIGHT)] = (sc_type)MAPID_KNIGHT,
SkillStatusChangeTable[SL_WIZARD] = (sc_type)MAPID_WIZARD, SkillStatusChangeTable[skill_get_index(SL_WIZARD)] = (sc_type)MAPID_WIZARD,
SkillStatusChangeTable[SL_PRIEST] = (sc_type)MAPID_PRIEST, SkillStatusChangeTable[skill_get_index(SL_PRIEST)] = (sc_type)MAPID_PRIEST,
SkillStatusChangeTable[SL_BARDDANCER] = (sc_type)MAPID_BARDDANCER, SkillStatusChangeTable[skill_get_index(SL_BARDDANCER)] = (sc_type)MAPID_BARDDANCER,
SkillStatusChangeTable[SL_ROGUE] = (sc_type)MAPID_ROGUE, SkillStatusChangeTable[skill_get_index(SL_ROGUE)] = (sc_type)MAPID_ROGUE,
SkillStatusChangeTable[SL_ASSASIN] = (sc_type)MAPID_ASSASSIN, SkillStatusChangeTable[skill_get_index(SL_ASSASIN)] = (sc_type)MAPID_ASSASSIN,
SkillStatusChangeTable[SL_BLACKSMITH] = (sc_type)MAPID_BLACKSMITH, SkillStatusChangeTable[skill_get_index(SL_BLACKSMITH)] = (sc_type)MAPID_BLACKSMITH,
SkillStatusChangeTable[SL_HUNTER] = (sc_type)MAPID_HUNTER, SkillStatusChangeTable[skill_get_index(SL_HUNTER)] = (sc_type)MAPID_HUNTER,
SkillStatusChangeTable[SL_SOULLINKER] = (sc_type)MAPID_SOUL_LINKER, SkillStatusChangeTable[skill_get_index(SL_SOULLINKER)] = (sc_type)MAPID_SOUL_LINKER,
/* Status that don't have a skill associated */ /* Status that don't have a skill associated */
StatusIconChangeTable[SC_WEIGHT50] = SI_WEIGHT50; StatusIconChangeTable[SC_WEIGHT50] = SI_WEIGHT50;

View File

@ -2067,6 +2067,7 @@ int status_change_spread( struct block_list *src, struct block_list *bl );
unsigned short status_base_atk(const struct block_list *bl, const struct status_data *status); unsigned short status_base_atk(const struct block_list *bl, const struct status_data *status);
void initChangeTables(void);
int status_readdb(void); int status_readdb(void);
int do_init_status(void); int do_init_status(void);
void do_final_status(void); void do_final_status(void);

View File

@ -1796,7 +1796,7 @@ int unit_skilluse_id2(struct block_list *src, int target_id, uint16 skill_id, ui
// Moved here to prevent Suffragium from ending if skill fails // Moved here to prevent Suffragium from ending if skill fails
#ifndef RENEWAL_CAST #ifndef RENEWAL_CAST
if (!(skill_get_castnodex(skill_id, skill_lv)&2)) if (!(skill_get_castnodex(skill_id)&2))
casttime = skill_castfix_sc(src, casttime); casttime = skill_castfix_sc(src, casttime);
#else #else
casttime = skill_vfcastfix(src, casttime, skill_id, skill_lv); casttime = skill_vfcastfix(src, casttime, skill_id, skill_lv);
@ -2013,7 +2013,7 @@ int unit_skilluse_pos2( struct block_list *src, short skill_x, short skill_y, ui
// Moved here to prevent Suffragium from ending if skill fails // Moved here to prevent Suffragium from ending if skill fails
#ifndef RENEWAL_CAST #ifndef RENEWAL_CAST
if (!(skill_get_castnodex(skill_id, skill_lv)&2)) if (!(skill_get_castnodex(skill_id)&2))
casttime = skill_castfix_sc(src, casttime); casttime = skill_castfix_sc(src, casttime);
#else #else
casttime = skill_vfcastfix(src, casttime, skill_id, skill_lv ); casttime = skill_vfcastfix(src, casttime, skill_id, skill_lv );