// 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() → 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: case VAR_MDEFPOWER: return 5; case IOPT_SCRESIST_POISON: case IOPT_SCRESIST_SILENCE: case IOPT_SCRESIST_CURSE: case IOPT_SCRESIST_BLIND: return 15; case VAR_MAXSPAMOUNT: case VAR_ITEMDEFPOWER: 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; }