// TMW2 Script
// Author:
// Jesusalva
// Description:
// Item Option System
// Notes:
// Awarded for crafters and their own base skill tree system
// Player knowledge structure
// CRAFTSYS[ SKILL_SCOPE ] = SKILL_LV
// Player craft skills selection:
// CRAFTSYS_CURRENT
// Generate() takes the scope and finds out the skills on the group
// It'll fill the following variables:
// @csys_attr → Available attributes
// @csys_penalty → Penalty attribute array
//
// use getarraysize(@csys_attr) to know how many are there.
// Players can active the bonus groups they want to use
// csys_equip( )
// Returns a bonus from equips (max: 1)
function script csys_equip {
// Same as: isequippedcnt(BlacksmithAxe{, BlacksmithHelmet, etc.})
return (isequippedcnt(BlacksmithAxe, Monocle, DemureAxe));
}
// csys_Generate( cr_id{, preserve, override} )
// Return average level
function script csys_Generate {
.@gid=getarg(0);
if (!getarg(1, false)) {
deletearray(@csys_attr);
deletearray(@csys_penalty);
}
.@OVR=getarg(2, false);
//.@lvl=getd("CRAFTSYS["+.@gid+"]");
.@avg=0;
.@stk=0;
/////////////////////////////////////////////////////////////
// Basic tier
if (.@gid & CRGROUP_BASE) {
.@lvl=(.@OVR ? 100 : CRAFTSYS[CRGROUP_BASE]);
if (.@lvl >= 1) {
array_push(@csys_attr, VAR_STRAMOUNT);
array_push(@csys_attr, VAR_INTAMOUNT);
}
if (.@lvl >= 3) {
array_push(@csys_attr, VAR_DEXAMOUNT);
array_push(@csys_attr, VAR_MAXHPAMOUNT);
}
if (.@lvl >= 5) {
array_push(@csys_attr, VAR_AGIAMOUNT);
array_push(@csys_attr, VAR_MAXSPAMOUNT);
}
if (.@lvl >= 7) {
array_push(@csys_attr, VAR_LUKAMOUNT);
array_push(@csys_attr, VAR_VITAMOUNT);
}
if (rand2(60) < .@lv)
array_push(@csys_penalty, CLASS_DAMAGE_BOSS_TARGET);
// Update averages
.@avg+=.@lvl;
.@stk+=1;
}
/////////////////////////////////////////////////////////////
// First tier
if (.@gid & CRGROUP_ATK) {
.@lvl=(.@OVR ? 100 : CRAFTSYS[CRGROUP_ATK]);
if (.@lvl >= 1) {
array_push(@csys_attr, VAR_ATTPOWER);
array_push(@csys_attr, VAR_ATTMPOWER);
}
if (.@lvl >= 5) {
array_push(@csys_attr, VAR_MAGICATKPERCENT);
array_push(@csys_attr, VAR_ATKPERCENT);
}
array_push(@csys_penalty, VAR_VITAMOUNT);
array_push(@csys_penalty, VAR_MAXHPAMOUNT);
// Update averages
.@avg+=.@lvl;
.@stk+=1;
}
if (.@gid & CRGROUP_DEF) {
.@lvl=(.@OVR ? 100 : CRAFTSYS[CRGROUP_DEF]);
if (.@lvl >= 1) {
array_push(@csys_attr, VAR_ITEMDEFPOWER);
array_push(@csys_attr, VAR_MDEFPOWER);
}
if (.@lvl >= 5) {
array_push(@csys_attr, DAMAGE_CRI_USER);
array_push(@csys_attr, RANGE_ATTACK_DAMAGE_USER);
}
array_push(@csys_penalty, VAR_DEXAMOUNT);
array_push(@csys_penalty, VAR_INTAMOUNT);
// Update averages
.@avg+=.@lvl;
.@stk+=1;
}
if (.@gid & CRGROUP_ACC) {
.@lvl=(.@OVR ? 100 : CRAFTSYS[CRGROUP_ACC]);
if (.@lvl >= 1) {
array_push(@csys_attr, VAR_HITSUCCESSVALUE);
}
if (.@lvl >= 5) {
array_push(@csys_attr, VAR_CRITICALRATE);
}
if (.@lvl >= 10) {
array_push(@csys_attr, VAR_CRITICALSUCCESSVALUE);
}
array_push(@csys_penalty, VAR_LUKAMOUNT);
array_push(@csys_penalty, VAR_MDEFPOWER);
array_push(@csys_penalty, VAR_ITEMDEFPOWER);
// Update averages
.@avg+=.@lvl;
.@stk+=1;
}
if (.@gid & CRGROUP_EVD) {
.@lvl=(.@OVR ? 100 : CRAFTSYS[CRGROUP_EVD]);
if (.@lvl >= 1) {
array_push(@csys_attr, VAR_AVOIDSUCCESSVALUE);
}
if (.@lvl >= 5) {
array_push(@csys_attr, VAR_PLUSAVOIDSUCCESSVALUE);
}
array_push(@csys_penalty, VAR_ATTPOWER);
array_push(@csys_penalty, VAR_ATTMPOWER);
array_push(@csys_penalty, IOPT_CRITDMG);
// Update averages
.@avg+=.@lvl;
.@stk+=1;
}
/////////////////////////////////////////////////////////////
// Second tier
if (.@gid & CRGROUP_REGEN) {
.@lvl=(.@OVR ? 100 : CRAFTSYS[CRGROUP_REGEN]);
if (.@lvl >= 1) {
array_push(@csys_attr, VAR_HPACCELERATION);
}
if (.@lvl >= 5) {
array_push(@csys_attr, VAR_SPACCELERATION);
}
array_push(@csys_penalty, VAR_PLUSASPD);
// Update averages
.@avg+=.@lvl;
.@stk+=1;
}
if (.@gid & CRGROUP_SPEED) {
.@lvl=(.@OVR ? 100 : CRAFTSYS[CRGROUP_SPEED]);
if (.@lvl >= 1) {
array_push(@csys_attr, VAR_PLUSASPD);
}
if (.@lvl >= 3) {
array_push(@csys_attr, VAR_PLUSASPDPERCENT);
}
if (.@lvl >= 5) {
array_push(@csys_attr, IOPT_WALKSPEED);
}
array_push(@csys_penalty, VAR_MAXSPAMOUNT);
// Update averages
.@avg+=.@lvl;
.@stk+=1;
}
if (.@gid & CRGROUP_DOUBLE) {
.@lvl=(.@OVR ? 100 : CRAFTSYS[CRGROUP_DOUBLE]);
if (.@lvl >= 1) {
array_push(@csys_attr, IOPT_CRITDMG);
}
if (.@lvl >= 5) {
array_push(@csys_attr, IOPT_DOUBLEATTACK);
}
array_push(@csys_penalty, RANGE_ATTACK_DAMAGE_USER);
// Update averages
.@avg+=.@lvl;
.@stk+=1;
}
if (.@gid & CRGROUP_MAXPC) {
.@lvl=(.@OVR ? 100 : CRAFTSYS[CRGROUP_MAXPC]);
if (.@lvl >= 1) {
array_push(@csys_attr, VAR_MAXHPPERCENT);
array_push(@csys_attr, VAR_MAXSPPERCENT);
}
if (.@lvl >= 5) {
array_push(@csys_attr, CLASS_DAMAGE_BOSS_USER);
}
array_push(@csys_penalty, DAMAGE_CRI_USER);
// Update averages
.@avg+=.@lvl;
.@stk+=1;
}
/////////////////////////////////////////////////////////////
// Third tier
if (.@gid & CRGROUP_SCRESIST) {
.@lvl=(.@OVR ? 100 : CRAFTSYS[CRGROUP_SCRESIST]);
if (.@lvl >= 1) {
array_push(@csys_attr, IOPT_SCRESIST_POISON);
}
if (.@lvl >= 2) {
array_push(@csys_attr, IOPT_SCRESIST_SILENCE);
}
if (.@lvl >= 3) {
array_push(@csys_attr, IOPT_SCRESIST_BLIND);
}
if (.@lvl >= 4) {
array_push(@csys_attr, IOPT_SCRESIST_CURSE);
}
array_push(@csys_penalty, VAR_CRITICALSUCCESSVALUE);
array_push(@csys_penalty, IOPT_CRITDMG);
// Update averages
.@avg+=.@lvl;
.@stk+=1;
}
if (.@gid & CRGROUP_SCINFLICT) {
.@lvl=(.@OVR ? 100 : CRAFTSYS[CRGROUP_SCINFLICT]);
if (.@lvl >= 1) {
array_push(@csys_attr, IOPT_SCPROVOKE_POISON);
}
if (.@lvl >= 2) {
array_push(@csys_attr, IOPT_SCPROVOKE_SILENCE);
}
if (.@lvl >= 3) {
array_push(@csys_attr, IOPT_SCPROVOKE_BLIND);
}
if (.@lvl >= 4) {
array_push(@csys_attr, IOPT_SCPROVOKE_CURSE);
}
array_push(@csys_penalty, IOPT_SCRESIST_POISON);
array_push(@csys_penalty, IOPT_SCRESIST_SILENCE);
array_push(@csys_penalty, IOPT_SCRESIST_BLIND);
array_push(@csys_penalty, IOPT_SCRESIST_CURSE);
array_push(@csys_penalty, VAR_MAXHPAMOUNT);
// Update averages
.@avg+=.@lvl;
.@stk+=1;
}
if (.@gid & CRGROUP_MANAUSE) {
.@lvl=(.@OVR ? 100 : CRAFTSYS[CRGROUP_MANAUSE]);
if (.@lvl >= 1) {
array_push(@csys_attr, SP_DRAIN);
}
if (.@lvl >= 5) {
array_push(@csys_attr, DEC_SP_CONSUMPTION);
}
array_push(@csys_penalty, VAR_ATTPOWER);
array_push(@csys_penalty, VAR_ITEMDEFPOWER);
// Update averages
.@avg+=.@lvl;
.@stk+=1;
}
if (.@gid & CRGROUP_BOSSATK) {
.@lvl=(.@OVR ? 100 : CRAFTSYS[CRGROUP_BOSSATK]);
if (.@lvl >= 1) {
array_push(@csys_attr, HP_DRAIN);
}
if (.@lvl >= 5) {
array_push(@csys_attr, CLASS_DAMAGE_BOSS_TARGET);
}
array_push(@csys_penalty, VAR_AVOIDSUCCESSVALUE);
array_push(@csys_penalty, VAR_PLUSAVOIDSUCCESSVALUE);
// Update averages
.@avg+=.@lvl;
.@stk+=1;
}
/////////////////////////////////////////////////////////////
// Final tier (needs minimum lv 3)
if (.@gid & CRGROUP_FINAL) {
.@lvl=(.@OVR ? 100 : CRAFTSYS[CRGROUP_FINAL]);
if (.@lvl >= 1) {
array_push(@csys_attr, IOPT_EXPGAIN);
}
if (.@lvl >= 3) {
array_push(@csys_attr, IOPT_RICHNESS);
}
if (.@lvl >= 5) {
array_push(@csys_attr, IOPT_SPLASHDAMAGE);
}
array_push(@csys_penalty, IOPT_WALKSPEED);
// Update averages
.@avg+=.@lvl;
.@stk+=1;
}
///////////////////////////////
// Return the average level
if (!.@stk)
return 0;
return (.@avg/.@stk);
}
// Confirms if player really wants to tweak a craft.
// Do not cast after new crafts. Returns false to stop script.
// csys_Confirm( invindex )
function script csys_Confirm {
.@id=getarg(0);
// Sanitize input
if (.@id < 0)
return false;
// *getequipisenableopt(<equipment slot>) → cannot use here
// Not an equipment
if (!getiteminfo(.@id, ITEMINFO_LOC))
return false;
mesc l("Really try to tweak this item? All current options will be deleted.");
mesc l("NOTE: You're tweaking a(n): @@", getinvindexlink(.@id));
next;
if (askyesno() == ASK_NO)
return false;
return true;
}
// Check if you'll have success in applying options or not
// Returns true if you was successful, and also cleans previous options
// If you only want cleaning, just disregard the output.
// csys_Check( invindex{, base} )
function script csys_Check {
.@id=getarg(0);
.@base=getarg(1, 40000);
// Clear all five options
setitemoptionbyindex(.@id, 0, 0, 0);
setitemoptionbyindex(.@id, 1, 0, 0);
setitemoptionbyindex(.@id, 2, 0, 0);
setitemoptionbyindex(.@id, 3, 0, 0);
setitemoptionbyindex(.@id, 4, 0, 0);
// Base Success Rate is: 40% + 5% each craft skill level
.@base+=(getskilllv(TMW2_CRAFT)*500);
// Bonus from equips: 4% each
.@base+=csys_equip()*400;
// Make the roll
if (rand(10000) < .@base)
return true;
return false;
}
// csys_Multiplier( cr_id )
// Returns a multiplier for bonus (it can be zero)
function script csys_Multiplier {
.@sk=getarg(0);
switch (.@sk) {
case IOPT_SPLASHDAMAGE:
return 0;
case IOPT_WALKSPEED:
case IOPT_RICHNESS:
return 2;
case VAR_STRAMOUNT:
case VAR_AGIAMOUNT:
case VAR_INTAMOUNT:
case VAR_DEXAMOUNT:
case VAR_LUKAMOUNT:
case VAR_CRITICALSUCCESSVALUE:
return 4;
case VAR_MAXHPPERCENT:
case VAR_MAXSPPERCENT:
case VAR_VITAMOUNT:
case HP_DRAIN:
case SP_DRAIN:
case IOPT_DOUBLEATTACK:
case VAR_PLUSAVOIDSUCCESSVALUE:
case IOPT_EXPGAIN:
case VAR_CRITICALRATE:
case DEC_SP_CONSUMPTION:
case VAR_PLUSASPDPERCENT:
case VAR_MAGICATKPERCENT:
case VAR_ATKPERCENT:
return 5;
case IOPT_SCRESIST_POISON:
case IOPT_SCRESIST_SILENCE:
case IOPT_SCRESIST_CURSE:
case IOPT_SCRESIST_BLIND:
return 15;
case VAR_MAXSPAMOUNT:
return 25;
case VAR_MAXHPAMOUNT:
return 35;
default:
return 10;
}
return 0;
}
// Remove problematic bonuses from armors
// Use getiteminfo before
// csys_ArmorFix( item{, perfect=False} )
function script csys_ArmorFix {
// Rare bonus
if (rand2(100) >= 5 && !getarg(1, false))
array_remove(@csys_attr, IOPT_SPLASHDAMAGE);
// Sublevel
if (getiteminfo(getarg(0), ITEMINFO_ELV) < 20) {
array_remove(@csys_attr, IOPT_SPLASHDAMAGE);
array_remove(@csys_attr, IOPT_CRITDMG);
}
// Remove bonuses
array_remove(@csys_attr, IOPT_WALKSPEED);
array_remove(@csys_attr, HP_DRAIN);
array_remove(@csys_attr, SP_DRAIN);
array_remove(@csys_attr, IOPT_DOUBLEATTACK);
array_remove(@csys_attr, VAR_CRITICALSUCCESSVALUE);
// VAR_PLUSASPDPERCENT and VAR_PLUSASPD ?
// Remove penalties
array_remove(@csys_penalty, VAR_ITEMDEFPOWER);
array_remove(@csys_penalty, VAR_MDEFPOWER);
// If the options were wiped, add a random one
if (getarraysize(@csys_attr) == 0)
array_push(@csys_attr, VAR_MAXHPAMOUNT);
// Save for csys_BonusCalc
@csysArmor=CSYS_ARMOR;
// Shields
if (getiteminfo(getarg(0), ITEMINFO_LOC) == EQP_HAND_L)
@csysArmor=@csysArmor|CSYS_SHIELD;
// Aegis Shield is special and is not classified as armor
if (compare("aegis shield", strtolower(getitemname(getarg(0)))))
@csysArmor=@csysArmor^CSYS_ARMOR;
// Special sets
if (compare("savior", strtolower(getitemname(getarg(0)))))
@csysArmor=@csysArmor|CSYS_SAVIOR;
// Legendary Weapons, this formula is hardcoded in C
if (is_between(3600, 3610, getarg(0)))
@csysArmor=@csysArmor|CSYS_LEGENDARY;
return;
}
// Update problematic bonuses for weapons
// Use getiteminfo before
// csys_WeaponFix( {item} )
function script csys_WeaponFix {
.@sub=getiteminfo(getarg(0,Acorn), ITEMINFO_SUBTYPE);
@csysArmor=0;
// Remove the defense options
array_remove(@csys_attr, VAR_ITEMDEFPOWER);
array_remove(@csys_attr, VAR_MDEFPOWER);
// If the options were wiped, add a random one
if (getarraysize(@csys_attr) == 0)
array_push(@csys_attr, VAR_MAXHPAMOUNT);
// Weapon Subtype
if (.@sub == W_FIST || .@sub == W_KNUCKLE)
@csysArmor=@csysArmor|CSYS_BRAWLING;
else if (.@sub == W_2HSWORD || .@sub == W_2HSPEAR ||
.@sub == W_2HAXE || .@sub == W_2HMACE ||
.@sub == W_2HSTAFF)
@csysArmor=@csysArmor|CSYS_ZWEIHANDER;
else if (.@sub == W_BOW || .@sub == W_REVOLVER ||
.@sub == W_RIFLE || .@sub == W_GATLING ||
.@sub == W_SHOTGUN || .@sub == W_GRENADE)
@csysArmor=@csysArmor|CSYS_RANGED;
else if (.@sub == W_STAFF || .@sub == W_BOOK)
@csysArmor=@csysArmor|CSYS_MAGICAL;
else if (.@sub == W_KATAR)
@csysArmor=@csysArmor|CSYS_SPECIAL;
else
@csysArmor=@csysArmor|CSYS_OTHER;
// Special sets
if (compare("savior", strtolower(getitemname(getarg(0)))))
@csysArmor=@csysArmor|CSYS_SAVIOR;
// Legendary Weapons, this formula is hardcoded in C
if (is_between(3600, 3610, getarg(0)))
@csysArmor=@csysArmor|CSYS_LEGENDARY;
// Lightbringer have even higher bonuses
if (getarg(0) == Lightbringer)
@csysArmor=@csysArmor|CSYS_SAVIOR;
return;
}
// csys_BonusCalc( lv1, lv2, vartp{, equip lvl, skip=false} )
// Calculates the due bonus
function script csys_BonusCalc {
.@craft=getarg(0);
.@skill=getarg(1);
.@var=getarg(2);
.@eqlv=getarg(3, 0);
.@skip=getarg(4, false);
.@mult=csys_Multiplier(.@var);
.@avmult=(.@craft+.@skill)*.@mult;
.@avg=.@avmult/10;
// Equip Level Cap
if (!(@csysArmor & CSYS_LEGENDARY))
.@avg=.@avg*(5+min(5, .@eqlv/20))/10;
// Roll or no roll
if (!.@skip) {
.@base=rand2(1, .@avg+1);
// Re-roll if you got a too bad result:
// Each equip level will yield 0.2% reroll
// Means a lv 100 equip gets 20% of grace-reroll.
// By default, this rule is skipped for maluses!
if (.@base < (.@avg+1)*.@eqlv/500)
.@base=rand2(1, .@avg+1);
// If you are in the upper 70%, we do a re-roll
// It usually will lower the result, but is up to luck
if (.@base >= (.@avg+1)*7/10)
.@base=rand2(1, .@avg+1);
// Bonus grace reroll if crafting is maxed at 10 (SCRIPT only)
if (.@craft >= 10 && .@base < (.@avg+1)*.@eqlv/500) {
.@base=rand2(1, .@avg+1);
}
} else {
.@base=rand2(max(1, .@avg*8/10), .@avg+1);
}
////////////////////////////////////
// Legendary Weapon? Effects +50%
if (@csysArmor & CSYS_LEGENDARY)
.@base=max(1, .@base*3/2);
// Savior Set? Effects +20%
if (@csysArmor & CSYS_SAVIOR)
.@base=max(1, .@base*6/5);
////////////////////////////////////
// Normal Attack for 2H?
if (.@var == VAR_ATTPOWER || .@var == VAR_ATKPERCENT) {
// Two Hands/Bows: +50%
if ((@csysArmor & CSYS_ZWEIHANDER) || (@csysArmor & CSYS_RANGED))
.@base=max(1, .@base*3/2);
// Brawling: +40%
else if (@csysArmor & CSYS_BRAWLING)
.@base=max(1, .@base*7/5);
}
// Similar rule but for MATK and Wands
if (.@var == VAR_MAGICATKPERCENT || .@var == VAR_ATTMPOWER) {
// Magical: +50%
if (@csysArmor & CSYS_MAGICAL)
.@base=max(1, .@base*3/2);
// Brawling: +25%
else if (@csysArmor & CSYS_BRAWLING)
.@base=max(1, .@base*5/4);
}
////////////////////////////////////
// Armor? Cap it to 25%
if (@csysArmor & CSYS_ARMOR)
.@base=max(1, .@base/4);
// HP/DEF/MDEF for shields? Revert the cap and round it
if (.@var == VAR_ITEMDEFPOWER || .@var == VAR_MAXHPAMOUNT ||
.@var == VAR_MDEFPOWER) {
if (@csysArmor & CSYS_SHIELD)
.@base*=4;
}
return .@base;
}
// Attribute item options
// Does NOT performs success chance check, and can be used by NPC
// csys_Apply( invindex{, lvl, scope} )
function script csys_Apply {
.@id=getarg(0);
.@lv=getarg(1, getskilllv(TMW2_CRAFT))+csys_equip();
.@sc=getarg(2, CRAFTSYS_CURRENT);
.@lv2=csys_Generate(.@sc);
// @csys_attr → Available attributes
// @csys_penalty → Penalty attribute array
// Remove weapon-only bonuses if it is armor
delinventorylist();
getinventorylist();
.@itemid=@inventorylist_id[.@id];
if (getiteminfo(.@itemid, ITEMINFO_TYPE) != IT_WEAPON)
csys_ArmorFix(.@itemid);
else
csys_WeaponFix(.@itemid);
.@eqplv=getiteminfo(.@itemid, ITEMINFO_ELV);
// Shuffle the arrays
array_shuffle(@csys_attr);
array_shuffle(@csys_penalty);
// How many bonuses we'll have? Never more than 3 bonus and 2 onus.
.@max_attr=getarraysize(@csys_attr);
.@max_pena=getarraysize(@csys_penalty);
if ($@GM_OVERRIDE)
debugmes "We have %d attributes and %d penalties",
.@max_attr, .@max_pena;
.@slot=0;
while (.@slot < min(3, .@max_attr)) {
// You have 100% for first bonus, -45% each, depending on skill lv
.@base=4500-(.@lv*75);
if (rand(10000) > 10000-(.@base*.@slot))
break;
// Apply a bonus using array_pop (it was shuffled so we're fine)
.@vartp=array_pop(@csys_attr);
.@bonus=csys_BonusCalc(.@lv, .@lv2, .@vartp, .@eqplv);
setitemoptionbyindex(.@id, .@slot, .@vartp, .@bonus);
//debugmes "Bonus applied: %d at %d (slot: %d)", .@vartp, .@bonus, .@slot;
.@slot+=1;
}
// You have 102% chance of a malus, skill and equips lower it in 0.5% each
.@base=10200-(.@lv*50);
if (rand(10000) < .@base && .@max_pena) {
// Apply a malus using array_pop (it was shuffled so we're fine)
.@vartp=array_pop(@csys_penalty);
.@malus=csys_BonusCalc(.@lv, .@lv2, .@vartp); // .@eqplv ?
.@malus=.@malus*70/100;
if (.@vartp > 0 && .@malus > 0)
setitemoptionbyindex(.@id, .@slot, .@vartp, -(.@malus));
.@slot+=1;
}
// The options have been attributed, clear temporary variables
@csysArmor=false;
return;
}
// Attribute perfect item options
// For Fortress Island only
// csys_ApplyPerfect( invindex, lvl{, scope} )
function script csys_ApplyPerfect {
.@id=getarg(0);
.@lv=getarg(1);
.@sc=getarg(2, CRAFTSYS_CURRENT);
// Generate lists, disregarding level
csys_Generate(.@sc, false, true);
// @csys_attr → Available attributes
// @csys_penalty → Penalty attribute array
// Remove weapon-only bonuses if it is armor
delinventorylist();
getinventorylist();
.@itemid=@inventorylist_id[.@id];
if (getiteminfo(.@itemid, ITEMINFO_TYPE) != IT_WEAPON)
csys_ArmorFix(.@itemid, (rand2(.@lv/10) != 0));
else
csys_WeaponFix(.@itemid);
.@eqplv=getiteminfo(.@itemid, ITEMINFO_ELV);
// Shuffle the arrays
array_shuffle(@csys_attr);
array_shuffle(@csys_penalty);
// How many bonuses we'll have? Never more than 3 bonus and 2 onus.
.@max_attr=getarraysize(@csys_attr);
.@max_pena=getarraysize(@csys_penalty);
if ($@GM_OVERRIDE)
debugmes "ApplyPerfect: We have %d attributes and %d penalties",
.@max_attr, .@max_pena;
.@slot=0;
while (.@slot < min(3, .@max_attr)) {
// Apply a bonus using array_pop (it was shuffled so we're fine)
.@vartp=array_pop(@csys_attr);
.@bonus=csys_BonusCalc(0, .@lv, .@vartp, .@eqplv, true);
setitemoptionbyindex(.@id, .@slot, .@vartp, .@bonus);
//debugmes "Bonus applied: %d at %d (slot: %d)", .@vartp, .@bonus, .@slot;
.@slot+=1;
}
if (.@max_pena) {
// Apply a malus using array_pop (it was shuffled so we're fine)
.@vartp=array_pop(@csys_penalty);
.@malus=csys_BonusCalc(0, .@lv, .@vartp, .@eqplv, true);
.@malus=.@malus*70/100;
if (.@vartp > 0 && .@malus > 0)
setitemoptionbyindex(.@id, .@slot, .@vartp, -(.@malus));
.@slot+=1;
}
// The options have been attributed, clear temporary variables
@csysArmor=false;
return;
}
////////////////////////////////////////
/////////////////
///////
// Interface System for Options Craft
function script csys_ttlgrouptoit {
.@cr=getarg(0);
switch (.@cr) {
case CRGROUP_BASE:
return CRITEM_BASE;
case CRGROUP_ATK:
return CRITEM_ATK;
case CRGROUP_DEF:
return CRITEM_DEF;
case CRGROUP_ACC:
return CRITEM_ACC;
case CRGROUP_EVD:
return CRITEM_EVD;
case CRGROUP_REGEN:
return CRITEM_REGEN;
case CRGROUP_SPEED:
return CRITEM_SPEED;
case CRGROUP_DOUBLE:
return CRITEM_DOUBLE;
case CRGROUP_MAXPC:
return CRITEM_MAXPC;
case CRGROUP_SCRESIST:
return CRITEM_SCRESIST;
case CRGROUP_SCINFLICT:
return CRITEM_SCINFLICT;
case CRGROUP_MANAUSE:
return CRITEM_MANAUSE;
case CRGROUP_BOSSATK:
return CRITEM_BOSSATK;
case CRGROUP_FINAL:
return CRITEM_FINAL;
}
return Bread;
}
function script csys_ISON {
.@cr=getarg(0);
.@it=csys_ttlgrouptoit(.@cr);
if (CRAFTSYS_CURRENT & .@cr)
return "%%E"+getitemlink(.@it);
else
return getitemlink(.@it);
}
// csysGUI_Report( {silent} )
// Report craft skill levels
function script csysGUI_Report {
mes l("Crafting Skill: Lv @@", getskilllv(TMW2_CRAFT));
if (!getarg(0, false)) {
if (getskilllv(TMW2_CRAFT) >= 1) {
mes "";
mes ".:: " + l("Base Tier") + " ::.";
mes "";
mes l("@@: Lv @@", csys_ISON(CRGROUP_BASE), CRAFTSYS[CRGROUP_BASE]);
} else {
mes "";
mes ".:: " + l("Base Tier") + " ::.";
mes "";
mesc l("Reach level @@ to unlock this tier!", 1), 1;
}
if (getskilllv(TMW2_CRAFT) >= 2) {
mes "";
mes ".:: " + l("First Tier") + " ::.";
mes "";
mes l("@@: Lv @@", csys_ISON(CRGROUP_ATK), CRAFTSYS[CRGROUP_ATK]);
mes "";
mes l("@@: Lv @@", csys_ISON(CRGROUP_DEF), CRAFTSYS[CRGROUP_DEF]);
mes "";
mes l("@@: Lv @@", csys_ISON(CRGROUP_ACC), CRAFTSYS[CRGROUP_ACC]);
mes "";
mes l("@@: Lv @@", csys_ISON(CRGROUP_EVD), CRAFTSYS[CRGROUP_EVD]);
next;
} else {
mes "";
mes ".:: " + l("First Tier") + " ::.";
mes "";
mesc l("Reach level @@ to unlock this tier!", 2), 1;
}
if (getskilllv(TMW2_CRAFT) >= 3) {
mes "";
mes ".:: " + l("Second Tier") + " ::.";
mes "";
mes l("@@: Lv @@", csys_ISON(CRGROUP_REGEN), CRAFTSYS[CRGROUP_REGEN]);
mes "";
mes l("@@: Lv @@", csys_ISON(CRGROUP_SPEED), CRAFTSYS[CRGROUP_SPEED]);
mes "";
mes l("@@: Lv @@", csys_ISON(CRGROUP_DOUBLE), CRAFTSYS[CRGROUP_DOUBLE]);
mes "";
mes l("@@: Lv @@", csys_ISON(CRGROUP_MAXPC), CRAFTSYS[CRGROUP_MAXPC]);
} else {
mes "";
mes ".:: " + l("Second Tier") + " ::.";
mes "";
mesc l("Reach level @@ to unlock this tier!", 3), 1;
next;
}
if (getskilllv(TMW2_CRAFT) >= 4) {
mes "";
mes ".:: " + l("Third Tier") + " ::.";
mes "";
mes l("@@: Lv @@", csys_ISON(CRGROUP_SCRESIST), CRAFTSYS[CRGROUP_SCRESIST]);
mes "";
mes l("@@: Lv @@", csys_ISON(CRGROUP_SCINFLICT), CRAFTSYS[CRGROUP_SCINFLICT]);
mes "";
mes l("@@: Lv @@", csys_ISON(CRGROUP_MANAUSE), CRAFTSYS[CRGROUP_MANAUSE]);
mes "";
mes l("@@: Lv @@", csys_ISON(CRGROUP_BOSSATK), CRAFTSYS[CRGROUP_BOSSATK]);
next;
} else {
mes "";
mes ".:: " + l("Third Tier") + " ::.";
mes "";
mesc l("Reach level @@ to unlock this tier!", 4), 1;
}
if (getskilllv(TMW2_CRAFT) >= 5) {
mes "";
mes ".:: " + l("Ultimate Tier") + " ::.";
mes "";
mes l("@@: Lv @@", csys_ISON(CRGROUP_FINAL), CRAFTSYS[CRGROUP_FINAL]);
mes "";
} else {
mes "";
mes ".:: " + l("Ultimate Tier") + " ::.";
mes "";
mesc l("Reach level @@ to unlock this tier!", 5), 1;
}
}
mesc l("Monster Points (Mobpt): @@ | Gold: @@",
format_number(Mobpt), format_number(Zeny));
next;
return;
}
// csysGUI_CRName( cr )
// Return group name for CR
function script csysGUI_CRName {
.@cr=getarg(0);
switch (.@cr) {
case CRGROUP_BASE:
return l("T0 - Base Bonus");
// Tier 1
case CRGROUP_ATK:
return l("T1 - Attack Bonus");
case CRGROUP_DEF:
return l("T1 - Defense Bonus");
case CRGROUP_ACC:
return l("T1 - Accuracy Bonus");
case CRGROUP_EVD:
return l("T1 - Evasion Bonus");
// Tier 2
case CRGROUP_REGEN:
return l("T2 - Regeneration Bonus");
case CRGROUP_SPEED:
return l("T2 - Speed Bonus");
case CRGROUP_DOUBLE:
return l("T2 - Double Power Bonus");
case CRGROUP_MAXPC:
return l("T2 - Max Stats Bonus");
// Tier 3
case CRGROUP_SCRESIST:
return l("T3 - SC Resist Bonus");
case CRGROUP_SCINFLICT:
return l("T3 - SC Inflict Bonus");
case CRGROUP_MANAUSE:
return l("T3 - Mana Economy Bonus");
case CRGROUP_BOSSATK:
return l("T3 - Boss Techniques Bonus");
case CRGROUP_FINAL:
return l("T4 - Ultimate Bonus");
default:
return Exception("Invalid optname group: "+.@cr);
}
return Exception("Definitely Invalid optname group: "+.@cr);
}
// csysGUI_OptToogleMenu( cr )
// Returns a Toogle Menu for option group (CR)
//
function script csysGUI_OptToogleMenu {
.@sk=getarg(0);
if (getd("CRAFTSYS["+.@sk+"]")) {
if (CRAFTSYS_CURRENT & .@sk)
return "Remove "+csysGUI_CRName(.@sk);
else
return "Active "+csysGUI_CRName(.@sk);
}
return "";
}
// csysGUI_ChangeOpt( cr )
// Change option
function script csysGUI_ChangeOpt {
.@sk=getarg(0);
CRAFTSYS_CURRENT=CRAFTSYS_CURRENT^.@sk;
return;
}
// csysGUI_OptReq( cr )
// Return true if all requisites for Option were met
function script csysGUI_OptReq {
.@sk=getarg(0);
switch (.@sk) {
case CRGROUP_BASE:
return (getskilllv(TMW2_CRAFT) >= 1);
// Tier 1
case CRGROUP_ATK:
return (getskilllv(TMW2_CRAFT) >= 2 &&
CRAFTSYS[CRGROUP_BASE]);
case CRGROUP_DEF:
return (getskilllv(TMW2_CRAFT) >= 2 &&
CRAFTSYS[CRGROUP_BASE]);
case CRGROUP_ACC:
return (getskilllv(TMW2_CRAFT) >= 2 &&
CRAFTSYS[CRGROUP_BASE]);
case CRGROUP_EVD:
return (getskilllv(TMW2_CRAFT) >= 2 &&
CRAFTSYS[CRGROUP_BASE]);
// Tier 2
case CRGROUP_REGEN:
return (getskilllv(TMW2_CRAFT) >= 3 &&
CRAFTSYS[CRGROUP_ATK] &&
CRAFTSYS[CRGROUP_DEF] &&
CRAFTSYS[CRGROUP_BASE] >= 2);
case CRGROUP_SPEED:
return (getskilllv(TMW2_CRAFT) >= 3 &&
CRAFTSYS[CRGROUP_ACC] &&
CRAFTSYS[CRGROUP_EVD] &&
CRAFTSYS[CRGROUP_BASE] >= 2);
case CRGROUP_DOUBLE:
return (getskilllv(TMW2_CRAFT) >= 3 &&
CRAFTSYS[CRGROUP_ATK] &&
CRAFTSYS[CRGROUP_ACC] &&
CRAFTSYS[CRGROUP_BASE] >= 2);
case CRGROUP_MAXPC:
return (getskilllv(TMW2_CRAFT) >= 3 &&
CRAFTSYS[CRGROUP_DEF] &&
CRAFTSYS[CRGROUP_EVD] &&
CRAFTSYS[CRGROUP_BASE] >= 2);
// Tier 3
case CRGROUP_SCRESIST:
return (getskilllv(TMW2_CRAFT) >= 4 &&
CRAFTSYS[CRGROUP_MAXPC] >= 2 &&
CRAFTSYS[CRGROUP_REGEN] >= 2 &&
CRAFTSYS[CRGROUP_BASE] >= 4);
case CRGROUP_SCINFLICT:
return (getskilllv(TMW2_CRAFT) >= 4 &&
CRAFTSYS[CRGROUP_SPEED] >= 2 &&
CRAFTSYS[CRGROUP_DOUBLE] >= 2 &&
CRAFTSYS[CRGROUP_BASE] >= 4);
case CRGROUP_MANAUSE:
return (getskilllv(TMW2_CRAFT) >= 4 &&
CRAFTSYS[CRGROUP_DEF] >= 3 &&
CRAFTSYS[CRGROUP_EVD] >= 3 &&
CRAFTSYS[CRGROUP_BASE] >= 4);
case CRGROUP_BOSSATK:
return (getskilllv(TMW2_CRAFT) >= 4 &&
CRAFTSYS[CRGROUP_ATK] >= 3 &&
CRAFTSYS[CRGROUP_ACC] >= 3 &&
CRAFTSYS[CRGROUP_BASE] >= 4);
case CRGROUP_FINAL:
return (getskilllv(TMW2_CRAFT) >= 5 &&
CRAFTSYS[CRGROUP_BOSSATK] &&
CRAFTSYS[CRGROUP_MANAUSE] &&
CRAFTSYS[CRGROUP_SCINFLICT] &&
CRAFTSYS[CRGROUP_SCRESIST] &&
CRAFTSYS[CRGROUP_BASE] >= 6);
default:
return Exception("Invalid optreq group: "+.@sk);
}
return Exception("Definitely Invalid optreq group: "+.@sk);
}
// csysGUI_OptPrice( cr )
// Return group option price and requisites
function script csysGUI_OptPrice {
.@sk=getarg(0);
.@lv=getd("CRAFTSYS["+.@sk+"]")+1;
// Every 99 skills levels (including the 0), price raises in 7
.@lv+=((.@lv/99)*7);
// Every 25 skills levels (including the 0), price raises in 5
.@lv+=((.@lv/25)*5);
// Every 15 skills levels (including the 0), price raises in 1
.@lv+=(.@lv/15);
// Every 10 skills levels (including the 0), price raises in 2
.@lv+=((.@lv/10)*2);
// Every 3 skills levels (including the 0), price raises in 1
.@lv+=(.@lv/3);
switch (.@sk) {
case CRGROUP_BASE:
return (.@lv < 10 ? 1000 : 1500)*.@lv;
// Tier 1
case CRGROUP_ATK:
case CRGROUP_DEF:
case CRGROUP_ACC:
case CRGROUP_EVD:
return (.@lv < 10 ? 7200 : 7000)*.@lv;
// Tier 2
case CRGROUP_REGEN:
case CRGROUP_SPEED:
case CRGROUP_DOUBLE:
case CRGROUP_MAXPC:
return (.@lv < 10 ? 16000 : 14000)*.@lv;
// Tier 3
case CRGROUP_SCRESIST:
case CRGROUP_SCINFLICT:
case CRGROUP_MANAUSE:
case CRGROUP_BOSSATK:
return (.@lv < 10 ? 32000 : 27000)*.@lv;
// Final
case CRGROUP_FINAL:
return (.@lv < 10 ? 40000 : 32000)*.@lv;
default:
return Exception("Invalid optprice group: "+.@cr);
}
return Exception("Definitely Invalid optprice group: "+.@cr);
}
// csysGUI_OptLearnMenu( cr )
// Returns the menu entry to learn the group skill.
// Cost is NOT taken as requisite, must check it later.
function script csysGUI_OptLearnMenu {
.@sk=getarg(0);
if (csysGUI_OptReq(.@sk)) {
return "Upgrade "+csysGUI_CRName(.@sk)+" for "+csysGUI_OptPrice(.@sk)+" Mobpt";
}
return "";
}
// csysGUI_RaiseOpt( cr )
// Returns true if can raise group, false otherwise
// You can't raise if max level (200) is exceeded
// At current max level (200) you'll have at most the following bonuses:
// 1 Splash Radius, 100% EXP, 500 HP, 300% SC RESIST, 80 AGI, 200 ATK, 100 VIT
// Walk Speed: 40% faster
// At ONE QUARTER max level (50) you'll have at most the following bonuses:
// 1 Splash Radius, 25% EXP, 125 HP, 75% SC RESIST, 20 AGI, 50 ATK, 25 VIT
// Walk Speed: 10% faster
// At level 10 it will be:
// 1 Splash Radius, 5% EXP, 25 HP, 15% SC RESIST, 4 AGI, 10 ATK, 5 VIT
// Walk Speed: 2% faster
// At level 1 it will be:
// 1 Splash Radius, 1% EXP, 2~3 HP, 1~2% SC RESIST, 1 AGI, 1 ATK, 1 VIT
// Walk Speed: 1% faster
function script csysGUI_RaiseOpt {
.@sk=getarg(0);
.@pc=csysGUI_OptPrice(.@sk);
.@lv=getd("CRAFTSYS["+.@sk+"]");
if (csysGUI_OptReq(.@sk)) {
if (.@lv > CRAFT_MAXLV) {
mesc l("You cannot raise crafting skills beyond level @@!", CRAFT_MAXLV), 1;
return false;
}
if (Mobpt >= .@pc) {
Mobpt-=.@pc;
.@lv=getd("CRAFTSYS["+.@sk+"]");
setd("CRAFTSYS["+.@sk+"]", .@lv+1);
return true;
}
}
return false;
}
////////////////////////////////////////
/////////////////
///////
// Misc Functions for Options Craft
// CsysNpcCraft( itemid, {bonus 1, value 1], {bonus 2, value 2}... )
// Create a craft item in a NPC's stead. Needless to say, never fails.
function script CsysNpcCraft {
// Illegal param number
if (getargcount() % 2 != 1)
return Exception("Invalid craft NPC argument count", RB_DEFAULT|RB_IRCBROADCAST);
// Setup variables
.@it=getarg(0);
.@opt1=getarg(1,0);
.@val1=getarg(2,0);
.@opt2=getarg(3,0);
.@val2=getarg(4,0);
.@opt3=getarg(5,0);
.@val3=getarg(6,0);
.@opt4=getarg(7,0);
.@val4=getarg(8,0);
.@opt5=getarg(9,0);
.@val5=getarg(10,0);
getitem(.@it, 1);
delinventorylist(); // Needed, because we'll rely on rfind()
getinventorylist();
.@index=array_rfind(@inventorylist_id, .@it);
// Apply the bonuses if needed
if (.@opt1)
setitemoptionbyindex(.@index, 0, .@opt1, .@val1);
if (.@opt2)
setitemoptionbyindex(.@index, 1, .@opt2, .@val2);
if (.@opt3)
setitemoptionbyindex(.@index, 2, .@opt3, .@val3);
if (.@opt4)
setitemoptionbyindex(.@index, 3, .@opt4, .@val4);
if (.@opt5)
setitemoptionbyindex(.@index, 4, .@opt5, .@val5);
return;
}