Verified Commit fc7119af authored by Daegaladh's avatar Daegaladh Committed by Andrei Karas
Browse files

Added Enable Skill patches, converted from NEMO v3

parent 2c844912
///=====================================================///
/// Patch Functions wrapping over EnableSkills function ///
///=====================================================///
SKL = //Used for Enable*Skills patches
{
"Offset" : -1,
"Prefix" : "",
"PatchID" : false,
"Error" : false
}
function EnablePlayerSkills()
{
return EnableSkills(
" 3D 7D 02 00 00" //CMP EAX, 27D
+ " 0F 8F AB AB 00 00" //JG addr
+ " 3D 7C 02 00 00" //CMP EAX, 27C
,
" 3D 06 01 00 00" //CMP EAX, 106
+ " 7F AB" //JG SHORT addr
+ " 0F 84 AB AB 00 00" //JE addr2
,
233,
"IsPlayerSkill\0",
true
);
}
function EnableHomunSkills() //Incomplete
{
return EnableSkills(
" 3D 40 1F 00 00" //CMP EAX, 1F40
+ " 7C AB" //JL SHORT addr
+ " 3D 51 1F 00 00" //CMP EAX, 1F51
,
" 05 C0 E0 FF FF" //ADD EAX, -1F40
+ " B9 2C 00 00 00" //MOV ECX, 2C
,
234,
"IsHomunSkill\0",
false
);
}
function EnableMerceSkills() //Incomplete
{
return EnableSkills(
" 3D 08 20 00 00" //CMP EAX, 2008
+ " 7C AB" //JL SHORT addr
+ " 3D 31 20 00 00" //CMP EAX, 2031
,
" 8D AB F8 DF FF FF" //LEA reg32_B, [reg32_A - 2008]
+ " 83 AB 29" //CMP reg32_B, 29
,
235,
"IsMercenarySkill\0",
false
);
}
//###############################################################\\
//# Modify the respective Skill ID checker function (returns 1) #\\
//# to use Custom Lua functions instead of hardcoded tables #\\
//###############################################################\\
function EnableSkills(oldPatn, newPatn, patchID, funcName, isPlayerFn)
{
//Step 1.1 - Prep the code to find the Skill ID checker function
if (exe.getClientDate() < 20100817)
var code = oldPatn; //VC6
else
var code = newPatn; //VC9+
//Step 1.2 - Find the code inside the function
var offset = exe.findCode(code, PTYPE_HEX, true, "\xAB");
if (offset === -1)
return "Failed in Step 1 - ID checker missing";
//Step 1.3 - Get the Function Address (will be a few bytes before offset)
if (HasFramePointer())
var fnBegin = offset - 6;//Account for PUSH EBP; MOV EBP, ESP and MOV EAX, DWORD PTR SS:[EBP+8]
else
var fnBegin = offset - 3;//Account for MOV EAX, DWORD PTR SS:[ESP+4]
//Step 2 - Inject Lua file Loaders
if (isPlayerFn)//Player Function is big enough to put all the code there instead of DIFF section
LoadSkillTypeLua(patchID, fnBegin + 0x100);
else
LoadSkillTypeLua(patchID);
if (typeof(SKL.Error) === "string")
return "Failed in Step 2 - " + SKL.Error;
if (isPlayerFn)
{
//Step 3.1 - Prep Lua Function caller
code =
" 8B 44 24 04" //MOV EAX, DWORD PTR SS:[ARG.1]
+ GenLuaCaller(fnBegin + 4, funcName, exe.Raw2Rva(fnBegin + 0x80), "d>d", " 50")
+ " C3" //RETN ; AL is already set
;
//Step 3.2 - Overwrite function with our code
exe.replace(fnBegin, code, PTYPE_HEX);
//Step 3.3 - Add the function Names after the codes
exe.replace(fnBegin + 0x80, funcName, PTYPE_STRING);
}
else
{
//Step 4.1 - Find Free space for insertion considering max size
var free = exe.findZeros(funcName.length + 0x3D + 1);//for RETN
if (free === -1)
return "Failed in Step 4 - Not enough free space";
//Step 4.2 - Prep function which calls the Lua function
code =
funcName.toHex()
+ GenLuaCaller(free, funcName, exe.Raw2Rva(fnBegin + 0x10), "d>d", " 52")
+ " C3" //RETN
;
//Step 4.3 - Insert at free space
exe.insert(free, code.hexlength(), code, PTYPE_HEX);
//Step 4.4 - Prep code which calls the above
code =
" 52" //PUSH EDX
+ " 8B 54 24 08" //MOV EDX, DWORD PTR SS:[ESP+8]
+ " E8" + GenVarHex(1) //CALL ourFunc
+ " 5A" //POP EDX
+ " C2 04 00" //RETN 4
;
code = ReplaceVarHex(code, 1, exe.Raw2Rva(free + funcName.length) - exe.Raw2Rva(fnBegin + 10));
//Step 4.5 - Overwrite original function
exe.replace(fnBegin, code, PTYPE_HEX);
}
return true;
}
///======================================================///
/// Patch Functions wrapping over _EnableSkills function ///
///======================================================///
function _EnablePlayerSkills()
{
_EnableSkills(233);
}
function _EnableHomunSkills()
{
_EnableSkills(234);
}
function _EnableMerceSkills()
{
_EnableSkills(235);
}
//#########################################################\\
//# Make sure atleast one of the other active patches are #\\
//# loading the lua files #\\
//#########################################################\\
function _EnableSkills(patchID)
{
if (SKL.PatchID === patchID)
{
SKL.PatchID = false;
for (var id = 229; id <= 231; id++)
{
if (id !== patchID && RefreshPatch(id))
break;
}
}
}
//################################################################################\\
//# Helper function which injects skill lua file loading and also fills SKL hash #\\
//################################################################################\\
function LoadSkillTypeLua(id, offset)
{
if (SKL.Prefix === "")
{
SKL.Prefix = "Lua Files\\SkillInfo";
if (exe.getClientDate() >= 20100817)
SKL.Prefix += "z";
}
if (!SKL.PatchID)
{
SKL.Offset = InjectLuaFiles(
SKL.Prefix + "\\SkillInfo_F",
[
SKL.Prefix + "\\SkillType",
SKL.Prefix + "\\SkillType_F"
],
offset
);
if (typeof(SKL.Offset) === "string")//Error was returned
{
SKL.Error = SKL.Offset;
SKL.Offset = -1;
}
else
{
SKL.Error = false;
SKL.PatchID = id;
}
}
}
\ No newline at end of file
......@@ -44,6 +44,8 @@ registerGroup(16, "WalkToDelay", true);
registerGroup(17, "Zero", false);
registerGroup(18, "EnableSkills", false);
//#########################################################################################################################################################
//# #
//# FORMAT for registering patch : registerPatch(patch id, functionName, patch Name, category, group id, author, description, recommended [true/false] ); #
......@@ -369,3 +371,9 @@ registerPatch(233, "HideSNSButton", "Hide SNS Button", "UI", 12, "Secret", "Hide
registerPatch(234, "IgnoreLuaErrors", "Ignore Lua Errors", "Fix", 0, "4144", "Prevents the client from displaying a error messages from lua code like 'attempt to call nil value'.", false);
registerPatch(235, "EnableGuildWhenInClan", "Enable guild while in clan", "Custom", 0, "Functor, Secret", "Remove restriction of guild functionality while being a member of a clan", false);
registerPatch(236, "EnablePlayerSkills", "Enable Custom Player Skills [Experimental]", "Custom", 18, "Neo", "Enables the use of custom skills castable on players (using Lua Files)", false);
registerPatch(237, "EnableHomunSkills", "Enable Custom Homunculus Skills [Experimental]", "Custom", 18, "Neo", "Enables the use of custom skills for Homunculus (using Lua Files)", false);
registerPatch(238, "EnableMerceSkills", "Enable Custom Mercenary Skills [Experimental]", "Custom", 18, "Neo", "Enables the use of custom skills for Mercenaries (using Lua Files)", false);
PLAYER_SKILLS = {
--SKID.SM_RECOVERY,
SKID.AL_HEAL,
SKID.AL_INCAGI,
SKID.AL_BLESSING,
SKID.AL_CURE,
SKID.TF_DETOXIFY,
SKID.ALL_RESURRECTION,
SKID.PR_IMPOSITIO,
SKID.PR_ASPERSIO,
SKID.PR_SLOWPOISON,
SKID.PR_STRECOVERY,
SKID.PR_KYRIE,
SKID.BS_REPAIRWEAPON,
SKID.AS_ENCHANTPOISON,
--SKID.AS_POISONREACT,
SKID.AM_POTIONPITCHER,
SKID.AM_CP_WEAPON,
SKID.AM_CP_SHIELD,
SKID.AM_CP_ARMOR,
SKID.AM_CP_HELM,
SKID.CR_DEVOTION,
SKID.CR_PROVIDENCE,
SKID.MO_ABSORBSPIRITS,
SKID.SA_FLAMELAUNCHER,
SKID.SA_FROSTWEAPON,
SKID.SA_LIGHTNINGLOADER,
SKID.SA_SEISMICWEAPON,
SKID.HP_ASSUMPTIO,
SKID.SL_ALCHEMIST,
SKID.AM_BERSERKPITCHER,
SKID.SL_MONK,
SKID.SL_STAR,
SKID.SL_SAGE,
SKID.SL_CRUSADER,
SKID.SL_SUPERNOVICE,
SKID.SL_KNIGHT,
SKID.SL_WIZARD,
SKID.SL_PRIEST,
SKID.SL_BARDDANCER,
SKID.SL_ROGUE,
SKID.SL_ASSASIN,
SKID.SL_BLACKSMITH,
SKID.SL_HUNTER,
SKID.SL_SOULLINKER,
SKID.SL_KAIZEL,
SKID.SL_KAAHI,
SKID.SL_KAUPE,
SKID.SL_KAITE,
SKID.CR_FULLPROTECTION,
SKID.SL_HIGH,
SKID.MB_B_EXCLUDE,
SKID.SL_DEATHKNIGHT,
SKID.SL_COLLECTOR,
SKID.SL_NINJA,
SKID.SL_GUNNER,
SKID.DA_RESET,
SKID.DE_COIL,
SKID.DA_FIRSTSLOT,
SKID.DA_HEADDEF,
SKID.DA_REWARD,
SKID.DA_EARPLUG,
SKID.DA_CONTRACT,
SKID.DA_COPY,
SKID.DA_CRYSTAL,
SKID.DA_EXP,
SKID.DA_REBUILD,
SKID.DA_JOBCHANGE,
SKID.GM_SANDMAN,
SKID.CASH_BLESSING,
SKID.CASH_INCAGI,
SKID.CASH_ASSUMPTIO,
SKID.ALL_ANGEL_PROTECT,
SKID.MO_KITRANSLATION,
SKID.RK_ENCHANTBLADE,
SKID.RK_CRUSHSTRIKE,
SKID.GC_ANTIDOTE,
SKID.AB_CLEMENTIA,
SKID.AB_CANTO,
SKID.AB_CHEAL,
SKID.AB_RENOVATIO,
SKID.AB_HIGHNESSHEAL,
SKID.AB_CLEARANCE,
SKID.AB_EXPIATIO,
SKID.NC_REPAIR,
SKID.SC_SHADOWFORM,
SKID.LG_PIETY,
SKID.SR_POWERVELOCITY,
SKID.SR_GENTLETOUCH_CURE,
SKID.SR_GENTLETOUCH_CHANGE,
SKID.SR_GENTLETOUCH_REVITALIZE,
SKID.MI_HARMONIZE,
SKID.WM_DEADHILLHERE,
SKID.WM_GLOOMYDAY,
SKID.SO_STRIKING,
SKID.GN_WALLOFTHORN,
SKID.AB_SECRAMENT,
SKID.ALL_ODINS_POWER,
SKID.KG_KAGEMUSYA,
SKID.OB_ZANGETSU,
SKID.OB_OBOROGENSOU,
SKID.ECL_SNOWFLIP,
SKID.ECL_PEONYMAMY,
SKID.ECL_SADAGUI,
SKID.ECL_SEQUOIADUST,
SKID.MH_PAIN_KILLER,
SKID.MER_REGAIN,
SKID.MER_TENDER,
SKID.MER_BENEDICTION,
SKID.MER_RECUPERATE,
SKID.MER_MENTALCURE,
SKID.MER_COMPRESS,
SKID.MER_KYRIE,
SKID.MER_BLESSING,
SKID.MER_INCAGI,
--Custom Skills
SKID.CUSTOM_HEAL
}
HOMUN_SKILLS = {
SKID.HOMUN_BEGIN,
SKID.HLIF_HEAL,
SKID.HLIF_AVOID,
SKID.HLIF_BRAIN,
SKID.HLIF_CHANGE,
SKID.HAMI_CASTLE,
SKID.HAMI_DEFENCE,
SKID.HAMI_SKIN,
SKID.HAMI_BLOODLUST,
SKID.HFLI_MOON,
SKID.HFLI_FLEET,
SKID.HFLI_SPEED,
SKID.HFLI_SBR44,
SKID.HVAN_CAPRICE,
SKID.HVAN_CHAOTIC,
SKID.HVAN_INSTRUCT,
SKID.HVAN_EXPLOSION,
SKID.MUTATION_BASEJOB,
SKID.MH_SUMMON_LEGION,
SKID.MH_NEEDLE_OF_PARALYZE,
SKID.MH_POISON_MIST,
SKID.MH_PAIN_KILLER,
SKID.MH_LIGHT_OF_REGENE,
SKID.MH_OVERED_BOOST,
SKID.MH_ERASER_CUTTER,
SKID.MH_XENO_SLASHER,
SKID.MH_SILENT_BREEZE,
SKID.MH_STYLE_CHANGE,
SKID.MH_SONIC_CRAW,
SKID.MH_SILVERVEIN_RUSH,
SKID.MH_MIDNIGHT_FRENZY,
SKID.MH_STAHL_HORN,
SKID.MH_GOLDENE_FERSE,
SKID.MH_STEINWAND,
SKID.MH_HEILIGE_STANGE,
SKID.MH_ANGRIFFS_MODUS,
SKID.MH_TINDER_BREAKER,
SKID.MH_CBC,
SKID.MH_EQC,
SKID.MH_MAGMA_FLOW,
SKID.MH_GRANITIC_ARMOR,
SKID.MH_LAVA_SLIDE,
SKID.MH_PYROCLASTIC,
SKID.MH_VOLCANIC_ASH,
SKID.MH_LAST,
SKID.HOMUN_LAST,
}
MERCENARY_SKILLS = {
}
\ No newline at end of file
IsPlayerSkill = function(skillid)
return CheckSkillID(skillid, PLAYER_SKILLS)
end
IsHomunSkill = function(skillid)
return CheckSkillID(skillid, HOMUN_SKILLS)
end
IsMercenarySkill = function(skillid)
return CheckSkillID(skillid, MERCENARY_SKILLS)
end
CheckSkillID = function(skillid, tblname)
for _, id in ipairs(tblname) do
if id == skillid then
return 1
end
end
return 0
end
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment