//:://///////////////////////////////////////////// //:: x2_inc_craft //:: Copyright (c) 2003 Bioare Corp. //::////////////////////////////////////////////// /* Central include for crafting feat and crafting skill system. */ //::////////////////////////////////////////////// //:: Created By: Georg Zoeller //:: Created On: 2003-05-09 //:: Last Updated On: 2003-10-14 //::////////////////////////////////////////////// //#include "x2_inc_itemprop" #include "x2_inc_switches" //#include "prc_inc_spells" struct craft_struct { int nRow; string sResRef; int nDC; int nCost; string sLabel; }; struct craft_receipe_struct { int nMode; object oMajor; object oMinor; }; const string X2_CI_CRAFTSKILL_CONV ="x2_p_craftskills"; // New constants for my Craft Magic revisions. -- Krit const string TK_CRAFTMAGIC_2DA = "tk_craft_magic"; // The Krit's craft magic .2da file. const string TK_CRAFTMAGIC_TAG = "TK_CRAFT_MAGIC_0"; // The beginning of the tag of a crafted magic item. const string TK_CRAFTMAGIC_LEVEL = "TK_CRAFT_MAGIC_Level"; // Local variable to lower caster level. const int TK_WIZARD_SORCERER_SHARE = FALSE; // Set this to TRUE if you want wizards to craft items usable by sorcerers and vice versa. // Brew Potion related Constants const int X2_CI_BREWPOTION_FEAT_ID = 944; // Brew Potion feat const int X2_CI_BREWPOTION_MAXLEVEL = 3; // Max Level for potions const int X2_CI_BREWPOTION_COSTMODIFIER = 50; // Brew Potion Cost Modifier const string X2_CI_BREWPOTION_NEWITEM_RESREF = "x2_it_pcpotion"; // ResRef for new potion item // Scribe Scroll related constants const int X2_CI_SCRIBESCROLL_FEAT_ID = 945; // Scribe Scroll feat const int X2_CI_SCRIBESCROLL_COSTMODIFIER = 25; // Scribe Scroll Cost Modifier const string X2_CI_SCRIBESCROLL_NEWITEM_RESREF = "x2_it_pcscroll"; // ResRef for new scroll item // Craft Wand related constants const int X2_CI_CRAFTWAND_FEAT_ID = 946; // Craft Wand feat const int X2_CI_CRAFTWAND_MAXLEVEL = 4; // Max Level for wands const int X2_CI_CRAFTWAND_COSTMODIFIER = 750; // Craft Wand Cost Modifier const string X2_CI_CRAFTWAND_NEWITEM_RESREF = "x2_it_pcwand"; // ResRef for new wand item // 2da for the craftskills const string X2_CI_CRAFTING_WP_2DA = "des_crft_weapon" ; const string X2_CI_CRAFTING_AR_2DA = "des_crft_armor" ; const string X2_CI_CRAFTING_MAT_2DA = "des_crft_mat"; // 2da for matching spells to properties const string X2_CI_CRAFTING_SP_2DA = "des_crft_spells" ; // Base custom token for item modification conversations (do not change unless you want to change the conversation too) const int X2_CI_CRAFTINGSKILL_CTOKENBASE = 13220; // Base custom token for DC item modification conversations (do not change unless you want to change the conversation too) const int X2_CI_CRAFTINGSKILL_DC_CTOKENBASE = 14220; // Base custom token for DC item modification conversations (do not change unless you want to change the conversation too) const int X2_CI_CRAFTINGSKILL_GP_CTOKENBASE = 14320; // Base custom token for DC item modification conversations (do not change unless you want to change the conversation too) const int X2_CI_MODIFYARMOR_GP_CTOKENBASE = 14420; //How many items per 2da row in X2_IP_CRAFTING_2DA, do not change>4 until you want to create more conversation condition scripts as well const int X2_CI_CRAFTING_ITEMS_PER_ROW = 5; // name of the scroll 2da const string X2_CI_2DA_SCROLLS = "des_crft_scroll"; const int X2_CI_CRAFTMODE_INVALID = 0; const int X2_CI_CRAFTMODE_CONTAINER = 1; // no longer used, but left in for the community to reactivate const int X2_CI_CRAFTMODE_BASE_ITEM = 2; const int X2_CI_CRAFTMODE_ASSEMBLE = 3; const int X2_CI_MAGICTYPE_INVALID = 0; const int X2_CI_MAGICTYPE_ARCANE = 1; const int X2_CI_MAGICTYPE_DIVINE = 2; const int X2_CI_MODMODE_INVALID = 0; const int X2_CI_MODMODE_ARMOR = 1; const int X2_CI_MODMODE_WEAPON = 2; // * Returns TRUE if an item is a Craft Base Item // * to be used in spellscript that can be cast on items - i.e light int CIGetIsCraftFeatBaseItem( object oItem ); // * Checks if the last spell cast was used to brew potion and will do the brewing process. // * Returns TRUE if the spell was indeed used to brew a potion (regardless of the actual outcome of the brewing process) // * Meant to be used in spellscripts only // This function has been superceded by TK_CICraftCheckCraftMagic(). // Uncomment it you still have some use for it, though. -- TK //int CICraftCheckBrewPotion(object oSpellTarget, object oCaster); // * Checks if the last spell cast was used to scribe a scroll and handles the scribe scroll process // * Returns TRUE if the spell was indeed used to scribe a scroll (regardless of the actual outcome) // * Meant to be used in spellscripts only // This function has been superceded by TK_CICraftCheckCraftMagic(). // Uncomment it you still have some use for it, though. -- TK //int CICraftCheckScribeScroll(object oSpellTarget, object oCaster); // * Create a new potion item based on the spell nSpellID on the creator // This function has been superceded by TK_CICraftMagic(). // Uncomment it you still have some use for it, though. -- TK //object CICraftBrewPotion(object oCreator, int nSpellID ); // * Create a new scroll item based on the spell nSpellID on the creator // This function has been superceded by TK_CICraftMagic(). // Uncomment it you still have some use for it, though. -- TK //object CICraftScribeScroll(object oCreator, int nSpellID); // * Checks if the caster intends to use his item creation feats and // * calls appropriate item creation subroutine if conditions are met (spell cast on correct item, etc). // * Returns TRUE if the spell was used for an item creation feat int CIGetSpellWasUsedForItemCreation(object oSpellTarget); // * Returns the innate level of a spell. If bDefaultZeroToOne is given // * Level 0 spell will be returned as level 1 spells int CIGetSpellInnateLevel(int nSpellID, int bDefaultZeroToOne = FALSE) { int nRet = StringToInt(Get2DAString(X2_CI_CRAFTING_SP_2DA, "Level", nSpellID)); if (nRet == 0) nRet =1; return nRet; } // * Makes oPC do a Craft check using nSkill to create the item supplied in sResRe // * If oContainer is specified, the item will be created there. // * Throwing weapons are created with stack sizes of 10, ammo with 20 // * oPC - The player crafting // * nSkill - SKILL_CRAFT_WEAPON or SKILL_CRAFT_ARMOR, // * sResRef - ResRef of the item to be crafted // * nDC - DC to beat to succeed // * oContainer - if a container is specified, create item inside object CIUseCraftItemSkill(object oPC, int nSkill, string sResRef, int nDC, object oContainer = OBJECT_INVALID); // * Returns TRUE if a spell is prevented from being used with one of the crafting feats int CIGetIsSpellRestrictedFromCraftFeat(int nSpellID, int nFeatID); // * Return craftitemstructdata struct craft_struct CIGetCraftItemStructFrom2DA(string s2DA, int nRow, int nItemNo); // ----------------------------------------------------------------------------- // Auxiliary function to identify the column group in TK_SCROLL_2DA to use. // nSpellID is the spell to look up. // nCasterLevel is the caster level to approximate. // ----------------------------------------------------------------------------- string TK_Get2DAColumnGroup(int nSpellID, int nCasterLevel) { // Find the .2da columns corresponding to the caster level. int nGroup = StringToInt(Get2DAString(TK_CRAFTMAGIC_2DA, "NumProps", nSpellID)); int nLevelMin = StringToInt(Get2DAString(TK_CRAFTMAGIC_2DA, "Level" + IntToString(nGroup), nSpellID)); // Loop until we find valid data. while ( nGroup > 1 && nLevelMin == 0 ) nLevelMin = StringToInt(Get2DAString(TK_CRAFTMAGIC_2DA, "Level" + IntToString(--nGroup), nSpellID)); // Loop until we find the right range. while ( nGroup > 1 && nLevelMin > nCasterLevel ) nLevelMin = StringToInt(Get2DAString(TK_CRAFTMAGIC_2DA, "Level" + IntToString(--nGroup), nSpellID)); // Return what we found. return IntToString(nGroup); } // ----------------------------------------------------------------------------- // Looks through oHolder's inventory for an item created from blueprint sResRef // with the tag sTag. // If found, attempts to increase the stack size by 1. // If successful, returns the increased stack. // If failed, looks for another such item. // If no increasable stack is found, returns OBJECT_INVALID. // ----------------------------------------------------------------------------- object TK_IncrementPartialStack(string sResRef, string sTag, object oHolder = OBJECT_SELF) { // Loop through oHolder's inventory. object oItem = GetFirstItemInInventory(oHolder); while ( GetIsObjectValid(oItem) ) { // Look for the right blueprint and tag. if ( GetResRef(oItem) == sResRef && GetTag(oItem) == sTag ) { // Try to increase the stack size. int nSize = GetItemStackSize(oItem); SetItemStackSize(oItem, nSize + 1); // See if successful. if ( GetItemStackSize(oItem) == nSize + 1 ) return oItem; } oItem = GetNextItemInInventory(oHolder); } // Failed to find a partial stack. return OBJECT_INVALID; } // * Return the type of magic as one of the following constants // * const int X2_CI_MAGICTYPE_INVALID = 0; // * const int X2_CI_MAGICTYPE_ARCANE = 1; // * const int X2_CI_MAGICTYPE_DIVINE = 2; // * Parameters: // * nClass - CLASS_TYPE_* constant // ----------------------------------------------------------------------------- // This function might no longer be used. // Uncomment it if I'm wrong. -- TK /* int CI_GetClassMagicType(int nClass) { switch (nClass) { case CLASS_TYPE_CLERIC: return X2_CI_MAGICTYPE_DIVINE; break; case CLASS_TYPE_DRUID: return X2_CI_MAGICTYPE_DIVINE; break; case CLASS_TYPE_PALADIN: return X2_CI_MAGICTYPE_DIVINE; break; case CLASS_TYPE_BARD: return X2_CI_MAGICTYPE_ARCANE; break; case CLASS_TYPE_SORCERER: return X2_CI_MAGICTYPE_ARCANE; break; case CLASS_TYPE_WIZARD: return X2_CI_MAGICTYPE_ARCANE; break; case CLASS_TYPE_RANGER: return X2_CI_MAGICTYPE_DIVINE; break; } return X2_CI_MAGICTYPE_INVALID; } */ // This function might no longer be used. // Uncomment it if I'm wrong. -- TK /* string GetMaterialComponentTag(int nPropID) { string sRet = Get2DAString("des_matcomp","comp_tag",nPropID); return sRet; } */ // ----------------------------------------------------------------------------- // Return true if oItem is a crafting target item // ----------------------------------------------------------------------------- int CIGetIsCraftFeatBaseItem(object oItem) { int nBt = GetBaseItemType(oItem); // blank scroll, empty potion, wand if (nBt == 101 || nBt == 102 || nBt == 103) return TRUE; else return FALSE; } // ----------------------------------------------------------------------------- // Georg, 2003-06-12 // Create a new playermade potion object with properties matching nSpellID and return it // ----------------------------------------------------------------------------- // This function has been superceded by TK_CICraftMagic(). // Uncomment it you still have some use for it, though. -- TK /* object CICraftBrewPotion(object oCreator, int nSpellID ) { int nPropID = IPGetIPConstCastSpellFromSpellID(nSpellID); object oTarget; // * GZ 2003-09-11: If the current spell cast is not acid fog, and // * returned property ID is 0, bail out to prevent // * creation of acid fog items. if (nPropID == 0 && nSpellID != 0) { FloatingTextStrRefOnCreature(84544,oCreator); return OBJECT_INVALID; } if (nPropID != -1) { itemproperty ipProp = ItemPropertyCastSpell(nPropID,IP_CONST_CASTSPELL_NUMUSES_SINGLE_USE); oTarget = CreateItemOnObject(X2_CI_BREWPOTION_NEWITEM_RESREF,oCreator); AddItemProperty(DURATION_TYPE_PERMANENT,ipProp,oTarget); } return oTarget; } */ // ----------------------------------------------------------------------------- // Wrapper for the crafting cost calculation, returns GP required // ----------------------------------------------------------------------------- // This function might no longer be used. // Uncomment it if I'm wrong. -- TK /* int CIGetCraftGPCost(int nLevel, int nMultipler) { int nLvlRow = IPGetIPConstCastSpellFromSpellID(GetSpellId()); int nCLevel = StringToInt(Get2DAString("iprp_spells","CasterLvl",nLvlRow)); // ------------------------------------------------------------------------- // in case we don't get a valid CLevel, use spell level instead // ------------------------------------------------------------------------- if (nCLevel ==0) { nCLevel = nLevel; } int nRet = nCLevel * nLevel * nMod; return nRet; } */ // ----------------------------------------------------------------------------- // Georg, 2003-06-12 // Create a new playermade wand object with properties matching nSpellID // and return it // ----------------------------------------------------------------------------- // This function has been superceded by TK_CICraftMagic(). // Uncomment it you still have some use for it, though. -- TK /* object CICraftCraftWand(object oCreator, int nSpellID ) { int nPropID = IPGetIPConstCastSpellFromSpellID(nSpellID); object oTarget; // * GZ 2003-09-11: If the current spell cast is not acid fog, and // * returned property ID is 0, bail out to prevent // * creation of acid fog items. if (nPropID == 0 && nSpellID != 0) { FloatingTextStrRefOnCreature(84544,oCreator); return OBJECT_INVALID; } if (nPropID != -1) { itemproperty ipProp = ItemPropertyCastSpell(nPropID,IP_CONST_CASTSPELL_NUMUSES_1_CHARGE_PER_USE); oTarget = CreateItemOnObject(X2_CI_CRAFTWAND_NEWITEM_RESREF,oCreator); AddItemProperty(DURATION_TYPE_PERMANENT,ipProp,oTarget); int nType = CI_GetClassMagicType(GetLastSpellCastClass()); itemproperty ipLimit; if (nType == X2_CI_MAGICTYPE_DIVINE) { ipLimit = ItemPropertyLimitUseByClass(CLASS_TYPE_PALADIN); AddItemProperty(DURATION_TYPE_PERMANENT,ipLimit,oTarget); ipLimit = ItemPropertyLimitUseByClass(CLASS_TYPE_RANGER); AddItemProperty(DURATION_TYPE_PERMANENT,ipLimit,oTarget); ipLimit = ItemPropertyLimitUseByClass(CLASS_TYPE_DRUID); AddItemProperty(DURATION_TYPE_PERMANENT,ipLimit,oTarget); ipLimit = ItemPropertyLimitUseByClass(CLASS_TYPE_CLERIC); AddItemProperty(DURATION_TYPE_PERMANENT,ipLimit,oTarget); } else if (nType == X2_CI_MAGICTYPE_ARCANE) { ipLimit = ItemPropertyLimitUseByClass(CLASS_TYPE_WIZARD); AddItemProperty(DURATION_TYPE_PERMANENT,ipLimit,oTarget); ipLimit = ItemPropertyLimitUseByClass(CLASS_TYPE_SORCERER); AddItemProperty(DURATION_TYPE_PERMANENT,ipLimit,oTarget); ipLimit = ItemPropertyLimitUseByClass(CLASS_TYPE_BARD); AddItemProperty(DURATION_TYPE_PERMANENT,ipLimit,oTarget); } int nCharges = GetLevelByClass(GetLastSpellCastClass(),OBJECT_SELF) + d20(); if (nCharges == 0) // stupi cheaters { nCharges = 10+d20(); } // Hard core rule mode enabled if (GetModuleSwitchValue(MODULE_SWITCH_ENABLE_CRAFT_WAND_50_CHARGES)) { SetItemCharges(oTarget,50); } else { SetItemCharges(oTarget,nCharges); } // TODOL Add use restrictions there when item becomes available } return oTarget; } */ // ----------------------------------------------------------------------------- // This function handles the actual creating of scribed scrolls. // ----------------------------------------------------------------------------- // This function has been superceded by TK_CICraftMagic(). // Uncomment it you still have some use for it, though. -- TK /* object CICraftScribeScroll(object oCreator, int nSpellID) { int nPropID = IPGetIPConstCastSpellFromSpellID(nSpellID); object oTarget; // Handle optional material components string sMat = GetMaterialComponentTag(nPropID); if (sMat != "") { object oMat = GetItemPossessedBy(oCreator,sMat); if (oMat== OBJECT_INVALID) { FloatingTextStrRefOnCreature(83374, oCreator); // Missing material component return OBJECT_INVALID; } else { DestroyObject (oMat); } } // get scroll resref from scrolls lookup 2da int nClass =GetLastSpellCastClass (); string sClass = "Wiz_Sorc"; switch (nClass) { case CLASS_TYPE_WIZARD: sClass = "Wiz_Sorc"; break; case CLASS_TYPE_SORCERER: sClass = "Wiz_Sorc"; break; case CLASS_TYPE_CLERIC: sClass = "Cleric"; break; case CLASS_TYPE_PALADIN: sClass = "Paladin"; break; case CLASS_TYPE_DRUID: sClass = "Druid"; break; case CLASS_TYPE_RANGER: sClass = "Ranger"; break; case CLASS_TYPE_BARD: sClass = "Bard"; break; } if (sClass != "") { string sResRef = Get2DAString(X2_CI_2DA_SCROLLS,sClass,nSpellID); if (sResRef != "") { oTarget = CreateItemOnObject(sResRef,oCreator); } if (oTarget == OBJECT_INVALID) { WriteTimestampedLogEntry("x2_inc_craft::CICraftScribeScroll failed - Resref: " + sResRef + " Class: " + sClass + "(" +IntToString(nClass) +") " + " SpellID " + IntToString (nSpellID)); } } return oTarget; } */ // ----------------------------------------------------------------------------- // Returns TRUE if the player used the last spell to brew a potion // ----------------------------------------------------------------------------- // This function has been superceded by TK_CICraftCheckCraftMagic(). // Uncomment it you still have some use for it, though. -- TK /* int CICraftCheckBrewPotion(object oSpellTarget, object oCaster) { object oSpellTarget = PRCGetSpellTargetObject(); object oCaster = OBJECT_SELF; int nID = GetSpellId(); int nLevel = CIGetSpellInnateLevel(nID,TRUE); // ------------------------------------------------------------------------- // check if brew potion feat is there // ------------------------------------------------------------------------- if (GetHasFeat(X2_CI_BREWPOTION_FEAT_ID, oCaster) != TRUE) { FloatingTextStrRefOnCreature(40487, oCaster); // Item Creation Failed - Don't know how to create that type of item return TRUE; } // ------------------------------------------------------------------------- // check if spell is below maxlevel for brew potions // ------------------------------------------------------------------------- if (nLevel > X2_CI_BREWPOTION_MAXLEVEL) { FloatingTextStrRefOnCreature(76416, oCaster); return TRUE; } // ------------------------------------------------------------------------- // Check if the spell is allowed to be used with Brew Potions // ------------------------------------------------------------------------- if (CIGetIsSpellRestrictedFromCraftFeat(nID, X2_CI_BREWPOTION_FEAT_ID)) { FloatingTextStrRefOnCreature(83450, oCaster); return TRUE; } // ------------------------------------------------------------------------- // XP/GP Cost Calculation // ------------------------------------------------------------------------- int nCost = CIGetCraftGPCost(nLevel, X2_CI_BREWPOTION_COSTMODIFIER); float nExperienceCost = 0.04 * nCost; // xp = 1/25 of gp value int nGoldCost = nCost ; // ------------------------------------------------------------------------- // Does Player have enough gold? // ------------------------------------------------------------------------- if (GetGold(oCaster) < nGoldCost) { FloatingTextStrRefOnCreature(3786, oCaster); // Item Creation Failed - not enough gold! return TRUE; } int nHD = GetHitDice(oCaster); int nMinXPForLevel = ((nHD * (nHD - 1)) / 2) * 1000; int nNewXP = FloatToInt(GetXP(oCaster) - nExperienceCost); // ------------------------------------------------------------------------- // check for sufficient XP to cast spell // ------------------------------------------------------------------------- if (nMinXPForLevel > nNewXP || nNewXP == 0 ) { FloatingTextStrRefOnCreature(3785, oCaster); // Item Creation Failed - Not enough XP return TRUE; } // ------------------------------------------------------------------------- // Here we brew the new potion // ------------------------------------------------------------------------- object oPotion = CICraftBrewPotion(oCaster, nID); // ------------------------------------------------------------------------- // Verify Results // ------------------------------------------------------------------------- if (GetIsObjectValid(oPotion)) { TakeGoldFromCreature(nGoldCost, oCaster, TRUE); SetXP(oCaster, nNewXP); DestroyObject (oSpellTarget); FloatingTextStrRefOnCreature(8502, oCaster); // Item Creation successful return TRUE; } else { FloatingTextStrRefOnCreature(76417, oCaster); // Item Creation Failed return TRUE; } } */ // ----------------------------------------------------------------------------- // Returns TRUE if the player used the last spell to create a scroll // ----------------------------------------------------------------------------- // This function has been superceded by TK_CICraftCheckCraftMagic(). // Uncomment it you still have some use for it, though. -- TK /* int CICraftCheckScribeScroll(object oSpellTarget, object oCaster) { int nID = GetSpellId(); // ------------------------------------------------------------------------- // check if scribe scroll feat is there // ------------------------------------------------------------------------- if (GetHasFeat(X2_CI_SCRIBESCROLL_FEAT_ID, oCaster) != TRUE) { FloatingTextStrRefOnCreature(40487, oCaster); // Item Creation Failed - Don't know how to create that type of item return TRUE; } // ------------------------------------------------------------------------- // Check if the spell is allowed to be used with Scribe Scroll // ------------------------------------------------------------------------- if (CIGetIsSpellRestrictedFromCraftFeat(nID, X2_CI_SCRIBESCROLL_FEAT_ID)) { FloatingTextStrRefOnCreature(83451, oCaster); // can not be used with this feat return TRUE; } // ------------------------------------------------------------------------- // XP/GP Cost Calculation // ------------------------------------------------------------------------- int nLevel = CIGetSpellInnateLevel(nID,TRUE); int nCost = CIGetCraftGPCost(nLevel, X2_CI_SCRIBESCROLL_COSTMODIFIER); float fExperienceCost = 0.04 * nCost; int nGoldCost = nCost ; // ------------------------------------------------------------------------- // Does Player have enough gold? // ------------------------------------------------------------------------- if (GetGold(oCaster) < nGoldCost) // enough gold? { FloatingTextStrRefOnCreature(3786, oCaster); // Item Creation Failed - not enough gold! return TRUE; } int nHD = GetHitDice(oCaster); int nMinXPForLevel = ((nHD * (nHD - 1)) / 2) * 1000; int nNewXP = FloatToInt(GetXP(oCaster) - fExperienceCost); // ------------------------------------------------------------------------- // check for sufficient XP to cast spell // ------------------------------------------------------------------------- if (nMinXPForLevel > nNewXP || nNewXP == 0 ) { FloatingTextStrRefOnCreature(3785, oCaster); // Item Creation Failed - Not enough XP return TRUE; } // ------------------------------------------------------------------------- // Here we scribe the scroll // ------------------------------------------------------------------------- object oScroll = CICraftScribeScroll(oCaster, nID); // ------------------------------------------------------------------------- // Verify Results // ------------------------------------------------------------------------- if (GetIsObjectValid(oScroll)) { //---------------------------------------------------------------------- // Some scrollsare ar not identified ... fix that here //---------------------------------------------------------------------- SetIdentified(oScroll,TRUE); ActionPlayAnimation (ANIMATION_FIREFORGET_READ,1.0); TakeGoldFromCreature(nGoldCost, oCaster, TRUE); SetXP(oCaster, nNewXP); DestroyObject (oSpellTarget); FloatingTextStrRefOnCreature(8502, oCaster); // Item Creation successful return TRUE; } else { FloatingTextStrRefOnCreature(76417, oCaster); // Item Creation Failed return TRUE; } return FALSE; } */ // ----------------------------------------------------------------------------- // Returns TRUE if the player used the last spell to craft a wand // ----------------------------------------------------------------------------- // This function has been superceded by TK_CICraftCheckCraftMagic(). // Uncomment it you still have some use for it, though. -- TK /* int CICraftCheckCraftWand(object oSpellTarget, object oCaster) { int nID = GetSpellId(); // ------------------------------------------------------------------------- // check if craft wand feat is there // ------------------------------------------------------------------------- if (GetHasFeat(X2_CI_CRAFTWAND_FEAT_ID, oCaster) != TRUE) { FloatingTextStrRefOnCreature(40487, oCaster); // Item Creation Failed - Don't know how to create that type of item return TRUE; // tried item creation but do not know how to do it } // ------------------------------------------------------------------------- // Check if the spell is allowed to be used with Craft Wand // ------------------------------------------------------------------------- if (CIGetIsSpellRestrictedFromCraftFeat(nID, X2_CI_CRAFTWAND_FEAT_ID)) { FloatingTextStrRefOnCreature(83452, oCaster); // can not be used with this feat return TRUE; } int nLevel = CIGetSpellInnateLevel(nID,TRUE); // ------------------------------------------------------------------------- // check if spell is below maxlevel for brew potions // ------------------------------------------------------------------------- if (nLevel > X2_CI_CRAFTWAND_MAXLEVEL) { FloatingTextStrRefOnCreature(83623, oCaster); return TRUE; } // ------------------------------------------------------------------------- // XP/GP Cost Calculation // ------------------------------------------------------------------------- int nCost = CIGetCraftGPCost( nLevel, X2_CI_CRAFTWAND_COSTMODIFIER); float nExperienceCost = 0.04 * nCost; int nGoldCost = nCost; // ------------------------------------------------------------------------- // Does Player have enough gold? // ------------------------------------------------------------------------- if (GetGold(oCaster) < nGoldCost) // enough gold? { FloatingTextStrRefOnCreature(3786, oCaster); // Item Creation Failed - not enough gold! return TRUE; } // more calculations on XP cost int nHD = GetHitDice(oCaster); int nMinXPForLevel = ((nHD * (nHD - 1)) / 2) * 1000; int nNewXP = FloatToInt(GetXP(oCaster) - nExperienceCost); // ------------------------------------------------------------------------- // check for sufficient XP to cast spell // ------------------------------------------------------------------------- if (nMinXPForLevel > nNewXP || nNewXP == 0 ) { FloatingTextStrRefOnCreature(3785, oCaster); // Item Creation Failed - Not enough XP return TRUE; } // ------------------------------------------------------------------------- // Here we craft the wand // ------------------------------------------------------------------------- object oWand = CICraftCraftWand(oCaster, nID); // ------------------------------------------------------------------------- // Verify Results // ------------------------------------------------------------------------- if (GetIsObjectValid(oWand)) { TakeGoldFromCreature(nGoldCost, oCaster, TRUE); SetXP(oCaster, nNewXP); DestroyObject (oSpellTarget); FloatingTextStrRefOnCreature(8502, oCaster); // Item Creation successful return TRUE; } else { FloatingTextStrRefOnCreature(76417, oCaster); // Item Creation Failed return TRUE; } return FALSE; } */ // ----------------------------------------------------------------------------- // This function handles the actual creating of crafted magic items. // The only check this makes is for optional material components. // // nSpellID is the ID of the spell that was cast. // sColumnGroup is the group of columns in TK_CRAFTMAGIC_2DA to be used. // sResRefColumn is the column in TK_CRAFTMAGIC_2DA containing the preferred blueprint. // sDefaultResRef is the blueprint used if there is no preferred blueprint. // bClassRestricted indicates if the resulting item should be restricted by class. // nCharges is the number of charges to give the resulting item. // If 0, charges are not set. // Should be 0 for stackable items (scrolls, potions). // // If successful, the crafted item is returned. // On failure, OBJECT_INVALID is returned. // ----------------------------------------------------------------------------- object TK_CICraftMagic(int nSpellID, string sColumnGroup, string sResRefColumn, string sDefaultResRef, int bClassRestricted, int nCharges) { // RETRIEVE CONSTRUCTION INFO (mostly from the 2da): // Get the blueprint to use. string sResRef = Get2DAString(TK_CRAFTMAGIC_2DA, sResRefColumn, nSpellID); if ( sResRef == "" ) sResRef = sDefaultResRef; // Get the spell-casting item property. int nIPSpell = StringToInt(Get2DAString(TK_CRAFTMAGIC_2DA, "IProp" + sColumnGroup, nSpellID)); // Retrieve the item property's caster level as a string for later use. string sLevel = Get2DAString(TK_CRAFTMAGIC_2DA, "Level" + sColumnGroup, nSpellID); // Determine the class-limitation item property to add. int nIPClass = -1; if ( bClassRestricted ) switch ( GetLastSpellCastClass() ) { case CLASS_TYPE_BARD: nIPClass = IP_CONST_CLASS_BARD; break; case CLASS_TYPE_CLERIC: nIPClass = IP_CONST_CLASS_CLERIC; break; case CLASS_TYPE_DRUID: nIPClass = IP_CONST_CLASS_DRUID; break; case CLASS_TYPE_PALADIN: nIPClass = IP_CONST_CLASS_PALADIN; break; case CLASS_TYPE_RANGER: nIPClass = IP_CONST_CLASS_RANGER; break; case CLASS_TYPE_SORCERER: nIPClass = IP_CONST_CLASS_SORCERER; break; case CLASS_TYPE_WIZARD: nIPClass = IP_CONST_CLASS_WIZARD; break; } // POSSIBLE ABORT BEFORE CONSUMING REAGENT: // Check for invalid data. if ( sResRef == "" || ( nIPSpell == 0 && nSpellID != 0 ) ) { // Inform the player of a problem. FloatingTextStrRefOnCreature(84544, OBJECT_SELF); // "* Failure - This spell is not supported on wands, scrolls or potions *" // Log the problem and abort. WriteTimestampedLogEntry( "x2_inc_craft::TK_CICraftMagic failed - SpellID: " + IntToString (nSpellID) + "; blueprint: " + sResRef + "; column group: " + sColumnGroup + "; ItemProp: " + IntToString(nIPSpell) + "."); return OBJECT_INVALID; } // CHECK FOR CONSUMABLES: // Handle optional material components. // (Currently, Harm, Time Stop, and True Seeing require dragon's blood.) string sMatCompTag = Get2DAString(TK_CRAFTMAGIC_2DA, "MatComp", nSpellID); if ( sMatCompTag != "" ) { // See if player has the required component. object oMatComp = GetItemPossessedBy(OBJECT_SELF, sMatCompTag); if ( oMatComp == OBJECT_INVALID ) { // No component; inform player and abort. FloatingTextStrRefOnCreature(83374, OBJECT_SELF); return OBJECT_INVALID; } // Consume the material component. DestroyObject(oMatComp); } // ITEM CREATION: // Construct a tag to prevent early stacking. // (The tag is unique for each class/spell/level combo.) string sTag = TK_CRAFTMAGIC_TAG + IntToString(nIPSpell) + "_0" + IntToString(abs(nIPClass)) + "_0" + sLevel; // Check for a stack that can be increased in size (and increment it). object oCrafted = TK_IncrementPartialStack(sResRef, sTag); if ( oCrafted == OBJECT_INVALID ) { // Create an item (with the correct description). oCrafted = CreateItemOnObject(sResRef, OBJECT_SELF, 1, sTag); // Check for an item creation error. if ( oCrafted == OBJECT_INVALID ) { // Log the error and abort. WriteTimestampedLogEntry( "x2_inc_craft::TK_CICraftMagic failed - SpellID: " + IntToString (nSpellID) + "; blueprint: '" + sResRef + "'."); return OBJECT_INVALID; } // Rename the item. string sName = GetName(oCrafted, TRUE); if ( sResRef == sDefaultResRef ) // Since this is the default item, add the spell name. sName += ": " + GetStringByStrRef(StringToInt(Get2DAString("spells", "Name", nSpellID))); sName += " (" + sLevel + ")"; SetName(oCrafted, sName); // Clear the item's properties. itemproperty ipTemp = GetFirstItemProperty(oCrafted); while ( GetIsItemPropertyValid(ipTemp) ) { RemoveItemProperty(oCrafted, ipTemp); ipTemp = GetNextItemProperty(oCrafted); } // Set the charges and item property number of uses. // (Uses then redefines nCharges.) if ( nCharges == 0 ) // Single use item. nCharges = IP_CONST_CASTSPELL_NUMUSES_SINGLE_USE; else { SetItemCharges(oCrafted, nCharges); nCharges = IP_CONST_CASTSPELL_NUMUSES_1_CHARGE_PER_USE; } // Add the spell-casting item property (with the redefined nCharges). AddItemProperty(DURATION_TYPE_PERMANENT, ItemPropertyCastSpell(nIPSpell, nCharges), oCrafted); if ( nIPClass >= 0 ) { // Add the class-limitation item property. AddItemProperty(DURATION_TYPE_PERMANENT, ItemPropertyLimitUseByClass(nIPClass), oCrafted); if ( TK_WIZARD_SORCERER_SHARE ) { // Allow sorcerers and wizards to use each other's items. if ( nIPClass == IP_CONST_CLASS_WIZARD ) AddItemProperty(DURATION_TYPE_PERMANENT, ItemPropertyLimitUseByClass(IP_CONST_CLASS_SORCERER), oCrafted); else if ( nIPClass == IP_CONST_CLASS_SORCERER ) AddItemProperty(DURATION_TYPE_PERMANENT, ItemPropertyLimitUseByClass(IP_CONST_CLASS_WIZARD), oCrafted); } } }//if ( oCrafted == OBJECT_INVALID ) (no partial stack found) // Return the item. return oCrafted; } // ----------------------------------------------------------------------------- // Returns TRUE if the player used the last spell to craft a magic item. // TK -- merge of the scroll, potion, and wand routines. // // oSpellTarget is the item to be crafted from. // ----------------------------------------------------------------------------- int TK_CICraftCheckCraftMagic(object oSpellTarget) { // Info about the spell. int nSpellID = GetSpellId(); int nSpellLevel = CIGetSpellInnateLevel(nSpellID, TRUE); // accesses X2_CI_CRAFTING_SP_2DA // Allow the caster level to be reduced by a local variable on the target. int nCasterLevel = GetLocalInt(oSpellTarget, TK_CRAFTMAGIC_LEVEL); if ( nCasterLevel == 0 || nCasterLevel > PRCGetCasterLevel(OBJECT_SELF) ) nCasterLevel = PRCGetCasterLevel(OBJECT_SELF); // Parameters to be set based on the type of crafting. int nFeat = -1; int nCantUseStrRef = 0; int nMaxLevel = 0; int nMaxLevelStrRef = 0; int nCostModifier = 1; string sDefaultResRef = ""; string sResRefColumn = ""; int bClassRestricted = FALSE; int nCharges = 0; // ------------------------------------------------------------------------- // Set parameters based on target's base item type. // ------------------------------------------------------------------------- switch ( GetBaseItemType(oSpellTarget) ) { case BASE_ITEM_BLANK_POTION: nFeat = X2_CI_BREWPOTION_FEAT_ID; nCantUseStrRef = 83450; // "This spell can not be used with the Brew Potion feat" nMaxLevel = X2_CI_BREWPOTION_MAXLEVEL; nMaxLevelStrRef = 76416;// "* Failure - potions can not hold spells higher than level 3 *" nCostModifier = X2_CI_BREWPOTION_COSTMODIFIER; sDefaultResRef = X2_CI_BREWPOTION_NEWITEM_RESREF; sResRefColumn = "BasePotion"; bClassRestricted = FALSE; nCharges = 0; break; case BASE_ITEM_BLANK_SCROLL: nFeat = X2_CI_SCRIBESCROLL_FEAT_ID; nCantUseStrRef = 83451; // "This spell can not be used with the Scribe Scroll feat" nMaxLevel = 10; nMaxLevelStrRef = 0; nCostModifier = X2_CI_SCRIBESCROLL_COSTMODIFIER; sDefaultResRef = X2_CI_SCRIBESCROLL_NEWITEM_RESREF; sResRefColumn = "BaseScroll"; bClassRestricted = TRUE; nCharges = 0; break; case BASE_ITEM_BLANK_WAND: nFeat = X2_CI_CRAFTWAND_FEAT_ID; nCantUseStrRef = 83452; // "This spell can not be used with the Craft Wand feat" nMaxLevel = X2_CI_CRAFTWAND_MAXLEVEL; nMaxLevelStrRef = 83623;// "* Failure! - wands can not hold spells higher than level 4 *" nCostModifier = X2_CI_CRAFTWAND_COSTMODIFIER; sDefaultResRef = X2_CI_CRAFTWAND_NEWITEM_RESREF; sResRefColumn = "BaseWand"; bClassRestricted = TRUE; if (GetModuleSwitchValue(MODULE_SWITCH_ENABLE_CRAFT_WAND_50_CHARGES)) nCharges = 50; else nCharges = nCasterLevel + d20(); break; // Additional magic crafting types can be defined here. default:// Unrecognized type of crafting. Abort without crafting. return FALSE; } // ------------------------------------------------------------------------- // Make sure we have the required feat. // ------------------------------------------------------------------------- if ( !GetHasFeat(nFeat, OBJECT_SELF) ) { // Failure. Inform player and abort. FloatingTextStrRefOnCreature(40487, OBJECT_SELF); // "* Failure - You do not have the necessary feat to enchant this item *" return TRUE; } // ------------------------------------------------------------------------- // Make sure the spell is allowed to be used with the feat. // ------------------------------------------------------------------------- if ( CIGetIsSpellRestrictedFromCraftFeat(nSpellID, nFeat) ) // accesses X2_CI_CRAFTING_SP_2DA { // Failure. Inform player and abort. FloatingTextStrRefOnCreature(nCantUseStrRef, OBJECT_SELF); return TRUE; } // ------------------------------------------------------------------------- // Make sure spell is below maximum. // ------------------------------------------------------------------------- if ( nSpellLevel > nMaxLevel ) { // Failure. Inform player and abort. FloatingTextStrRefOnCreature(nMaxLevelStrRef, OBJECT_SELF); return TRUE; } // ------------------------------------------------------------------------- // Determine the columns in TK_CRAFTMAGIC_2DA to use. // Located below other .2da access points to optimize .2da caching. // ------------------------------------------------------------------------- string sColumnGroup = TK_Get2DAColumnGroup(nSpellID, nCasterLevel); // accesses TK_SCROLL_2DA // ------------------------------------------------------------------------- // Retrieve the caster level that will be given to the item. // ------------------------------------------------------------------------- int nItemLevel = StringToInt(Get2DAString(TK_CRAFTMAGIC_2DA, "Level" + sColumnGroup, nSpellID)); // Minimum level is 1. if ( nItemLevel < 1 ) nItemLevel = 1; // ------------------------------------------------------------------------- // XP/GP Cost Calculation // ------------------------------------------------------------------------- int nGoldCost = nSpellLevel * nItemLevel * nCostModifier; int nExperienceCost = (nGoldCost + 24) / 25; // 4% of gold cost, rounded up. int nNewXP = GetXP(OBJECT_SELF) - nExperienceCost; // ------------------------------------------------------------------------- // Does Player have enough gold? // ------------------------------------------------------------------------- if ( GetGold(OBJECT_SELF) < nGoldCost ) { // Failure. Inform player and abort. FloatingTextStrRefOnCreature(3786, OBJECT_SELF); // "* Failure! - You do not possess enough gold to create that item *" return TRUE; } // ------------------------------------------------------------------------- // Does player have enough XP? // ------------------------------------------------------------------------- int nHD = GetHitDice(OBJECT_SELF); int nMinXPForLevel = ((nHD * (nHD - 1)) / 2) * 1000; if ( nMinXPForLevel > nNewXP || nNewXP == 0 ) { // Failure. Inform player and abort. FloatingTextStrRefOnCreature(3785, OBJECT_SELF); // "* Failure - Not enough XP to create that item *" return TRUE; } // ------------------------------------------------------------------------- // Here we craft the item // ------------------------------------------------------------------------- object oCrafted = TK_CICraftMagic(nSpellID, sColumnGroup, sResRefColumn, // accesses TK_SCROLL_2DA, then possibly spells.2da sDefaultResRef, bClassRestricted, nCharges); // ------------------------------------------------------------------------- // Verify Results // ------------------------------------------------------------------------- if ( !GetIsObjectValid(oCrafted) ) { // Failure. Inform player and abort. FloatingTextStrRefOnCreature(76417, OBJECT_SELF); // "* Failure - Item creation not successful! *" return TRUE; } // Some scrolls are not identified ... fix that here SetIdentified(oCrafted, TRUE); // Make player pay gold and experience. TakeGoldFromCreature(nGoldCost, OBJECT_SELF, TRUE); SetXP(OBJECT_SELF, nNewXP); // Remove the source item and inform player. DestroyObject (oSpellTarget); FloatingTextStrRefOnCreature(8502, OBJECT_SELF); // "* Success - Item created! *" return TRUE; } // ----------------------------------------------------------------------------- // Georg, July 2003 // Checks if the caster intends to use his item creation feats and // calls appropriate item creation subroutine if conditions are met // (spell cast on correct item, etc). // Returns TRUE if the spell was used for an item creation feat // ----------------------------------------------------------------------------- // Rewritten May 2007 -- The Krit // ----------------------------------------------------------------------------- int CIGetSpellWasUsedForItemCreation(object oSpellTarget) { // ------------------------------------------------------------------------- // Check: Is this item creation? // ------------------------------------------------------------------------- if ( !CIGetIsCraftFeatBaseItem(oSpellTarget) ) // Not a craftable scroll/wand/potion baseitem. Skip further checks. return FALSE; // --------------------------------------------------------------------- // Check: Were item creation feats disabled through x2_inc_switches? // --------------------------------------------------------------------- if ( GetModuleSwitchValue(MODULE_SWITCH_DISABLE_ITEM_CREATION_FEATS) ) { // Item creation disabled; inform player and abort. FloatingTextStrRefOnCreature(83612, OBJECT_SELF); // "* Item creation feats are not enabled in this module *" return FALSE; } // --------------------------------------------------------------------- // Item creation does not work when one item was cast on another. // --------------------------------------------------------------------- if ( PRCGetSpellCastItem() != OBJECT_INVALID ) { // Inform player and abort. FloatingTextStrRefOnCreature(83373, OBJECT_SELF); // "* Failure - Can not use one item to enchant another! *" return TRUE; } // --------------------------------------------------------------------- // Call the generic crafting function. (Will check the base item.) // --------------------------------------------------------------------- return TK_CICraftCheckCraftMagic(oSpellTarget); } // ----------------------------------------------------------------------------- // Makes oPC do a Craft check using nSkill to create the item supplied in sResRe // If oContainer is specified, the item will be created there. // Throwing weapons are created with stack sizes of 10, ammo with 20 // ----------------------------------------------------------------------------- object CIUseCraftItemSkill(object oPC, int nSkill, string sResRef, int nDC, object oContainer = OBJECT_INVALID) { int bSuccess = GetIsSkillSuccessful(oPC, nSkill, nDC); object oNew; if (bSuccess) { // actual item creation // if a crafting container was specified, create inside int bFix; if (oContainer == OBJECT_INVALID) { //------------------------------------------------------------------ // We create the item in the work container to get rid of the // stackable item problems that happen when we create the item // directly on the player //------------------------------------------------------------------ oNew =CreateItemOnObject(sResRef,IPGetIPWorkContainer(oPC)); bFix = TRUE; } else { oNew =CreateItemOnObject(sResRef,oContainer); } int nBase = GetBaseItemType(oNew); if (nBase == BASE_ITEM_BOLT || nBase == BASE_ITEM_ARROW || nBase == BASE_ITEM_BULLET) { SetItemStackSize(oNew, 20); } else if (nBase == BASE_ITEM_THROWINGAXE || nBase == BASE_ITEM_SHURIKEN || nBase == BASE_ITEM_DART) { SetItemStackSize(oNew, 10); } //---------------------------------------------------------------------- // Get around the whole stackable item mess... //---------------------------------------------------------------------- if (bFix) { object oRet = CopyObject(oNew,GetLocation(oPC),oPC); DestroyObject(oNew); oNew = oRet; } } else { oNew = OBJECT_INVALID; } return oNew; } // ----------------------------------------------------------------------------- // georg, 2003-06-13 ( // Craft an item. This is only to be called from the crafting conversation // spawned by x2_s2_crafting!!! // ----------------------------------------------------------------------------- int CIDoCraftItemFromConversation(int nNumber) { string sNumber = IntToString(nNumber); object oPC = GetPCSpeaker(); //object oMaterial = GetLocalObject(oPC,"X2_CI_CRAFT_MATERIAL"); object oMajor = GetLocalObject(oPC,"X2_CI_CRAFT_MAJOR"); object oMinor = GetLocalObject(oPC,"X2_CI_CRAFT_MINOR"); int nSkill = GetLocalInt(oPC,"X2_CI_CRAFT_SKILL"); int nMode = GetLocalInt(oPC,"X2_CI_CRAFT_MODE"); string sResult; string s2DA; int nDC; DeleteLocalObject(oPC,"X2_CI_CRAFT_MAJOR"); DeleteLocalObject(oPC,"X2_CI_CRAFT_MINOR"); if (!GetIsObjectValid(oMajor)) { FloatingTextStrRefOnCreature(83374,oPC); //"Invalid target" DeleteLocalInt(oPC,"X2_CRAFT_SUCCESS"); return FALSE; } else { if (GetItemPossessor(oMajor) != oPC) { FloatingTextStrRefOnCreature(83354,oPC); //"Invalid target" DeleteLocalInt(oPC,"X2_CRAFT_SUCCESS"); return FALSE; } } // If we are in container mode, if (nMode == X2_CI_CRAFTMODE_CONTAINER) { if (!GetIsObjectValid(oMinor)) { FloatingTextStrRefOnCreature(83374,oPC); //"Invalid target" DeleteLocalInt(oPC,"X2_CRAFT_SUCCESS"); return FALSE; } else if (GetItemPossessor(oMinor) != oPC) { FloatingTextStrRefOnCreature(83354,oPC); //"Invalid target" DeleteLocalInt(oPC,"X2_CRAFT_SUCCESS"); return FALSE; } } if (nSkill == 26) // craft weapon { s2DA = X2_CI_CRAFTING_WP_2DA; } else if (nSkill == 25) { s2DA = X2_CI_CRAFTING_AR_2DA; } int nRow = GetLocalInt(oPC,"X2_CI_CRAFT_RESULTROW"); struct craft_struct stItem = CIGetCraftItemStructFrom2DA(s2DA,nRow,nNumber); object oContainer = OBJECT_INVALID; // --------------------------------------------------------------------------- // We once used a crafting container, but found it too complicated. Code is still // left in here for the community // --------------------------------------------------------------------------- if (nMode == X2_CI_CRAFTMODE_CONTAINER) { oContainer = GetItemPossessedBy(oPC,"x2_it_craftcont"); } // Do the crafting... object oRet = CIUseCraftItemSkill( oPC, nSkill, stItem.sResRef, stItem.nDC, oContainer) ; // * If you made an item, it should always be identified; SetIdentified(oRet,TRUE); if (GetIsObjectValid(oRet)) { // ----------------------------------------------------------------------- // Copy all item properties from the major object on the resulting item // Through we problably won't use this, its a neat thing to have for the // community // to enable magic item creation from the crafting system // ----------------------------------------------------------------------- if (GetGold(oPC) GetGoldPieceValue(oOldItem)) { nTotal = GetGoldPieceValue(oOldItem)+1; } return nTotal; } // ----------------------------------------------------------------------------- // returns the cost in gold piece that it would // cost to modify oOlditem to look like oNewItem // ----------------------------------------------------------------------------- int CIGetArmorModificationDC(object oOldItem, object oNewItem) { int nTotal = 0; int nPart; int nDC =0; for (nPart = 0; nPartnTotal) { nTotal = nDC; } } } nTotal = GetItemACValue(oOldItem) + nTotal + 5; return nTotal; } // ----------------------------------------------------------------------------- // returns TRUE if the spell matching nSpellID is prevented from being used // with the CraftFeat matching nFeatID // This is controlled in des_crft_spells.2da // ----------------------------------------------------------------------------- int CIGetIsSpellRestrictedFromCraftFeat(int nSpellID, int nFeatID) { string sCol; if (nFeatID == X2_CI_BREWPOTION_FEAT_ID) { sCol ="NoPotion"; } else if (nFeatID == X2_CI_SCRIBESCROLL_FEAT_ID) { sCol = "NoScroll"; } else if (nFeatID == X2_CI_CRAFTWAND_FEAT_ID) { sCol = "NoWand"; } string sRet = Get2DAString(X2_CI_CRAFTING_SP_2DA,sCol,nSpellID); int nRet = (sRet == "1") ; return nRet; } // ----------------------------------------------------------------------------- // Retrieve the row in des_crft_bmat too look up receipe // ----------------------------------------------------------------------------- int CIGetCraftingReceipeRow(int nMode, object oMajor, object oMinor, int nSkill) { if (nMode == X2_CI_CRAFTMODE_CONTAINER || nMode == X2_CI_CRAFTMODE_ASSEMBLE ) { int nMinorId = StringToInt(Get2DAString("des_crft_amat",GetTag(oMinor),1)); int nMajorId = StringToInt(Get2DAString("des_crft_bmat",GetTag(oMajor),nMinorId)); return nMajorId; } else if (nMode == X2_CI_CRAFTMODE_BASE_ITEM) { int nLookUpRow; string sTag = GetTag(oMajor); switch (nSkill) { case 26: nLookUpRow =1 ; break; case 25: nLookUpRow= 2 ; break; } int nRet = StringToInt(Get2DAString(X2_CI_CRAFTING_MAT_2DA,sTag,nLookUpRow)); return nRet; } else { return 0; // error } } // ----------------------------------------------------------------------------- // used to set all variable required for the crafting conversation // (Used materials, number of choises, 2da row, skill and mode) // ----------------------------------------------------------------------------- void CISetupCraftingConversation(object oPC, int nNumber, int nSkill, int nReceipe, object oMajor, object oMinor, int nMode) { SetLocalObject(oPC,"X2_CI_CRAFT_MAJOR",oMajor); if (nMode == X2_CI_CRAFTMODE_CONTAINER || nMode == X2_CI_CRAFTMODE_ASSEMBLE ) { SetLocalObject(oPC,"X2_CI_CRAFT_MINOR", oMinor); } SetLocalInt(oPC,"X2_CI_CRAFT_NOOFITEMS",nNumber); // number of crafting choises for this material SetLocalInt(oPC,"X2_CI_CRAFT_SKILL",nSkill); // skill used (craft armor or craft waeapon) SetLocalInt(oPC,"X2_CI_CRAFT_RESULTROW",nReceipe); // number of crafting choises for this material SetLocalInt(oPC,"X2_CI_CRAFT_MODE",nMode); } // ----------------------------------------------------------------------------- // oItem - The item used for crafting // ----------------------------------------------------------------------------- struct craft_receipe_struct CIGetCraftingModeFromTarget(object oPC,object oTarget, object oItem = OBJECT_INVALID) { struct craft_receipe_struct stStruct; if (GetBaseItemType(oItem) == 112 ) // small { stStruct.oMajor = oItem; stStruct.nMode = X2_CI_CRAFTMODE_BASE_ITEM; return stStruct; } if (!GetIsObjectValid(oTarget)) { stStruct.nMode = X2_CI_CRAFTMODE_INVALID; return stStruct; } // A small craftitem was used on a large one if (GetBaseItemType(oItem) == 110 ) // small { if (GetBaseItemType(oTarget) == 109) // large { stStruct.nMode = X2_CI_CRAFTMODE_ASSEMBLE; // Mode is ASSEMBLE stStruct.oMajor = oTarget; stStruct.oMinor = oItem; return stStruct; } else { FloatingTextStrRefOnCreature(84201,oPC); } } // ----------------------------------------------------------------------------- // *** CONTAINER IS NO LONGER USED IN OFFICIAL CAMPAIGN // BUT CODE LEFT IN FOR COMMUNITY. // THE FOLLOWING CONDITION IS NEVER TRUE FOR THE OC (no crafting container) // To reactivate, create a container with tag x2_it_craftcont int bCraftCont = (GetTag(oTarget) == "x2_it_craftcont"); if (bCraftCont == TRUE) { // First item in container is baseitem .. mode = baseitem if ( GetBaseItemType(GetFirstItemInInventory(oTarget)) == 112) { stStruct.nMode = X2_CI_CRAFTMODE_BASE_ITEM; stStruct.oMajor = GetFirstItemInInventory(oTarget); return stStruct; } else { object oTest = GetFirstItemInInventory(oTarget); int nCount =1; int bMajor = FALSE; int bMinor = FALSE; // No item in inventory ... mode = fail if (!GetIsObjectValid(oTest)) { FloatingTextStrRefOnCreature(84200,oPC); stStruct.nMode = X2_CI_CRAFTMODE_INVALID; return stStruct; } else { while (GetIsObjectValid(oTest) && nCount <3) { if (GetBaseItemType(oTest) == 109) { stStruct.oMajor = oTest; bMajor = TRUE; } else if (GetBaseItemType(oTest) == 110) { stStruct.oMinor = oTest; bMinor = TRUE; } else if ( GetBaseItemType(oTest) == 112) { stStruct.nMode = X2_CI_CRAFTMODE_BASE_ITEM; stStruct.oMajor = oTest; return stStruct; } oTest = GetNextItemInInventory(oTarget); if (GetIsObjectValid(oTest)) { nCount ++; } } if (nCount >2) { FloatingTextStrRefOnCreature(84356,oPC); stStruct.nMode = X2_CI_CRAFTMODE_INVALID; return stStruct; } else if (nCount <2) { FloatingTextStrRefOnCreature(84356,oPC); stStruct.nMode = X2_CI_CRAFTMODE_INVALID; return stStruct; } if (bMajor && bMinor) { stStruct.nMode = X2_CI_CRAFTMODE_CONTAINER; return stStruct; } else { FloatingTextStrRefOnCreature(84356,oPC); //FloatingTextStringOnCreature("Temp: Wrong combination of items in the crafting container",oPC); stStruct.nMode = X2_CI_CRAFTMODE_INVALID; return stStruct; } } } } else { // not a container but a baseitem if (GetBaseItemType(oTarget) == 112) { stStruct.nMode = X2_CI_CRAFTMODE_BASE_ITEM; stStruct.oMajor = oTarget; return stStruct; } else { if (GetBaseItemType(oTarget) == 109 || GetBaseItemType(oTarget) == 110) { FloatingTextStrRefOnCreature(84357,oPC); stStruct.nMode = X2_CI_CRAFTMODE_INVALID; return stStruct; } else { FloatingTextStrRefOnCreature(84357,oPC); // not a valid item stStruct.nMode = X2_CI_CRAFTMODE_INVALID; return stStruct; } } } } // ----------------------------------------------------------------------------- // *** Crafting Conversation Functions *** // ----------------------------------------------------------------------------- int CIGetInModWeaponOrArmorConv(object oPC) { return GetLocalInt(oPC,"X2_L_CRAFT_MODIFY_CONVERSATION"); } void CISetCurrentModMode(object oPC, int nMode) { if (nMode == X2_CI_MODMODE_INVALID) { DeleteLocalInt(oPC,"X2_L_CRAFT_MODIFY_MODE"); } else { SetLocalInt(oPC,"X2_L_CRAFT_MODIFY_MODE",nMode); } } int CIGetCurrentModMode(object oPC) { return GetLocalInt(oPC,"X2_L_CRAFT_MODIFY_MODE"); } object CIGetCurrentModBackup(object oPC) { return GetLocalObject(GetPCSpeaker(),"X2_O_CRAFT_MODIFY_BACKUP"); } object CIGetCurrentModItem(object oPC) { return GetLocalObject(GetPCSpeaker(),"X2_O_CRAFT_MODIFY_ITEM"); } void CISetCurrentModBackup(object oPC, object oBackup) { SetLocalObject(GetPCSpeaker(),"X2_O_CRAFT_MODIFY_BACKUP",oBackup); } void CISetCurrentModItem(object oPC, object oItem) { SetLocalObject(GetPCSpeaker(),"X2_O_CRAFT_MODIFY_ITEM",oItem); } // ----------------------------------------------------------------------------- // * This does multiple things: // - store the part currently modified // - setup the custom token for the conversation // - zoom the camera to that part // ----------------------------------------------------------------------------- void CISetCurrentModPart(object oPC, int nPart, int nStrRef) { SetLocalInt(oPC,"X2_TAILOR_CURRENT_PART",nPart); if (CIGetCurrentModMode(oPC) == X2_CI_MODMODE_ARMOR) { // * Make the camera float near the PC float fFacing = GetFacing(oPC) + 180.0; if (nPart == ITEM_APPR_ARMOR_MODEL_LSHOULDER || nPart == ITEM_APPR_ARMOR_MODEL_LFOREARM || nPart == ITEM_APPR_ARMOR_MODEL_LHAND || nPart == ITEM_APPR_ARMOR_MODEL_LBICEP) { fFacing += 80.0; } if (nPart == ITEM_APPR_ARMOR_MODEL_RSHOULDER || nPart == ITEM_APPR_ARMOR_MODEL_RFOREARM || nPart == ITEM_APPR_ARMOR_MODEL_RHAND || nPart == ITEM_APPR_ARMOR_MODEL_RBICEP) { fFacing -= 80.0; } float fPitch = 75.0; if (fFacing > 359.0) { fFacing -=359.0; } float fDistance = 3.5f; if (nPart == ITEM_APPR_ARMOR_MODEL_PELVIS || nPart == ITEM_APPR_ARMOR_MODEL_BELT ) { fDistance = 2.0f; } if (nPart == ITEM_APPR_ARMOR_MODEL_LSHOULDER || nPart == ITEM_APPR_ARMOR_MODEL_RSHOULDER ) { fPitch = 50.0f; fDistance = 3.0f; } else if (nPart == ITEM_APPR_ARMOR_MODEL_LFOREARM || nPart == ITEM_APPR_ARMOR_MODEL_LHAND) { fDistance = 2.0f; fPitch = 60.0f; } else if (nPart == ITEM_APPR_ARMOR_MODEL_NECK) { fPitch = 90.0f; } else if (nPart == ITEM_APPR_ARMOR_MODEL_RFOOT || nPart == ITEM_APPR_ARMOR_MODEL_LFOOT ) { fDistance = 3.5f; fPitch = 47.0f; } else if (nPart == ITEM_APPR_ARMOR_MODEL_LTHIGH || nPart == ITEM_APPR_ARMOR_MODEL_RTHIGH ) { fDistance = 2.5f; fPitch = 65.0f; } else if ( nPart == ITEM_APPR_ARMOR_MODEL_RSHIN || nPart == ITEM_APPR_ARMOR_MODEL_LSHIN ) { fDistance = 3.5f; fPitch = 95.0f; } if (GetRacialType(oPC) == RACIAL_TYPE_HALFORC) { fDistance += 1.0f; } SetCameraFacing(fFacing, fDistance, fPitch,CAMERA_TRANSITION_TYPE_VERY_FAST) ; } int nCost = GetLocalInt(oPC,"X2_TAILOR_CURRENT_COST"); int nDC = GetLocalInt(oPC,"X2_TAILOR_CURRENT_DC"); SetCustomToken(X2_CI_MODIFYARMOR_GP_CTOKENBASE,IntToString(nCost)); SetCustomToken(X2_CI_MODIFYARMOR_GP_CTOKENBASE+1,IntToString(nDC)); SetCustomToken(XP_IP_ITEMMODCONVERSATION_CTOKENBASE,GetStringByStrRef(nStrRef)); } int CIGetCurrentModPart(object oPC) { return GetLocalInt(oPC,"X2_TAILOR_CURRENT_PART"); } void CISetDefaultModItemCamera(object oPC) { float fDistance = 3.5f; float fPitch = 75.0f; float fFacing; if (CIGetCurrentModMode(oPC) == X2_CI_MODMODE_ARMOR) { fFacing = GetFacing(oPC) + 180.0; if (fFacing > 359.0) { fFacing -=359.0; } } else if (CIGetCurrentModMode(oPC) == X2_CI_MODMODE_WEAPON) { fFacing = GetFacing(oPC) + 180.0; fFacing -= 90.0; if (fFacing > 359.0) { fFacing -=359.0; } } SetCameraFacing(fFacing, fDistance, fPitch,CAMERA_TRANSITION_TYPE_VERY_FAST) ; } void CIUpdateModItemCostDC(object oPC, int nDC, int nCost) { SetLocalInt(oPC,"X2_TAILOR_CURRENT_COST", nCost); SetLocalInt(oPC,"X2_TAILOR_CURRENT_DC",nDC); SetCustomToken(X2_CI_MODIFYARMOR_GP_CTOKENBASE,IntToString(nCost)); SetCustomToken(X2_CI_MODIFYARMOR_GP_CTOKENBASE+1,IntToString(nDC)); } // dc to modify oOlditem to look like oNewItem int CIGetWeaponModificationCost(object oOldItem, object oNewItem) { int nTotal = 0; int nPart; for (nPart = 0; nPart<=2; nPart++) { if (GetItemAppearance(oOldItem,ITEM_APPR_TYPE_WEAPON_MODEL, nPart) !=GetItemAppearance(oNewItem,ITEM_APPR_TYPE_WEAPON_MODEL, nPart)) { nTotal+= (GetGoldPieceValue(oOldItem)/4)+1; } } // Modification Cost should not exceed value of old item +1 GP if (nTotal > GetGoldPieceValue(oOldItem)) { nTotal = GetGoldPieceValue(oOldItem)+1; } return nTotal; }