// 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_Generate( cr_id{, preserve} )
// Return average level
function script csys_Generate {
.@gid=getarg(0);
if (!getarg(1, false)) {
deletearray(@csys_attr);
deletearray(@csys_penalty);
}
//.@lvl=getd("CRAFTSYS["+.@gid+"]");
.@avg=0;
.@stk=0;
/////////////////////////////////////////////////////////////
// Basic tier
if (.@gid & CRGROUP_BASE) {
.@lvl=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);
}
// Update averages
.@avg+=.@lvl;
.@stk+=1;
}
/////////////////////////////////////////////////////////////
// First tier
if (.@gid & CRGROUP_ATK) {
.@lvl=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=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=CRAFTSYS[CRGROUP_ACC];
if (.@lvl >= 1) {
array_push(@csys_attr, VAR_HITSUCCESSVALUE);
}
if (.@lvl >= 5) {
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=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=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=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=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=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=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=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=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=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=CRAFTSYS[CRGROUP_FINAL];
if (.@lvl >= 3) {
array_push(@csys_attr, IOPT_EXPGAIN);
}
// 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.");
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 )
function script csys_Check {
.@id=getarg(0);
// 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=4000+(getskilllv(TMW2_CRAFT)*500);
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 VAR_STRAMOUNT:
case VAR_AGIAMOUNT:
case VAR_VITAMOUNT:
case VAR_INTAMOUNT:
case VAR_DEXAMOUNT:
case VAR_LUKAMOUNT:
case HP_DRAIN:
case SP_DRAIN:
case IOPT_DOUBLEATTACK:
return 1;
case IOPT_SCRESIST_POISON:
case IOPT_SCRESIST_SILENCE:
case IOPT_SCRESIST_CURSE:
case IOPT_SCRESIST_BLIND:
return 3;
case VAR_MAXHPAMOUNT:
case VAR_MAXSPAMOUNT:
case VAR_ITEMDEFPOWER:
case VAR_MDEFPOWER:
return 5;
default:
return 2;
}
return 0;
}
// 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));
.@sc=getarg(1, CRAFTSYS_CURRENT);
.@lv2=csys_Generate(.@sc);
// @csys_attr → Available attributes
// @csys_penalty → Penalty attribute array
// 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);
//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, -30% each, depending on skill lv
.@base=3000-(.@lv*75);
if (rand(10000) > 10000-(.@base*.@slot))
break;
// Apply a bonus using array_pop (it was shuffled so we're fine)
// A pity 1 str and 1 hp is so different.
.@vartp=array_pop(@csys_attr);
.@bonus=rand(1, (.@lv+.@lv2)/2+1)*csys_Multiplier(.@vartp)+1;
setitemoptionbyindex(.@id, .@slot, .@vartp, .@bonus);
//debugmes "Bonus applied: %d at %d (slot: %d)", .@vartp, .@bonus, .@slot;
.@slot+=1;
}
// We need a new temp var
.@slt=0;
while (.@slt < min(2, .@max_pena)) {
// You have 95% for first onus, -30% each, depending on skill lv
.@base=3000+(.@lv*75);
if (rand(10000) > 9500-(.@base*.@slt))
break;
// Apply a bonus using array_pop (it was shuffled so we're fine)
// A pity 1 str and 1 hp is so different.
.@vartp=array_pop(@csys_penalty);
.@bonus=rand(1, (.@lv+.@lv2)/2+1)*csys_Multiplier(.@vartp)+1;
setitemoptionbyindex(.@id, .@slot, .@vartp, .@bonus);
.@slot+=1;
.@slt+=1;
}
// The options have been attributed
return;
}
////////////////////////////////////////
/////////////////
///////
// Interface System for Options Craft
// csysGUI_Report( )
// Report craft skill levels
function script csysGUI_Report {
mes l("Crafting Skill: Lv @@", getskilllv(TMW2_CRAFT));
mes "";
mes ".:: " + l("First Tier") + " ::.";
mesc l("Craft Min Level: 1");
mes "";
mes l("BASIC SKILLS: Lv @@", CRAFTSYS[CRGROUP_BASE]);
mesc l("Lv 1 - Str, Int");
mesc l("Lv 3 - Dex, MaxHP");
mesc l("Lv 5 - Agi, MaxMP");
mesc l("Lv 7 - Luk, Vit");
next;
mes "";
mes ".:: " + l("Second Tier") + " ::.";
mesc l("Craft Min Level: 2");
mes "";
mes l("ATTACK SKILLS: Lv @@", CRAFTSYS[CRGROUP_ATK]);
mesc l("BASIC Min Level: 2");
mesc l("Lv 1 - Atk, MAtk");
mesc l("Lv 5 - Atk %, MAtk %");
mes "";
mes l("DEFENSE SKILLS: Lv @@", CRAFTSYS[CRGROUP_DEF]);
mesc l("BASIC Min Level: 2");
mesc l("Lv 1 - Def, MDef");
mesc l("Lv 5 - Crit DEF, Ranged DEF");
next;
return;
}
// csysGUI_CRName( cr )
// Return group name for CR
function script csysGUI_CRName {
.@cr=getarg(0);
switch (.@cr) {
case CRGROUP_BASE:
return l("0 - Base Bonus");
// Tier 1
case CRGROUP_ATK:
return l("1 - Attack Bonus");
case CRGROUP_DEF:
return l("1 - Defense Bonus");
case CRGROUP_ACC:
return l("1 - Accuracy Bonus");
case CRGROUP_EVD:
return l("1 - Evasion Bonus");
// Tier 2
case CRGROUP_REGEN:
return l("2 - Regeneration Bonus");
case CRGROUP_SPEED:
return l("2 - Speed Bonus");
case CRGROUP_DOUBLE:
return l("2 - Double Power Bonus");
case CRGROUP_MAXPC:
return l("2 - Max Stats Bonus");
// Tier 3
case CRGROUP_SCRESIST:
return l("3 - SC Resist Bonus");
case CRGROUP_SCINFLICT:
return l("3 - SC Inflict Bonus");
case CRGROUP_MANAUSE:
return l("3 - Mana Economy Bonus");
case CRGROUP_BOSSATK:
return l("3 - Boss Techniques Bonus");
case CRGROUP_FINAL:
return l("4 - EXP 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 "Active "+csysGUI_CRName(.@sk);
else
return "Remove "+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_HIT] >= 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+"]");
switch (.@sk) {
case CRGROUP_BASE:
return 1000*.@lv;
// Tier 1
case CRGROUP_ATK:
case CRGROUP_DEF:
case CRGROUP_ACC:
case CRGROUP_EVD:
return 10000*.@lv;
// Tier 2
case CRGROUP_REGEN:
case CRGROUP_SPEED:
case CRGROUP_DOUBLE:
case CRGROUP_MAXPC:
return 40000*.@lv;
// Tier 3
case CRGROUP_SCRESIST:
case CRGROUP_SCINFLICT:
case CRGROUP_MANAUSE:
case CRGROUP_BOSSATK:
return 120000*.@lv;
// Final
case CRGROUP_FINAL:
return 200000*.@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)) {
.@ms$="Upgrade "+csysGUI_CRName(.@sk)+" for "+csysGUI_OptPrice(.@sk)+" Mobpt";
}
return "";
}
// csysGUI_RaiseOpt( cr )
// Returns true if can raise group, false otherwise
function script csysGUI_RaiseOpt {
.@sk=getarg(0);
.@pc=csysGUI_OptPrice(.@sk);
if (csysGUI_OptReq(.@sk)) {
if (Mobpt >= .@pc) {
Mobpt-=.@pc;
.@lv=getd("CRAFTSYS["+.@sk+"]");
setd("CRAFTSYS["+.@sk+"]", .@lv+1);
return true;
}
}
return false;
}