diff options
author | Jesusaves <cpntb1@ymail.com> | 2022-10-23 21:44:22 -0300 |
---|---|---|
committer | Jesusaves <cpntb1@ymail.com> | 2022-10-23 21:44:22 -0300 |
commit | a7c45a192268da2601cef47a4cdba987ae2327ca (patch) | |
tree | c5fb5b97db109fe7106496dd96498c475881046b /npc/craft | |
download | serverdata-a7c45a192268da2601cef47a4cdba987ae2327ca.tar.gz serverdata-a7c45a192268da2601cef47a4cdba987ae2327ca.tar.bz2 serverdata-a7c45a192268da2601cef47a4cdba987ae2327ca.tar.xz serverdata-a7c45a192268da2601cef47a4cdba987ae2327ca.zip |
Initial commit (Moubootaur Legends fork)
Diffstat (limited to 'npc/craft')
-rw-r--r-- | npc/craft/alchemy.txt | 147 | ||||
-rw-r--r-- | npc/craft/options.txt | 1198 | ||||
-rw-r--r-- | npc/craft/price.txt | 232 | ||||
-rw-r--r-- | npc/craft/recipes.txt | 605 | ||||
-rw-r--r-- | npc/craft/smith.txt | 91 | ||||
-rw-r--r-- | npc/craft/tweak.txt | 128 |
6 files changed, 2401 insertions, 0 deletions
diff --git a/npc/craft/alchemy.txt b/npc/craft/alchemy.txt new file mode 100644 index 0000000..ec26800 --- /dev/null +++ b/npc/craft/alchemy.txt @@ -0,0 +1,147 @@ +// TMW2 Script +// Author: +// Jesusalva +// Description: +// Alchemy System (Player, Guild, NPC) +// Notes: +// Base for Evol MR + +// Usage: AlchemySystem ({scope}) +// Scopes: CRAFT_NPC, CRAFT_PLAYER, CRAFT_GUILD +// If an invalid scope is passed, .knowledge won't be set but will be required +// Returns true on success, false on failure +function script AlchemySystem { + // Set .scope, .knowledge and .success + .scope=getarg(0, CRAFT_PLAYER); + if (.scope == CRAFT_PLAYER) + { + copyarray(.knowledge,RECIPES_ALCHEMY,getarraysize(RECIPES_ALCHEMY)); + } + else if (.scope == CRAFT_GUILD) + { + copyarray( .knowledge,getd("$RECIPES_ALCHEMY_"+getcharid(2)),getarraysize(getd("$RECIPES_ALCHEMY_"+getcharid(2))) ); + } + .success=false; + + setskin "craft2"; + .@var$ = requestcraft(2); + .@craft = initcraft(.@var$); + .@entry = findcraftentry(.@craft, CRAFT_ALCHEMY); + if (debug || $@GM_OVERRIDE) mes "found craft entry: " + .@entry; + if (debug || $@GM_OVERRIDE) mes "knowledge value: " + .knowledge[.@entry]; + if (.@entry < 0) { + .success=false; + } else { + if (.scope == CRAFT_NPC || .knowledge[.@entry]) { + if (GSET_FIXED_ALCHEMY) { + .@m=limit(1, GSET_FIXED_ALCHEMY, 25); + } else { + .@max=(is_sponsor() ? 25 : 10); + mesc l("How many to brew? (%d-%d)", 1, .@max); + input(.@m, 1, .@max); + } + // Alchemy loop + .@i=0; + while (.@i < .@m) { + .@s=validatecraft(.@craft); + // Could not validate (not enough resources) + if (!.@s) { + mesc l("Not crafting - insufficient materials!"), 1; + break; + } + .@s=usecraft(.@craft); + .@i++; + callfunc "FYE_Olympics_AL"; + // Exploiting?! + if (!.@s) + break; + } + .success=true; + } else { + .success=false; + } + } + deletecraft .@craft; + setskin ""; + return .success; +} + +/* +Alchemy can rely in cross-building +Where a weaker potion is base for a stronger one +Standard Duration = 2 minutes ~ 5 minutes + +Reagents: + Water + ...Eggs? + ...Milk? + Nymph Poison + Death Potion + Manapple + +Products: + Tea (Chamomile, Spearmint, Oolong, Jasmine, Yerba Mate?) + → Argaes Water + «Herbal Reagent» +OK Coffee (Shadow Herb + Tonori Water) +OK Piberries Infusion (Piberries + Curshroom) +OK Atropos Mixture (Lachesis Brew + Clotho Liquor) +OK Death Potion (Dragonfruit + Nightshade Tea) +OK Smoke Grenade (Cactus pot + Coal) +OK Grenade (Cactus pot + Sulfur Powder) +OK Scented Grenade (Cactus pot + Moss) +OK Haste Potion (Plushshroom) +OK Strength Potion (Chagashroom) + Return Potion (Hurnscald Recipe => Ocean Croc Claw + Hard Spike? Grass Seeds?) +OK Status Reset (Curshroom + Mana Piou Feather) +OK Homun Stat Reset (Curshroom + Manapple) +OK Move Speed (Gem Powder + Fluor Powder) +OK Precision (Piberries + Mt. Snake Egg) +OK Dodge Potion (Piberries + Snake Egg) +OK Luck, Dex, Int, Vit, Agi (Gems + Tea) +OK Sacred Life (Golden Apple + Elixir of Life) +OK Sacred Mana (Golden Apple + Celestia Tea) +OK Sacred Revival (Sacred Life + Sacred Mana) +OK Broken Warp Crystal? (Wurtizite + Black Mamba Skin) +OK Magic Apple? (Divine Apple + Manapple? Death Potion? Sacred Life/Revival?) +OK Purification Potion (Nymph Poison + Sacred Life) +OK Iced Bottle (Tonori W. + Argaes W.) +OK Insurance Contract (» Insurance?) (Quill + Reed Bundle) +OK Insurance (Quill + Death Potion) + Mysterious Fruit? (Legendary) + +For all Scrolls: Quill + ? (depends on scroll itself) + » Summon Scrolls (Based on mob parts, 1× mob?) + → alignment_cansummon() + SummonMagic() or summon() directly + → Criteria between weak/strong version is alignment + → When aligned, scrolls always summon strongest ver + → Level must be equal or superior to strongest, tho + » Maggot/Giant Maggot: Bug Leg (Lv 40) + » CaveMaggot: Maggot Slime + » Green Dragon/Nightmare: Dragon Scales (Lv 105) + » Wolvern: Wolvern Pelt + » Moggun/Yeti: Frozen Yeti Tear (Lv 60) + » Terranite/T.Prot.: Terranite Ore (Lv 90) + » Magnus Heal (Lifestone) + » Area Provoke? → Scent grenade? + » Guild Skills? +OK » ScrollAngelLightA ( + ) +OK » ScrollBattlePlansA ( + ) +OK » ScrollDefenseBlessA ( + ) +OK » ScrollCriticalFortuneA ( + ) + → TODO: Kyrie Eleison (Absolute Shield) + → With self-stun, makes you a temporary wall? + → Maybe a item of Quill + LoF Coin for guild skills? (LoF Quill) + + // Skills for Aegis Shield, all beyond maximum level + // Slimes, Snakes, Fairies, Darth Duck, Mr. Prickel + // PoisonS.Mushroom + // TODO: Lizards, (Black)Scorpions, Moonshroom, Black Mamba, Centaur + skill TMW2_HALHISS, 10; + skill TMW2_KALSPIKE, 9; + skill TMW2_LIMERIZER, 10; + skill TMW2_FAIRYKINGDOM, 9; + skill TMW2_DUCKY, 10; + skill TMW2_FAIRYEMPIRE, 10; + +*/ + diff --git a/npc/craft/options.txt b/npc/craft/options.txt new file mode 100644 index 0000000..1ab7203 --- /dev/null +++ b/npc/craft/options.txt @@ -0,0 +1,1198 @@ +// 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; +} + diff --git a/npc/craft/price.txt b/npc/craft/price.txt new file mode 100644 index 0000000..4b0ab9c --- /dev/null +++ b/npc/craft/price.txt @@ -0,0 +1,232 @@ +// TMW-2 Script. +// Author: +// Jesusalva +// Description: +// Modifies the sell price for crafts +// Always run this when casting @reloaditemdb +function script _fix_cPrice { + .@const$ = data_to_string(getarg(0)); + .@m = getarg(1, 35); + + // Shady code by gumi + if (startswith(.@const$, "Craft")) { + // infer the item constant from the craft constant + .@recipe = getarg(0); + + .@item = string_to_data(substr(.@const$, 5, getstrlen(.@const$) - 1)); + } else { + // infer the craft constant from the item constant + .@recipe = string_to_data(sprintf("Craft%s", .@const$)); + .@item = getarg(0); + } + + if (.@item <= 0) { + // target item not found + consolebug("ERROR, INVALID ITEM ID DETECTED at _fix_cPrice"); + return; + } + + .@price = 0; + // More shady code by gumi + for (.@inv = 0; .@inv < 9; ++.@inv) { + .@size = getcraftrecipe(.@recipe, .@inv, .@qty[0], .@item_id[0]); + + if (.@size < 0) { + if (.@size == -1) { + // recipe does not exist + break; + } + // inventory does not exist + break; + } + + // More shady code to build new price + for (.@it = 0; .@it < .@size; ++.@it) { + .@recipe_item = .@item_id[.@it]; + .@recipe_qty = .@qty[.@it]; + + if (.@recipe_item <= 0) { + break; + } + + // Increase the final price + //debugmes("Price %d + %d GP (%dx %s)", .@price, getiteminfo(.@recipe_item, ITEMINFO_SELLPRICE), + // .@recipe_qty, getitemname(.@recipe_item)); + .@price += getiteminfo(.@recipe_item, ITEMINFO_SELLPRICE) * .@recipe_qty; + //debugmes("New price: %d", .@price); + } + + // Update the final price + if (.@price > 0) { + debugmes("Price for %s adjusted from %d (%d) to %d (%d) GP", getitemname(.@item), getiteminfo(.@item, ITEMINFO_BUYPRICE), getiteminfo(.@item, ITEMINFO_SELLPRICE), .@price * .@m / 10, .@price); + setiteminfo(.@item, ITEMINFO_BUYPRICE, .@price * .@m / 10); + setiteminfo(.@item, ITEMINFO_SELLPRICE, .@price); + //debugmes("New Price for %s is now %d (%d) GP", getitemname(.@item), getiteminfo(.@item, ITEMINFO_BUYPRICE), getiteminfo(.@item, ITEMINFO_SELLPRICE)); + } + } + return; +} + +function script fix_cPrice { + // In some cases, we don't care + if (debug) return; + + // Otherwise... + freeloop(true); + + // Fix potions prices + _fix_cPrice(AgiPotionA); + _fix_cPrice(AgiPotionB); + _fix_cPrice(AgiPotionC); + _fix_cPrice(VitPotionA); + _fix_cPrice(VitPotionB); + _fix_cPrice(VitPotionC); + _fix_cPrice(IntPotionA); + _fix_cPrice(IntPotionB); + _fix_cPrice(IntPotionC); + _fix_cPrice(DexPotionA); + _fix_cPrice(DexPotionB); + _fix_cPrice(DexPotionC); + _fix_cPrice(LukPotionA); + _fix_cPrice(LukPotionB); + _fix_cPrice(LukPotionC); + //_fix_cPrice(HastePotion); // 240 -> 75 + //_fix_cPrice(StrengthPotion); // 240 -> 195 + + // TODO: Scrolls? Reagents? + // And reagents should happen before potions + + // And weapons + _fix_cPrice(WoodenSword); + _fix_cPrice(BugSlayer); + _fix_cPrice(ShortGladius); + _fix_cPrice(Backsword); + _fix_cPrice(ShortSword); + _fix_cPrice(Kitana); + _fix_cPrice(BoneKnife); + _fix_cPrice(LongSword); + _fix_cPrice(RockKnife); + _fix_cPrice(DivineSword); + + // And two hand weapons + _fix_cPrice(MiereCleaver); + _fix_cPrice(Broadsword); + _fix_cPrice(Halberd); + _fix_cPrice(ImmortalSword); + + // And archery + _fix_cPrice(ShortBow); + _fix_cPrice(ForestBow); + _fix_cPrice(ElficBow); + _fix_cPrice(ChampionshipBow); + _fix_cPrice(BansheeBow); + + // And magic + _fix_cPrice(TrainingWand, 22); + _fix_cPrice(NoviceWand, 27); + _fix_cPrice(ApprenticeWand); + _fix_cPrice(LeaderWand); + _fix_cPrice(MysticWand); + + // And Firestaves + _fix_cPrice(PynRevolver); + _fix_cPrice(PynRifle); + _fix_cPrice(PynGatling); + _fix_cPrice(PynShotgun); + + // And misc + _fix_cPrice(TerranitePants); + _fix_cPrice(TerraniteArmor); + _fix_cPrice(Skypiercer, 50); + + // And shields + _fix_cPrice(WoodenShield); + _fix_cPrice(BladeShield); + _fix_cPrice(BraknarShield); + _fix_cPrice(BritShield); + _fix_cPrice(BromenalShield); + _fix_cPrice(BlueKnightShield); + _fix_cPrice(SteelShield); + _fix_cPrice(DragonShield); + _fix_cPrice(SaviorShield, 50); + + // Chest Armor + _fix_cPrice(LeatherShirt); + _fix_cPrice(LieutenantArmor); + _fix_cPrice(Chainmail); + _fix_cPrice(CopperArmor); + _fix_cPrice(LightPlatemail); + _fix_cPrice(GoldenLightPlatemail); + _fix_cPrice(WarlordPlate); + _fix_cPrice(GoldenWarlordPlate); + _fix_cPrice(BromenalChest); + _fix_cPrice(AssassinChest); + _fix_cPrice(SaviorArmor, 50); + + // Pants + //_fix_cPrice(JeansShorts); + _fix_cPrice(RaidTrousers); + _fix_cPrice(LeatherTrousers); + _fix_cPrice(JeansChaps); + _fix_cPrice(SilkPants); + _fix_cPrice(ChainmailSkirt); // <= Pre-Fortress + _fix_cPrice(BromenalPants); // <= Fortress + _fix_cPrice(WarlordPants); + _fix_cPrice(AssassinPants); + + // Gloves (more expensive due ASPD) + _fix_cPrice(SilkGloves, 40); + _fix_cPrice(LeatherGloves, 40); + _fix_cPrice(BromenalGloves, 40); + _fix_cPrice(ManaGloves, 40); + _fix_cPrice(WarlordGloves, 40); + _fix_cPrice(AssassinGloves, 40); + + // Helmets + _fix_cPrice(InfantryHelmet); + _fix_cPrice(DesertHelmet); + _fix_cPrice(BromenalHelmet); + _fix_cPrice(CandleHelmet); + _fix_cPrice(CrusadeHelmet); + _fix_cPrice(WarlordHelmet); + _fix_cPrice(VikingHelmet); + _fix_cPrice(TerraniteHelmet); // Cheaper than the real cost due 2x Earth Powder + _fix_cPrice(CenturionHelmet); + _fix_cPrice(BullHelmet); + _fix_cPrice(DarkHelm); + _fix_cPrice(DarkKnightHelmet); + _fix_cPrice(SamuraiHelmet); + _fix_cPrice(SaviorHelmet); + + // Footwear + _fix_cPrice(LeatherBoots); + _fix_cPrice(DeepBlackBoots); + _fix_cPrice(BromenalBoots); + _fix_cPrice(WarlordBoots); + _fix_cPrice(AssassinBoots); + _fix_cPrice(SaviorBoots, 50); + + // We're done + freeloop(false); + + // Manual fixes (handling _fix_cPrice shortcomings) + setiteminfo(DarkCrystal, ITEMINFO_SELLPRICE, rand2(150, 250)); + return; +} + +- script craft_price_fix -1,{ + end; + +OnCall: + atcommand("@reloaditemdb"); + fix_cPrice(); + end; + +OnInit: + bindatcmd "reloaditemdb2", "craft_price_fix::OnCall", 99, 100, 1; + // This should be called after craft_db is loaded + sleep(750); + fix_cPrice(); + end; +} + diff --git a/npc/craft/recipes.txt b/npc/craft/recipes.txt new file mode 100644 index 0000000..0647ff4 --- /dev/null +++ b/npc/craft/recipes.txt @@ -0,0 +1,605 @@ +// TMW-2 script. +// Author: +// Jesusalva +// Description: +// Recipe Books in TMW2 + +- script #RecipeBook NPC_HIDDEN,{ + function showRecipe; + function readCooking; + function readAlchemy; + function readCrafting; + +OnUse: + setnpcdialogtitle l("Recipe Book"); + + mesc l("You open the Recipe Book. Each recipe you get can be put here."); + next; + do { + mesc l("Which recipes do you want to read?"); + select + l("Nothing."), + l("Cooking Recipes."), + l("Alchemy Recipes."), + l("Crafting Recipes."); + mes ""; + switch (@menu) { + case 2: + readCooking(); break; + case 3: + readAlchemy(); break; + case 4: + readCrafting(); break; + } + } while (@menu != 1); + closeclientdialog; + close; + +// Expects: @scope$ +// showRecipe( recipe{, recipe...} ) +function showRecipe { + if (@scope$ == "") + return Exception("Faulty recipe skill command invoked - error"); + + freeloop(true); + for (.@a = 0; .@a < getargcount(); ++.@a) { + .@const$ = data_to_string(getarg(.@a)); + + if (startswith(.@const$, "Craft")) { + // infer the item constant from the craft constant + .@recipe = getarg(.@a); + + .@item = string_to_data(substr(.@const$, 5, getstrlen(.@const$) - 1)); + } else { + // infer the craft constant from the item constant + .@recipe = string_to_data(sprintf("Craft%s", .@const$)); + .@item = getarg(.@a); + } + + if (.@item <= 0) { + // target item not found + consolebug("ERROR, INVALID ITEM ID DETECTED at showRecipe"); + continue; + } + + if (!getd("RECIPES_"+@scope$+"["+.@recipe+"]") && !$@GM_OVERRIDE) { + // does not have the recipe + continue; + } + + for (.@inv = 0; .@inv < 9; ++.@inv) { + .@size = getcraftrecipe(.@recipe, .@inv, .@qty[0], .@item_id[0]); + + if (.@size < 0) { + if (.@size == -1) { + // recipe does not exist + break; + } + // inventory does not exist + break; + } + + mes(l(".:: %s Recipe ::.", getitemlink(.@item))); + + for (.@it = 0; .@it < .@size; ++.@it) { + .@recipe_item = .@item_id[.@it]; + .@recipe_qty = .@qty[.@it]; + + if (.@recipe_item <= 0) { + break; + } + + mesc(sprintf("%d/%d %s", countitem(.@recipe_item), .@recipe_qty, getitemlink(.@recipe_item))); + } + + mes(""); + .@count++; + } + } + freeloop(false); + + return .@count > 0; +} + +// =============================== Cooking Functions +function readCooking { + setnpcdialogtitle l("Cooking Recipes"); + @scope$="COOKING"; + + mesc l("Eating is a necessity, but cooking is an art."); + mesc l("(All items must be placed exactly in this order.)"); + next; + mesc l("List of known cooking recipes:"); + mes ""; + //showRecipe(0, Iten, WarpedLog, 9999); + next; + @scope$=""; + return; +} + +// =============================== Cooking Functions +function readAlchemy { + setnpcdialogtitle l("Alchemy Recipes"); + @scope$="ALCHEMY"; + + mesc l("Alchemy. The art of having quasi-magical effects without magic."); + mesc l("(All items must be placed exactly in this order.)"); + next; + mesc l("List of known alchemy recipes:"); + mes ""; + // Healing + mesc "----------"+l("Healing Recipes")+"----------", 2; + showRecipe(PiberriesInfusion, + AtroposMixture, + Coffee); + dnext; + + // General Boosts + mesc "----------"+l("General Boosts")+"----------", 2; + showRecipe(HastePotion, + StrengthPotion, + StatusResetPotion, // BROKEN + HomunResetPotion, + MoveSpeedPotion, // BROKEN + PrecisionPotion, + DodgePotion, + SacredLifePotion, + SacredManaPotion, + SacredImmortalityPotion, + MagicApple); + dnext; + + // Stats Boosts + mesc "----------"+l("Stat Boost Recipes")+"----------", 2; + showRecipe(LukPotionA, + LukPotionB, + LukPotionC); + + showRecipe(IntPotionA, + IntPotionB, + IntPotionC); + + showRecipe(VitPotionA, + VitPotionB, + VitPotionC); + + showRecipe(AgiPotionA, + AgiPotionB, + AgiPotionC); + + showRecipe(DexPotionA, + DexPotionB, + DexPotionC); + + // Scrolls + mesc "----------"+l("Magic Scrolls")+"----------", 2; + showRecipe(ScrollSCave, + ScrollSMaggot, + ScrollSWolvern, + ScrollSYeti, + ScrollSTerranite, + ScrollSDragon, + ScrollMagnusHealA, + ScrollAngelLightA, + ScrollBattlePlansA, + ScrollDefenseBlessA, + ScrollCriticalFortuneA); + + // General Stuff + mesc "----------"+l("Reagents & Other Potions")+"----------", 2; + showRecipe(IcedBottle, + PurificationPotion, + DeathPotion, + BrokenWarpCrystal, + SmokeGrenade, + ScentGrenade, + Grenade, + Insurance, + InsuranceContract); + + next; + @scope$=""; + return; +} + +// =============================== Crafting Functions +function readCrafting { + setnpcdialogtitle l("Crafting Recipes"); + @scope$="EQUIPMENT"; + + mesc l("There is only one way towards the best equipment: Smith away!"); + mesc l("(All items must be placed exactly in this order.)"); + next; + mesc l("List of known crafting recipes:"); + mes ""; + // Melee Weapons: Never use Titanium nor Lead. Iron-based, no silver + mesc "----------"+l("One Hand Weapon Recipes")+"----------", 2; + showRecipe(Dagger, + WoodenSword, + BugSlayer, + ShortGladius, + Backsword, + ShortSword, + Kitana, + BoneKnife, + LongSword, + RockKnife, + DivineSword); + dnext; + // Two Hands Melee Weapons: Never use Titanium nor Lead. Silver-based. + mesc "----------"+l("Two Hands Weapon Recipes")+"----------", 2; + // Reserved ID 63 and 64 + // Halberd is really cheap as it doesn't uses Platinum/Iridium :P + showRecipe(MiereCleaver, + Broadsword, + Halberd, + ImmortalSword); + + dnext; + // Archery Weapons: Always use Wood, Root and Carp. + mesc "----------"+l("Archery Weapon Recipes")+"----------", 2; + showRecipe(ShortBow, + ForestBow, + ElficBow, + ChampionshipBow, + BansheeBow); + dnext; + // Magical Weapons: Wood + powders + mesc "----------"+l("Magical Weapon Recipes")+"----------", 2; + showRecipe(TrainingWand, + NoviceWand, + ApprenticeWand, + LeaderWand, + MysticWand); + dnext; + // Firestaff Weapons: Lead + Titanium + mesc "----------"+l("Fire Staffs Recipes")+"----------", 2; + showRecipe(PynRevolver, + PynRifle, + PynGatling, + PynShotgun); + dnext; + // Shields: May use Leather. Titanium or Lead, but never both + mesc "----------"+l("Shield Recipes")+"----------", 2; + // Exception to shield rule: Braknar Shield + showRecipe(WoodenShield, + BladeShield, + BraknarShield, + BritShield, + BromenalShield, + BlueKnightShield, + SteelShield, + DragonShield, + SaviorShield); + dnext; + // Chest Armors -> Primary Ore + Secondary Ore + Iron Powder + Earth Powder + mesc "----------"+l("Chest Armor Recipes")+"----------", 2; + showRecipe(LeatherShirt, + LieutenantArmor, + Chainmail, + CopperArmor, + LightPlatemail, + GoldenLightPlatemail, + WarlordPlate, + GoldenWarlordPlate, + BromenalChest, + AssassinChest, + SaviorArmor); + dnext; + // Pants -> Primary Item + Secondary Item + Leather Patch + Earth Powder + mesc "----------"+l("Pants Recipes")+"----------", 2; + showRecipe(JeansShorts, + RaidTrousers, + LeatherTrousers, + JeansChaps, + SilkPants, + ChainmailSkirt, + BromenalPants, + WarlordPants, + AssassinPants); + dnext; + // Gloves: Gloves items + mesc "----------"+l("Gloves Recipes")+"----------", 2; + showRecipe(SilkGloves, + LeatherGloves, + BromenalGloves, + ManaGloves, + WarlordGloves, + AssassinGloves); + dnext; + // Feet: Shoes items + mesc "----------"+l("Footwear Recipes")+"----------", 2; + showRecipe(LeatherBoots, + DeepBlackBoots, + BromenalBoots, + WarlordBoots, + AssassinBoots, + SaviorBoots); + dnext; + // Helmets: Helmet items + mesc "----------"+l("Helmet Recipes")+"----------", 2; + showRecipe(InfantryHelmet, + DesertHelmet, + BromenalHelmet, + CandleHelmet, + CrusadeHelmet, + WarlordHelmet, + VikingHelmet, + TerraniteHelmet, + CenturionHelmet, + BullHelmet, + DarkHelm, + DarkKnightHelmet, + SamuraiHelmet, + SaviorHelmet); + dnext; + // Misc: Misc items + mesc "----------"+l("Miscellaneous Recipes")+"----------", 2; + showRecipe(GoldenRing, + TerranitePants, + TerraniteArmor, + Skypiercer); + next; + @scope$=""; + return; +} + +OnInit: + .sex = G_OTHER; + .distance = 1; + end; +} + +// Below this line are utils for Gacha. We use callfunc() on itemDB. +// Types: CRAFT_COOKING, CRAFT_ALCHEMY, CRAFT_EQUIPMENT +// Rarity: 1 - basic, 2 - intermediary, 4 - advanced, 8 - expert, 16 - master +// Level equivalents: 1: (1~20) 2: (21~44), 3: (45~75), 4: (76~99), 5: 100+ +function script MakeBlueprint { + .@type=getarg(0, -1); + .@rarity=getarg(1, 1); + + switch (.@type) { + ///////////////////////////////////////////////////// + ///// Alchemy Recipes + ///////////////////////////////////////////////////// + case CRAFT_ALCHEMY: + if (.@rarity & CRAFT_BASIC) { + array_push(.@recipes, CraftPiberriesInfusion); + array_push(.@recipes, CraftHastePotion); + array_push(.@recipes, CraftStrengthPotion); + array_push(.@recipes, CraftCoffee); + array_push(.@recipes, CraftScrollSCave); + array_push(.@recipes, CraftScrollSMaggot); + } + if (.@rarity & CRAFT_INTERMEDIARY) { + array_push(.@recipes, CraftLukPotionA); + array_push(.@recipes, CraftDexPotionA); + array_push(.@recipes, CraftIntPotionA); + array_push(.@recipes, CraftAgiPotionA); + array_push(.@recipes, CraftVitPotionA); + array_push(.@recipes, CraftSpeedPotion); + array_push(.@recipes, CraftIcedBottle); + array_push(.@recipes, CraftInsuranceContract); + array_push(.@recipes, CraftScrollSWolvern); + } + if (.@rarity & CRAFT_ADVANCED) { + array_push(.@recipes, CraftResetPotion); + array_push(.@recipes, CraftPrecisionPotion); + array_push(.@recipes, CraftDodgePotion); + array_push(.@recipes, CraftDeathPotion); + array_push(.@recipes, CraftSmokeGrenade); + array_push(.@recipes, CraftScentGrenade); + array_push(.@recipes, CraftGrenade); + array_push(.@recipes, CraftInsurance); + array_push(.@recipes, CraftScrollSYeti); + } + if (.@rarity & CRAFT_EXPERT) { + array_push(.@recipes, CraftLukPotionB); + array_push(.@recipes, CraftDexPotionB); + array_push(.@recipes, CraftIntPotionB); + array_push(.@recipes, CraftAgiPotionB); + array_push(.@recipes, CraftVitPotionB); + array_push(.@recipes, CraftAtroposMixture); + array_push(.@recipes, CraftPurificationPotion); + array_push(.@recipes, CraftHomunResetPotion); + array_push(.@recipes, CraftScrollSTerranite); + array_push(.@recipes, CraftScrollMagnusHealA); + } + if (.@rarity & CRAFT_MASTER) { + array_push(.@recipes, CraftLukPotionC); + array_push(.@recipes, CraftDexPotionC); + array_push(.@recipes, CraftIntPotionC); + array_push(.@recipes, CraftAgiPotionC); + array_push(.@recipes, CraftVitPotionC); + array_push(.@recipes, CraftSacredLifePotion); + array_push(.@recipes, CraftSacredManaPotion); + array_push(.@recipes, CraftSacredImmortalityPotion); + array_push(.@recipes, CraftBrokenWarpCrystal); + array_push(.@recipes, CraftMagicApple); + array_push(.@recipes, CraftScrollSDragon); + if (getcharid(2) > 0) { + if (getguildlvl(getcharid(2)) >= 4) + array_push(.@recipes, CraftScrollAngelLightA); + if (getguildlvl(getcharid(2)) >= 5) + array_push(.@recipes, CraftScrollBattlePlansA); + if (getguildlvl(getcharid(2)) >= 3) + array_push(.@recipes, CraftScrollDefenseBlessA); + if (getguildlvl(getcharid(2)) >= 6) + array_push(.@recipes, CraftScrollCriticalFortuneA); + } + } + + // Now you'll learn some recipe! + .@rcp=any_of(.@recipes); + + // Half precision failsafe + if (RECIPES_EQUIPMENT[.@rcp] && any(true, false)) + .@rcp=any_of(.@recipes); + + // Maybe you already knew it? + if (RECIPES_ALCHEMY[.@rcp]) { + .@mpot=rand2(900, 1000*.@rarity); + dispbottom l("It was a recipe you already knew... (+ @@ Mobpt)", .@mpot); + getexp (BaseLevel+JobLevel)*rand2(1,.@rarity), JobLevel+rand2(1,.@rarity); + // Give you some Monster Points to use with Intense Beard + // You do NOT need to be registered with Aidan for this. + Mobpt+=.@mpot; + } else { + dispbottom l("Learned a new recipe!"); + RECIPES_ALCHEMY[.@rcp]=true; + } + break; + ///////////////////////////////////////////////////// + ///// Equipment Recipes + ///////////////////////////////////////////////////// +// array_push(.@recipes, Craft); + case CRAFT_EQUIPMENT: + if (.@rarity & CRAFT_BASIC) { + array_push(.@recipes, CraftWoodenSword); + array_push(.@recipes, CraftWoodenShield); + array_push(.@recipes, CraftTrainingWand); + array_push(.@recipes, CraftShortBow); + array_push(.@recipes, CraftSilkGloves); + array_push(.@recipes, CraftInfantryHelmet); + array_push(.@recipes, CraftLeatherShirt); + array_push(.@recipes, CraftJeansShorts); + array_push(.@recipes, CraftLeatherBoots); + } + if (.@rarity & CRAFT_INTERMEDIARY) { + array_push(.@recipes, CraftBugSlayer); + array_push(.@recipes, CraftShortGladius); + array_push(.@recipes, CraftMiereCleaver); + array_push(.@recipes, CraftBladeShield); + array_push(.@recipes, CraftNoviceWand); + array_push(.@recipes, CraftForestBow); + array_push(.@recipes, CraftLeatherGloves); + array_push(.@recipes, CraftDesertHelmet); + array_push(.@recipes, CraftBromenalHelmet); + array_push(.@recipes, CraftLieutenantArmor); + array_push(.@recipes, CraftRaidTrousers); + array_push(.@recipes, CraftDeepBlackBoots); + } + if (.@rarity & CRAFT_ADVANCED) { + array_push(.@recipes, CraftBacksword); + array_push(.@recipes, CraftShortSword); + array_push(.@recipes, CraftBoneKnife); + array_push(.@recipes, CraftKitana); + array_push(.@recipes, CraftBroadsword); + array_push(.@recipes, CraftPynRevolver); + array_push(.@recipes, CraftApprenticeWand); + array_push(.@recipes, CraftElficBow); + array_push(.@recipes, CraftBritShield); + array_push(.@recipes, CraftBromenalShield); + array_push(.@recipes, CraftBlueKnightShield); + array_push(.@recipes, CraftBromenalGloves); + array_push(.@recipes, CraftCandleHelmet); + array_push(.@recipes, CraftCrusadeHelmet); + array_push(.@recipes, CraftWarlordHelmet); + array_push(.@recipes, CraftVikingHelmet); + array_push(.@recipes, CraftChainmail); + array_push(.@recipes, CraftCopperArmor); + array_push(.@recipes, CraftLightPlatemail); + array_push(.@recipes, CraftWarlordPlate); + array_push(.@recipes, CraftBromenalChest); + array_push(.@recipes, CraftLeatherTrousers); + array_push(.@recipes, CraftJeansChaps); + array_push(.@recipes, CraftSilkPants); + array_push(.@recipes, CraftChainmailSkirt); + array_push(.@recipes, CraftBromenalPants); + array_push(.@recipes, CraftWarlordPants); + array_push(.@recipes, CraftBromenalBoots); + } + if (.@rarity & CRAFT_EXPERT) { + array_push(.@recipes, CraftGoldenRing); + array_push(.@recipes, CraftLongSword); + array_push(.@recipes, CraftRockKnife); + array_push(.@recipes, CraftHalberd); + array_push(.@recipes, CraftPynRifle); + array_push(.@recipes, CraftPynGatling); + array_push(.@recipes, CraftLeaderWand); + array_push(.@recipes, CraftChampionshipBow); + array_push(.@recipes, CraftSteelShield); + array_push(.@recipes, CraftDragonShield); + array_push(.@recipes, CraftManaGloves); + array_push(.@recipes, CraftWarlordGloves); + array_push(.@recipes, CraftTerraniteHelmet); + array_push(.@recipes, CraftCenturionHelmet); + array_push(.@recipes, CraftBullHelmet); + array_push(.@recipes, CraftDarkHelm); + array_push(.@recipes, CraftTerraniteArmor); + array_push(.@recipes, CraftTerranitePants); + array_push(.@recipes, CraftWarlordBoots); + array_push(.@recipes, CraftAssassinChest); + array_push(.@recipes, CraftAssassinPants); + } + if (.@rarity & CRAFT_MASTER) { + array_push(.@recipes, CraftDivineSword); + array_push(.@recipes, CraftImmortalSword); + array_push(.@recipes, CraftPynShotgun); + array_push(.@recipes, CraftMysticWand); + array_push(.@recipes, CraftBansheeBow); + array_push(.@recipes, CraftAssassinGloves); + array_push(.@recipes, CraftAssassinBoots); + array_push(.@recipes, CraftDarkKnightHelmet); + array_push(.@recipes, CraftSamuraiHelmet); + } + + // Now you'll learn some recipe! + .@rcp=any_of(.@recipes); + + // Double precision failsafe + if (RECIPES_EQUIPMENT[.@rcp]) + .@rcp=any_of(.@recipes); + + // Maybe you already knew it? + if (RECIPES_EQUIPMENT[.@rcp]) { + .@mpot=rand2(900*.@rarity, 1000*.@rarity); + dispbottom l("It was a recipe you already knew... (+ @@ Mobpt)", .@mpot); + getexp (BaseLevel+JobLevel)*rand2(1,.@rarity), JobLevel+rand2(1,.@rarity); + // Give you some Monster Points to use with Intense Beard + // You do NOT need to be registered with Aidan for this. + Mobpt+=.@mpot; + } else { + dispbottom l("Learned a new recipe!"); + RECIPES_EQUIPMENT[.@rcp]=true; + } + break; + default: + return Exception("Invalid blueprint type "+.@type+" - item was lost."); + } + return; +} + +// Create a blueprint based on level. Extra chance for weaker Blueprint. +// Level equivalents: 1: (1~20) 2: (21~44), 3: (45~75), 4: (76~99), 5: 100+ +function script MakeRandomBlueprint { + array_push(.@blueprints, AlchemyBlueprintA); + array_push(.@blueprints, EquipmentBlueprintA); + if (BaseLevel > 20) { + array_push(.@blueprints, AlchemyBlueprintB); + array_push(.@blueprints, EquipmentBlueprintB); + } + if (BaseLevel > 44) { + array_push(.@blueprints, AlchemyBlueprintB); + array_push(.@blueprints, EquipmentBlueprintB); + array_push(.@blueprints, AlchemyBlueprintC); + array_push(.@blueprints, EquipmentBlueprintC); + } + if (BaseLevel > 75) { + array_push(.@blueprints, AlchemyBlueprintC); + array_push(.@blueprints, EquipmentBlueprintC); + array_push(.@blueprints, AlchemyBlueprintD); + array_push(.@blueprints, EquipmentBlueprintD); + } + if (BaseLevel > 100) { + array_push(.@blueprints, AlchemyBlueprintD); + array_push(.@blueprints, EquipmentBlueprintD); + if (any(true,false)) { + array_push(.@blueprints, AlchemyBlueprintE); + array_push(.@blueprints, EquipmentBlueprintE); + } + } + getitem any_of(.@blueprints), 1; + return; +} + diff --git a/npc/craft/smith.txt b/npc/craft/smith.txt new file mode 100644 index 0000000..9b8387c --- /dev/null +++ b/npc/craft/smith.txt @@ -0,0 +1,91 @@ +// TMW2 Script +// Author: +// Jesusalva +// Description: +// Smith System (Player, Guild, NPC) +// Notes: +// Base for Evol MR +// This one is more crazy. Cannot be equipping target craft. +// After successful craft, we use CraftDB return code to equip() the +// new item and apply a random option bonus based on crafter skills +// eg. setequipoption(EQI_HAND_R, 1, VAR_STRAMOUNT, 5) +// We should be able to apply several bonuses for the nicest experience :3 +// We should also add a movespeed bonus... So demure can specialize herself in +// crafting really fast weapons in every aspects, and this system would allow her +// to do so :> But then, maybe we should have a crafting skill where players can +// allocate status points? + +// Usage: SmithSystem ({scope}) +// Scopes: CRAFT_NPC, CRAFT_PLAYER, CRAFT_GUILD +// CRAFT_NPC - Unlocks all recipes +// CRAFT_PLAYER - Normal behavior +// CRAFT_GUILD - Items created will be Guild-bound +// Returns true on success, false on failure +function script SmithSystem { + // Set .scope, .knowledge and .success + .scope=getarg(0, CRAFT_PLAYER); + copyarray(.knowledge,RECIPES_EQUIPMENT,getarraysize(RECIPES_EQUIPMENT)); + .success=false; + + mesc l("WARNING: Strange bugs may happen if you attempt to craft an item you already have on inventory!"), 1; + setskin "craft4"; + .@var$ = requestcraft(4); + .@craft = initcraft(.@var$); + .@entry = findcraftentry(.@craft, CRAFT_EQUIPMENT); + if (debug || $@GM_OVERRIDE) mes "found craft entry: " + .@entry; + if (debug || $@GM_OVERRIDE) mes "knowledge value: " + .knowledge[.@entry]; + if (.@entry < 0) { + .success=false; + } else { + if (.scope == CRAFT_NPC) { + usecraft .@craft; + .@it=getcraftcode(.@entry); + getitem(.@it, 1); + .success=true; + } else if (.knowledge[.@entry] || $@GM_OVERRIDE) { + // Player craft item + usecraft .@craft; + .@it=getcraftcode(.@entry); + + // Mark the crafting in your score variable + CRAFTING_SCORE_COMPLETE+=getiteminfo(.@it, ITEMINFO_ELV); + // Update your score book + CRAFTING_SCORE=(CRAFTING_SCORE_COMPLETE/40); + + if (.scope == CRAFT_GUILD) + getitembound(.@it, 1, 2); // Create a guild-bound item + else if (GSET_CRAFT_BOUND) + getitembound(.@it, 1, 1); // Create an account-bound item + else + getnameditem(.@it, strcharinfo(0)); + if (getskilllv(TMW2_CRAFT)) { + delinventorylist(); // Needed, because we'll rely on rfind() + getinventorylist(); + .@index=array_rfind(@inventorylist_id, .@it); + + // Just to be sure, if this have an option, get something else + if (getitemoptionparambyindex(.@index, 0)) { + .@index=array_find(@inventorylist_id, .@it); + } + + if (csys_Check(.@index, 75000)) { + csys_Apply(.@index); + } + } + + // Get experience for the craft + .@xp=getiteminfo(.@it, ITEMINFO_SELLPRICE); + getexp .@xp+BaseLevel, (.@xp/3)+BaseLevel+JobLevel; + // Monster points too, if appliable - by your Job Level + if (MPQUEST) + Mobpt+=JobLevel; + + .success=true; + } else { + .success=false; + } + } + deletecraft .@craft; + setskin ""; + return .success; +} diff --git a/npc/craft/tweak.txt b/npc/craft/tweak.txt new file mode 100644 index 0000000..1124afa --- /dev/null +++ b/npc/craft/tweak.txt @@ -0,0 +1,128 @@ +// TMW2 Script +// Author: +// Jesusalva +// Description: +// Smith System (Player, Guild, NPC) +// Notes: +// It's like smithing, but it only change an item options + +// Usage: SmithTweakReset () +// Asks if player wants to remove an item options. And remove them. +function script SmithTweakReset { + mesc b(l("You are REMOVING an item option.")), 1; + mesc l("Note: This action cannot be undone."), 1; + mes l("Drag and drop here the item you want to remove the options."); + + .@id=requestitemindex(); + mes ""; + + // Ask player to confirm + mesc l("Are you sure?"), 1; + mesc l("Note: This action cannot be undone."), 1; + if (!csys_Confirm(.@id)) + return; + + csys_Check(.@id); + return; +} + +// Usage: SmithTweakSystem ({price=600, retries=1}) +// Returns true on success, false on failure +function script SmithTweakSystem { + .@price=getarg(0, 600); + .@retry=getarg(1, 1); + + // Adjust price (if relevant) + if (.@retry == 1) + .@price=POL_AdjustPrice(.@price); + + // How many times more can you tweak? + // You get 1 action, capped to 6 + .@left=gettimeparam(GETTIME_HOUR)-SMITH_TWEAKS; + if (.@left > 6) { + .@left=6; + SMITH_TWEAKS=gettimeparam(GETTIME_HOUR)-6; + } + + mes l("Which item will you tweak?"); + mesc l("Note: You can only perform this operation @@/6 times.", .@left); + mesc l("You recover a tweaking point every hour."); + mesc l("EXPERTS ONLY - If you are not a talented crafter, avoid this."), 1; + mesc l("The item must have a previous bonus, which WILL BE LOST!"), 1; + mesc l("Note: You may fail to write skills to it."), 1; + mesc l("Operation Cost: @@ GP", .@price), 3; + + // Do you have money or AP + if (Zeny < .@price || !.@left) { + mesc l("You lack money or Action Points."), 1; + return false; + } + + .@id=requestitemindex(); + mes ""; + + // Ask player to confirm + if (!csys_Confirm(.@id)) + return false; + + // Collect the item ID + delinventorylist(); + getinventorylist(); + .@x=@inventorylist_id[.@id]; + + // No duplicates + if (countitem(.@x) > 1) { + mesc l("You are carrying duplicates of the same item. Sorry, but I have no idea which one you want to tweak."), 1; + return false; + } + + // Skip equipped items + if (isequipped(.@x)) { + mesc l("You should unequip this item first."), 1; + return false; + } + + // If the item have no bonuses - fail + setarray .@AlwaysTweaks, 65535, BlacksmithAxe, Dustynator, Lightbringer, + DemureAxe, Tyranny, Runestaff, AegisShield, + SaviorShield, SaviorArmor, SaviorBoots, SaviorPants, + Skypiercer; + + // Tweaked items + if (getitemoptionidbyindex(.@id, 0) <= 0 && !is_master() && array_find(.@AlwaysTweaks, .@x) < 0) { + mesc l("This item have no bonuses, and cannot be tweaked."), 1; + return false; + } + + // Take the money and AP away + POL_PlayerMoney(.@price); + if (.@x != Lightbringer) + SMITH_TWEAKS+=1; + + // Apply the bonuses. This will only loop if `continue;` is cast. + // `continue` will only be cast if .@retry is set + do + { + .@retry-=1; + // Check if you fail + if (!csys_Check(.@id)) { + mesc l("YOU FAIL! It is a simple item now."), 1; + if (.@retry) { + mesc l("...Automatically retrying..."); + continue; + } + return false; + } + + csys_Apply(.@id); + mesc l("SUCCESS! Congratulations, the item was improved!"), 3; + if (.@retry) { + next; + mesc l("Do you want to re-roll?"), 1; + if (askyesno() == ASK_YES) { + continue; + } + } + return true; + } while (.@retry > 0); +} |