summaryrefslogblamecommitdiff
path: root/npc/craft/options.txt
blob: 1ab7203a49a925f7e39704809d28501482b0c52b (plain) (tree)
1
2
3
4
5
6
7
8
9
10
11










                                                             



                                                                   




                                                                
                                                       
 



                                                                      
                                                              

 
                                               
                       
                                         


                                
                                   
     
                           



                                        

                                                                 
                               
                                                     
                         
                                                  
                                                  

                         
                                                  
                                                    


                                                  
                                                    




                                                  
 
                             
                                                                
 



                          


                                                                 
                              
                                                    







                                                        

                                                   





                              
                                                    







                                                             

                                                 





                              
                                                    



                                                        


                                                     

                                                             


                                                    





                              
                                                    







                                                              
                                                





                          

                                                                 
                                
                                                      





                                                       
                                                


                          


                                
                                                      








                                                        
                                                   





                                 
                                                       





                                                      
                                                            





                                
                                                      






                                                           
                                                   


                          
                 
     
 


                                                                 
                                                         











                                                          

                                                            





                                    
                                                          











                                                           




                                                         





                                  
                                                        






                                                       
                                                    





                                  
                                                        





                                                             

                                                             








                                                                 
                                                      
                         

                                                 
                         


                                                  

                                                      
                                                  




                          
 
                                   



                               

 















                                                                                  
                                                                    






                             


                                                                       
                                 

                                         
                            
 







                                                            
                                         




                                 


                             

 





                                                  
                     
                            
                           
                     
                           
                           
                           
                           
                           
                                      
                     

                              
                           


                               
                                       
                          
                              
                                
                                 

                                 
                     



                                   
                      
                             
                      

                             
                
                      



             

                                         
                                         
                                         
                 
                                             

                                                    





                                                    
                     



                                                
                                                       



                                                  
 



                                                  
                              

                          







                                                                    


                                                              



                                                        


           

                                         
                           
                                         


                                                         






                                                  
 





















                                                              




                                                        


                                          


           
                                                             




                                         
                        
                            
 
                                  

                                      
                      


                                             

                      

                                 





                                                         
 









                                                                      
                                                  

     
                                        



                                     



                                  
                                        
                            
                                                           


                                                                         

                                            


                                      




                                                                 
                         
                                            
                                      


                                        

                                
                                
 
                                                           
                                                                
                                 


                                         
                  


 

                                                                 
                                       

                                         
                                                        
                                     
 
                              

                                                
 


                                                


                                                          
        
                                 
                                                
 







                                                                       


                                                          
 

                                         

                                                                          
                                                


                                                                        
                                      
                                                              
                                                             
                                                                                  


                  

                                                                              


                                                                        
                                                                  




                                                                    
 

                                                                  

           
 








                                                 
                                     







                                                          
                                                       



















                                                                        
                                                                







                                                                                  
                                                                










                                                                    


 

























                                        











































                                                 
                             


                                         
                                                           
 




                                                 
                                                                                










                                                                
                                                                              
                   
                                                                              
                   
                                                                              
                   
                                                                              











                                                                
                                                                                  
                   
                                                                                  
                   
                                                                                    
                   
                                                                                  












                                                                
                                                                                        
                   
                                                                                          
                   
                                                                                      
                   
                                                                                      











                                                                
                                                                                  






                                                                
     
                                                         

                                                    









                                         
                                        

                         
                                          
                         
                                           
                         
                                            
                         
                                           

                           
                                                
                           
                                         
                            
                                                
                           
                                             

                              
                                             
                               
                                              
                             
                                                
                             
                                                   
                           
                                            













                                                                
                                                  

                                                  




              








                                                 



                                                    
 























































                                                    
                                                 

















                                                               

                                      

                                                                  
 

                                                                  
 


                                                                  

                                                                  
 

                                                                 

                   
                          
                                                                       




                         
                                                  




                            
                                                    




                               
                                                    

                           
                                                    

                                                              
     
                                                                 
 

 
                             

                                                       
                                                 

                               
                                                                                       



              
 
 

                                                   
                                                 
                                                                        
                                                                              
                         
                                                                           
                                                                          
                         
                          
                                                                      
                        
                         
                                                                       
                        


                                                 
                                    
                               

                                                                                        

                         









                                               























































                                                                                         
                                                         
               
                                                         
               
                                                         
               
                                                         
               
                                                         



           
// 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 < 40 ? (.@lv < 10 ? 1000 : 1500) : 3000)*.@lv;
        // Tier 1
        case CRGROUP_ATK:
        case CRGROUP_DEF:
        case CRGROUP_ACC:
        case CRGROUP_EVD:
            return (.@lv < 10 ? 6200 : 6000)*.@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 ? 27000 : 22000)*.@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;
}